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 -------------------------------------------------------------------------*/
42 static char *stringLiteral(void);
45 extern int lineno, column;
46 extern char *filename;
48 static void count(void);
49 static int process_pragma(char *);
55 #define YY_PROTO(proto) proto
57 #define YY_PROTO(proto) ()
62 int yywrap YY_PROTO((void))
67 static void yyunput (int, char *);
69 static void my_unput(char c)
71 yyunput(c, (yytext_ptr));
74 #define TKEYWORD(token) return (isTargetKeyword(yytext) ? token :\
79 static int check_type(void);
80 static int isTargetKeyword(char *s);
81 static int checkCurrFile (char *s);
82 struct optimize save_optimize;
83 struct options save_options;
90 asmp = asmbuff = realloc (asmbuff, INITIAL_INLINEASM);
91 asmbuffSize=INITIAL_INLINEASM;
97 yylval.yyinline = strdup (asmbuff);
102 if (asmp-asmbuff >= asmbuffSize-2) {
103 /* increase the buffersize with 50% */
104 int size=asmp-asmbuff;
105 asmbuffSize=asmbuffSize*3/2;
106 asmbuff = realloc (asmbuff, asmbuffSize);
113 if (asmp-asmbuff >= asmbuffSize-3) {
114 /* increase the buffersize with 50% */
115 int size=asmp-asmbuff;
116 asmbuffSize=asmbuffSize*3/2;
117 asmbuff = realloc (asmbuff, asmbuffSize);
122 "at" { count(); TKEYWORD(AT) ; }
123 "auto" { count(); return(AUTO); }
124 "bit" { count(); TKEYWORD(BIT) ; }
125 "break" { count(); return(BREAK); }
126 "case" { count(); return(CASE); }
127 "char" { count(); return(CHAR); }
128 "code" { count(); TKEYWORD(CODE); }
129 "const" { count(); return(CONST); }
130 "continue" { count(); return(CONTINUE); }
131 "critical" { count(); TKEYWORD(CRITICAL); }
132 "data" { count(); TKEYWORD(DATA); }
133 "default" { count(); return(DEFAULT); }
134 "do" { count(); return(DO); }
135 "double" { count(); werror(W_DOUBLE_UNSUPPORTED);return(FLOAT); }
136 "else" { count(); return(ELSE); }
137 "enum" { count(); return(ENUM); }
138 "extern" { count(); return(EXTERN); }
139 "far" { count(); TKEYWORD(XDATA); }
140 "eeprom" { count(); TKEYWORD(EEPROM); }
141 "float" { count(); return(FLOAT); }
142 "flash" { count(); TKEYWORD(CODE);}
143 "for" { count(); return(FOR); }
144 "goto" { count(); return(GOTO); }
145 "idata" { count(); TKEYWORD(IDATA);}
146 "if" { count(); return(IF); }
147 "int" { count(); return(INT); }
148 "interrupt" { count(); return(INTERRUPT);}
149 "nonbanked" { count(); TKEYWORD(NONBANKED);}
150 "banked" { count(); TKEYWORD(BANKED);}
151 "long" { count(); return(LONG); }
152 "near" { count(); TKEYWORD(DATA);}
153 "pdata" { count(); TKEYWORD(PDATA); }
154 "reentrant" { count(); TKEYWORD(REENTRANT);}
155 "register" { count(); return(REGISTER); }
156 "return" { count(); return(RETURN); }
157 "sfr" { count(); TKEYWORD(SFR) ; }
158 "sbit" { count(); TKEYWORD(SBIT) ; }
159 "short" { count(); return(SHORT); }
160 "signed" { count(); return(SIGNED); }
161 "sizeof" { count(); return(SIZEOF); }
162 "sram" { count(); TKEYWORD(XDATA);}
163 "static" { count(); return(STATIC); }
164 "struct" { count(); return(STRUCT); }
165 "switch" { count(); return(SWITCH); }
166 "typedef" { count(); return(TYPEDEF); }
167 "union" { count(); return(UNION); }
168 "unsigned" { count(); return(UNSIGNED); }
169 "void" { count(); return(VOID); }
170 "volatile" { count(); return(VOLATILE); }
171 "using" { count(); TKEYWORD(USING); }
172 "_naked" { count(); TKEYWORD(NAKED); }
173 "while" { count(); return(WHILE); }
174 "xdata" { count(); TKEYWORD(XDATA); }
175 "..." { count(); return(VAR_ARGS);}
176 "__typeof" { count(); return TYPEOF;}
177 "_JavaNative" { count(); TKEYWORD(JAVANATIVE);}
178 "_overlay" { count(); TKEYWORD(OVERLAY);}
179 {L}({L}|{D})* { count(); return(check_type()); }
180 0[xX]{H}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
181 0{D}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
182 {D}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
183 '(\\.|[^\\'])+' { count();yylval.val = charVal (yytext); return(CONSTANT); /* ' make syntax highliter happy */}
184 {D}+{E}{FS}? { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
185 {D}*"."{D}+({E})?{FS}? { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
186 {D}+"."{D}*({E})?{FS}? { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
187 \" { count(); yylval.val=strVal(stringLiteral()); return(STRING_LITERAL);}
188 ">>=" { count(); yylval.yyint = RIGHT_ASSIGN ; return(RIGHT_ASSIGN); }
189 "<<=" { count(); yylval.yyint = LEFT_ASSIGN ; return(LEFT_ASSIGN) ; }
190 "+=" { count(); yylval.yyint = ADD_ASSIGN ; return(ADD_ASSIGN) ; }
191 "-=" { count(); yylval.yyint = SUB_ASSIGN ; return(SUB_ASSIGN) ; }
192 "*=" { count(); yylval.yyint = MUL_ASSIGN ; return(MUL_ASSIGN) ; }
193 "/=" { count(); yylval.yyint = DIV_ASSIGN ; return(DIV_ASSIGN) ; }
194 "%=" { count(); yylval.yyint = MOD_ASSIGN ; return(MOD_ASSIGN) ; }
195 "&=" { count(); yylval.yyint = AND_ASSIGN ; return(AND_ASSIGN) ; }
196 "^=" { count(); yylval.yyint = XOR_ASSIGN ; return(XOR_ASSIGN) ; }
197 "|=" { count(); yylval.yyint = OR_ASSIGN ; return(OR_ASSIGN) ; }
198 ">>" { count(); return(RIGHT_OP); }
199 "<<" { count(); return(LEFT_OP); }
200 "++" { count(); return(INC_OP); }
201 "--" { count(); return(DEC_OP); }
202 "->" { count(); return(PTR_OP); }
203 "&&" { count(); return(AND_OP); }
204 "||" { count(); return(OR_OP); }
205 "<=" { count(); return(LE_OP); }
206 ">=" { count(); return(GE_OP); }
207 "==" { count(); return(EQ_OP); }
208 "!=" { count(); return(NE_OP); }
209 ";" { count(); return(';'); }
210 "{" { count(); NestLevel++ ; return('{'); }
211 "}" { count(); NestLevel--; return('}'); }
212 "," { count(); return(','); }
213 ":" { count(); 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 ^#line.*"\n" { count(); checkCurrFile(yytext); }
234 ^#pragma.*"\n" { count(); process_pragma(yytext); }
236 ^[^(]+"("[0-9]+") : error"[^\n]+ { werror(E_PRE_PROC_FAILED,yytext);count(); }
237 ^[^(]+"("[0-9]+") : warning"[^\n]+ { werror(W_PRE_PROC_WARNING,yytext);count(); }
240 [ \t\v\f] { count(); }
244 /* that could have been removed by the preprocessor anyway */
245 werror (W_STRAY_BACKSLASH, column);
252 static int checkCurrFile (char *s)
258 /* first check if this is a #line */
259 if ( strncmp(s,"#line",5) )
262 /* get to the line number */
269 sscanf(lineNum,"%d",&lNum);
271 /* now see if we have a file name */
272 while (*s != '\"' && *s)
275 /* if we don't have a filename then */
276 /* set the current line number to */
277 /* line number if printFlag is on */
279 lineno = mylineno = lNum ;
283 /* if we have a filename then check */
284 /* if it is "standard in" if yes then */
285 /* get the currentfile name info */
288 /* in c1mode fullSrcFileName is NULL */
289 if ( fullSrcFileName &&
290 strncmp(s,fullSrcFileName,strlen(fullSrcFileName)) == 0) {
291 lineno = mylineno = lNum;
292 currFname = fullSrcFileName ;
295 /* mark the end of the filename */
296 while (*s != '"') s++;
298 currFname = strdup (sb);
299 lineno = mylineno = lNum;
301 filename = currFname ;
308 static void count(void)
311 for (i = 0; yytext[i] != '\0'; i++) {
312 if (yytext[i] == '\n') {
314 lineno = ++mylineno ;
317 if (yytext[i] == '\t')
318 column += 8 - (column % 8);
325 static int check_type(void)
327 /* check if it is in the typedef table */
328 if (findSym(TypedefTab,NULL,yytext)) {
329 strncpyz(yylval.yychar,yytext, SDCC_NAME_MAX);
333 strncpyz (yylval.yychar,yytext, SDCC_NAME_MAX);
339 * Change by JTV 2001-05-19 to not concantenate strings
340 * to support ANSI hex and octal escape sequences in string liteals
343 static char *stringLiteral(void)
345 #define STR_BUF_CHUNCK_LEN 1024
347 static struct dbuf_s dbuf;
351 dbuf_init(&dbuf, STR_BUF_CHUNCK_LEN);
353 dbuf_set_size(&dbuf, 0);
356 dbuf_append(&dbuf, "\"", 1);
357 /* put into the buffer till we hit the first \" */
359 while ((ch = input()) != 0) {
362 /* if it is a \ then escape char's are allowed */
365 /* \<newline> is a continuator */
372 dbuf_append(&dbuf, buf, 2); /* get the escape char, no further check */
374 break; /* carry on */
377 /* if new line we have a new line break, which is illegal */
378 werror(W_NEWLINE_IN_STRING);
379 dbuf_append(&dbuf, "\n", 1);
385 /* if this is a quote then we have work to do */
386 /* find the next non whitespace character */
387 /* if that is a double quote then carry on */
388 dbuf_append(&dbuf, "\"", 1); /* Pass end of this string or substring to evaluator */
389 while ((ch = input()) && (isspace(ch) || ch=='\\')) {
392 if ((ch = input()) != '\n') {
393 werror(W_STRAY_BACKSLASH, column);
419 dbuf_append(&dbuf, buf, 1); /* Put next substring introducer into output string */
424 return (char *)dbuf_c_str(&dbuf);
443 P_OVERLAY_ /* I had a strange conflict with P_OVERLAY while */
444 /* cross-compiling for MINGW32 with gcc 3.2 */
448 /* SAVE/RESTORE stack */
449 #define SAVE_RESTORE_SIZE 128
451 STACK_DCL(options_stack, struct options *, SAVE_RESTORE_SIZE)
452 STACK_DCL(optimize_stack, struct optimize *, SAVE_RESTORE_SIZE)
455 * cloneXxx functions should be updated every time a new set is
456 * added to the options or optimize structure!
459 static struct options *cloneOptions(struct options *opt)
461 struct options *new_opt;
463 new_opt = Safe_malloc(sizeof (struct options));
465 /* clone scalar values */
469 new_opt->calleeSavesSet = setFromSetNonRev(opt->calleeSavesSet);
470 new_opt->excludeRegsSet = setFromSetNonRev(opt->excludeRegsSet);
471 /* not implemented yet: */
472 /* new_opt->olaysSet = setFromSetNonRev(opt->olaysSet); */
477 static struct optimize *cloneOptimize(struct optimize *opt)
479 struct optimize *new_opt;
481 new_opt = Safe_malloc(sizeof (struct options));
483 /* clone scalar values */
489 static void copyAndFreeOptions(struct options *dest, struct options *src)
491 /* delete dest sets */
492 deleteSet(&dest->calleeSavesSet);
493 deleteSet(&dest->excludeRegsSet);
494 /* not implemented yet: */
495 /* deleteSet(&dest->olaysSet); */
497 /* dopy src to dest */
503 static void copyAndFreeOptimize(struct optimize *dest, struct optimize *src)
505 /* dopy src to dest */
511 static void doPragma(int op, char *cp)
516 STACK_PUSH(options_stack, cloneOptions(&options));
517 STACK_PUSH(optimize_stack, cloneOptimize(&optimize));
523 struct options *optionsp;
524 struct optimize *optimizep;
526 optionsp = STACK_POP(options_stack);
527 copyAndFreeOptions(&options, optionsp);
529 optimizep = STACK_POP(optimize_stack);
530 copyAndFreeOptimize(&optimize, optimizep);
535 optimize.loopInduction = 0 ;
539 optimize.loopInvariant = 0 ;
543 optimize.loopInduction = 1 ;
547 options.stackAuto = 1;
551 optimize.noJTabBoundary = 1;
555 optimize.global_cse = 0;
559 options.noOverlay = 1;
563 options.lessPedantic = 1;
567 /* append to the functions already listed
569 setParseWithComma(&options.calleeSavesSet, cp);
574 deleteSet(&options.excludeRegsSet);
575 setParseWithComma(&options.excludeRegsSet, cp);
584 optimize.noLoopReverse = 1;
592 static int process_pragma(char *s)
594 #define NELEM(x) (sizeof (x) / sizeof (x)[0])
595 #define PRAGMA "#pragma"
597 static struct pragma_s {
602 { "RESTORE", P_RESTORE },
603 { "NOINDUCTION", P_NOINDUCTION },
604 { "NOINVARIANT", P_NOINVARIANT },
605 { "NOLOOPREVERSE", P_LOOPREV },
606 { "INDUCTION", P_INDUCTION },
607 { "STACKAUTO", P_STACKAUTO },
608 { "NOJTBOUND", P_NOJTBOUND },
609 { "NOGCSE", P_NOGCSE },
610 { "NOOVERLAY", P_NOOVERLAY },
611 { "CALLEE-SAVES", P_CALLEE_SAVES },
612 { "EXCLUDE", P_EXCLUDE },
614 { "OVERLAY", P_OVERLAY_ },
615 { "LESS_PEDANTIC", P_LESSPEDANTIC },
620 /* find the pragma */
621 while (strncmp(s, PRAGMA, (sizeof PRAGMA) - 1))
623 s += (sizeof PRAGMA) - 1;
625 /* look for the directive */
630 /* look for the end of the directive */
631 while ((!isspace(*s)) && (*s != '\n'))
634 /* First give the port a chance */
635 if (port->process_pragma && !port->process_pragma(cp))
638 for (i = 0; i < NELEM(pragma_tbl); i++) {
639 /* now compare and do what needs to be done */
640 size_t len = strlen(pragma_tbl[i].name);
642 if (strncmp(cp, pragma_tbl[i].name, len) == 0) {
643 doPragma(pragma_tbl[i].id, cp + len);
648 werror(W_UNKNOWN_PRAGMA,cp);
652 /* will return 1 if the string is a part
653 of a target specific keyword */
654 static int isTargetKeyword(char *s)
658 if (port->keywords == NULL)
660 for ( i = 0 ; port->keywords[i] ; i++ ) {
661 if (strcmp(port->keywords[i],s) == 0)
672 if (mylineno && filename) {
673 if(options.vc_err_style)
674 fprintf(stderr,"\n%s(%d) : %s: token -> '%s' ; column %d\n",
678 fprintf(stderr,"\n%s:%d: %s: token -> '%s' ; column %d\n",
683 /* this comes from an empy file, no problem */