small optimizations, improved regexp handling
[swftools.git] / lib / as3 / tokenizer.lex
1 /* tokenizer.lex
2
3    Routines for compiling Flash2 AVM2 ABC Actionscript
4
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7
8    Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
9  
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
23 %{
24
25
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <stdarg.h>
30 #include "../utf8.h"
31 #include "tokenizer.h"
32 #include "files.h"
33
34 static int verbose = 1;
35 static void dbg(const char*format, ...)
36 {
37     char buf[1024];
38     int l;
39     va_list arglist;
40     if(!verbose)
41         return;
42     va_start(arglist, format);
43     vsprintf(buf, format, arglist);
44     va_end(arglist);
45     l = strlen(buf);
46     while(l && buf[l-1]=='\n') {
47         buf[l-1] = 0;
48         l--;
49     }
50     printf("(tokenizer) ");
51     printf("%s\n", buf);
52     fflush(stdout);
53 }
54
55 void syntaxerror(const char*format, ...)
56 {
57     char buf[1024];
58     int l;
59     va_list arglist;
60     if(!verbose)
61         return;
62     va_start(arglist, format);
63     vsprintf(buf, format, arglist);
64     va_end(arglist);
65     fprintf(stderr, "%s:%d:%d: error: %s\n", current_filename_short, current_line, current_column, buf);
66     fflush(stderr);
67     exit(1);
68 }
69 void warning(const char*format, ...)
70 {
71     return;
72     char buf[1024];
73     int l;
74     va_list arglist;
75     if(!verbose)
76         return;
77     va_start(arglist, format);
78     vsprintf(buf, format, arglist);
79     va_end(arglist);
80     fprintf(stderr, "%s:%d:%d: warning: %s\n", current_filename_short, current_line, current_column, buf);
81     fflush(stderr);
82 }
83
84
85 #ifndef YY_CURRENT_BUFFER
86 #define YY_CURRENT_BUFFER yy_current_buffer
87 #endif
88
89 void handleInclude(char*text, int len, char quotes)
90 {
91     char*filename = 0;
92     if(quotes) {
93         char*p1 = strchr(text, '"');
94         char*p2 = strrchr(text, '"');
95         if(!p1 || !p2 || p1==p2) {
96             syntaxerror("Invalid include in line %d\n", current_line);
97         }
98         *p2 = 0;
99         filename = strdup(p1+1);
100     } else {
101         int i1=0,i2=len;
102         // find start
103         while(!strchr(" \n\r\t", text[i1])) i1++;
104         // strip
105         while(strchr(" \n\r\t", text[i1])) i1++;
106         while(strchr(" \n\r\t", text[i2-1])) i2--;
107         if(i2!=len) text[i2]=0;
108         filename = strdup(&text[i1]);
109     }
110     
111     char*fullfilename = enter_file(filename, YY_CURRENT_BUFFER);
112     yyin = fopen(fullfilename, "rb");
113     if (!yyin) {
114         syntaxerror("Couldn't open include file \"%s\"\n", fullfilename);
115     }
116
117     yy_switch_to_buffer(yy_create_buffer( yyin, YY_BUF_SIZE ) );
118     //BEGIN(INITIAL); keep context
119 }
120
121 static int do_unescape(const char*s, const char*end, char*n) 
122 {
123     char*o = n;
124     int len=0;
125     while(s<end) {
126         if(*s!='\\') {
127             if(o) o[len] = *s;len++;
128             s++;
129             continue;
130         }
131         s++; //skip past '\'
132         if(s==end) syntaxerror("invalid \\ at end of string");
133
134         /* handle the various line endings (mac, dos, unix) */
135         if(*s=='\r') { 
136             s++; 
137             if(s==end) break;
138             if(*s=='\n') 
139                 s++;
140             continue;
141         }
142         if(*s=='\n')  {
143             s++;
144             continue;
145         }
146         switch(*s) {
147             case '\\': if(o) o[len] = '\\';s++;len++; break;
148             case '"': if(o) o[len] = '"';s++;len++; break;
149             case 'b': if(o) o[len] = '\b';s++;len++; break;
150             case 'f': if(o) o[len] = '\f';s++;len++; break;
151             case 'n': if(o) o[len] = '\n';s++;len++; break;
152             case 'r': if(o) o[len] = '\r';s++;len++; break;
153             case 't': if(o) o[len] = '\t';s++;len++; break;
154             case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': {
155                 unsigned int num=0;
156                 int nr = 0;
157                 while(strchr("01234567", *s) && nr<3 && s<end) {
158                     num <<= 3;
159                     num |= *s-'0';
160                     nr++;
161                     s++;
162                 }
163                 if(num>256) 
164                     syntaxerror("octal number out of range (0-255): %d", num);
165                 if(o) o[len] = num;len++;
166                 continue;
167             }
168             case 'x': case 'u': {
169                 int max=2;
170                 char bracket = 0;
171                 char unicode = 0;
172                 if(*s == 'u') {
173                     max = 6;
174                     unicode = 1;
175                 }
176                 s++;
177                 if(s==end) syntaxerror("invalid \\u or \\x at end of string");
178                 if(*s == '{')  {
179                     s++;
180                     if(s==end) syntaxerror("invalid \\u{ at end of string");
181                     bracket=1;
182                 }
183                 unsigned int num=0;
184                 int nr = 0;
185                 while(strchr("0123456789abcdefABCDEF", *s) && (bracket || nr < max) && s<end) {
186                     num <<= 4;
187                     if(*s>='0' && *s<='9') num |= *s - '0';
188                     if(*s>='a' && *s<='f') num |= *s - 'a' + 10;
189                     if(*s>='A' && *s<='F') num |= *s - 'A' + 10;
190                     nr++;
191                     s++;
192                 }
193                 if(bracket) {
194                     if(*s=='}' && s<end) {
195                         s++;
196                     } else {
197                         syntaxerror("missing terminating '}'");
198                     }
199                 }
200                 if(unicode) {
201                     char*utf8 = getUTF8(num);
202                     while(*utf8) {
203                         if(o) o[len] = *utf8;utf8++;len++;
204                     }
205                 } else {
206                     if(num>256) 
207                         syntaxerror("byte out of range (0-255): %d", num);
208                     if(o) o[len] = num;len++;
209                 }
210                 break;
211             }
212             default:
213                 syntaxerror("unknown escape sequence: \"\\%c\"", *s);
214         }
215     }
216     if(o) o[len]=0;
217     return len;
218 }
219
220 static string_t string_unescape(const char*in, int l)
221 {
222     const char*s = in;
223     const char*end = &in[l];
224
225     int len = do_unescape(s, end, 0);
226     char*n = (char*)malloc(len+1);
227     do_unescape(s, end, n);
228     string_t out = string_new(n, len);
229     return out; 
230 }
231
232 static void handleString(char*s, int len)
233 {
234     if(s[0]=='"') {
235         if(s[len-1]!='"') syntaxerror("String doesn't end with '\"'");
236         s++;len-=2;
237     }
238     else if(s[0]=='\'') {
239         if(s[len-1]!='\'') syntaxerror("String doesn't end with '\"'");
240         s++;len-=2;
241     }
242     else syntaxerror("String incorrectly terminated");
243
244     
245     avm2_lval.str = string_unescape(s, len);
246 }
247
248
249 char start_of_expression;
250
251 static inline int mkid(int type)
252 {
253     char*s = malloc(yyleng+1);
254     memcpy(s, yytext, yyleng);
255     s[yyleng]=0;
256     avm2_lval.id = s;
257     return type;
258 }
259
260 static inline int m(int type)
261 {
262     avm2_lval.token = type;
263     return type;
264 }
265
266
267 static char numberbuf[64];
268 static char*nrbuf()
269 {
270     if(yyleng>sizeof(numberbuf)-1)
271         syntaxerror("decimal number overflow");
272     char*s = numberbuf;
273     memcpy(s, yytext, yyleng);
274     s[yyleng]=0;
275     return s;
276 }
277
278 static inline int setint(int v)
279 {
280     avm2_lval.number_int = v;
281     if(v>-128)
282         return T_BYTE;
283     else if(v>=-32768)
284         return T_SHORT;
285     else
286         return T_INT;
287 }
288 static inline int setuint(unsigned int v)
289 {
290     avm2_lval.number_uint = v;
291     if(v<128)
292         return T_BYTE;
293     else if(v<32768)
294         return T_SHORT;
295     else
296         return T_UINT;
297 }
298 static inline int setfloat(double v)
299 {
300     avm2_lval.number_float = v;
301     return T_FLOAT;
302 }
303
304 static inline int handlefloat()
305 {
306     char*s = nrbuf();
307     avm2_lval.number_float = atof(s);
308     return T_FLOAT;
309 }
310
311 static inline int handleint()
312 {
313     char*s = nrbuf();
314     char l = (yytext[0]=='-');
315
316     char*max = l?"1073741824":"2147483647";
317     if(yyleng-l>10) {
318         warning("integer overflow: %s", s);
319         return handlefloat();
320     }
321     if(yyleng-l==10) {
322         int t;
323         for(t=0;t<yyleng-l;t++) {
324             if(yytext[l+t]>max[t]) {
325                 warning("integer overflow: %s", s);
326                 return handlefloat();
327             }
328             else if(yytext[l+t]<max[t])
329                 break;
330         }
331     }
332     if(yytext[0]=='-') {
333         int v = atoi(s);
334         return setint(v);
335     } else {
336         unsigned int v = 0;
337         int t;
338         for(t=0;t<yyleng;t++) {
339             v*=10;
340             v+=yytext[t]-'0';
341         }
342         return setuint(v);
343     }
344 }
345
346 static inline int handlehex()
347 {
348     char l = (yytext[0]=='-')+2;
349
350     if(yyleng-l>8) {
351         char*s = nrbuf();
352         syntaxerror("integer overflow %s", s);
353     }
354
355     int t;
356     unsigned int v = 0;
357     for(t=l;t<yyleng;t++) {
358         v<<=4;
359         char c = yytext[t];
360         if(c>='0' && c<='9')
361             v|=(c&15);
362         else if(c>='a' && c<='f' ||
363                 c>='A' && c<='F')
364             v|=(c&0x0f)+9;
365     }
366     if(l && v>1073741824) {
367         char*s = nrbuf();
368         warning("signed integer overflow: %s", s);
369         return setfloat(v);
370     }
371     if(!l && v>2147483647) {
372         char*s = nrbuf();
373         warning("unsigned integer overflow: %s", s);
374         return setfloat(v);
375     }
376
377     if(l==3) {
378         return setint(-(int)v);
379     } else {
380         return setuint(v);
381     }
382 }
383
384 void handleLabel(char*text, int len)
385 {
386     int t;
387     for(t=len-1;t>=0;--t) {
388         if(text[t]!=' ' &&
389            text[t]!=':')
390             break;
391     }
392     char*s = malloc(t+1);
393     memcpy(s, yytext, t);
394     s[t]=0;
395     avm2_lval.id = s;
396 }
397
398 static int handleregexp()
399 {
400     char*s = malloc(yyleng);
401     int len=yyleng-1;
402     memcpy(s, yytext+1, len);
403     s[len] = 0;
404     int t;
405     for(t=len;t>=0;--t) {
406         if(s[t]=='/') {
407             s[t] = 0;
408             break;
409         }
410     }
411     avm2_lval.regexp.pattern = s;
412     if(t==len) {
413         avm2_lval.regexp.options = 0;
414     } else {
415         avm2_lval.regexp.options = s+t+1;
416     }
417     return T_REGEXP;
418 }
419
420 void initialize_scanner();
421 #define YY_USER_INIT initialize_scanner();
422
423 /* count the number of lines+columns consumed by this token */
424 static inline void l() {
425     int t;
426     for(t=0;t<yyleng;t++) {
427         if(yytext[t]=='\n') {
428             current_line++;
429             current_column=0;
430         } else {
431             current_column++;
432         }
433     }
434 }
435 /* count the number of columns consumed by this token */
436 static inline void c() {
437     current_column+=yyleng;
438 }
439
440 //Boolean                      {c();return m(KW_BOOLEAN);}
441 //int                          {c();return m(KW_INT);}
442 //uint                         {c();return m(KW_UINT);}
443 //Number                       {c();return m(KW_NUMBER);}
444
445
446 %}
447
448 %s REGEXPOK
449 %s BEGINNING
450
451 NAME     [a-zA-Z_][a-zA-Z0-9_\\]*
452 _        [^a-zA-Z0-9_\\]
453
454 HEXINT    0x[a-zA-Z0-9]+
455 INT       [0-9]+
456 FLOAT     [0-9]+(\.[0-9]*)?|\.[0-9]+
457
458 HEXWITHSIGN [+-]?({HEXINT})
459 INTWITHSIGN [+-]?({INT})
460 FLOATWITHSIGN [+-]?({FLOAT})
461
462 STRING   ["](\\[\x00-\xff]|[^\\"\n])*["]|['](\\[\x00-\xff]|[^\\'\n])*[']
463 S        [ \n\r\t]
464 MULTILINE_COMMENT [/][*]+([*][^/]|[^/*]|[^*][/]|[\x00-\x1f])*[*]+[/]
465 SINGLELINE_COMMENT \/\/[^\n]*\n
466 REGEXP   [/]([^/\n]|\\[/])*[/][a-zA-Z]*
467 %%
468
469
470 {SINGLELINE_COMMENT}         {l(); /* single line comment */}
471 {MULTILINE_COMMENT}          {l(); /* multi line comment */}
472 [/][*]                       {syntaxerror("syntax error: unterminated comment", yytext);}
473
474 ^include{S}+{STRING}{S}*/\n    {l();handleInclude(yytext, yyleng, 1);}
475 ^include{S}+[^" \t\r\n][\x20-\xff]*{S}*/\n    {l();handleInclude(yytext, yyleng, 0);}
476 {STRING}                     {l(); BEGIN(INITIAL);handleString(yytext, yyleng);return T_STRING;}
477
478 <BEGINNING,REGEXPOK>{
479 {REGEXP}                     {c(); BEGIN(INITIAL);return handleregexp();} 
480 {HEXWITHSIGN}                {c(); BEGIN(INITIAL);return handlehex();}
481 {INTWITHSIGN}                {c(); BEGIN(INITIAL);return handleint();}
482 {FLOATWITHSIGN}              {c(); BEGIN(INITIAL);return handlefloat();}
483 }
484
485 \xef\xbb\xbf                 {/* utf 8 bom */}
486 {S}                          {l();}
487
488 {HEXINT}                     {c(); BEGIN(INITIAL);return handlehex();}
489 {INT}                        {c(); BEGIN(INITIAL);return handleint();}
490 {FLOAT}                      {c(); BEGIN(INITIAL);return handlefloat();}
491
492 3rr0r                        {/* for debugging: generates a tokenizer-level error */
493                               syntaxerror("3rr0r");}
494
495 {NAME}{S}*:{S}*for/{_}        {l();handleLabel(yytext, yyleng-3);return T_FOR;}
496 {NAME}{S}*:{S}*do/{_}         {l();handleLabel(yytext, yyleng-2);return T_DO;}
497 {NAME}{S}*:{S}*while/{_}      {l();handleLabel(yytext, yyleng-5);return T_WHILE;}
498 {NAME}{S}*:{S}*switch/{_}     {l();handleLabel(yytext, yyleng-6);return T_SWITCH;}
499 for                          {c();avm2_lval.id="";return T_FOR;}
500 do                           {c();avm2_lval.id="";return T_DO;}
501 while                        {c();avm2_lval.id="";return T_WHILE;}
502 switch                       {c();avm2_lval.id="";return T_SWITCH;}
503
504 [&][&]                       {c();BEGIN(REGEXPOK);return m(T_ANDAND);}
505 [|][|]                       {c();BEGIN(REGEXPOK);return m(T_OROR);}
506 [!][=]                       {c();BEGIN(REGEXPOK);return m(T_NE);}
507 [!][=][=]                    {c();BEGIN(REGEXPOK);return m(T_NEE);}
508 [=][=][=]                    {c();BEGIN(REGEXPOK);return m(T_EQEQEQ);}
509 [=][=]                       {c();BEGIN(REGEXPOK);return m(T_EQEQ);}
510 [>][=]                       {c();return m(T_GE);}
511 [<][=]                       {c();return m(T_LE);}
512 [-][-]                       {c();BEGIN(INITIAL);return m(T_MINUSMINUS);}
513 [+][+]                       {c();BEGIN(INITIAL);return m(T_PLUSPLUS);}
514 [+][=]                       {c();return m(T_PLUSBY);}
515 [-][=]                       {c();return m(T_MINUSBY);}
516 [/][=]                       {c();return m(T_DIVBY);}
517 [%][=]                       {c();return m(T_MODBY);}
518 [*][=]                       {c();return m(T_MULBY);}
519 [|][=]                       {c();return m(T_ORBY);}
520 [>][>][=]                    {c();return m(T_SHRBY);}
521 [<][<][=]                    {c();return m(T_SHLBY);}
522 [>][>][>][=]                 {c();return m(T_USHRBY);}
523 [<][<]                       {c();return m(T_SHL);}
524 [>][>][>]                    {c();return m(T_USHR);}
525 [>][>]                       {c();return m(T_SHR);}
526 \.\.\.                       {c();return m(T_DOTDOTDOT);}
527 \.\.                         {c();return m(T_DOTDOT);}
528 \.                           {c();return m('.');}
529 ::                           {c();return m(T_COLONCOLON);}
530 :                            {c();return m(':');}
531 instanceof                   {c();return m(KW_INSTANCEOF);}
532 implements                   {c();return m(KW_IMPLEMENTS);}
533 interface                    {c();return m(KW_INTERFACE);}
534 namespace                    {c();return m(KW_NAMESPACE);}
535 protected                    {c();return m(KW_PROTECTED);}
536 undefined                    {c();return m(KW_UNDEFINED);}
537 continue                     {c();return m(KW_CONTINUE);}
538 override                     {c();return m(KW_OVERRIDE);}
539 internal                     {c();return m(KW_INTERNAL);}
540 function                     {c();return m(KW_FUNCTION);}
541 default                      {c();return m(KW_DEFAULT);}
542 package                      {c();return m(KW_PACKAGE);}
543 private                      {c();return m(KW_PRIVATE);}
544 dynamic                      {c();return m(KW_DYNAMIC);}
545 extends                      {c();return m(KW_EXTENDS);}
546 delete                       {c();return m(KW_DELETE);}
547 return                       {c();return m(KW_RETURN);}
548 public                       {c();return m(KW_PUBLIC);}
549 native                       {c();return m(KW_NATIVE);}
550 static                       {c();return m(KW_STATIC);}
551 import                       {c();return m(KW_IMPORT);}
552 typeof                       {c();return m(KW_TYPEOF);}
553 throw                        {c();return m(KW_THROW);}
554 class                        {c();return m(KW_CLASS);}
555 const                        {c();return m(KW_CONST);}
556 catch                        {c();return m(KW_CATCH);}
557 final                        {c();return m(KW_FINAL);}
558 false                        {c();return m(KW_FALSE);}
559 break                        {c();return m(KW_BREAK);}
560 super                        {c();return m(KW_SUPER);}
561 each                         {c();return m(KW_EACH);}
562 void                         {c();return m(KW_VOID);}
563 true                         {c();return m(KW_TRUE);}
564 null                         {c();return m(KW_NULL);}
565 else                         {c();return m(KW_ELSE);}
566 case                         {c();return m(KW_CASE);}
567 with                         {c();return m(KW_WITH);}
568 use                          {c();return m(KW_USE);}
569 new                          {c();return m(KW_NEW);}
570 get                          {c();return m(KW_GET);}
571 set                          {c();return m(KW_SET);}
572 var                          {c();return m(KW_VAR);}
573 try                          {c();return m(KW_TRY);}
574 is                           {c();return m(KW_IS) ;}
575 in                           {c();return m(KW_IN) ;}
576 if                           {c();return m(KW_IF) ;}
577 as                           {c();return m(KW_AS);}
578 {NAME}                       {c();BEGIN(INITIAL);return mkid(T_IDENTIFIER);}
579
580 [+-\/*^~@$!%&\(=\[\]\{\}|?:;,<>] {c();BEGIN(REGEXPOK);return m(yytext[0]);}
581 [\)\]]                           {c();BEGIN(INITIAL);return m(yytext[0]);}
582
583 .                            {char c1=yytext[0];
584                               char buf[128];
585                               buf[0] = yytext[0];
586                               int t;
587                               for(t=1;t<128;t++) {
588                                   char c = buf[t]=input();
589                                   if(c=='\n' || c==EOF)  {
590                                       buf[t] = 0;
591                                       break;
592                                   }
593                               }
594                               if(c1>='0' && c1<='9')
595                                   syntaxerror("syntax error: %s (identifiers must not start with a digit)");
596                               else
597                                   syntaxerror("syntax error: %s", buf);
598                               printf("\n");
599                               exit(1);
600                               yyterminate();
601                              }
602 <<EOF>>                      {l();
603                               void*b = leave_file();
604                               if (!b) {
605                                  yyterminate();
606                                  yy_delete_buffer(YY_CURRENT_BUFFER);
607                                  return m(T_EOF);
608                               } else {
609                                   yy_delete_buffer(YY_CURRENT_BUFFER);
610                                   yy_switch_to_buffer(b);
611                               }
612                              }
613
614 %%
615
616 int yywrap()
617 {
618     return 1;
619 }
620
621 static char mbuf[256];
622 char*token2string(enum yytokentype nr, YYSTYPE v)
623 {
624     if(nr==T_STRING)     return "<string>";
625     else if(nr==T_INT)     return "<int>";
626     else if(nr==T_UINT)     return "<uint>";
627     else if(nr==T_BYTE)     return "<byte>";
628     else if(nr==T_FLOAT)     return "<float>";
629     else if(nr==T_REGEXP)     return "REGEXP";
630     else if(nr==T_EOF)        return "***END***";
631     else if(nr==T_GE)         return ">=";
632     else if(nr==T_LE)         return "<=";
633     else if(nr==T_MINUSMINUS) return "--";
634     else if(nr==T_PLUSPLUS)   return "++";
635     else if(nr==KW_IMPLEMENTS) return "implements";
636     else if(nr==KW_INTERFACE)  return "interface";
637     else if(nr==KW_NAMESPACE)  return "namespace";
638     else if(nr==KW_PROTECTED)  return "protected";
639     else if(nr==KW_OVERRIDE)   return "override";
640     else if(nr==KW_INTERNAL)   return "internal";
641     else if(nr==KW_FUNCTION)   return "function";
642     else if(nr==KW_PACKAGE)    return "package";
643     else if(nr==KW_PRIVATE)    return "private";
644     else if(nr==KW_BOOLEAN)    return "Boolean";
645     else if(nr==KW_DYNAMIC)    return "dynamic";
646     else if(nr==KW_EXTENDS)    return "extends";
647     else if(nr==KW_PUBLIC)     return "public";
648     else if(nr==KW_NATIVE)     return "native";
649     else if(nr==KW_STATIC)     return "static";
650     else if(nr==KW_IMPORT)     return "import";
651     else if(nr==KW_NUMBER)     return "number";
652     else if(nr==KW_CLASS)      return "class";
653     else if(nr==KW_CONST)      return "const";
654     else if(nr==KW_FINAL)      return "final";
655     else if(nr==KW_FALSE)      return "False";
656     else if(nr==KW_TRUE)       return "True";
657     else if(nr==KW_UINT)       return "uint";
658     else if(nr==KW_NULL)       return "null";
659     else if(nr==KW_ELSE)       return "else";
660     else if(nr==KW_USE)        return "use";
661     else if(nr==KW_INT)        return "int";
662     else if(nr==KW_NEW)        return "new";
663     else if(nr==KW_GET)        return "get";
664     else if(nr==KW_SET)        return "set";
665     else if(nr==KW_VAR)        return "var";
666     else if(nr==KW_IS)         return "is";
667     else if(nr==KW_AS)         return "as";
668     else if(nr==T_IDENTIFIER)  return "ID";
669     else {
670         sprintf(mbuf, "%d", nr);
671         return mbuf;
672     }
673 }
674
675 void initialize_scanner()
676 {
677     BEGIN(BEGINNING);
678 }
679