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