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