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