Applied patch from bug 737905 (renamed yylineo to mylineno)
[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 %option noyywrap
26
27 D        [0-9]
28 L        [a-zA-Z_]
29 H        [a-fA-F0-9]
30 E        [Ee][+-]?{D}+
31 FS       (f|F|l|L)
32 IS       (u|U|l|L)*
33 %{
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include "common.h"
39 #include "newalloc.h"
40 #include "dbuf.h"
41
42 char *stringLiteral();
43 char *currFname;
44
45 extern int lineno, column;
46 extern char *filename ;
47 int   mylineno = 1               ;
48 void count()                     ;
49 int process_pragma(char *);
50 #undef yywrap
51
52 #ifndef YYPROTO
53
54 #ifdef YY_USE_PROTOS
55 #define YY_PROTO(proto) proto
56 #else
57 #define YY_PROTO(proto) ()
58 #endif
59
60 #endif
61
62 int yywrap YY_PROTO((void))
63 {
64    return(1);
65 }
66
67 static void yyunput (int, char *);
68
69 static void my_unput(char c)
70 {
71   yyunput(c, (yytext_ptr));
72 }
73
74 #define TKEYWORD(token) return (isTargetKeyword(yytext) ? token :\
75                                 check_type(yytext))
76 char *asmbuff=NULL;
77 int asmbuffSize=0;
78 char *asmp ;
79 extern int check_type           ();
80  extern int isTargetKeyword     ();
81 extern int checkCurrFile        (char *);
82 extern int processPragma        (char *);
83 extern int printListing         (int   );
84 struct optimize save_optimize ;
85 struct options  save_options  ;
86 %}
87
88 %x asm
89 %%
90 "_asm"         {  
91   count(); 
92   asmp = asmbuff = realloc (asmbuff, INITIAL_INLINEASM);
93   asmbuffSize=INITIAL_INLINEASM;
94   BEGIN(asm) ;
95 }
96 <asm>"_endasm" { 
97   count();
98   *asmp = '\0';
99   yylval.yyinline = strdup (asmbuff);
100   BEGIN(INITIAL);
101   return (INLINEASM);
102 }
103 <asm>.         { 
104   if (asmp-asmbuff >= asmbuffSize-2) {
105     // increase the buffersize with 50%
106     int size=asmp-asmbuff;
107     asmbuffSize=asmbuffSize*3/2;
108     asmbuff = realloc (asmbuff, asmbuffSize); 
109     asmp=asmbuff+size;
110   }
111   *asmp++ = yytext[0];
112 }
113 <asm>\n        { 
114   count(); 
115   if (asmp-asmbuff >= asmbuffSize-3) {
116     // increase the buffersize with 50%
117     int size=asmp-asmbuff;
118     asmbuffSize=asmbuffSize*3/2;
119     asmbuff = realloc (asmbuff, asmbuffSize); 
120     asmp=asmbuff+size;
121   }
122   *asmp++ = '\n' ;
123 }
124 "at"           { count(); TKEYWORD(AT)  ; }
125 "auto"         { count(); return(AUTO); }
126 "bit"          { count(); TKEYWORD(BIT) ; }
127 "break"        { count(); return(BREAK); }
128 "case"         { count(); return(CASE); }
129 "char"         { count(); return(CHAR); }
130 "code"         { count(); TKEYWORD(CODE); }
131 "const"        { count(); return(CONST); }
132 "continue"     { count(); return(CONTINUE); }
133 "critical"     { count(); TKEYWORD(CRITICAL); } 
134 "data"         { count(); TKEYWORD(DATA);   }
135 "default"      { count(); return(DEFAULT); }
136 "do"           { count(); return(DO); }
137 "double"       { count(); werror(W_DOUBLE_UNSUPPORTED);return(FLOAT); }
138 "else"         { count(); return(ELSE); }
139 "enum"         { count(); return(ENUM); }
140 "extern"       { count(); return(EXTERN); }
141 "far"          { count(); TKEYWORD(XDATA);  }
142 "eeprom"       { count(); TKEYWORD(EEPROM);  }
143 "float"        { count(); return(FLOAT); }
144 "flash"        { count(); TKEYWORD(CODE);}
145 "for"          { count(); return(FOR); }
146 "goto"         { count(); return(GOTO); }
147 "idata"        { count(); TKEYWORD(IDATA);}
148 "if"           { count(); return(IF); }
149 "int"          { count(); return(INT); }
150 "interrupt"    { count(); return(INTERRUPT);}
151 "nonbanked"    { count(); TKEYWORD(NONBANKED);}
152 "banked"       { count(); TKEYWORD(BANKED);}
153 "long"         { count(); return(LONG); }
154 "near"         { count(); TKEYWORD(DATA);}
155 "pdata"        { count(); TKEYWORD(PDATA); }
156 "reentrant"    { count(); TKEYWORD(REENTRANT);}
157 "register"     { count(); return(REGISTER); }
158 "return"       { count(); return(RETURN); }
159 "sfr"          { count(); TKEYWORD(SFR) ; }
160 "sbit"         { count(); TKEYWORD(SBIT)        ; }
161 "short"        { count(); return(SHORT); }
162 "signed"       { count(); return(SIGNED); }
163 "sizeof"       { count(); return(SIZEOF); }
164 "sram"         { count(); TKEYWORD(XDATA);}
165 "static"       { count(); return(STATIC); }
166 "struct"       { count(); return(STRUCT); }
167 "switch"       { count(); return(SWITCH); }
168 "typedef"      { count(); return(TYPEDEF); }
169 "union"        { count(); return(UNION); }
170 "unsigned"     { count(); return(UNSIGNED); }
171 "void"         { count(); return(VOID); }
172 "volatile"     { count(); return(VOLATILE); }
173 "using"        { count(); TKEYWORD(USING); }
174 "_naked"       { count(); TKEYWORD(NAKED); }
175 "while"        { count(); return(WHILE); }
176 "xdata"        { count(); TKEYWORD(XDATA); }
177 "..."          { count(); return(VAR_ARGS);}
178 "__typeof"     { count(); return TYPEOF;}
179 "_JavaNative"  { count(); TKEYWORD(JAVANATIVE);}
180 "_overlay"     { count(); TKEYWORD(OVERLAY);}
181 {L}({L}|{D})*  { count(); return(check_type()); }
182 0[xX]{H}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
183 0{D}+{IS}?     { count(); yylval.val = constVal(yytext); return(CONSTANT); }
184 {D}+{IS}?      { count(); yylval.val = constVal(yytext); return(CONSTANT); }
185 '(\\.|[^\\'])+' { count();yylval.val = charVal (yytext); return(CONSTANT); /* ' make syntax highliter happy */}
186 {D}+{E}{FS}?   { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
187 {D}*"."{D}+({E})?{FS}?  { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
188 {D}+"."{D}*({E})?{FS}?  { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
189 \"             { count(); yylval.val=strVal(stringLiteral()); return(STRING_LITERAL);}
190 ">>=" { count(); yylval.yyint = RIGHT_ASSIGN ; return(RIGHT_ASSIGN); }
191 "<<=" { count(); yylval.yyint = LEFT_ASSIGN  ; return(LEFT_ASSIGN) ; }
192 "+="  { count(); yylval.yyint = ADD_ASSIGN   ; return(ADD_ASSIGN)  ; }
193 "-="  { count(); yylval.yyint = SUB_ASSIGN   ; return(SUB_ASSIGN)  ; }
194 "*="  { count(); yylval.yyint = MUL_ASSIGN   ; return(MUL_ASSIGN)  ; }
195 "/="  { count(); yylval.yyint = DIV_ASSIGN   ; return(DIV_ASSIGN)  ; }
196 "%="  { count(); yylval.yyint = MOD_ASSIGN   ; return(MOD_ASSIGN)  ; }
197 "&="  { count(); yylval.yyint = AND_ASSIGN   ; return(AND_ASSIGN)  ; }
198 "^="  { count(); yylval.yyint = XOR_ASSIGN   ; return(XOR_ASSIGN)  ; }
199 "|="  { count(); yylval.yyint = OR_ASSIGN    ; return(OR_ASSIGN)   ; }
200 ">>"           { count(); return(RIGHT_OP); }
201 "<<"           { count(); return(LEFT_OP); }
202 "++"           { count(); return(INC_OP); }
203 "--"           { count(); return(DEC_OP); }
204 "->"           { count(); return(PTR_OP); }
205 "&&"           { count(); return(AND_OP); }
206 "||"           { count(); return(OR_OP); }
207 "<="           { count(); return(LE_OP); }
208 ">="           { count(); return(GE_OP); }
209 "=="           { count(); return(EQ_OP); }
210 "!="           { count(); return(NE_OP); }
211 ";"            { count(); return(';'); }
212 "{"            { count(); NestLevel++ ;  return('{'); }
213 "}"            { count(); NestLevel--; 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 "?"            { count(); return('?'); }
235 ^#line.*"\n"       { count(); checkCurrFile(yytext); }
236 ^#pragma.*"\n"   { count(); process_pragma(yytext); }
237
238 ^[^(]+"("[0-9]+") : error"[^\n]+ { werror(E_PRE_PROC_FAILED,yytext);count(); }
239 ^[^(]+"("[0-9]+") : warning"[^\n]+ { werror(W_PRE_PROC_WARNING,yytext);count(); }
240 "\r\n"             { count(); }
241 "\n"               { count(); }
242 [ \t\v\f]      { count(); }
243 \\ {
244   char ch=input();
245   if (ch!='\n') {
246     // that could have been removed by the preprocessor anyway
247     werror (W_STRAY_BACKSLASH, column);
248     my_unput(ch);
249   }
250 }
251 .                          { count()    ; }
252 %%
253
254 int checkCurrFile ( char *s)
255 {
256     char lineNum[10]                    ;
257     int  lNum                           ;
258     char *tptr                          ;
259        
260     /* first check if this is a #line */
261     if ( strncmp(s,"#line",5) )
262         return  0                               ;
263     
264     /* get to the line number */
265     while (!isdigit(*s))
266         s++ ;
267     tptr = lineNum ;
268     while (isdigit(*s))
269         *tptr++ = *s++ ;
270     *tptr = '\0'; 
271     sscanf(lineNum,"%d",&lNum);
272     
273     /* now see if we have a file name */
274     while (*s != '\"' && *s) 
275         s++ ;
276     
277     /* if we don't have a filename then */
278     /* set the current line number to   */
279     /* line number if printFlag is on   */
280     if (!*s) {          
281       lineno = mylineno = lNum ;
282       return 0;
283     }
284     
285     /* if we have a filename then check */
286     /* if it is "standard in" if yes then */
287     /* get the currentfile name info    */
288     s++ ;
289
290     /* in c1mode fullSrcFileName is NULL */
291     if ( fullSrcFileName &&
292          strncmp(s,fullSrcFileName,strlen(fullSrcFileName)) == 0) {
293       lineno = mylineno = lNum;                                 
294       currFname = fullSrcFileName ;
295     }  else {
296         char *sb = s;
297         /* mark the end of the filename */
298         while (*s != '"') s++;
299         *s = '\0';
300         currFname = strdup (sb);
301         lineno = mylineno = lNum;
302     }
303     filename = currFname ;
304     return 0;
305 }
306     
307 int column = 0;
308 int plineIdx=0;
309
310 void count()
311 {
312   int i;
313   for (i = 0; yytext[i] != '\0'; i++)   {                               
314     if (yytext[i] == '\n')      {         
315       column = 0;
316       lineno = ++mylineno ;
317     }
318     else 
319       if (yytext[i] == '\t')
320         column += 8 - (column % 8);
321       else
322         column++;
323   }
324   /* ECHO; */
325 }
326
327 int check_type()
328 {
329         /* check if it is in the typedef table */
330         if (findSym(TypedefTab,NULL,yytext)) {
331                 strncpyz(yylval.yychar,yytext, SDCC_NAME_MAX);
332                 return (TYPE_NAME) ;
333         }
334         else   {
335                 strncpyz (yylval.yychar,yytext, SDCC_NAME_MAX);
336                 return(IDENTIFIER);
337         }
338 }
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 {
347 #define STR_BUF_CHUNCK_LEN  1024
348   int ch;
349   static struct dbuf_s dbuf;
350   char buf[2];
351
352   if (dbuf.alloc == 0)
353     dbuf_init(&dbuf, STR_BUF_CHUNCK_LEN);
354   else
355     dbuf_set_size(&dbuf, 0);
356
357
358   dbuf_append(&dbuf, "\"", 1);
359   /* put into the buffer till we hit the first \" */
360
361   while ((ch = input()) != 0) {
362     switch (ch) {
363     case '\\':
364       /* if it is a \ then escape char's are allowed */
365       ch = input();
366       if (ch == '\n') {
367         /* \<newline> is a continuator */
368         lineno = ++mylineno;
369         column = 0;
370       }
371       else {
372         buf[0] = '\\';
373         buf[1] = ch;
374         dbuf_append(&dbuf, buf, 2); /* get the escape char, no further check */
375       }
376       break; /* carry on */
377
378     case '\n':
379       /* if new line we have a new line break, which is illegal */
380       werror(W_NEWLINE_IN_STRING);
381       dbuf_append(&dbuf, "\n", 1);
382       lineno = ++mylineno;
383       column = 0;
384       break;
385
386     case '"':
387       /* if this is a quote then we have work to do */
388       /* find the next non whitespace character     */
389       /* if that is a double quote then carry on    */
390       dbuf_append(&dbuf, "\"", 1);  /* Pass end of this string or substring to evaluator */
391       while ((ch = input()) && (isspace(ch) || ch=='\\')) {
392         switch (ch) {
393         case '\\':
394           if ((ch = input()) != '\n') {
395             werror(W_STRAY_BACKSLASH, column);
396             my_unput(ch);
397           }
398           else {
399             lineno = ++mylineno;
400             column = 0;
401           }
402           break;
403
404         case '\n':
405           mylineno++;
406           break;
407         }
408       }
409
410       if (!ch) 
411         goto out;
412
413       if (ch != '\"') {
414         my_unput(ch) ;
415         goto out;
416       }
417       break;
418
419     default:
420       buf[0] = ch;
421       dbuf_append(&dbuf, buf, 1);  /* Put next substring introducer into output string */
422     }
423   }
424
425 out:
426   return (char *)dbuf_c_str(&dbuf);
427 }
428
429
430 enum pragma_id {
431      P_SAVE = 1,
432      P_RESTORE ,
433      P_NOINDUCTION,
434      P_NOINVARIANT,
435      P_INDUCTION ,
436      P_STACKAUTO ,
437      P_NOJTBOUND ,
438      P_NOOVERLAY ,
439      P_LESSPEDANTIC,
440      P_NOGCSE    ,
441      P_CALLEE_SAVES,
442      P_EXCLUDE   ,
443      P_NOIV      ,
444      P_LOOPREV   ,
445      P_OVERLAY_      /* I had a strange conflict with P_OVERLAY while */
446                      /* cross-compiling for MINGW32 with gcc 3.2 */
447 };
448
449
450 /* SAVE/RESTORE stack */
451 #define SAVE_RESTORE_SIZE 128
452
453 STACK_DCL(options_stack, struct options *, SAVE_RESTORE_SIZE)
454 STACK_DCL(optimize_stack, struct optimize *, SAVE_RESTORE_SIZE)
455
456
457 void doPragma (int op, char *cp)
458 {
459   switch (op) {
460   case P_SAVE:
461     {
462       struct options *optionsp;
463       struct optimize *optimizep;
464
465       optionsp = Safe_malloc(sizeof (struct options));
466       *optionsp = options;
467       STACK_PUSH(options_stack, optionsp);
468
469       optimizep = Safe_malloc(sizeof (struct optimize));
470       *optimizep = optimize;
471       STACK_PUSH(optimize_stack, optimizep);
472     }
473     break;
474
475   case P_RESTORE:
476     {
477       struct options *optionsp;
478       struct optimize *optimizep;
479
480       optionsp = STACK_POP(options_stack);
481       options = *optionsp;
482       Safe_free(optionsp);
483
484       optimizep = STACK_POP(optimize_stack);
485       optimize = *optimizep;
486       Safe_free(optimizep);
487     }
488     break;
489
490   case P_NOINDUCTION:
491     optimize.loopInduction = 0 ;
492     break;
493
494   case P_NOINVARIANT:
495     optimize.loopInvariant = 0 ;
496     break;
497
498   case P_INDUCTION:
499     optimize.loopInduction = 1 ;
500     break;
501
502   case P_STACKAUTO:
503     options.stackAuto = 1;
504     break;
505
506   case P_NOJTBOUND:
507     optimize.noJTabBoundary = 1;
508     break;
509
510   case P_NOGCSE:
511     optimize.global_cse = 0;
512     break;
513
514   case P_NOOVERLAY:
515     options.noOverlay = 1;
516     break;
517
518   case P_LESSPEDANTIC:
519     options.lessPedantic = 1;
520     break;
521
522   case P_CALLEE_SAVES:
523     {
524       int i=0;
525       /* append to the functions already listed
526          in callee-saves */
527       for (; options.calleeSaves[i] ;i++);
528         parseWithComma(&options.calleeSaves[i], Safe_strdup(cp));
529     }
530     break;
531
532   case P_EXCLUDE:
533     parseWithComma(options.excludeRegs, Safe_strdup(cp));
534     break;
535
536   case P_NOIV:
537     options.noiv = 1;
538     break;
539
540   case P_LOOPREV:
541     optimize.noLoopReverse = 1;
542     break;
543
544   case P_OVERLAY_:
545     break; /* notyet */
546   }
547 }
548
549 int process_pragma(char *s)
550 {
551 #define NELEM(x)  (sizeof (x) / sizeof (x)[0])
552 #define PRAGMA    "#pragma"
553
554   static struct pragma_s {
555     const char *name;
556     enum pragma_id id;
557   } pragma_tbl[] = {
558     { "SAVE",           P_SAVE },
559     { "RESTORE",        P_RESTORE },
560     { "NOINDUCTION",    P_NOINDUCTION },
561     { "NOINVARIANT",    P_NOINVARIANT },
562     { "NOLOOPREVERSE",  P_LOOPREV },
563     { "INDUCTION",      P_INDUCTION },
564     { "STACKAUTO",      P_STACKAUTO },
565     { "NOJTBOUND",      P_NOJTBOUND },
566     { "NOGCSE",         P_NOGCSE },
567     { "NOOVERLAY",      P_NOOVERLAY },
568     { "CALLEE-SAVES",   P_CALLEE_SAVES },
569     { "EXCLUDE",        P_EXCLUDE },
570     { "NOIV",           P_NOIV },
571     { "OVERLAY",        P_OVERLAY_ },
572     { "LESS_PEDANTIC",  P_LESSPEDANTIC },
573   };
574   char *cp ;
575   int i;
576
577   /* find the pragma */
578   while (strncmp(s, PRAGMA, (sizeof PRAGMA) - 1))
579     s++;
580   s += (sizeof PRAGMA) - 1;
581     
582   /* look for the directive */
583   while(isspace(*s))
584     s++;
585
586   cp = s;
587   /* look for the end of the directive */
588   while ((!isspace(*s)) && (*s != '\n')) 
589     s++ ;    
590
591   /* First give the port a chance */
592   if (port->process_pragma && !port->process_pragma(cp))
593     return 0;
594
595   for (i = 0; i < NELEM(pragma_tbl); i++) {
596     /* now compare and do what needs to be done */
597     size_t len = strlen(pragma_tbl[i].name);
598
599     if (strncmp(cp, pragma_tbl[i].name, len) == 0) {
600       doPragma(pragma_tbl[i].id, cp + len);
601       return 0;
602     }
603   }
604
605   werror(W_UNKNOWN_PRAGMA,cp);
606   return 0;
607 }
608
609 /* will return 1 if the string is a part
610    of a target specific keyword */
611 int isTargetKeyword(char *s)
612 {
613     int i;
614     
615     if (port->keywords == NULL)
616         return 0;
617     for ( i = 0 ; port->keywords[i] ; i++ ) {
618         if (strcmp(port->keywords[i],s) == 0)
619             return 1;
620     }
621     
622     return 0;
623 }
624
625 extern int fatalError;
626
627 int yyerror(char *s)
628 {
629    fflush(stdout);
630
631    if (mylineno && filename) {
632      fprintf(stdout,"\n%s:%d: %s: token -> '%s' ; column %d\n",
633              filename,mylineno,
634              s,yytext,column);
635      fatalError++;
636    } else {
637      // this comes from an empy file, no problem
638    }
639    return 0;
640 }