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