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)
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
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.
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.
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 -------------------------------------------------------------------------*/
40 #define TKEYWORD(token) return (isTargetKeyword(yytext) ? token :\
43 extern int lineno, column;
44 extern char *filename;
46 /* global definitions */
50 /* local definitions */
51 static struct dbuf_s asmbuff;
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);
66 assert(asmbuff.alloc == 0 && asmbuff.len == 0 && asmbuff.buf == NULL);
67 dbuf_init(&asmbuff, INITIAL_INLINEASM);
72 yylval.yyinline = dbuf_c_str(&asmbuff);
73 dbuf_detach(&asmbuff);
79 dbuf_append(&asmbuff, yytext, 1);
82 dbuf_append(&asmbuff, yytext, 1);
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[0-7]*{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
144 [1-9]{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++ ; ignoreTypedefType = 0; return('{'); }
173 "}" { count(); NestLevel--; return('}'); }
174 "," { count(); return(','); }
175 ":" { count(); return(':'); }
176 "=" { count(); return('='); }
177 "(" { count(); ignoreTypedefType = 0; 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); }
198 ^[^(]+"("[0-9]+") : error"[^\n]+ { werror(E_PRE_PROC_FAILED, yytext); count(); }
199 ^[^(]+"("[0-9]+") : warning"[^\n]+ { werror(W_PRE_PROC_WARNING, yytext); count(); }
202 [ \t\v\f] { count(); }
206 /* that could have been removed by the preprocessor anyway */
207 werror (W_STRAY_BACKSLASH, column);
214 /* flex 2.5.31 undefines yytext_ptr, so we have to define it again */
216 #define yytext_ptr yytext
220 static int checkCurrFile (char *s)
225 /* skip '#' character */
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)
234 if (strncmp(s, LINE_STR, LINE_LEN) == 0)
237 /* get the line number */
238 lNum = strtol(s, &tptr, 10);
239 if (tptr == s || !isspace(*tptr))
243 /* now see if we have a file name */
244 while (*s != '\"' && *s)
247 /* if we don't have a filename then */
248 /* set the current line number to */
249 /* line number if printFlag is on */
251 lineno = mylineno = lNum;
255 /* if we have a filename then check */
256 /* if it is "standard in" if yes then */
257 /* get the currentfile name info */
260 /* in c1mode fullSrcFileName is NULL */
261 if (fullSrcFileName &&
262 strncmp(s, fullSrcFileName, strlen(fullSrcFileName)) == 0) {
263 lineno = mylineno = lNum;
264 currFname = fullSrcFileName;
267 /* mark the end of the filename */
268 while (*s != '"') s++;
270 currFname = strdup (sb);
271 lineno = mylineno = lNum;
273 filename = currFname ;
280 static void count(void)
283 for (i = 0; yytext[i] != '\0'; i++) {
284 if (yytext[i] == '\n') {
289 if (yytext[i] == '\t')
290 column += 8 - (column % 8);
297 static int check_type(void)
299 symbol *sym = findSym(SymbolTab, NULL, yytext);
301 /* check if it is in the table as a typedef */
302 if (!ignoreTypedefType && sym && IS_SPEC (sym->etype)
303 && SPEC_TYPEDEF (sym->etype)) {
304 strncpyz(yylval.yychar, yytext, SDCC_NAME_MAX);
308 strncpyz (yylval.yychar, yytext, SDCC_NAME_MAX);
314 * Change by JTV 2001-05-19 to not concantenate strings
315 * to support ANSI hex and octal escape sequences in string literals
318 static char *stringLiteral(void)
320 #define STR_BUF_CHUNCK_LEN 1024
322 static struct dbuf_s dbuf;
326 dbuf_init(&dbuf, STR_BUF_CHUNCK_LEN);
328 dbuf_set_size(&dbuf, 0);
330 dbuf_append(&dbuf, "\"", 1);
331 /* put into the buffer till we hit the first \" */
333 while ((ch = input()) != 0) {
336 /* if it is a \ then escape char's are allowed */
339 /* \<newline> is a continuator */
346 dbuf_append(&dbuf, buf, 2); /* get the escape char, no further check */
348 break; /* carry on */
351 /* if new line we have a new line break, which is illegal */
352 werror(W_NEWLINE_IN_STRING);
353 dbuf_append(&dbuf, "\n", 1);
359 /* if this is a quote then we have work to do */
360 /* find the next non whitespace character */
361 /* if that is a double quote then carry on */
362 dbuf_append(&dbuf, "\"", 1); /* Pass end of this string or substring to evaluator */
363 while ((ch = input()) && (isspace(ch) || ch == '\\')) {
366 if ((ch = input()) != '\n') {
367 werror(W_STRAY_BACKSLASH, column);
393 dbuf_append(&dbuf, buf, 1); /* Put next substring introducer into output string */
398 return (char *)dbuf_c_str(&dbuf);
417 P_OVERLAY_, /* I had a strange conflict with P_OVERLAY while */
418 /* cross-compiling for MINGW32 with gcc 3.2 */
426 /* SAVE/RESTORE stack */
427 #define SAVE_RESTORE_SIZE 128
429 STACK_DCL(options_stack, struct options *, SAVE_RESTORE_SIZE)
430 STACK_DCL(optimize_stack, struct optimize *, SAVE_RESTORE_SIZE)
433 * cloneXxx functions should be updated every time a new set is
434 * added to the options or optimize structure!
437 static struct options *cloneOptions(struct options *opt)
439 struct options *new_opt;
441 new_opt = Safe_malloc(sizeof (struct options));
443 /* clone scalar values */
447 new_opt->calleeSavesSet = setFromSetNonRev(opt->calleeSavesSet);
448 new_opt->excludeRegsSet = setFromSetNonRev(opt->excludeRegsSet);
449 /* not implemented yet: */
450 /* new_opt->olaysSet = setFromSetNonRev(opt->olaysSet); */
455 static struct optimize *cloneOptimize(struct optimize *opt)
457 struct optimize *new_opt;
459 new_opt = Safe_malloc(sizeof (struct options));
461 /* clone scalar values */
467 static void copyAndFreeOptions(struct options *dest, struct options *src)
469 /* delete dest sets */
470 deleteSet(&dest->calleeSavesSet);
471 deleteSet(&dest->excludeRegsSet);
472 /* not implemented yet: */
473 /* deleteSet(&dest->olaysSet); */
475 /* dopy src to dest */
481 static void copyAndFreeOptimize(struct optimize *dest, struct optimize *src)
483 /* dopy src to dest */
489 static void doPragma(int op, char *cp)
496 STACK_PUSH(options_stack, cloneOptions(&options));
497 STACK_PUSH(optimize_stack, cloneOptimize(&optimize));
503 struct options *optionsp;
504 struct optimize *optimizep;
506 optionsp = STACK_POP(options_stack);
507 copyAndFreeOptions(&options, optionsp);
509 optimizep = STACK_POP(optimize_stack);
510 copyAndFreeOptimize(&optimize, optimizep);
515 optimize.loopInduction = 0;
519 optimize.loopInvariant = 0;
523 optimize.loopInduction = 1;
527 options.stackAuto = 1;
531 optimize.noJTabBoundary = 1;
535 optimize.global_cse = 0;
539 options.noOverlay = 1;
543 options.lessPedantic = 1;
547 /* append to the functions already listed
549 setParseWithComma(&options.calleeSavesSet, cp);
554 deleteSet(&options.excludeRegsSet);
555 setParseWithComma(&options.excludeRegsSet, cp);
564 optimize.noLoopReverse = 1;
571 if (sscanf(cp, "%d", &i) && (i<MAX_ERROR_WARNING))
573 setWarningDisabled(i);
578 optimize.codeSpeed = 1;
579 optimize.codeSize = 0;
583 optimize.codeSpeed = 0;
584 optimize.codeSize = 1;
587 case P_OPTCODEBALANCED:
588 optimize.codeSpeed = 0;
589 optimize.codeSize = 0;
595 static int process_pragma(char *s)
597 #define NELEM(x) (sizeof (x) / sizeof (x)[0])
598 #define PRAGMA_STR "#pragma"
599 #define PRAGMA_LEN ((sizeof PRAGMA_STR) - 1)
601 static struct pragma_s
607 { "save", P_SAVE, 0 },
608 { "restore", P_RESTORE, 0 },
609 { "noinduction", P_NOINDUCTION, 0 },
610 { "noinvariant", P_NOINVARIANT, 0 },
611 { "noloopreverse", P_LOOPREV, 0 },
612 { "induction", P_INDUCTION, 0 },
613 { "stackauto", P_STACKAUTO, 0 },
614 { "nojtbound", P_NOJTBOUND, 0 },
615 { "nogcse", P_NOGCSE, 0 },
616 { "nooverlay", P_NOOVERLAY, 0 },
617 { "callee_saves", P_CALLEE_SAVES, 0 },
618 { "exclude", P_EXCLUDE, 0 },
619 { "noiv", P_NOIV, 0 },
620 { "overlay", P_OVERLAY_, 0 },
621 { "less_pedantic", P_LESSPEDANTIC, 0 },
622 { "disable_warning",P_DISABLEWARN, 0 },
623 { "opt_code_speed", P_OPTCODESPEED, 0 },
624 { "opt_code_size", P_OPTCODESIZE, 0 },
625 { "opt_code_balanced", P_OPTCODEBALANCED, 0 },
628 * The following lines are deprecated pragmas,
629 * only for bacward compatibility.
630 * They should be removed in next major release after 1.4.0
633 { "SAVE", P_SAVE, 1 },
634 { "RESTORE", P_RESTORE, 1 },
635 { "NOINDUCTION", P_NOINDUCTION, 1 },
636 { "NOINVARIANT", P_NOINVARIANT, 1 },
637 { "NOLOOPREVERSE", P_LOOPREV, 1 },
638 { "INDUCTION", P_INDUCTION, 1 },
639 { "STACKAUTO", P_STACKAUTO, 1 },
640 { "NOJTBOUND", P_NOJTBOUND, 1 },
641 { "NOGCSE", P_NOGCSE, 1 },
642 { "NOOVERLAY", P_NOOVERLAY, 1 },
643 { "CALLEE-SAVES", P_CALLEE_SAVES, 1 },
644 { "EXCLUDE", P_EXCLUDE, 1 },
645 { "NOIV", P_NOIV, 1 },
646 { "OVERLAY", P_OVERLAY_, 1 },
647 { "LESS_PEDANTIC", P_LESSPEDANTIC, 1 },
652 /* find the pragma */
653 while (strncmp(s, PRAGMA_STR, PRAGMA_LEN))
657 /* look for the directive */
662 /* look for the end of the directive */
663 while ((!isspace(*s)) && (*s != '\n'))
666 /* First give the port a chance */
667 if (port->process_pragma && !port->process_pragma(cp))
670 for (i = 0; i < NELEM(pragma_tbl); i++)
672 /* now compare and do what needs to be done */
673 size_t len = strlen(pragma_tbl[i].name);
675 if (strncmp(cp, pragma_tbl[i].name, len) == 0)
677 if (pragma_tbl[i].deprecated != 0)
678 werror(W_DEPRECATED_PRAGMA, pragma_tbl[i].name);
680 doPragma(pragma_tbl[i].id, cp + len);
685 werror(W_UNKNOWN_PRAGMA, cp);
689 /* will return 1 if the string is a part
690 of a target specific keyword */
691 static int isTargetKeyword(char *s)
695 if (port->keywords == NULL)
697 for (i = 0 ; port->keywords[i] ; i++ ) {
698 if (strcmp(port->keywords[i],s) == 0)
707 if (!STACK_EMPTY(options_stack) || !STACK_EMPTY(optimize_stack))
708 werror(W_SAVE_RESTORE);
717 if (mylineno && filename) {
718 if(options.vc_err_style)
719 fprintf(stderr, "\n%s(%d) : %s: token -> '%s' ; column %d\n",
720 filename, mylineno, s, yytext, column);
722 fprintf(stderr, "\n%s:%d: %s: token -> '%s' ; column %d\n",
723 filename, mylineno, s ,yytext, column);
726 /* this comes from an empy file, no problem */