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