* doc/sdccman.lyx: new pragma NOIV by Johannes Stezenbach <js@convergence.de>
[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_NOIV      ,
80      P_LOOPREV   ,
81      P_OVERLAY_      /* I had a strange conflict with P_OVERLAY while */
82                      /* cross-compiling for MINGW32 with gcc 3.2 */
83  };
84
85 %}
86 %x asm
87 %%
88 "_asm"         {  
89   count(); 
90   asmp = asmbuff = realloc (asmbuff, INITIAL_INLINEASM);
91   asmbuffSize=INITIAL_INLINEASM;
92   BEGIN(asm) ;
93 }
94 <asm>"_endasm" { 
95   count();
96   *asmp = '\0';
97   yylval.yyinline = malloc (strlen(asmbuff)+1);
98   strcpy(yylval.yyinline,asmbuff);
99   BEGIN(INITIAL);
100   return (INLINEASM);
101 }
102 <asm>.         { 
103   if (asmp-asmbuff >= asmbuffSize-2) {
104     // increase the buffersize with 50%
105     int size=asmp-asmbuff;
106     asmbuffSize=asmbuffSize*3/2;
107     asmbuff = realloc (asmbuff, asmbuffSize); 
108     asmp=asmbuff+size;
109   }
110   *asmp++ = yytext[0];
111 }
112 <asm>\n        { 
113   count(); 
114   if (asmp-asmbuff >= asmbuffSize-3) {
115     // increase the buffersize with 50%
116     int size=asmp-asmbuff;
117     asmbuffSize=asmbuffSize*3/2;
118     asmbuff = realloc (asmbuff, asmbuffSize); 
119     asmp=asmbuff+size;
120   }
121   *asmp++ = '\n' ;
122 }
123 "at"           { count(); TKEYWORD(AT)  ; }
124 "auto"         { count(); return(AUTO); }
125 "bit"          { count(); TKEYWORD(BIT) ; }
126 "break"        { count(); return(BREAK); }
127 "case"         { count(); return(CASE); }
128 "char"         { count(); return(CHAR); }
129 "code"         { count(); TKEYWORD(CODE); }
130 "const"        { count(); return(CONST); }
131 "continue"     { count(); return(CONTINUE); }
132 "critical"     { count(); TKEYWORD(CRITICAL); } 
133 "data"         { count(); TKEYWORD(DATA);   }
134 "default"      { count(); return(DEFAULT); }
135 "do"           { count(); return(DO); }
136 "double"       { count(); werror(W_DOUBLE_UNSUPPORTED);return(FLOAT); }
137 "else"         { count(); return(ELSE); }
138 "enum"         { count(); return(ENUM); }
139 "extern"       { count(); return(EXTERN); }
140 "far"          { count(); TKEYWORD(XDATA);  }
141 "eeprom"       { count(); TKEYWORD(EEPROM);  }
142 "float"        { count(); return(FLOAT); }
143 "flash"        { count(); TKEYWORD(CODE);}
144 "for"          { count(); return(FOR); }
145 "goto"         { count(); return(GOTO); }
146 "idata"        { count(); TKEYWORD(IDATA);}
147 "if"           { count(); return(IF); }
148 "int"          { count(); return(INT); }
149 "interrupt"    { count(); return(INTERRUPT);}
150 "nonbanked"    { count(); TKEYWORD(NONBANKED);}
151 "banked"       { count(); TKEYWORD(BANKED);}
152 "long"         { count(); return(LONG); }
153 "near"         { count(); TKEYWORD(DATA);}
154 "pdata"        { count(); TKEYWORD(PDATA); }
155 "reentrant"    { count(); TKEYWORD(REENTRANT);}
156 "register"     { count(); return(REGISTER); }
157 "return"       { count(); return(RETURN); }
158 "sfr"          { count(); TKEYWORD(SFR) ; }
159 "sbit"         { count(); TKEYWORD(SBIT)        ; }
160 "short"        { count(); return(SHORT); }
161 "signed"       { count(); return(SIGNED); }
162 "sizeof"       { count(); return(SIZEOF); }
163 "sram"         { count(); TKEYWORD(XDATA);}
164 "static"       { count(); return(STATIC); }
165 "struct"       { count(); return(STRUCT); }
166 "switch"       { count(); return(SWITCH); }
167 "typedef"      { count(); return(TYPEDEF); }
168 "union"        { count(); return(UNION); }
169 "unsigned"     { count(); return(UNSIGNED); }
170 "void"         { count(); return(VOID); }
171 "volatile"     { count(); return(VOLATILE); }
172 "using"        { count(); TKEYWORD(USING); }
173 "_naked"       { count(); TKEYWORD(NAKED); }
174 "while"        { count(); return(WHILE); }
175 "xdata"        { count(); TKEYWORD(XDATA); }
176 "..."          { count(); return(VAR_ARGS);}
177 "__typeof"     { count(); return TYPEOF;}
178 "_JavaNative"  { count(); TKEYWORD(JAVANATIVE);}
179 "_overlay"     { count(); TKEYWORD(OVERLAY);}
180 {L}({L}|{D})*  { count(); return(check_type()); }
181 0[xX]{H}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
182 0{D}+{IS}?     { count(); yylval.val = constVal(yytext); return(CONSTANT); }
183 {D}+{IS}?      { count(); yylval.val = constVal(yytext); return(CONSTANT); }
184 '(\\.|[^\\'])+' { count();yylval.val = charVal (yytext); return(CONSTANT); /* ' make syntax highliter happy */}
185 {D}+{E}{FS}?   { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
186 {D}*"."{D}+({E})?{FS}?  { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
187 {D}+"."{D}*({E})?{FS}?  { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
188 \"             { count(); yylval.val=strVal(stringLiteral()); return(STRING_LITERAL);}
189 ">>=" { count(); yylval.yyint = RIGHT_ASSIGN ; return(RIGHT_ASSIGN); }
190 "<<=" { count(); yylval.yyint = LEFT_ASSIGN  ; return(LEFT_ASSIGN) ; }
191 "+="  { count(); yylval.yyint = ADD_ASSIGN   ; return(ADD_ASSIGN)  ; }
192 "-="  { count(); yylval.yyint = SUB_ASSIGN   ; return(SUB_ASSIGN)  ; }
193 "*="  { count(); yylval.yyint = MUL_ASSIGN   ; return(MUL_ASSIGN)  ; }
194 "/="  { count(); yylval.yyint = DIV_ASSIGN   ; return(DIV_ASSIGN)  ; }
195 "%="  { count(); yylval.yyint = MOD_ASSIGN   ; return(MOD_ASSIGN)  ; }
196 "&="  { count(); yylval.yyint = AND_ASSIGN   ; return(AND_ASSIGN)  ; }
197 "^="  { count(); yylval.yyint = XOR_ASSIGN   ; return(XOR_ASSIGN)  ; }
198 "|="  { count(); yylval.yyint = OR_ASSIGN    ; return(OR_ASSIGN)   ; }
199 ">>"           { count(); return(RIGHT_OP); }
200 "<<"           { count(); return(LEFT_OP); }
201 "++"           { count(); return(INC_OP); }
202 "--"           { count(); return(DEC_OP); }
203 "->"           { count(); return(PTR_OP); }
204 "&&"           { count(); return(AND_OP); }
205 "||"           { count(); return(OR_OP); }
206 "<="           { count(); return(LE_OP); }
207 ">="           { count(); return(GE_OP); }
208 "=="           { count(); return(EQ_OP); }
209 "!="           { count(); return(NE_OP); }
210 ";"            { count(); return(';'); }
211 "{"            { count(); NestLevel++ ;  return('{'); }
212 "}"            { count(); NestLevel--; 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 "%"            { count(); return('%'); }
229 "<"            { count(); return('<'); }
230 ">"            { count(); return('>'); }
231 "^"            { count(); return('^'); }
232 "|"            { count(); return('|'); }
233 "?"            { count(); return('?'); }
234 ^#line.*"\n"       { count(); checkCurrFile(yytext); }
235 ^#pragma.*"\n"   { count(); process_pragma(yytext); }
236
237 ^[^(]+"("[0-9]+") : error"[^\n]+ { werror(E_PRE_PROC_FAILED,yytext);count(); }
238 ^[^(]+"("[0-9]+") : warning"[^\n]+ { werror(W_PRE_PROC_WARNING,yytext);count(); }
239 "\r\n"             { count(); }
240 "\n"               { count(); }
241 [ \t\v\f]      { count(); }
242 \\ {
243   char ch=input();
244   if (ch!='\n') {
245     // that could have been removed by the preprocessor anyway
246     werror (W_STRAY_BACKSLASH, column);
247     unput(ch);
248   }
249 }
250 .                          { count()    ; }
251 %%
252
253 int checkCurrFile ( char *s)
254 {
255     char lineNum[10]                    ;
256     int  lNum                           ;
257     char *tptr                          ;
258        
259     /* first check if this is a #line */
260     if ( strncmp(s,"#line",5) )
261         return  0                               ;
262     
263     /* get to the line number */
264     while (!isdigit(*s))
265         s++ ;
266     tptr = lineNum ;
267     while (isdigit(*s))
268         *tptr++ = *s++ ;
269     *tptr = '\0'; 
270     sscanf(lineNum,"%d",&lNum);
271     
272     /* now see if we have a file name */
273     while (*s != '\"' && *s) 
274         s++ ;
275     
276     /* if we don't have a filename then */
277     /* set the current line number to   */
278     /* line number if printFlag is on   */
279     if (!*s) {          
280       lineno = yylineno = lNum ;
281       return 0;
282     }
283     
284     /* if we have a filename then check */
285     /* if it is "standard in" if yes then */
286     /* get the currentfile name info    */
287     s++ ;
288
289     if ( strncmp(s,fullSrcFileName,strlen(fullSrcFileName)) == 0) {
290       lineno = yylineno = lNum;                                 
291       currFname = fullSrcFileName ;
292     }  else {
293         char *sb = s;
294         /* mark the end of the filename */
295         while (*s != '"') s++;
296         *s = '\0';
297         currFname = malloc (strlen(sb)+1);
298         strcpy(currFname,sb);
299         lineno = yylineno = lNum;
300     }
301     filename = currFname ;
302     return 0;
303 }
304     
305 int column = 0;
306 int plineIdx=0;
307
308 void count()
309 {
310   int i;
311   for (i = 0; yytext[i] != '\0'; i++)   {                               
312     if (yytext[i] == '\n')      {         
313       column = 0;
314       lineno = ++yylineno ;
315     }
316     else 
317       if (yytext[i] == '\t')
318         column += 8 - (column % 8);
319       else
320         column++;
321   }
322   /* ECHO; */
323 }
324
325 int check_type()
326 {
327         /* check if it is in the typedef table */
328         if (findSym(TypedefTab,NULL,yytext)) {
329                 strcpy(yylval.yychar,yytext);
330                 return (TYPE_NAME) ;
331         }
332         else   {
333                 strcpy (yylval.yychar,yytext);
334                 return(IDENTIFIER);
335         }
336 }
337
338 char strLitBuff[2048]; // TODO: this is asking for the next bug :)
339
340 /*
341  * Change by JTV 2001-05-19 to not concantenate strings
342  * to support ANSI hex and octal escape sequences in string liteals 
343  */
344
345 char *stringLiteral () {
346   int ch;
347   char *str = strLitBuff;
348   
349   *str++ = '\"';
350   /* put into the buffer till we hit the first \" */
351   
352   while (1) {
353     ch = input();
354     
355     if (!ch)
356       break; /* end of input */
357     
358     /* if it is a \ then escape char's are allowed */
359     if (ch == '\\') {
360       ch=input();
361       if (ch=='\n') {
362         /* \<newline> is a continuator */
363         lineno=++yylineno;
364         column=0;
365         continue;
366       }
367       *str++ = '\\'; /* backslash in place */
368       *str++ = ch; /* get the escape char, no further check */
369       continue; /* carry on */
370     }
371     
372     /* if new line we have a new line break, which is illegal */
373     if (ch == '\n') {
374       werror (W_NEWLINE_IN_STRING);
375       *str++ = '\n';
376       lineno=++yylineno;
377       column=0;
378       continue;
379     }
380     
381     /* if this is a quote then we have work to do */
382     /* find the next non whitespace character     */
383     /* if that is a double quote then carry on    */
384     if (ch == '\"') {
385       *str++  = ch ; /* Pass end of this string or substring to evaluator */
386       while ((ch = input()) && (isspace(ch) || ch=='\\')) {
387         switch (ch) {
388         case '\\':
389           if ((ch=input())!='\n') {
390             werror (W_STRAY_BACKSLASH, column);
391             unput(ch);
392           } else {
393             lineno=++yylineno;
394             column=0;
395           }
396           break;
397         case '\n':
398           yylineno++;
399           break;
400         }
401       }
402
403       if (!ch) 
404         break; 
405
406       if (ch != '\"') {
407         unput(ch) ;
408         break ;
409       }
410     }
411     *str++  = ch; /* Put next substring introducer into output string */
412   }  
413   *str = '\0';
414   
415   return strLitBuff;
416 }
417
418 void doPragma (int op, char *cp)
419 {
420     switch (op) {
421     case P_SAVE:
422         memcpy(&save_options,&options,sizeof(options));
423         memcpy(&save_optimize,&optimize,sizeof(optimize));
424         break;
425     case P_RESTORE:
426         memcpy(&options,&save_options,sizeof(options));
427         memcpy(&optimize,&save_optimize,sizeof(optimize));
428         break;
429     case P_NOINDUCTION:
430         optimize.loopInduction = 0 ;
431         break;
432     case P_NOINVARIANT:
433         optimize.loopInvariant = 0 ;
434         break;
435     case P_INDUCTION:
436         optimize.loopInduction = 1 ;
437         break;
438     case P_STACKAUTO:
439         options.stackAuto = 1;
440         break;
441     case P_NOJTBOUND:
442         optimize.noJTabBoundary = 1;
443         break;
444     case P_NOGCSE:
445         optimize.global_cse = 0;
446         break;
447     case P_NOOVERLAY:
448         options.noOverlay = 1;
449         break;
450     case P_CALLEE_SAVES:
451         {
452             int i=0;
453             /* append to the functions already listed
454                in callee-saves */
455             for (; options.calleeSaves[i] ;i++);
456             parseWithComma(&options.calleeSaves[i], Safe_strdup(cp));
457         }
458         break;
459     case P_EXCLUDE:
460         parseWithComma(options.excludeRegs, Safe_strdup(cp));
461         break;
462     case P_NOIV:
463         options.noiv = 1;
464         break;
465     case P_LOOPREV:
466         optimize.noLoopReverse = 1;
467         break;
468     case P_OVERLAY_:
469         break; /* notyet */
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_NOIV,strlen(PRAGMA_NOIV)) == 0) {
551         doPragma(P_NOIV,cp+strlen(PRAGMA_NOIV));
552         return 0;
553     }
554
555     if (strncmp(cp,PRAGMA_NOLOOPREV,strlen(PRAGMA_NOLOOPREV)) == 0) {
556         doPragma(P_LOOPREV,NULL);
557         return 0;
558     }
559
560     werror(W_UNKNOWN_PRAGMA,cp);
561     return 0;
562 }
563
564 /* will return 1 if the string is a part
565    of a target specific keyword */
566 int isTargetKeyword(char *s)
567 {
568     int i;
569     
570     if (port->keywords == NULL)
571         return 0;
572     for ( i = 0 ; port->keywords[i] ; i++ ) {
573         if (strcmp(port->keywords[i],s) == 0)
574             return 1;
575     }
576     
577     return 0;
578 }
579
580 extern int fatalError;
581
582 int yyerror(char *s)
583 {
584    fflush(stdout);
585
586    if (yylineno && filename) {
587      fprintf(stdout,"\n%s:%d: %s: token -> '%s' ; column %d\n",
588              filename,yylineno,
589              s,yytext,column);
590      fatalError++;
591    } else {
592      // this comes from an empy file, no problem
593    }
594    return 0;
595 }