"unsigned u" and "signed s" are also allowed.
[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                       ;
43 extern char *filename ;
44 extern char *fullSrcFileName ;
45 int   yylineno = 1               ;
46 void count()                     ;
47 void comment();
48 int process_pragma(char *);
49 #undef yywrap
50
51 int yywrap YY_PROTO((void))
52 {
53    return(1);
54 }
55 #define TKEYWORD(token) return (isTargetKeyword(yytext) ? token :\
56                                 check_type(yytext))
57 char *asmbuff=NULL;
58 int asmbuffSize=0;
59 char *asmp ;
60 extern int check_type           ();
61  extern int isTargetKeyword     ();
62 extern int checkCurrFile        (char *);
63 extern int processPragma        (char *);
64 extern int printListing         (int   );
65 struct optimize save_optimize ;
66 struct options  save_options  ;
67
68  enum {
69      P_SAVE = 1,
70      P_RESTORE ,
71      P_NOINDUCTION,
72      P_NOINVARIANT,
73      P_INDUCTION ,
74      P_STACKAUTO ,
75      P_NOJTBOUND ,
76      P_NOOVERLAY ,
77      P_NOGCSE    ,
78      P_CALLEE_SAVES,
79      P_EXCLUDE   ,
80      P_LOOPREV
81  };
82
83 %}
84 %x asm
85 %%
86 "_asm"         {  
87   count(); 
88   asmp = asmbuff = Safe_realloc (asmbuff, INITIAL_INLINEASM);
89   asmbuffSize=INITIAL_INLINEASM;
90   BEGIN(asm) ;
91 }
92 <asm>"_endasm" { 
93   count();
94   *asmp = '\0';
95   yylval.yyinline = Safe_calloc (1, strlen(asmbuff)+1);
96   strcpy(yylval.yyinline,asmbuff);
97   BEGIN(INITIAL);
98   return (INLINEASM);
99 }
100 <asm>.         { 
101   if (asmp-asmbuff >= asmbuffSize-2) {
102     // increase the buffersize with 50%
103     int size=asmp-asmbuff;
104     asmbuffSize=asmbuffSize*3/2;
105     asmbuff = Safe_realloc (asmbuff, asmbuffSize); 
106     asmp=asmbuff+size;
107   }
108   *asmp++ = yytext[0];
109 }
110 <asm>\n        { 
111   count(); 
112   if (asmp-asmbuff >= asmbuffSize-3) {
113     // increase the buffersize with 50%
114     int size=asmp-asmbuff;
115     asmbuffSize=asmbuffSize*3/2;
116     asmbuff = Safe_realloc (asmbuff, asmbuffSize); 
117     asmp=asmbuff+size;
118   }
119   *asmp++ = '\n' ;
120 }
121 "/*"           { comment(); }
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 "_data"        { count(); TKEYWORD(_NEAR); }
176 "_code"        { count(); TKEYWORD(_CODE); }
177 "_eeprom"      { count(); TKEYWORD(_EEPROM); }
178 "_flash"       { count(); TKEYWORD(_CODE); }
179 "_generic"     { count(); TKEYWORD(_GENERIC); }
180 "_near"        { count(); TKEYWORD(_NEAR); }
181 "_sram"        { count(); TKEYWORD(_XDATA);}
182 "_xdata"       { count(); TKEYWORD(_XDATA);}
183 "_pdata"       { count(); TKEYWORD(_PDATA); }
184 "_idata"       { count(); TKEYWORD(_IDATA); }
185 "..."          { count(); return(VAR_ARGS);}
186 {L}({L}|{D})*  { count(); return(check_type()); }
187 0[xX]{H}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
188 0{D}+{IS}?     { count(); yylval.val = constVal(yytext); return(CONSTANT); }
189 {D}+{IS}?      { count(); yylval.val = constVal(yytext); return(CONSTANT); }
190 '(\\.|[^\\'])+' { count();yylval.val = charVal (yytext); return(CONSTANT); }
191 {D}+{E}{FS}?   { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
192 {D}*"."{D}+({E})?{FS}?  { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
193 {D}+"."{D}*({E})?{FS}?  { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
194 \"             { count(); yylval.val=strVal(stringLiteral()); return(STRING_LITERAL);}
195 ">>=" { count(); yylval.yyint = RIGHT_ASSIGN ; return(RIGHT_ASSIGN); }
196 "<<=" { count(); yylval.yyint = LEFT_ASSIGN  ; return(LEFT_ASSIGN) ; }
197 "+="  { count(); yylval.yyint = ADD_ASSIGN   ; return(ADD_ASSIGN)  ; }
198 "-="  { count(); yylval.yyint = SUB_ASSIGN   ; return(SUB_ASSIGN)  ; }
199 "*="  { count(); yylval.yyint = MUL_ASSIGN   ; return(MUL_ASSIGN)  ; }
200 "/="  { count(); yylval.yyint = DIV_ASSIGN   ; return(DIV_ASSIGN)  ; }
201 "%="  { count(); yylval.yyint = MOD_ASSIGN   ; return(MOD_ASSIGN)  ; }
202 "&="  { count(); yylval.yyint = AND_ASSIGN   ; return(AND_ASSIGN)  ; }
203 "^="  { count(); yylval.yyint = XOR_ASSIGN   ; return(XOR_ASSIGN)  ; }
204 "|="  { count(); yylval.yyint = OR_ASSIGN    ; return(OR_ASSIGN)   ; }
205 ">>"           { count(); return(RIGHT_OP); }
206 "<<"           { count(); return(LEFT_OP); }
207 "++"           { count(); return(INC_OP); }
208 "--"           { count(); return(DEC_OP); }
209 "->"           { count(); return(PTR_OP); }
210 "&&"           { count(); return(AND_OP); }
211 "||"           { count(); return(OR_OP); }
212 "<="           { count(); return(LE_OP); }
213 ">="           { count(); return(GE_OP); }
214 "=="           { count(); return(EQ_OP); }
215 "!="           { count(); return(NE_OP); }
216 ";"            { count(); return(';'); }
217 "{"            { count(); NestLevel++ ;  return('{'); }
218 "}"            { count(); NestLevel--; 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 "|"            { count(); return('|'); }
239 "?"            { count(); return('?'); }
240 ^#line.*"\n"       { count(); checkCurrFile(yytext); }
241 ^#pragma.*"\n"   { count(); process_pragma(yytext); }
242
243 ^[^(]+"("[0-9]+") : error"[^\n]+ { werror(E_PRE_PROC_FAILED,yytext);count(); }
244 ^[^(]+"("[0-9]+") : warning"[^\n]+ { werror(W_PRE_PROC_WARNING,yytext);count(); }
245 "\r\n"             { count(); }
246 "\n"               { count(); }
247 [ \t\v\f]      { count(); }
248 .                          { count()    ; }
249 %%
250    
251 int checkCurrFile ( char *s)
252 {
253     char lineNum[10]                    ;
254     int  lNum                           ;
255     char *tptr                          ;
256        
257     /* first check if this is a #line */
258     if ( strncmp(s,"#line",5) )
259         return  0                               ;
260     
261     /* get to the line number */
262     while (!isdigit(*s))
263         s++ ;
264     tptr = lineNum ;
265     while (isdigit(*s))
266         *tptr++ = *s++ ;
267     *tptr = '\0'; 
268     sscanf(lineNum,"%d",&lNum);
269     
270     /* now see if we have a file name */
271     while (*s != '\"' && *s) 
272         s++ ;
273     
274     /* if we don't have a filename then */
275     /* set the current line number to   */
276     /* line number if printFlag is on   */
277     if (!*s) {          
278         yylineno = lNum ;
279         return 0;
280     }
281     
282     /* if we have a filename then check */
283     /* if it is "standard in" if yes then */
284     /* get the currentfile name info    */
285     s++ ;
286
287     if ( strncmp(s,fullSrcFileName,strlen(fullSrcFileName)) == 0) {
288             yylineno = lNum - 2;                                        
289             currFname = fullSrcFileName ;
290     }  else {
291         char *sb = s;
292         /* mark the end of the filename */
293         while (*s != '"') s++;
294         *s = '\0';
295         currFname = Safe_calloc(1,strlen(sb)+1);
296         strcpy(currFname,sb);
297         yylineno = lNum - 2;
298     }
299     filename = currFname ;
300     return 0;
301 }
302     
303 void comment()
304 {
305         char c, c1;
306
307 loop:
308         while ((c = input()) != '*' && c != 0)
309                 if ( c == '\n')
310                         yylineno++ ;
311
312         if ((c1 = input()) != '/' && c != 0)  {
313                 if ( c1 == '\n' )
314                         yylineno++ ;
315
316                 unput(c1);
317                 goto loop;
318    }
319
320 }
321    
322    
323
324 int column = 0;
325 int plineIdx=0;
326
327 void count()
328 {
329         int i;
330         for (i = 0; yytext[i] != '\0'; i++)   {                         
331                 if (yytext[i] == '\n')      {         
332                    column = 0;
333                    lineno = ++yylineno ;
334                 }
335                 else 
336                         if (yytext[i] == '\t')
337                                 column += 8 - (column % 8);
338                         else
339                                 column++;
340    }
341          
342    /* ECHO; */
343 }
344
345 int check_type()
346 {
347         /* check if it is in the typedef table */
348         if (findSym(TypedefTab,NULL,yytext)) {
349                 strcpy(yylval.yychar,yytext);
350                 return (TYPE_NAME) ;
351         }
352         else   {
353                 strcpy (yylval.yychar,yytext);
354                 return(IDENTIFIER);
355         }
356 }
357
358 char strLitBuff[2048]                   ;
359
360 /*
361  * Change by JTV 2001-05-19 to not concantenate strings
362  * to support ANSI hex and octal escape sequences in string liteals 
363  */
364
365 char *stringLiteral ()
366
367 {
368 int ch;
369 char *str = strLitBuff                  ;
370
371 *str++ = '\"'                   ;
372 /* put into the buffer till we hit the */
373 /* first \" */
374
375 while (1) 
376   {
377   ch = input()                  ;
378
379   if (!ch)
380     break       ; /* end of input */
381
382   /* if it is a \ then everything allowed */
383
384   if (ch == '\\') 
385     {
386     *str++ = ch     ; /* backslash in place */
387     *str++ = input()            ; /* following char in place */
388     continue                    ;      /* carry on */
389     }
390
391   /* if new line we have a new line break */
392   if (ch == '\n') 
393     break               ;
394
395   /* if this is a quote then we have work to do */
396   /* find the next non whitespace character     */
397   /* if that is a double quote then carry on    */
398
399   if (ch == '\"') 
400     {
401     *str++  = ch ;      /* Pass end of this string or substring to evaluator */
402
403     while ((ch = input()) && isspace(ch)) ;
404
405     if (!ch) 
406       break ; 
407
408     if (ch != '\"') 
409       {
410       unput(ch) ;
411       break ;
412       }
413     }
414
415   *str++  = ch;       /* Put next substring introducer into output string */
416   }  
417
418 *str = '\0';
419
420 return strLitBuff                       ;
421 }
422
423 void doPragma (int op, char *cp)
424 {
425     switch (op) {
426     case P_SAVE:
427         memcpy(&save_options,&options,sizeof(options));
428         memcpy(&save_optimize,&optimize,sizeof(optimize));
429         break;
430     case P_RESTORE:
431         memcpy(&options,&save_options,sizeof(options));
432         memcpy(&optimize,&save_optimize,sizeof(optimize));
433         break;
434     case P_NOINDUCTION:
435         optimize.loopInduction = 0 ;
436         break;
437     case P_NOINVARIANT:
438         optimize.loopInvariant = 0 ;
439         break;
440     case P_INDUCTION:
441         optimize.loopInduction = 1 ;
442         break;
443     case P_STACKAUTO:
444         options.stackAuto = 1;
445         break;
446     case P_NOJTBOUND:
447         optimize.noJTabBoundary = 1;
448         break;
449     case P_NOGCSE:
450         optimize.global_cse = 0;
451         break;
452     case P_NOOVERLAY:
453         options.noOverlay = 1;
454         break;
455     case P_CALLEE_SAVES:
456         {
457             int i=0;
458             /* append to the functions already listed
459                in callee-saves */
460             for (; options.calleeSaves[i] ;i++);
461             parseWithComma(&options.calleeSaves[i],strdup(cp));
462         }
463         break;
464     case P_EXCLUDE:
465         parseWithComma(options.excludeRegs,strdup(cp));
466         break;
467     case P_LOOPREV:
468         optimize.noLoopReverse = 1;
469         break;
470     }
471 }
472
473 int process_pragma(char *s)
474 {
475     char *cp ;
476     /* find the pragma */
477     while (strncmp(s,"#pragma",7))
478         s++;
479     s += 7;
480     
481     /* look for the directive */
482     while(isspace(*s)) s++;
483
484     cp = s;
485     /* look for the end of the directive */
486     while ((! isspace(*s)) && 
487            (*s != '\n')) 
488         s++ ;    
489
490     /* First give the port a chance */
491     if (port->process_pragma && !port->process_pragma(cp))
492         return 0;
493
494     /* now compare and do what needs to be done */
495     if (strncmp(cp,PRAGMA_SAVE,strlen(PRAGMA_SAVE)) == 0) {
496         doPragma(P_SAVE,cp+strlen(PRAGMA_SAVE));
497         return 0;
498     }
499
500     if (strncmp(cp,PRAGMA_RESTORE,strlen(PRAGMA_RESTORE)) == 0) {
501         doPragma (P_RESTORE,cp+strlen(PRAGMA_RESTORE));
502         return 0;
503     }
504
505     if (strncmp(cp,PRAGMA_NOINDUCTION,strlen(PRAGMA_NOINDUCTION)) == 0) {
506         doPragma (P_NOINDUCTION,cp+strlen(PRAGMA_NOINDUCTION))  ;
507         return 0;
508     }
509
510     if (strncmp(cp,PRAGMA_NOINVARIANT,strlen(PRAGMA_NOINVARIANT)) == 0) {
511         doPragma (P_NOINVARIANT,NULL)   ;
512         return 0;
513     }
514
515     if (strncmp(cp,PRAGMA_INDUCTION,strlen(PRAGMA_INDUCTION)) == 0) {
516         doPragma (P_INDUCTION,NULL)     ;
517         return 0;
518     }
519
520     if (strncmp(cp,PRAGMA_STACKAUTO,strlen(PRAGMA_STACKAUTO)) == 0) {
521         doPragma (P_STACKAUTO,NULL);
522         return 0;
523     }
524
525     if (strncmp(cp,PRAGMA_NOJTBOUND,strlen(PRAGMA_NOJTBOUND)) == 0) {
526         doPragma (P_NOJTBOUND,NULL);
527         return 0;
528     }
529
530     if (strncmp(cp,PRAGMA_NOGCSE,strlen(PRAGMA_NOGCSE)) == 0) {
531         doPragma (P_NOGCSE,NULL);
532         return 0;
533     }
534
535     if (strncmp(cp,PRAGMA_NOOVERLAY,strlen(PRAGMA_NOOVERLAY)) == 0) {
536         doPragma (P_NOOVERLAY,NULL);
537         return 0;
538     }
539     
540     if (strncmp(cp,PRAGMA_CALLEESAVES,strlen(PRAGMA_CALLEESAVES)) == 0) {
541         doPragma(P_CALLEE_SAVES,cp+strlen(PRAGMA_CALLEESAVES));
542         return 0;
543     }
544     
545     if (strncmp(cp,PRAGMA_EXCLUDE,strlen(PRAGMA_EXCLUDE)) == 0) {
546         doPragma(P_EXCLUDE,cp+strlen(PRAGMA_EXCLUDE));
547         return 0;
548     }
549
550     if (strncmp(cp,PRAGMA_NOLOOPREV,strlen(PRAGMA_NOLOOPREV)) == 0) {
551         doPragma(P_EXCLUDE,NULL);
552         return 0;
553     }
554
555     werror(W_UNKNOWN_PRAGMA,cp);
556     return 0;
557 }
558
559 /* will return 1 if the string is a part
560    of a target specific keyword */
561 int isTargetKeyword(char *s)
562 {
563     int i;
564     
565     if (port->keywords == NULL)
566         return 0;
567     for ( i = 0 ; port->keywords[i] ; i++ ) {
568         if (strcmp(port->keywords[i],s) == 0)
569             return 1;
570     }
571     
572     return 0;
573 }
574
575 extern int fatalError;
576
577 int yyerror(char *s)
578 {
579    fflush(stdout);
580
581    if (yylineno && filename)
582         fprintf(stdout,"\n%s(%d) %s: token -> '%s' ; column %d\n",
583                 filename,yylineno,
584                 s,yytext,column);
585    fatalError++;
586    return 0;
587 }