fixed bug #451453
[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 D        [0-9]
26 L        [a-zA-Z_]
27 H        [a-fA-F0-9]
28 E        [Ee][+-]?{D}+
29 FS       (f|F|l|L)
30 IS       (u|U|l|L)*
31 %{
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include "common.h"
37 #include "newalloc.h"
38     
39 char *stringLiteral();
40 char *currFname;
41
42 extern int lineno, column;
43 extern char *filename ;
44 extern char *fullSrcFileName ;
45 int   yylineno = 1               ;
46 void count()                     ;
47 int process_pragma(char *);
48 #undef yywrap
49
50 int yywrap YY_PROTO((void))
51 {
52    return(1);
53 }
54 #define TKEYWORD(token) return (isTargetKeyword(yytext) ? token :\
55                                 check_type(yytext))
56 char *asmbuff=NULL;
57 int asmbuffSize=0;
58 char *asmp ;
59 extern int check_type           ();
60  extern int isTargetKeyword     ();
61 extern int checkCurrFile        (char *);
62 extern int processPragma        (char *);
63 extern int printListing         (int   );
64 struct optimize save_optimize ;
65 struct options  save_options  ;
66
67  enum {
68      P_SAVE = 1,
69      P_RESTORE ,
70      P_NOINDUCTION,
71      P_NOINVARIANT,
72      P_INDUCTION ,
73      P_STACKAUTO ,
74      P_NOJTBOUND ,
75      P_NOOVERLAY ,
76      P_NOGCSE    ,
77      P_CALLEE_SAVES,
78      P_EXCLUDE   ,
79      P_LOOPREV
80  };
81
82 %}
83 %x asm
84 %%
85 "_asm"         {  
86   count(); 
87   asmp = asmbuff = Safe_realloc (asmbuff, INITIAL_INLINEASM);
88   asmbuffSize=INITIAL_INLINEASM;
89   BEGIN(asm) ;
90 }
91 <asm>"_endasm" { 
92   count();
93   *asmp = '\0';
94   yylval.yyinline = Safe_calloc (1, strlen(asmbuff)+1);
95   strcpy(yylval.yyinline,asmbuff);
96   BEGIN(INITIAL);
97   return (INLINEASM);
98 }
99 <asm>.         { 
100   if (asmp-asmbuff >= asmbuffSize-2) {
101     // increase the buffersize with 50%
102     int size=asmp-asmbuff;
103     asmbuffSize=asmbuffSize*3/2;
104     asmbuff = Safe_realloc (asmbuff, asmbuffSize); 
105     asmp=asmbuff+size;
106   }
107   *asmp++ = yytext[0];
108 }
109 <asm>\n        { 
110   count(); 
111   if (asmp-asmbuff >= asmbuffSize-3) {
112     // increase the buffersize with 50%
113     int size=asmp-asmbuff;
114     asmbuffSize=asmbuffSize*3/2;
115     asmbuff = Safe_realloc (asmbuff, asmbuffSize); 
116     asmp=asmbuff+size;
117   }
118   *asmp++ = '\n' ;
119 }
120 "at"           { count(); TKEYWORD(AT)  ; }
121 "auto"         { count(); return(AUTO); }
122 "bit"          { count(); TKEYWORD(BIT) ; }
123 "break"        { count(); return(BREAK); }
124 "case"         { count(); return(CASE); }
125 "char"         { count(); return(CHAR); }
126 "code"         { count(); TKEYWORD(CODE); }
127 "const"        { count(); return(CONST); }
128 "continue"     { count(); return(CONTINUE); }
129 "critical"     { count(); TKEYWORD(CRITICAL); } 
130 "data"         { count(); TKEYWORD(DATA);   }
131 "default"      { count(); return(DEFAULT); }
132 "do"           { count(); return(DO); }
133 "double"       { count(); werror(W_DOUBLE_UNSUPPORTED);return(FLOAT); }
134 "else"         { count(); return(ELSE); }
135 "enum"         { count(); return(ENUM); }
136 "extern"       { count(); return(EXTERN); }
137 "far"          { count(); TKEYWORD(XDATA);  }
138 "eeprom"       { count(); TKEYWORD(EEPROM);  }
139 "float"        { count(); return(FLOAT); }
140 "flash"        { count(); TKEYWORD(CODE);}
141 "for"          { count(); return(FOR); }
142 "goto"         { count(); return(GOTO); }
143 "idata"        { count(); TKEYWORD(IDATA);}
144 "if"           { count(); return(IF); }
145 "int"          { count(); return(INT); }
146 "interrupt"    { count(); return(INTERRUPT);}
147 "nonbanked"    { count(); TKEYWORD(NONBANKED);}
148 "banked"       { count(); TKEYWORD(BANKED);}
149 "long"         { count(); return(LONG); }
150 "near"         { count(); TKEYWORD(DATA);}
151 "pdata"        { count(); TKEYWORD(PDATA); }
152 "reentrant"    { count(); TKEYWORD(REENTRANT);}
153 "register"     { count(); return(REGISTER); }
154 "return"       { count(); return(RETURN); }
155 "sfr"          { count(); TKEYWORD(SFR) ; }
156 "sbit"         { count(); TKEYWORD(SBIT)        ; }
157 "short"        { count(); return(SHORT); }
158 "signed"       { count(); return(SIGNED); }
159 "sizeof"       { count(); return(SIZEOF); }
160 "sram"         { count(); TKEYWORD(XDATA);}
161 "static"       { count(); return(STATIC); }
162 "struct"       { count(); return(STRUCT); }
163 "switch"       { count(); return(SWITCH); }
164 "typedef"      { count(); return(TYPEDEF); }
165 "union"        { count(); return(UNION); }
166 "unsigned"     { count(); return(UNSIGNED); }
167 "void"         { count(); return(VOID); }
168 "volatile"     { count(); return(VOLATILE); }
169 "using"        { count(); TKEYWORD(USING); }
170 "_naked"       { count(); TKEYWORD(NAKED); }
171 "while"        { count(); return(WHILE); }
172 "xdata"        { count(); TKEYWORD(XDATA); }
173 "_data"        { count(); TKEYWORD(_NEAR); }
174 "_code"        { count(); TKEYWORD(_CODE); }
175 "_eeprom"      { count(); TKEYWORD(_EEPROM); }
176 "_flash"       { count(); TKEYWORD(_CODE); }
177 "_generic"     { count(); TKEYWORD(_GENERIC); }
178 "_near"        { count(); TKEYWORD(_NEAR); }
179 "_sram"        { count(); TKEYWORD(_XDATA);}
180 "_xdata"       { count(); TKEYWORD(_XDATA);}
181 "_pdata"       { count(); TKEYWORD(_PDATA); }
182 "_idata"       { count(); TKEYWORD(_IDATA); }
183 "..."          { count(); return(VAR_ARGS);}
184 {L}({L}|{D})*  { count(); return(check_type()); }
185 0[xX]{H}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
186 0{D}+{IS}?     { count(); yylval.val = constVal(yytext); return(CONSTANT); }
187 {D}+{IS}?      { count(); yylval.val = constVal(yytext); return(CONSTANT); }
188 '(\\.|[^\\'])+' { count();yylval.val = charVal (yytext); return(CONSTANT); }
189 {D}+{E}{FS}?   { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
190 {D}*"."{D}+({E})?{FS}?  { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
191 {D}+"."{D}*({E})?{FS}?  { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
192 \"             { count(); yylval.val=strVal(stringLiteral()); return(STRING_LITERAL);}
193 ">>=" { count(); yylval.yyint = RIGHT_ASSIGN ; return(RIGHT_ASSIGN); }
194 "<<=" { count(); yylval.yyint = LEFT_ASSIGN  ; return(LEFT_ASSIGN) ; }
195 "+="  { count(); yylval.yyint = ADD_ASSIGN   ; return(ADD_ASSIGN)  ; }
196 "-="  { count(); yylval.yyint = SUB_ASSIGN   ; return(SUB_ASSIGN)  ; }
197 "*="  { count(); yylval.yyint = MUL_ASSIGN   ; return(MUL_ASSIGN)  ; }
198 "/="  { count(); yylval.yyint = DIV_ASSIGN   ; return(DIV_ASSIGN)  ; }
199 "%="  { count(); yylval.yyint = MOD_ASSIGN   ; return(MOD_ASSIGN)  ; }
200 "&="  { count(); yylval.yyint = AND_ASSIGN   ; return(AND_ASSIGN)  ; }
201 "^="  { count(); yylval.yyint = XOR_ASSIGN   ; return(XOR_ASSIGN)  ; }
202 "|="  { count(); yylval.yyint = OR_ASSIGN    ; return(OR_ASSIGN)   ; }
203 ">>"           { count(); return(RIGHT_OP); }
204 "<<"           { count(); return(LEFT_OP); }
205 "++"           { count(); return(INC_OP); }
206 "--"           { count(); return(DEC_OP); }
207 "->"           { count(); return(PTR_OP); }
208 "&&"           { count(); return(AND_OP); }
209 "||"           { count(); return(OR_OP); }
210 "<="           { count(); return(LE_OP); }
211 ">="           { count(); return(GE_OP); }
212 "=="           { count(); return(EQ_OP); }
213 "!="           { count(); return(NE_OP); }
214 ";"            { count(); return(';'); }
215 "{"            { count(); NestLevel++ ;  return('{'); }
216 "}"            { count(); NestLevel--; 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 "<"            { count(); return('<'); }
234 ">"            { count(); return('>'); }
235 "^"            { count(); return('^'); }
236 "|"            { count(); return('|'); }
237 "?"            { count(); return('?'); }
238 ^#line.*"\n"       { count(); checkCurrFile(yytext); }
239 ^#pragma.*"\n"   { count(); process_pragma(yytext); }
240
241 ^[^(]+"("[0-9]+") : error"[^\n]+ { werror(E_PRE_PROC_FAILED,yytext);count(); }
242 ^[^(]+"("[0-9]+") : warning"[^\n]+ { werror(W_PRE_PROC_WARNING,yytext);count(); }
243 "\r\n"             { count(); }
244 "\n"               { count(); }
245 [ \t\v\f]      { count(); }
246 \\ {
247   char ch=input();
248   if (ch!='\n') {
249     // that could have been removed by the preprocessor anyway
250     werror (W_STRAY_BACKSLASH, column);
251     unput(ch);
252   }
253 }
254 .                          { count()    ; }
255 %%
256    
257 int checkCurrFile ( char *s)
258 {
259     char lineNum[10]                    ;
260     int  lNum                           ;
261     char *tptr                          ;
262        
263     /* first check if this is a #line */
264     if ( strncmp(s,"#line",5) )
265         return  0                               ;
266     
267     /* get to the line number */
268     while (!isdigit(*s))
269         s++ ;
270     tptr = lineNum ;
271     while (isdigit(*s))
272         *tptr++ = *s++ ;
273     *tptr = '\0'; 
274     sscanf(lineNum,"%d",&lNum);
275     
276     /* now see if we have a file name */
277     while (*s != '\"' && *s) 
278         s++ ;
279     
280     /* if we don't have a filename then */
281     /* set the current line number to   */
282     /* line number if printFlag is on   */
283     if (!*s) {          
284       lineno = yylineno = lNum ;
285       return 0;
286     }
287     
288     /* if we have a filename then check */
289     /* if it is "standard in" if yes then */
290     /* get the currentfile name info    */
291     s++ ;
292
293     if ( strncmp(s,fullSrcFileName,strlen(fullSrcFileName)) == 0) {
294       lineno = yylineno = lNum;                                 
295       currFname = fullSrcFileName ;
296     }  else {
297         char *sb = s;
298         /* mark the end of the filename */
299         while (*s != '"') s++;
300         *s = '\0';
301         currFname = Safe_calloc(1,strlen(sb)+1);
302         strcpy(currFname,sb);
303         lineno = yylineno = lNum;
304     }
305     filename = currFname ;
306     return 0;
307 }
308     
309 int column = 0;
310 int plineIdx=0;
311
312 void count()
313 {
314   int i;
315   for (i = 0; yytext[i] != '\0'; i++)   {                               
316     if (yytext[i] == '\n')      {         
317       column = 0;
318       lineno = ++yylineno ;
319     }
320     else 
321       if (yytext[i] == '\t')
322         column += 8 - (column % 8);
323       else
324         column++;
325   }
326   /* ECHO; */
327 }
328
329 int check_type()
330 {
331         /* check if it is in the typedef table */
332         if (findSym(TypedefTab,NULL,yytext)) {
333                 strcpy(yylval.yychar,yytext);
334                 return (TYPE_NAME) ;
335         }
336         else   {
337                 strcpy (yylval.yychar,yytext);
338                 return(IDENTIFIER);
339         }
340 }
341
342 char strLitBuff[2048]; // TODO: this is asking for the next bug :)
343
344 /*
345  * Change by JTV 2001-05-19 to not concantenate strings
346  * to support ANSI hex and octal escape sequences in string liteals 
347  */
348
349 char *stringLiteral () {
350   int ch;
351   char *str = strLitBuff;
352   
353   *str++ = '\"';
354   /* put into the buffer till we hit the first \" */
355   
356   while (1) {
357     ch = input();
358     
359     if (!ch)
360       break; /* end of input */
361     
362     /* if it is a \ then escape char's are allowed */
363     if (ch == '\\') {
364       ch=input();
365       if (ch=='\n') {
366         /* \<newline> is a continuator */
367         lineno=++yylineno;
368         column=0;
369         continue;
370       }
371       *str++ = '\\'; /* backslash in place */
372       *str++ = ch; /* get the escape char, no further check */
373       continue; /* carry on */
374     }
375     
376     /* if new line we have a new line break, which is illegal */
377     if (ch == '\n') {
378       werror (W_NEWLINE_IN_STRING);
379       *str++ = '\n';
380       lineno=++yylineno;
381       column=0;
382       continue;
383     }
384     
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     if (ch == '\"') {
389       *str++  = ch ; /* Pass end of this string or substring to evaluator */
390       while ((ch = input()) && (isspace(ch) || ch=='\\')) {
391         switch (ch) {
392         case '\\':
393           if ((ch=input())!='\n') {
394             werror (W_STRAY_BACKSLASH, column);
395             unput(ch);
396           } else {
397             lineno=++yylineno;
398             column=0;
399           }
400           break;
401         case '\n':
402           yylineno++;
403           break;
404         }
405       }
406
407       if (!ch) 
408         break; 
409
410       if (ch != '\"') {
411         unput(ch) ;
412         break ;
413       }
414     }
415     *str++  = ch; /* Put next substring introducer into output string */
416   }  
417   *str = '\0';
418   
419   return strLitBuff;
420 }
421
422 void doPragma (int op, char *cp)
423 {
424     switch (op) {
425     case P_SAVE:
426         memcpy(&save_options,&options,sizeof(options));
427         memcpy(&save_optimize,&optimize,sizeof(optimize));
428         break;
429     case P_RESTORE:
430         memcpy(&options,&save_options,sizeof(options));
431         memcpy(&optimize,&save_optimize,sizeof(optimize));
432         break;
433     case P_NOINDUCTION:
434         optimize.loopInduction = 0 ;
435         break;
436     case P_NOINVARIANT:
437         optimize.loopInvariant = 0 ;
438         break;
439     case P_INDUCTION:
440         optimize.loopInduction = 1 ;
441         break;
442     case P_STACKAUTO:
443         options.stackAuto = 1;
444         break;
445     case P_NOJTBOUND:
446         optimize.noJTabBoundary = 1;
447         break;
448     case P_NOGCSE:
449         optimize.global_cse = 0;
450         break;
451     case P_NOOVERLAY:
452         options.noOverlay = 1;
453         break;
454     case P_CALLEE_SAVES:
455         {
456             int i=0;
457             /* append to the functions already listed
458                in callee-saves */
459             for (; options.calleeSaves[i] ;i++);
460             parseWithComma(&options.calleeSaves[i],strdup(cp));
461         }
462         break;
463     case P_EXCLUDE:
464         parseWithComma(options.excludeRegs,strdup(cp));
465         break;
466     case P_LOOPREV:
467         optimize.noLoopReverse = 1;
468         break;
469     }
470 }
471
472 int process_pragma(char *s)
473 {
474     char *cp ;
475     /* find the pragma */
476     while (strncmp(s,"#pragma",7))
477         s++;
478     s += 7;
479     
480     /* look for the directive */
481     while(isspace(*s)) s++;
482
483     cp = s;
484     /* look for the end of the directive */
485     while ((! isspace(*s)) && 
486            (*s != '\n')) 
487         s++ ;    
488
489     /* First give the port a chance */
490     if (port->process_pragma && !port->process_pragma(cp))
491         return 0;
492
493     /* now compare and do what needs to be done */
494     if (strncmp(cp,PRAGMA_SAVE,strlen(PRAGMA_SAVE)) == 0) {
495         doPragma(P_SAVE,cp+strlen(PRAGMA_SAVE));
496         return 0;
497     }
498
499     if (strncmp(cp,PRAGMA_RESTORE,strlen(PRAGMA_RESTORE)) == 0) {
500         doPragma (P_RESTORE,cp+strlen(PRAGMA_RESTORE));
501         return 0;
502     }
503
504     if (strncmp(cp,PRAGMA_NOINDUCTION,strlen(PRAGMA_NOINDUCTION)) == 0) {
505         doPragma (P_NOINDUCTION,cp+strlen(PRAGMA_NOINDUCTION))  ;
506         return 0;
507     }
508
509     if (strncmp(cp,PRAGMA_NOINVARIANT,strlen(PRAGMA_NOINVARIANT)) == 0) {
510         doPragma (P_NOINVARIANT,NULL)   ;
511         return 0;
512     }
513
514     if (strncmp(cp,PRAGMA_INDUCTION,strlen(PRAGMA_INDUCTION)) == 0) {
515         doPragma (P_INDUCTION,NULL)     ;
516         return 0;
517     }
518
519     if (strncmp(cp,PRAGMA_STACKAUTO,strlen(PRAGMA_STACKAUTO)) == 0) {
520         doPragma (P_STACKAUTO,NULL);
521         return 0;
522     }
523
524     if (strncmp(cp,PRAGMA_NOJTBOUND,strlen(PRAGMA_NOJTBOUND)) == 0) {
525         doPragma (P_NOJTBOUND,NULL);
526         return 0;
527     }
528
529     if (strncmp(cp,PRAGMA_NOGCSE,strlen(PRAGMA_NOGCSE)) == 0) {
530         doPragma (P_NOGCSE,NULL);
531         return 0;
532     }
533
534     if (strncmp(cp,PRAGMA_NOOVERLAY,strlen(PRAGMA_NOOVERLAY)) == 0) {
535         doPragma (P_NOOVERLAY,NULL);
536         return 0;
537     }
538     
539     if (strncmp(cp,PRAGMA_CALLEESAVES,strlen(PRAGMA_CALLEESAVES)) == 0) {
540         doPragma(P_CALLEE_SAVES,cp+strlen(PRAGMA_CALLEESAVES));
541         return 0;
542     }
543     
544     if (strncmp(cp,PRAGMA_EXCLUDE,strlen(PRAGMA_EXCLUDE)) == 0) {
545         doPragma(P_EXCLUDE,cp+strlen(PRAGMA_EXCLUDE));
546         return 0;
547     }
548
549     if (strncmp(cp,PRAGMA_NOLOOPREV,strlen(PRAGMA_NOLOOPREV)) == 0) {
550         doPragma(P_LOOPREV,NULL);
551         return 0;
552     }
553
554     werror(W_UNKNOWN_PRAGMA,cp);
555     return 0;
556 }
557
558 /* will return 1 if the string is a part
559    of a target specific keyword */
560 int isTargetKeyword(char *s)
561 {
562     int i;
563     
564     if (port->keywords == NULL)
565         return 0;
566     for ( i = 0 ; port->keywords[i] ; i++ ) {
567         if (strcmp(port->keywords[i],s) == 0)
568             return 1;
569     }
570     
571     return 0;
572 }
573
574 extern int fatalError;
575
576 int yyerror(char *s)
577 {
578    fflush(stdout);
579
580    if (yylineno && filename)
581         fprintf(stdout,"\n%s(%d) %s: token -> '%s' ; column %d\n",
582                 filename,yylineno,
583                 s,yytext,column);
584    fatalError++;
585    return 0;
586 }