9607a9d4595b2e58cf5d547e687902b75dd3072f
[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 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 \\ {
249   char ch=input();
250   if (ch!='\n') {
251     werror (W_STRAY_BACKSLASH, column);
252     unput(ch);
253   }
254 }
255 .                          { count()    ; }
256 %%
257    
258 int checkCurrFile ( char *s)
259 {
260     char lineNum[10]                    ;
261     int  lNum                           ;
262     char *tptr                          ;
263        
264     /* first check if this is a #line */
265     if ( strncmp(s,"#line",5) )
266         return  0                               ;
267     
268     /* get to the line number */
269     while (!isdigit(*s))
270         s++ ;
271     tptr = lineNum ;
272     while (isdigit(*s))
273         *tptr++ = *s++ ;
274     *tptr = '\0'; 
275     sscanf(lineNum,"%d",&lNum);
276     
277     /* now see if we have a file name */
278     while (*s != '\"' && *s) 
279         s++ ;
280     
281     /* if we don't have a filename then */
282     /* set the current line number to   */
283     /* line number if printFlag is on   */
284     if (!*s) {          
285         yylineno = lNum ;
286         return 0;
287     }
288     
289     /* if we have a filename then check */
290     /* if it is "standard in" if yes then */
291     /* get the currentfile name info    */
292     s++ ;
293
294     if ( strncmp(s,fullSrcFileName,strlen(fullSrcFileName)) == 0) {
295             yylineno = lNum - 2;                                        
296             currFname = fullSrcFileName ;
297     }  else {
298         char *sb = s;
299         /* mark the end of the filename */
300         while (*s != '"') s++;
301         *s = '\0';
302         currFname = Safe_calloc(1,strlen(sb)+1);
303         strcpy(currFname,sb);
304         yylineno = lNum - 2;
305     }
306     filename = currFname ;
307     return 0;
308 }
309     
310 void comment()
311 {
312   char c, c1;
313   
314  loop:
315   while ((c = input()) != '*' && c) {
316     if ( c == '\n') {
317       lineno=++yylineno;
318     }
319   }
320   
321   if (c && (c1 = input()) != '/') {
322     unput(c1);
323     goto loop;
324   }
325 }
326    
327    
328
329 int column = 0;
330 int plineIdx=0;
331
332 void count()
333 {
334   int i;
335   for (i = 0; yytext[i] != '\0'; i++)   {                               
336     if (yytext[i] == '\n')      {         
337       column = 0;
338       lineno = ++yylineno ;
339     }
340     else 
341       if (yytext[i] == '\t')
342         column += 8 - (column % 8);
343       else
344         column++;
345   }
346   /* ECHO; */
347 }
348
349 int check_type()
350 {
351         /* check if it is in the typedef table */
352         if (findSym(TypedefTab,NULL,yytext)) {
353                 strcpy(yylval.yychar,yytext);
354                 return (TYPE_NAME) ;
355         }
356         else   {
357                 strcpy (yylval.yychar,yytext);
358                 return(IDENTIFIER);
359         }
360 }
361
362 char strLitBuff[2048]; // TODO: this is asking for the next bug :)
363
364 /*
365  * Change by JTV 2001-05-19 to not concantenate strings
366  * to support ANSI hex and octal escape sequences in string liteals 
367  */
368
369 char *stringLiteral () {
370   int ch;
371   char *str = strLitBuff;
372   
373   *str++ = '\"';
374   /* put into the buffer till we hit the first \" */
375   
376   while (1) {
377     ch = input();
378     
379     if (!ch)
380       break; /* end of input */
381     
382     /* if it is a \ then escape char's are allowed */
383     if (ch == '\\') {
384       ch=input();
385       if (ch=='\r') {
386         // input() translates \n into \r\n
387         if ((ch=input())!='\n') {
388           unput (ch);
389         }
390         /* \<newline> is a continuator */
391         lineno=++yylineno;
392         continue;
393       }
394       *str++ = '\\'; /* backslash in place */
395       *str++ = ch; /* get the escape char, no further check */
396       continue; /* carry on */
397     }
398     
399     /* if new line we have a new line break, which is illegal */
400     if (ch == '\r') {
401       // input() translates \n into \r\n
402       if ((ch=input())!='\n') {
403         unput (ch);
404       }
405       werror (W_NEWLINE_IN_STRING);
406       *str++ = '\n';
407       lineno=++yylineno;
408       continue;
409     }
410     
411     /* if this is a quote then we have work to do */
412     /* find the next non whitespace character     */
413     /* if that is a double quote then carry on    */
414     if (ch == '\"') {
415       *str++  = ch ; /* Pass end of this string or substring to evaluator */
416       while ((ch = input()) && (isspace(ch) || ch=='\\')) {
417         switch (ch) {
418         case '\\':
419           if ((ch=input())!='\n') {
420             werror (W_STRAY_BACKSLASH, column);
421             unput(ch);
422           }
423           break;
424         case '\n':
425           yylineno++;
426           break;
427         }
428       }
429
430       if (!ch) 
431         break; 
432       
433       if (ch != '\"') {
434         unput(ch) ;
435         break ;
436       }
437     }
438     *str++  = ch; /* Put next substring introducer into output string */
439   }  
440   *str = '\0';
441   
442   return strLitBuff;
443 }
444
445 void doPragma (int op, char *cp)
446 {
447     switch (op) {
448     case P_SAVE:
449         memcpy(&save_options,&options,sizeof(options));
450         memcpy(&save_optimize,&optimize,sizeof(optimize));
451         break;
452     case P_RESTORE:
453         memcpy(&options,&save_options,sizeof(options));
454         memcpy(&optimize,&save_optimize,sizeof(optimize));
455         break;
456     case P_NOINDUCTION:
457         optimize.loopInduction = 0 ;
458         break;
459     case P_NOINVARIANT:
460         optimize.loopInvariant = 0 ;
461         break;
462     case P_INDUCTION:
463         optimize.loopInduction = 1 ;
464         break;
465     case P_STACKAUTO:
466         options.stackAuto = 1;
467         break;
468     case P_NOJTBOUND:
469         optimize.noJTabBoundary = 1;
470         break;
471     case P_NOGCSE:
472         optimize.global_cse = 0;
473         break;
474     case P_NOOVERLAY:
475         options.noOverlay = 1;
476         break;
477     case P_CALLEE_SAVES:
478         {
479             int i=0;
480             /* append to the functions already listed
481                in callee-saves */
482             for (; options.calleeSaves[i] ;i++);
483             parseWithComma(&options.calleeSaves[i],strdup(cp));
484         }
485         break;
486     case P_EXCLUDE:
487         parseWithComma(options.excludeRegs,strdup(cp));
488         break;
489     case P_LOOPREV:
490         optimize.noLoopReverse = 1;
491         break;
492     }
493 }
494
495 int process_pragma(char *s)
496 {
497     char *cp ;
498     /* find the pragma */
499     while (strncmp(s,"#pragma",7))
500         s++;
501     s += 7;
502     
503     /* look for the directive */
504     while(isspace(*s)) s++;
505
506     cp = s;
507     /* look for the end of the directive */
508     while ((! isspace(*s)) && 
509            (*s != '\n')) 
510         s++ ;    
511
512     /* First give the port a chance */
513     if (port->process_pragma && !port->process_pragma(cp))
514         return 0;
515
516     /* now compare and do what needs to be done */
517     if (strncmp(cp,PRAGMA_SAVE,strlen(PRAGMA_SAVE)) == 0) {
518         doPragma(P_SAVE,cp+strlen(PRAGMA_SAVE));
519         return 0;
520     }
521
522     if (strncmp(cp,PRAGMA_RESTORE,strlen(PRAGMA_RESTORE)) == 0) {
523         doPragma (P_RESTORE,cp+strlen(PRAGMA_RESTORE));
524         return 0;
525     }
526
527     if (strncmp(cp,PRAGMA_NOINDUCTION,strlen(PRAGMA_NOINDUCTION)) == 0) {
528         doPragma (P_NOINDUCTION,cp+strlen(PRAGMA_NOINDUCTION))  ;
529         return 0;
530     }
531
532     if (strncmp(cp,PRAGMA_NOINVARIANT,strlen(PRAGMA_NOINVARIANT)) == 0) {
533         doPragma (P_NOINVARIANT,NULL)   ;
534         return 0;
535     }
536
537     if (strncmp(cp,PRAGMA_INDUCTION,strlen(PRAGMA_INDUCTION)) == 0) {
538         doPragma (P_INDUCTION,NULL)     ;
539         return 0;
540     }
541
542     if (strncmp(cp,PRAGMA_STACKAUTO,strlen(PRAGMA_STACKAUTO)) == 0) {
543         doPragma (P_STACKAUTO,NULL);
544         return 0;
545     }
546
547     if (strncmp(cp,PRAGMA_NOJTBOUND,strlen(PRAGMA_NOJTBOUND)) == 0) {
548         doPragma (P_NOJTBOUND,NULL);
549         return 0;
550     }
551
552     if (strncmp(cp,PRAGMA_NOGCSE,strlen(PRAGMA_NOGCSE)) == 0) {
553         doPragma (P_NOGCSE,NULL);
554         return 0;
555     }
556
557     if (strncmp(cp,PRAGMA_NOOVERLAY,strlen(PRAGMA_NOOVERLAY)) == 0) {
558         doPragma (P_NOOVERLAY,NULL);
559         return 0;
560     }
561     
562     if (strncmp(cp,PRAGMA_CALLEESAVES,strlen(PRAGMA_CALLEESAVES)) == 0) {
563         doPragma(P_CALLEE_SAVES,cp+strlen(PRAGMA_CALLEESAVES));
564         return 0;
565     }
566     
567     if (strncmp(cp,PRAGMA_EXCLUDE,strlen(PRAGMA_EXCLUDE)) == 0) {
568         doPragma(P_EXCLUDE,cp+strlen(PRAGMA_EXCLUDE));
569         return 0;
570     }
571
572     if (strncmp(cp,PRAGMA_NOLOOPREV,strlen(PRAGMA_NOLOOPREV)) == 0) {
573         doPragma(P_EXCLUDE,NULL);
574         return 0;
575     }
576
577     werror(W_UNKNOWN_PRAGMA,cp);
578     return 0;
579 }
580
581 /* will return 1 if the string is a part
582    of a target specific keyword */
583 int isTargetKeyword(char *s)
584 {
585     int i;
586     
587     if (port->keywords == NULL)
588         return 0;
589     for ( i = 0 ; port->keywords[i] ; i++ ) {
590         if (strcmp(port->keywords[i],s) == 0)
591             return 1;
592     }
593     
594     return 0;
595 }
596
597 extern int fatalError;
598
599 int yyerror(char *s)
600 {
601    fflush(stdout);
602
603    if (yylineno && filename)
604         fprintf(stdout,"\n%s(%d) %s: token -> '%s' ; column %d\n",
605                 filename,yylineno,
606                 s,yytext,column);
607    fatalError++;
608    return 0;
609 }