4eddd3ee77a507cd4513327bcce86108b9577e48
[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_alloc (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 "..."          { count(); return(VAR_ARGS);}
174 {L}({L}|{D})*  { count(); return(check_type()); }
175 0[xX]{H}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
176 0{D}+{IS}?     { count(); yylval.val = constVal(yytext); return(CONSTANT); }
177 {D}+{IS}?      { count(); yylval.val = constVal(yytext); return(CONSTANT); }
178 '(\\.|[^\\'])+' { count();yylval.val = charVal (yytext); return(CONSTANT); }
179 {D}+{E}{FS}?   { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
180 {D}*"."{D}+({E})?{FS}?  { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
181 {D}+"."{D}*({E})?{FS}?  { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
182 \"             { count(); yylval.val=strVal(stringLiteral()); return(STRING_LITERAL);}
183 ">>=" { count(); yylval.yyint = RIGHT_ASSIGN ; return(RIGHT_ASSIGN); }
184 "<<=" { count(); yylval.yyint = LEFT_ASSIGN  ; return(LEFT_ASSIGN) ; }
185 "+="  { count(); yylval.yyint = ADD_ASSIGN   ; return(ADD_ASSIGN)  ; }
186 "-="  { count(); yylval.yyint = SUB_ASSIGN   ; return(SUB_ASSIGN)  ; }
187 "*="  { count(); yylval.yyint = MUL_ASSIGN   ; return(MUL_ASSIGN)  ; }
188 "/="  { count(); yylval.yyint = DIV_ASSIGN   ; return(DIV_ASSIGN)  ; }
189 "%="  { count(); yylval.yyint = MOD_ASSIGN   ; return(MOD_ASSIGN)  ; }
190 "&="  { count(); yylval.yyint = AND_ASSIGN   ; return(AND_ASSIGN)  ; }
191 "^="  { count(); yylval.yyint = XOR_ASSIGN   ; return(XOR_ASSIGN)  ; }
192 "|="  { count(); yylval.yyint = OR_ASSIGN    ; return(OR_ASSIGN)   ; }
193 ">>"           { count(); return(RIGHT_OP); }
194 "<<"           { count(); return(LEFT_OP); }
195 "++"           { count(); return(INC_OP); }
196 "--"           { count(); return(DEC_OP); }
197 "->"           { count(); return(PTR_OP); }
198 "&&"           { count(); return(AND_OP); }
199 "||"           { count(); return(OR_OP); }
200 "<="           { count(); return(LE_OP); }
201 ">="           { count(); return(GE_OP); }
202 "=="           { count(); return(EQ_OP); }
203 "!="           { count(); return(NE_OP); }
204 ";"            { count(); return(';'); }
205 "{"            { count(); NestLevel++ ;  return('{'); }
206 "}"            { count(); NestLevel--; return('}'); }
207 ","            { count(); return(','); }
208 ":"            { count(); return(':'); }
209 "="            { count(); return('='); }
210 "("            { count(); return('('); }
211 ")"            { count(); 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 ^#line.*"\n"       { count(); checkCurrFile(yytext); }
229 ^#pragma.*"\n"   { count(); process_pragma(yytext); }
230
231 ^[^(]+"("[0-9]+") : error"[^\n]+ { werror(E_PRE_PROC_FAILED,yytext);count(); }
232 ^[^(]+"("[0-9]+") : warning"[^\n]+ { werror(W_PRE_PROC_WARNING,yytext);count(); }
233 "\r\n"             { count(); }
234 "\n"               { count(); }
235 [ \t\v\f]      { count(); }
236 \\ {
237   char ch=input();
238   if (ch!='\n') {
239     // that could have been removed by the preprocessor anyway
240     werror (W_STRAY_BACKSLASH, column);
241     unput(ch);
242   }
243 }
244 .                          { count()    ; }
245 %%
246    
247 int checkCurrFile ( char *s)
248 {
249     char lineNum[10]                    ;
250     int  lNum                           ;
251     char *tptr                          ;
252        
253     /* first check if this is a #line */
254     if ( strncmp(s,"#line",5) )
255         return  0                               ;
256     
257     /* get to the line number */
258     while (!isdigit(*s))
259         s++ ;
260     tptr = lineNum ;
261     while (isdigit(*s))
262         *tptr++ = *s++ ;
263     *tptr = '\0'; 
264     sscanf(lineNum,"%d",&lNum);
265     
266     /* now see if we have a file name */
267     while (*s != '\"' && *s) 
268         s++ ;
269     
270     /* if we don't have a filename then */
271     /* set the current line number to   */
272     /* line number if printFlag is on   */
273     if (!*s) {          
274       lineno = yylineno = lNum ;
275       return 0;
276     }
277     
278     /* if we have a filename then check */
279     /* if it is "standard in" if yes then */
280     /* get the currentfile name info    */
281     s++ ;
282
283     if ( strncmp(s,fullSrcFileName,strlen(fullSrcFileName)) == 0) {
284       lineno = yylineno = lNum;                                 
285       currFname = fullSrcFileName ;
286     }  else {
287         char *sb = s;
288         /* mark the end of the filename */
289         while (*s != '"') s++;
290         *s = '\0';
291         currFname = Safe_alloc (strlen(sb)+1);
292         strcpy(currFname,sb);
293         lineno = yylineno = lNum;
294     }
295     filename = currFname ;
296     return 0;
297 }
298     
299 int column = 0;
300 int plineIdx=0;
301
302 void count()
303 {
304   int i;
305   for (i = 0; yytext[i] != '\0'; i++)   {                               
306     if (yytext[i] == '\n')      {         
307       column = 0;
308       lineno = ++yylineno ;
309     }
310     else 
311       if (yytext[i] == '\t')
312         column += 8 - (column % 8);
313       else
314         column++;
315   }
316   /* ECHO; */
317 }
318
319 int check_type()
320 {
321         /* check if it is in the typedef table */
322         if (findSym(TypedefTab,NULL,yytext)) {
323                 strcpy(yylval.yychar,yytext);
324                 return (TYPE_NAME) ;
325         }
326         else   {
327                 strcpy (yylval.yychar,yytext);
328                 return(IDENTIFIER);
329         }
330 }
331
332 char strLitBuff[2048]; // TODO: this is asking for the next bug :)
333
334 /*
335  * Change by JTV 2001-05-19 to not concantenate strings
336  * to support ANSI hex and octal escape sequences in string liteals 
337  */
338
339 char *stringLiteral () {
340   int ch;
341   char *str = strLitBuff;
342   
343   *str++ = '\"';
344   /* put into the buffer till we hit the first \" */
345   
346   while (1) {
347     ch = input();
348     
349     if (!ch)
350       break; /* end of input */
351     
352     /* if it is a \ then escape char's are allowed */
353     if (ch == '\\') {
354       ch=input();
355       if (ch=='\n') {
356         /* \<newline> is a continuator */
357         lineno=++yylineno;
358         column=0;
359         continue;
360       }
361       *str++ = '\\'; /* backslash in place */
362       *str++ = ch; /* get the escape char, no further check */
363       continue; /* carry on */
364     }
365     
366     /* if new line we have a new line break, which is illegal */
367     if (ch == '\n') {
368       werror (W_NEWLINE_IN_STRING);
369       *str++ = '\n';
370       lineno=++yylineno;
371       column=0;
372       continue;
373     }
374     
375     /* if this is a quote then we have work to do */
376     /* find the next non whitespace character     */
377     /* if that is a double quote then carry on    */
378     if (ch == '\"') {
379       *str++  = ch ; /* Pass end of this string or substring to evaluator */
380       while ((ch = input()) && (isspace(ch) || ch=='\\')) {
381         switch (ch) {
382         case '\\':
383           if ((ch=input())!='\n') {
384             werror (W_STRAY_BACKSLASH, column);
385             unput(ch);
386           } else {
387             lineno=++yylineno;
388             column=0;
389           }
390           break;
391         case '\n':
392           yylineno++;
393           break;
394         }
395       }
396
397       if (!ch) 
398         break; 
399
400       if (ch != '\"') {
401         unput(ch) ;
402         break ;
403       }
404     }
405     *str++  = ch; /* Put next substring introducer into output string */
406   }  
407   *str = '\0';
408   
409   return strLitBuff;
410 }
411
412 void doPragma (int op, char *cp)
413 {
414     switch (op) {
415     case P_SAVE:
416         memcpy(&save_options,&options,sizeof(options));
417         memcpy(&save_optimize,&optimize,sizeof(optimize));
418         break;
419     case P_RESTORE:
420         memcpy(&options,&save_options,sizeof(options));
421         memcpy(&optimize,&save_optimize,sizeof(optimize));
422         break;
423     case P_NOINDUCTION:
424         optimize.loopInduction = 0 ;
425         break;
426     case P_NOINVARIANT:
427         optimize.loopInvariant = 0 ;
428         break;
429     case P_INDUCTION:
430         optimize.loopInduction = 1 ;
431         break;
432     case P_STACKAUTO:
433         options.stackAuto = 1;
434         break;
435     case P_NOJTBOUND:
436         optimize.noJTabBoundary = 1;
437         break;
438     case P_NOGCSE:
439         optimize.global_cse = 0;
440         break;
441     case P_NOOVERLAY:
442         options.noOverlay = 1;
443         break;
444     case P_CALLEE_SAVES:
445         {
446             int i=0;
447             /* append to the functions already listed
448                in callee-saves */
449             for (; options.calleeSaves[i] ;i++);
450             parseWithComma(&options.calleeSaves[i],strdup(cp));
451         }
452         break;
453     case P_EXCLUDE:
454         parseWithComma(options.excludeRegs,strdup(cp));
455         break;
456     case P_LOOPREV:
457         optimize.noLoopReverse = 1;
458         break;
459     }
460 }
461
462 int process_pragma(char *s)
463 {
464     char *cp ;
465     /* find the pragma */
466     while (strncmp(s,"#pragma",7))
467         s++;
468     s += 7;
469     
470     /* look for the directive */
471     while(isspace(*s)) s++;
472
473     cp = s;
474     /* look for the end of the directive */
475     while ((! isspace(*s)) && 
476            (*s != '\n')) 
477         s++ ;    
478
479     /* First give the port a chance */
480     if (port->process_pragma && !port->process_pragma(cp))
481         return 0;
482
483     /* now compare and do what needs to be done */
484     if (strncmp(cp,PRAGMA_SAVE,strlen(PRAGMA_SAVE)) == 0) {
485         doPragma(P_SAVE,cp+strlen(PRAGMA_SAVE));
486         return 0;
487     }
488
489     if (strncmp(cp,PRAGMA_RESTORE,strlen(PRAGMA_RESTORE)) == 0) {
490         doPragma (P_RESTORE,cp+strlen(PRAGMA_RESTORE));
491         return 0;
492     }
493
494     if (strncmp(cp,PRAGMA_NOINDUCTION,strlen(PRAGMA_NOINDUCTION)) == 0) {
495         doPragma (P_NOINDUCTION,cp+strlen(PRAGMA_NOINDUCTION))  ;
496         return 0;
497     }
498
499     if (strncmp(cp,PRAGMA_NOINVARIANT,strlen(PRAGMA_NOINVARIANT)) == 0) {
500         doPragma (P_NOINVARIANT,NULL)   ;
501         return 0;
502     }
503
504     if (strncmp(cp,PRAGMA_INDUCTION,strlen(PRAGMA_INDUCTION)) == 0) {
505         doPragma (P_INDUCTION,NULL)     ;
506         return 0;
507     }
508
509     if (strncmp(cp,PRAGMA_STACKAUTO,strlen(PRAGMA_STACKAUTO)) == 0) {
510         doPragma (P_STACKAUTO,NULL);
511         return 0;
512     }
513
514     if (strncmp(cp,PRAGMA_NOJTBOUND,strlen(PRAGMA_NOJTBOUND)) == 0) {
515         doPragma (P_NOJTBOUND,NULL);
516         return 0;
517     }
518
519     if (strncmp(cp,PRAGMA_NOGCSE,strlen(PRAGMA_NOGCSE)) == 0) {
520         doPragma (P_NOGCSE,NULL);
521         return 0;
522     }
523
524     if (strncmp(cp,PRAGMA_NOOVERLAY,strlen(PRAGMA_NOOVERLAY)) == 0) {
525         doPragma (P_NOOVERLAY,NULL);
526         return 0;
527     }
528     
529     if (strncmp(cp,PRAGMA_CALLEESAVES,strlen(PRAGMA_CALLEESAVES)) == 0) {
530         doPragma(P_CALLEE_SAVES,cp+strlen(PRAGMA_CALLEESAVES));
531         return 0;
532     }
533     
534     if (strncmp(cp,PRAGMA_EXCLUDE,strlen(PRAGMA_EXCLUDE)) == 0) {
535         doPragma(P_EXCLUDE,cp+strlen(PRAGMA_EXCLUDE));
536         return 0;
537     }
538
539     if (strncmp(cp,PRAGMA_NOLOOPREV,strlen(PRAGMA_NOLOOPREV)) == 0) {
540         doPragma(P_LOOPREV,NULL);
541         return 0;
542     }
543
544     werror(W_UNKNOWN_PRAGMA,cp);
545     return 0;
546 }
547
548 /* will return 1 if the string is a part
549    of a target specific keyword */
550 int isTargetKeyword(char *s)
551 {
552     int i;
553     
554     if (port->keywords == NULL)
555         return 0;
556     for ( i = 0 ; port->keywords[i] ; i++ ) {
557         if (strcmp(port->keywords[i],s) == 0)
558             return 1;
559     }
560     
561     return 0;
562 }
563
564 extern int fatalError;
565
566 int yyerror(char *s)
567 {
568    fflush(stdout);
569
570    if (yylineno && filename)
571         fprintf(stdout,"\n%s(%d) %s: token -> '%s' ; column %d\n",
572                 filename,yylineno,
573                 s,yytext,column);
574    fatalError++;
575    return 0;
576 }