warn about a stray \
[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           break;
420         case '\n':
421           yylineno++;
422           break;
423         }
424       }
425
426       if (!ch) 
427         break; 
428       
429       if (ch != '\"') {
430         unput(ch) ;
431         break ;
432       }
433     }
434     *str++  = ch; /* Put next substring introducer into output string */
435   }  
436   *str = '\0';
437   
438   return strLitBuff;
439 }
440
441 void doPragma (int op, char *cp)
442 {
443     switch (op) {
444     case P_SAVE:
445         memcpy(&save_options,&options,sizeof(options));
446         memcpy(&save_optimize,&optimize,sizeof(optimize));
447         break;
448     case P_RESTORE:
449         memcpy(&options,&save_options,sizeof(options));
450         memcpy(&optimize,&save_optimize,sizeof(optimize));
451         break;
452     case P_NOINDUCTION:
453         optimize.loopInduction = 0 ;
454         break;
455     case P_NOINVARIANT:
456         optimize.loopInvariant = 0 ;
457         break;
458     case P_INDUCTION:
459         optimize.loopInduction = 1 ;
460         break;
461     case P_STACKAUTO:
462         options.stackAuto = 1;
463         break;
464     case P_NOJTBOUND:
465         optimize.noJTabBoundary = 1;
466         break;
467     case P_NOGCSE:
468         optimize.global_cse = 0;
469         break;
470     case P_NOOVERLAY:
471         options.noOverlay = 1;
472         break;
473     case P_CALLEE_SAVES:
474         {
475             int i=0;
476             /* append to the functions already listed
477                in callee-saves */
478             for (; options.calleeSaves[i] ;i++);
479             parseWithComma(&options.calleeSaves[i],strdup(cp));
480         }
481         break;
482     case P_EXCLUDE:
483         parseWithComma(options.excludeRegs,strdup(cp));
484         break;
485     case P_LOOPREV:
486         optimize.noLoopReverse = 1;
487         break;
488     }
489 }
490
491 int process_pragma(char *s)
492 {
493     char *cp ;
494     /* find the pragma */
495     while (strncmp(s,"#pragma",7))
496         s++;
497     s += 7;
498     
499     /* look for the directive */
500     while(isspace(*s)) s++;
501
502     cp = s;
503     /* look for the end of the directive */
504     while ((! isspace(*s)) && 
505            (*s != '\n')) 
506         s++ ;    
507
508     /* First give the port a chance */
509     if (port->process_pragma && !port->process_pragma(cp))
510         return 0;
511
512     /* now compare and do what needs to be done */
513     if (strncmp(cp,PRAGMA_SAVE,strlen(PRAGMA_SAVE)) == 0) {
514         doPragma(P_SAVE,cp+strlen(PRAGMA_SAVE));
515         return 0;
516     }
517
518     if (strncmp(cp,PRAGMA_RESTORE,strlen(PRAGMA_RESTORE)) == 0) {
519         doPragma (P_RESTORE,cp+strlen(PRAGMA_RESTORE));
520         return 0;
521     }
522
523     if (strncmp(cp,PRAGMA_NOINDUCTION,strlen(PRAGMA_NOINDUCTION)) == 0) {
524         doPragma (P_NOINDUCTION,cp+strlen(PRAGMA_NOINDUCTION))  ;
525         return 0;
526     }
527
528     if (strncmp(cp,PRAGMA_NOINVARIANT,strlen(PRAGMA_NOINVARIANT)) == 0) {
529         doPragma (P_NOINVARIANT,NULL)   ;
530         return 0;
531     }
532
533     if (strncmp(cp,PRAGMA_INDUCTION,strlen(PRAGMA_INDUCTION)) == 0) {
534         doPragma (P_INDUCTION,NULL)     ;
535         return 0;
536     }
537
538     if (strncmp(cp,PRAGMA_STACKAUTO,strlen(PRAGMA_STACKAUTO)) == 0) {
539         doPragma (P_STACKAUTO,NULL);
540         return 0;
541     }
542
543     if (strncmp(cp,PRAGMA_NOJTBOUND,strlen(PRAGMA_NOJTBOUND)) == 0) {
544         doPragma (P_NOJTBOUND,NULL);
545         return 0;
546     }
547
548     if (strncmp(cp,PRAGMA_NOGCSE,strlen(PRAGMA_NOGCSE)) == 0) {
549         doPragma (P_NOGCSE,NULL);
550         return 0;
551     }
552
553     if (strncmp(cp,PRAGMA_NOOVERLAY,strlen(PRAGMA_NOOVERLAY)) == 0) {
554         doPragma (P_NOOVERLAY,NULL);
555         return 0;
556     }
557     
558     if (strncmp(cp,PRAGMA_CALLEESAVES,strlen(PRAGMA_CALLEESAVES)) == 0) {
559         doPragma(P_CALLEE_SAVES,cp+strlen(PRAGMA_CALLEESAVES));
560         return 0;
561     }
562     
563     if (strncmp(cp,PRAGMA_EXCLUDE,strlen(PRAGMA_EXCLUDE)) == 0) {
564         doPragma(P_EXCLUDE,cp+strlen(PRAGMA_EXCLUDE));
565         return 0;
566     }
567
568     if (strncmp(cp,PRAGMA_NOLOOPREV,strlen(PRAGMA_NOLOOPREV)) == 0) {
569         doPragma(P_EXCLUDE,NULL);
570         return 0;
571     }
572
573     werror(W_UNKNOWN_PRAGMA,cp);
574     return 0;
575 }
576
577 /* will return 1 if the string is a part
578    of a target specific keyword */
579 int isTargetKeyword(char *s)
580 {
581     int i;
582     
583     if (port->keywords == NULL)
584         return 0;
585     for ( i = 0 ; port->keywords[i] ; i++ ) {
586         if (strcmp(port->keywords[i],s) == 0)
587             return 1;
588     }
589     
590     return 0;
591 }
592
593 extern int fatalError;
594
595 int yyerror(char *s)
596 {
597    fflush(stdout);
598
599    if (yylineno && filename)
600         fprintf(stdout,"\n%s(%d) %s: token -> '%s' ; column %d\n",
601                 filename,yylineno,
602                 s,yytext,column);
603    fatalError++;
604    return 0;
605 }