code cleaning, // comments replaced with /* */
[fw/sdcc] / src / SDCC.lex
1 /*-----------------------------------------------------------------------
2   SDCC.lex - lexical analyser for use with sdcc ( a freeware compiler for
3   8/16 bit microcontrollers)
4   Written by : Sandeep Dutta . sandeep.dutta@usa.net (1997)
5   
6   This program is free software; you can redistribute it and/or modify it
7   under the terms of the GNU General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any
9    later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19     
20    In other words, you are welcome to use, share and improve this program.
21    You are forbidden to forbid anyone else to use, share and improve
22    what you give them.   Help stamp out software-hoarding!  
23 -------------------------------------------------------------------------*/
24
25 %option noyywrap
26
27 D        [0-9]
28 L        [a-zA-Z_]
29 H        [a-fA-F0-9]
30 E        [Ee][+-]?{D}+
31 FS       (f|F|l|L)
32 IS       (u|U|l|L)*
33 %{
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include "common.h"
39 #include "newalloc.h"
40 #include "dbuf.h"
41
42 static char *stringLiteral(void);
43 char *currFname;
44
45 extern int lineno, column;
46 extern char *filename;
47 int  mylineno = 1;
48 static void count(void);
49 static int process_pragma(char *);
50 #undef yywrap
51
52 #ifndef YYPROTO
53
54 #ifdef YY_USE_PROTOS
55 #define YY_PROTO(proto) proto
56 #else
57 #define YY_PROTO(proto) ()
58 #endif
59
60 #endif
61
62 int yywrap YY_PROTO((void))
63 {
64    return(1);
65 }
66
67 static void yyunput (int, char *);
68
69 static void my_unput(char c)
70 {
71   yyunput(c, (yytext_ptr));
72 }
73
74 #define TKEYWORD(token) return (isTargetKeyword(yytext) ? token :\
75                                 check_type())
76 char *asmbuff=NULL;
77 int asmbuffSize=0;
78 char *asmp ;
79 static int check_type(void);
80 static int isTargetKeyword(char *s);
81 static int checkCurrFile (char *s);
82 struct optimize save_optimize;
83 struct options  save_options;
84 %}
85
86 %x asm
87 %%
88 "_asm"         {  
89   count(); 
90   asmp = asmbuff = realloc (asmbuff, INITIAL_INLINEASM);
91   asmbuffSize=INITIAL_INLINEASM;
92   BEGIN(asm) ;
93 }
94 <asm>"_endasm" { 
95   count();
96   *asmp = '\0';
97   yylval.yyinline = strdup (asmbuff);
98   BEGIN(INITIAL);
99   return (INLINEASM);
100 }
101 <asm>.         { 
102   if (asmp-asmbuff >= asmbuffSize-2) {
103     /* increase the buffersize with 50% */
104     int size=asmp-asmbuff;
105     asmbuffSize=asmbuffSize*3/2;
106     asmbuff = realloc (asmbuff, asmbuffSize); 
107     asmp=asmbuff+size;
108   }
109   *asmp++ = yytext[0];
110 }
111 <asm>\n        { 
112   count(); 
113   if (asmp-asmbuff >= asmbuffSize-3) {
114     /* increase the buffersize with 50% */
115     int size=asmp-asmbuff;
116     asmbuffSize=asmbuffSize*3/2;
117     asmbuff = realloc (asmbuff, asmbuffSize); 
118     asmp=asmbuff+size;
119   }
120   *asmp++ = '\n' ;
121 }
122 "at"           { count(); TKEYWORD(AT)  ; }
123 "auto"         { count(); return(AUTO); }
124 "bit"          { count(); TKEYWORD(BIT) ; }
125 "break"        { count(); return(BREAK); }
126 "case"         { count(); return(CASE); }
127 "char"         { count(); return(CHAR); }
128 "code"         { count(); TKEYWORD(CODE); }
129 "const"        { count(); return(CONST); }
130 "continue"     { count(); return(CONTINUE); }
131 "critical"     { count(); TKEYWORD(CRITICAL); } 
132 "data"         { count(); TKEYWORD(DATA);   }
133 "default"      { count(); return(DEFAULT); }
134 "do"           { count(); return(DO); }
135 "double"       { count(); werror(W_DOUBLE_UNSUPPORTED);return(FLOAT); }
136 "else"         { count(); return(ELSE); }
137 "enum"         { count(); return(ENUM); }
138 "extern"       { count(); return(EXTERN); }
139 "far"          { count(); TKEYWORD(XDATA);  }
140 "eeprom"       { count(); TKEYWORD(EEPROM);  }
141 "float"        { count(); return(FLOAT); }
142 "flash"        { count(); TKEYWORD(CODE);}
143 "for"          { count(); return(FOR); }
144 "goto"         { count(); return(GOTO); }
145 "idata"        { count(); TKEYWORD(IDATA);}
146 "if"           { count(); return(IF); }
147 "int"          { count(); return(INT); }
148 "interrupt"    { count(); return(INTERRUPT);}
149 "nonbanked"    { count(); TKEYWORD(NONBANKED);}
150 "banked"       { count(); TKEYWORD(BANKED);}
151 "long"         { count(); return(LONG); }
152 "near"         { count(); TKEYWORD(DATA);}
153 "pdata"        { count(); TKEYWORD(PDATA); }
154 "reentrant"    { count(); TKEYWORD(REENTRANT);}
155 "register"     { count(); return(REGISTER); }
156 "return"       { count(); return(RETURN); }
157 "sfr"          { count(); TKEYWORD(SFR) ; }
158 "sbit"         { count(); TKEYWORD(SBIT)        ; }
159 "short"        { count(); return(SHORT); }
160 "signed"       { count(); return(SIGNED); }
161 "sizeof"       { count(); return(SIZEOF); }
162 "sram"         { count(); TKEYWORD(XDATA);}
163 "static"       { count(); return(STATIC); }
164 "struct"       { count(); return(STRUCT); }
165 "switch"       { count(); return(SWITCH); }
166 "typedef"      { count(); return(TYPEDEF); }
167 "union"        { count(); return(UNION); }
168 "unsigned"     { count(); return(UNSIGNED); }
169 "void"         { count(); return(VOID); }
170 "volatile"     { count(); return(VOLATILE); }
171 "using"        { count(); TKEYWORD(USING); }
172 "_naked"       { count(); TKEYWORD(NAKED); }
173 "while"        { count(); return(WHILE); }
174 "xdata"        { count(); TKEYWORD(XDATA); }
175 "..."          { count(); return(VAR_ARGS);}
176 "__typeof"     { count(); return TYPEOF;}
177 "_JavaNative"  { count(); TKEYWORD(JAVANATIVE);}
178 "_overlay"     { count(); TKEYWORD(OVERLAY);}
179 {L}({L}|{D})*  { count(); return(check_type()); }
180 0[xX]{H}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
181 0{D}+{IS}?     { count(); yylval.val = constVal(yytext); return(CONSTANT); }
182 {D}+{IS}?      { count(); yylval.val = constVal(yytext); return(CONSTANT); }
183 '(\\.|[^\\'])+' { count();yylval.val = charVal (yytext); return(CONSTANT); /* ' make syntax highliter happy */}
184 {D}+{E}{FS}?   { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
185 {D}*"."{D}+({E})?{FS}?  { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
186 {D}+"."{D}*({E})?{FS}?  { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
187 \"             { count(); yylval.val=strVal(stringLiteral()); return(STRING_LITERAL);}
188 ">>=" { count(); yylval.yyint = RIGHT_ASSIGN ; return(RIGHT_ASSIGN); }
189 "<<=" { count(); yylval.yyint = LEFT_ASSIGN  ; return(LEFT_ASSIGN) ; }
190 "+="  { count(); yylval.yyint = ADD_ASSIGN   ; return(ADD_ASSIGN)  ; }
191 "-="  { count(); yylval.yyint = SUB_ASSIGN   ; return(SUB_ASSIGN)  ; }
192 "*="  { count(); yylval.yyint = MUL_ASSIGN   ; return(MUL_ASSIGN)  ; }
193 "/="  { count(); yylval.yyint = DIV_ASSIGN   ; return(DIV_ASSIGN)  ; }
194 "%="  { count(); yylval.yyint = MOD_ASSIGN   ; return(MOD_ASSIGN)  ; }
195 "&="  { count(); yylval.yyint = AND_ASSIGN   ; return(AND_ASSIGN)  ; }
196 "^="  { count(); yylval.yyint = XOR_ASSIGN   ; return(XOR_ASSIGN)  ; }
197 "|="  { count(); yylval.yyint = OR_ASSIGN    ; return(OR_ASSIGN)   ; }
198 ">>"           { count(); return(RIGHT_OP); }
199 "<<"           { count(); return(LEFT_OP); }
200 "++"           { count(); return(INC_OP); }
201 "--"           { count(); return(DEC_OP); }
202 "->"           { count(); return(PTR_OP); }
203 "&&"           { count(); return(AND_OP); }
204 "||"           { count(); return(OR_OP); }
205 "<="           { count(); return(LE_OP); }
206 ">="           { count(); return(GE_OP); }
207 "=="           { count(); return(EQ_OP); }
208 "!="           { count(); return(NE_OP); }
209 ";"            { count(); return(';'); }
210 "{"            { count(); NestLevel++ ;  return('{'); }
211 "}"            { count(); NestLevel--; return('}'); }
212 ","            { count(); return(','); }
213 ":"            { count(); return(':'); }
214 "="            { count(); return('='); }
215 "("            { count(); return('('); }
216 ")"            { count(); return(')'); }
217 "["            { count(); return('['); }
218 "]"            { count(); return(']'); }
219 "."            { count(); return('.'); }
220 "&"            { count(); return('&'); }
221 "!"            { count(); return('!'); }
222 "~"            { count(); return('~'); }
223 "-"            { count(); return('-'); }
224 "+"            { count(); return('+'); }
225 "*"            { count(); return('*'); }
226 "/"            { count(); return('/'); }
227 "%"            { count(); return('%'); }
228 "<"            { count(); return('<'); }
229 ">"            { count(); return('>'); }
230 "^"            { count(); return('^'); }
231 "|"            { count(); return('|'); }
232 "?"            { count(); return('?'); }
233 ^#line.*"\n"       { count(); checkCurrFile(yytext); }
234 ^#pragma.*"\n"   { count(); process_pragma(yytext); }
235
236 ^[^(]+"("[0-9]+") : error"[^\n]+ { werror(E_PRE_PROC_FAILED,yytext);count(); }
237 ^[^(]+"("[0-9]+") : warning"[^\n]+ { werror(W_PRE_PROC_WARNING,yytext);count(); }
238 "\r\n"             { count(); }
239 "\n"               { count(); }
240 [ \t\v\f]      { count(); }
241 \\ {
242   char ch=input();
243   if (ch!='\n') {
244     /* that could have been removed by the preprocessor anyway */
245     werror (W_STRAY_BACKSLASH, column);
246     my_unput(ch);
247   }
248 }
249 .                          { count()    ; }
250 %%
251
252 static int checkCurrFile (char *s)
253 {
254     char lineNum[10]                    ;
255     int  lNum                           ;
256     char *tptr                          ;
257        
258     /* first check if this is a #line */
259     if ( strncmp(s,"#line",5) )
260         return  0                               ;
261     
262     /* get to the line number */
263     while (!isdigit(*s))
264         s++ ;
265     tptr = lineNum ;
266     while (isdigit(*s))
267         *tptr++ = *s++ ;
268     *tptr = '\0'; 
269     sscanf(lineNum,"%d",&lNum);
270     
271     /* now see if we have a file name */
272     while (*s != '\"' && *s) 
273         s++ ;
274     
275     /* if we don't have a filename then */
276     /* set the current line number to   */
277     /* line number if printFlag is on   */
278     if (!*s) {          
279       lineno = mylineno = lNum ;
280       return 0;
281     }
282     
283     /* if we have a filename then check */
284     /* if it is "standard in" if yes then */
285     /* get the currentfile name info    */
286     s++ ;
287
288     /* in c1mode fullSrcFileName is NULL */
289     if ( fullSrcFileName &&
290          strncmp(s,fullSrcFileName,strlen(fullSrcFileName)) == 0) {
291       lineno = mylineno = lNum;                                 
292       currFname = fullSrcFileName ;
293     }  else {
294         char *sb = s;
295         /* mark the end of the filename */
296         while (*s != '"') s++;
297         *s = '\0';
298         currFname = strdup (sb);
299         lineno = mylineno = lNum;
300     }
301     filename = currFname ;
302     return 0;
303 }
304     
305 int column = 0;
306 int plineIdx =0;
307
308 static void count(void)
309 {
310   int i;
311   for (i = 0; yytext[i] != '\0'; i++)   {                               
312     if (yytext[i] == '\n')      {         
313       column = 0;
314       lineno = ++mylineno ;
315     }
316     else 
317       if (yytext[i] == '\t')
318         column += 8 - (column % 8);
319       else
320         column++;
321   }
322   /* ECHO; */
323 }
324
325 static int check_type(void)
326 {
327         /* check if it is in the typedef table */
328         if (findSym(TypedefTab,NULL,yytext)) {
329                 strncpyz(yylval.yychar,yytext, SDCC_NAME_MAX);
330                 return (TYPE_NAME) ;
331         }
332         else   {
333                 strncpyz (yylval.yychar,yytext, SDCC_NAME_MAX);
334                 return(IDENTIFIER);
335         }
336 }
337
338 /*
339  * Change by JTV 2001-05-19 to not concantenate strings
340  * to support ANSI hex and octal escape sequences in string liteals 
341  */
342
343 static char *stringLiteral(void)
344 {
345 #define STR_BUF_CHUNCK_LEN  1024
346   int ch;
347   static struct dbuf_s dbuf;
348   char buf[2];
349
350   if (dbuf.alloc == 0)
351     dbuf_init(&dbuf, STR_BUF_CHUNCK_LEN);
352   else
353     dbuf_set_size(&dbuf, 0);
354
355
356   dbuf_append(&dbuf, "\"", 1);
357   /* put into the buffer till we hit the first \" */
358
359   while ((ch = input()) != 0) {
360     switch (ch) {
361     case '\\':
362       /* if it is a \ then escape char's are allowed */
363       ch = input();
364       if (ch == '\n') {
365         /* \<newline> is a continuator */
366         lineno = ++mylineno;
367         column = 0;
368       }
369       else {
370         buf[0] = '\\';
371         buf[1] = ch;
372         dbuf_append(&dbuf, buf, 2); /* get the escape char, no further check */
373       }
374       break; /* carry on */
375
376     case '\n':
377       /* if new line we have a new line break, which is illegal */
378       werror(W_NEWLINE_IN_STRING);
379       dbuf_append(&dbuf, "\n", 1);
380       lineno = ++mylineno;
381       column = 0;
382       break;
383
384     case '"':
385       /* if this is a quote then we have work to do */
386       /* find the next non whitespace character     */
387       /* if that is a double quote then carry on    */
388       dbuf_append(&dbuf, "\"", 1);  /* Pass end of this string or substring to evaluator */
389       while ((ch = input()) && (isspace(ch) || ch=='\\')) {
390         switch (ch) {
391         case '\\':
392           if ((ch = input()) != '\n') {
393             werror(W_STRAY_BACKSLASH, column);
394             my_unput(ch);
395           }
396           else {
397             lineno = ++mylineno;
398             column = 0;
399           }
400           break;
401
402         case '\n':
403           mylineno++;
404           break;
405         }
406       }
407
408       if (!ch) 
409         goto out;
410
411       if (ch != '\"') {
412         my_unput(ch) ;
413         goto out;
414       }
415       break;
416
417     default:
418       buf[0] = ch;
419       dbuf_append(&dbuf, buf, 1);  /* Put next substring introducer into output string */
420     }
421   }
422
423 out:
424   return (char *)dbuf_c_str(&dbuf);
425 }
426
427
428 enum pragma_id {
429      P_SAVE = 1,
430      P_RESTORE ,
431      P_NOINDUCTION,
432      P_NOINVARIANT,
433      P_INDUCTION ,
434      P_STACKAUTO ,
435      P_NOJTBOUND ,
436      P_NOOVERLAY ,
437      P_LESSPEDANTIC,
438      P_NOGCSE    ,
439      P_CALLEE_SAVES,
440      P_EXCLUDE   ,
441      P_NOIV      ,
442      P_LOOPREV   ,
443      P_OVERLAY_      /* I had a strange conflict with P_OVERLAY while */
444                      /* cross-compiling for MINGW32 with gcc 3.2 */
445 };
446
447
448 /* SAVE/RESTORE stack */
449 #define SAVE_RESTORE_SIZE 128
450
451 STACK_DCL(options_stack, struct options *, SAVE_RESTORE_SIZE)
452 STACK_DCL(optimize_stack, struct optimize *, SAVE_RESTORE_SIZE)
453
454 /*
455  * cloneXxx functions should be updated every time a new set is
456  * added to the options or optimize structure!
457  */
458
459 static struct options *cloneOptions(struct options *opt)
460 {
461   struct options *new_opt;
462
463   new_opt = Safe_malloc(sizeof (struct options));
464
465   /* clone scalar values */
466   *new_opt = *opt;
467
468   /* clone sets */
469   new_opt->calleeSavesSet = setFromSetNonRev(opt->calleeSavesSet);
470   new_opt->excludeRegsSet = setFromSetNonRev(opt->excludeRegsSet);
471   /* not implemented yet: */
472   /* new_opt->olaysSet = setFromSetNonRev(opt->olaysSet); */
473
474   return new_opt;
475 }
476
477 static struct optimize *cloneOptimize(struct optimize *opt)
478 {
479   struct optimize *new_opt;
480
481   new_opt = Safe_malloc(sizeof (struct options));
482
483   /* clone scalar values */
484   *new_opt = *opt;
485
486   return new_opt;
487 }
488
489 static void copyAndFreeOptions(struct options *dest, struct options *src)
490 {
491   /* delete dest sets */
492   deleteSet(&dest->calleeSavesSet);
493   deleteSet(&dest->excludeRegsSet);
494   /* not implemented yet: */
495   /* deleteSet(&dest->olaysSet); */
496
497   /* dopy src to dest */
498   *dest = *src;
499
500   Safe_free(src);
501 }
502
503 static void copyAndFreeOptimize(struct optimize *dest, struct optimize *src)
504 {
505   /* dopy src to dest */
506   *dest = *src;
507
508   Safe_free(src);
509 }
510
511 static void doPragma(int op, char *cp)
512 {
513   switch (op) {
514   case P_SAVE:
515     {
516       STACK_PUSH(options_stack, cloneOptions(&options));
517       STACK_PUSH(optimize_stack, cloneOptimize(&optimize));
518     }
519     break;
520
521   case P_RESTORE:
522     {
523       struct options *optionsp;
524       struct optimize *optimizep;
525
526       optionsp = STACK_POP(options_stack);
527       copyAndFreeOptions(&options, optionsp);
528
529       optimizep = STACK_POP(optimize_stack);
530       copyAndFreeOptimize(&optimize, optimizep);
531     }
532     break;
533
534   case P_NOINDUCTION:
535     optimize.loopInduction = 0 ;
536     break;
537
538   case P_NOINVARIANT:
539     optimize.loopInvariant = 0 ;
540     break;
541
542   case P_INDUCTION:
543     optimize.loopInduction = 1 ;
544     break;
545
546   case P_STACKAUTO:
547     options.stackAuto = 1;
548     break;
549
550   case P_NOJTBOUND:
551     optimize.noJTabBoundary = 1;
552     break;
553
554   case P_NOGCSE:
555     optimize.global_cse = 0;
556     break;
557
558   case P_NOOVERLAY:
559     options.noOverlay = 1;
560     break;
561
562   case P_LESSPEDANTIC:
563     options.lessPedantic = 1;
564     break;
565
566   case P_CALLEE_SAVES:
567     /* append to the functions already listed
568        in callee-saves */
569     setParseWithComma(&options.calleeSavesSet, cp);
570     break;
571
572   case P_EXCLUDE:
573     {
574       deleteSet(&options.excludeRegsSet);
575       setParseWithComma(&options.excludeRegsSet, cp);
576     }
577     break;
578
579   case P_NOIV:
580     options.noiv = 1;
581     break;
582
583   case P_LOOPREV:
584     optimize.noLoopReverse = 1;
585     break;
586
587   case P_OVERLAY_:
588     break; /* notyet */
589   }
590 }
591
592 static int process_pragma(char *s)
593 {
594 #define NELEM(x)  (sizeof (x) / sizeof (x)[0])
595 #define PRAGMA    "#pragma"
596
597   static struct pragma_s {
598     const char *name;
599     enum pragma_id id;
600   } pragma_tbl[] = {
601     { "SAVE",           P_SAVE },
602     { "RESTORE",        P_RESTORE },
603     { "NOINDUCTION",    P_NOINDUCTION },
604     { "NOINVARIANT",    P_NOINVARIANT },
605     { "NOLOOPREVERSE",  P_LOOPREV },
606     { "INDUCTION",      P_INDUCTION },
607     { "STACKAUTO",      P_STACKAUTO },
608     { "NOJTBOUND",      P_NOJTBOUND },
609     { "NOGCSE",         P_NOGCSE },
610     { "NOOVERLAY",      P_NOOVERLAY },
611     { "CALLEE-SAVES",   P_CALLEE_SAVES },
612     { "EXCLUDE",        P_EXCLUDE },
613     { "NOIV",           P_NOIV },
614     { "OVERLAY",        P_OVERLAY_ },
615     { "LESS_PEDANTIC",  P_LESSPEDANTIC },
616   };
617   char *cp ;
618   int i;
619
620   /* find the pragma */
621   while (strncmp(s, PRAGMA, (sizeof PRAGMA) - 1))
622     s++;
623   s += (sizeof PRAGMA) - 1;
624     
625   /* look for the directive */
626   while(isspace(*s))
627     s++;
628
629   cp = s;
630   /* look for the end of the directive */
631   while ((!isspace(*s)) && (*s != '\n')) 
632     s++ ;    
633
634   /* First give the port a chance */
635   if (port->process_pragma && !port->process_pragma(cp))
636     return 0;
637
638   for (i = 0; i < NELEM(pragma_tbl); i++) {
639     /* now compare and do what needs to be done */
640     size_t len = strlen(pragma_tbl[i].name);
641
642     if (strncmp(cp, pragma_tbl[i].name, len) == 0) {
643       doPragma(pragma_tbl[i].id, cp + len);
644       return 0;
645     }
646   }
647
648   werror(W_UNKNOWN_PRAGMA,cp);
649   return 0;
650 }
651
652 /* will return 1 if the string is a part
653    of a target specific keyword */
654 static int isTargetKeyword(char *s)
655 {
656     int i;
657     
658     if (port->keywords == NULL)
659         return 0;
660     for ( i = 0 ; port->keywords[i] ; i++ ) {
661         if (strcmp(port->keywords[i],s) == 0)
662             return 1;
663     }
664     
665     return 0;
666 }
667
668 int yyerror(char *s)
669 {
670    fflush(stdout);
671
672    if (mylineno && filename) {
673          if(options.vc_err_style)
674                 fprintf(stdout,"\n%s(%d) : %s: token -> '%s' ; column %d\n",
675                         filename,mylineno,
676                         s,yytext,column);
677           else
678                 fprintf(stdout,"\n%s:%d: %s: token -> '%s' ; column %d\n",
679                         filename,mylineno,
680                         s,yytext,column);
681      fatalError++;
682    } else {
683      /* this comes from an empy file, no problem */
684    }
685    return 0;
686 }