Fix for bug #711240: dynamic buffer handling of C literal strings in stringLiteral()
[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  enum {
68      P_SAVE = 1,
69      P_RESTORE ,
70      P_NOINDUCTION,
71      P_NOINVARIANT,
72      P_INDUCTION ,
73      P_STACKAUTO ,
74      P_NOJTBOUND ,
75      P_NOOVERLAY ,
76      P_NOGCSE    ,
77      P_CALLEE_SAVES,
78      P_EXCLUDE   ,
79      P_NOIV      ,
80      P_LOOPREV   ,
81      P_OVERLAY_      /* I had a strange conflict with P_OVERLAY while */
82                      /* cross-compiling for MINGW32 with gcc 3.2 */
83  };
84
85 %}
86 %x asm
87 %%
88 "_asm"         {  
89   count(); 
90   asmp = asmbuff = realloc (asmbuff, INITIAL_INLINEASM);
91   asmbuffSize=INITIAL_INLINEASM;
92   BEGIN(asm) ;
93 }
94 <asm>"_endasm" { 
95   count();
96   *asmp = '\0';
97   yylval.yyinline = strdup (asmbuff);
98   BEGIN(INITIAL);
99   return (INLINEASM);
100 }
101 <asm>.         { 
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); 
107     asmp=asmbuff+size;
108   }
109   *asmp++ = yytext[0];
110 }
111 <asm>\n        { 
112   count(); 
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); 
118     asmp=asmbuff+size;
119   }
120   *asmp++ = '\n' ;
121 }
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); }
235
236 ^[^(]+"("[0-9]+") : error"[^\n]+ { werror(E_PRE_PROC_FAILED,yytext);count(); }
237 ^[^(]+"("[0-9]+") : warning"[^\n]+ { werror(W_PRE_PROC_WARNING,yytext);count(); }
238 "\r\n"             { count(); }
239 "\n"               { count(); }
240 [ \t\v\f]      { count(); }
241 \\ {
242   char ch=input();
243   if (ch!='\n') {
244     // that could have been removed by the preprocessor anyway
245     werror (W_STRAY_BACKSLASH, column);
246     unput(ch);
247   }
248 }
249 .                          { count()    ; }
250 %%
251
252 int checkCurrFile ( char *s)
253 {
254     char lineNum[10]                    ;
255     int  lNum                           ;
256     char *tptr                          ;
257        
258     /* first check if this is a #line */
259     if ( strncmp(s,"#line",5) )
260         return  0                               ;
261     
262     /* get to the line number */
263     while (!isdigit(*s))
264         s++ ;
265     tptr = lineNum ;
266     while (isdigit(*s))
267         *tptr++ = *s++ ;
268     *tptr = '\0'; 
269     sscanf(lineNum,"%d",&lNum);
270     
271     /* now see if we have a file name */
272     while (*s != '\"' && *s) 
273         s++ ;
274     
275     /* if we don't have a filename then */
276     /* set the current line number to   */
277     /* line number if printFlag is on   */
278     if (!*s) {          
279       lineno = yylineno = lNum ;
280       return 0;
281     }
282     
283     /* if we have a filename then check */
284     /* if it is "standard in" if yes then */
285     /* get the currentfile name info    */
286     s++ ;
287
288     /* in c1mode fullSrcFileName is NULL */
289     if ( fullSrcFileName &&
290          strncmp(s,fullSrcFileName,strlen(fullSrcFileName)) == 0) {
291       lineno = yylineno = lNum;                                 
292       currFname = fullSrcFileName ;
293     }  else {
294         char *sb = s;
295         /* mark the end of the filename */
296         while (*s != '"') s++;
297         *s = '\0';
298         currFname = strdup (sb);
299         lineno = yylineno = lNum;
300     }
301     filename = currFname ;
302     return 0;
303 }
304     
305 int column = 0;
306 int plineIdx=0;
307
308 void count()
309 {
310   int i;
311   for (i = 0; yytext[i] != '\0'; i++)   {                               
312     if (yytext[i] == '\n')      {         
313       column = 0;
314       lineno = ++yylineno ;
315     }
316     else 
317       if (yytext[i] == '\t')
318         column += 8 - (column % 8);
319       else
320         column++;
321   }
322   /* ECHO; */
323 }
324
325 int check_type()
326 {
327         /* check if it is in the typedef table */
328         if (findSym(TypedefTab,NULL,yytext)) {
329                 strncpyz(yylval.yychar,yytext, SDCC_NAME_MAX);
330                 return (TYPE_NAME) ;
331         }
332         else   {
333                 strncpyz (yylval.yychar,yytext, SDCC_NAME_MAX);
334                 return(IDENTIFIER);
335         }
336 }
337
338 /*
339  * Change by JTV 2001-05-19 to not concantenate strings
340  * to support ANSI hex and octal escape sequences in string liteals 
341  */
342
343 char *stringLiteral()
344 {
345 #define STR_BUF_CHUNCK_LEN  1024
346   int ch;
347   static struct dbuf_s dbuf;
348   char buf[2];
349
350   if (dbuf.alloc == 0)
351     dbuf_init(&dbuf, STR_BUF_CHUNCK_LEN);
352   else
353     dbuf_set_size(&dbuf, 0);
354
355
356   dbuf_append(&dbuf, "\"", 1);
357   /* put into the buffer till we hit the first \" */
358
359   while ((ch = input()) != 0) {
360     switch (ch) {
361     case '\\':
362       /* if it is a \ then escape char's are allowed */
363       ch = input();
364       if (ch == '\n') {
365         /* \<newline> is a continuator */
366         lineno = ++yylineno;
367         column = 0;
368       }
369       else {
370         buf[0] = '\\';
371         buf[1] = ch;
372         dbuf_append(&dbuf, buf, 2); /* get the escape char, no further check */
373       }
374       break; /* carry on */
375
376     case '\n':
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);
380       lineno = ++yylineno;
381       column = 0;
382       break;
383
384     case '"':
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=='\\')) {
390         switch (ch) {
391         case '\\':
392           if ((ch = input()) != '\n') {
393             werror(W_STRAY_BACKSLASH, column);
394             unput(ch);
395           }
396           else {
397             lineno = ++yylineno;
398             column = 0;
399           }
400           break;
401
402         case '\n':
403           yylineno++;
404           break;
405         }
406       }
407
408       if (!ch) 
409         goto out;
410
411       if (ch != '\"') {
412         unput(ch) ;
413         goto out;
414       }
415       break;
416
417     default:
418       buf[0] = ch;
419       dbuf_append(&dbuf, buf, 1);  /* Put next substring introducer into output string */
420     }
421   }
422
423 out:
424   return (char *)dbuf_c_str(&dbuf);
425 }
426
427 void doPragma (int op, char *cp)
428 {
429     switch (op) {
430     case P_SAVE:
431         memcpy(&save_options,&options,sizeof(options));
432         memcpy(&save_optimize,&optimize,sizeof(optimize));
433         break;
434     case P_RESTORE:
435         memcpy(&options,&save_options,sizeof(options));
436         memcpy(&optimize,&save_optimize,sizeof(optimize));
437         break;
438     case P_NOINDUCTION:
439         optimize.loopInduction = 0 ;
440         break;
441     case P_NOINVARIANT:
442         optimize.loopInvariant = 0 ;
443         break;
444     case P_INDUCTION:
445         optimize.loopInduction = 1 ;
446         break;
447     case P_STACKAUTO:
448         options.stackAuto = 1;
449         break;
450     case P_NOJTBOUND:
451         optimize.noJTabBoundary = 1;
452         break;
453     case P_NOGCSE:
454         optimize.global_cse = 0;
455         break;
456     case P_NOOVERLAY:
457         options.noOverlay = 1;
458         break;
459     case P_CALLEE_SAVES:
460         {
461             int i=0;
462             /* append to the functions already listed
463                in callee-saves */
464             for (; options.calleeSaves[i] ;i++);
465             parseWithComma(&options.calleeSaves[i], Safe_strdup(cp));
466         }
467         break;
468     case P_EXCLUDE:
469         parseWithComma(options.excludeRegs, Safe_strdup(cp));
470         break;
471     case P_NOIV:
472         options.noiv = 1;
473         break;
474     case P_LOOPREV:
475         optimize.noLoopReverse = 1;
476         break;
477     case P_OVERLAY_:
478         break; /* notyet */
479     }
480 }
481
482 int process_pragma(char *s)
483 {
484     char *cp ;
485     /* find the pragma */
486     while (strncmp(s,"#pragma",7))
487         s++;
488     s += 7;
489     
490     /* look for the directive */
491     while(isspace(*s)) s++;
492
493     cp = s;
494     /* look for the end of the directive */
495     while ((! isspace(*s)) && 
496            (*s != '\n')) 
497         s++ ;    
498
499     /* First give the port a chance */
500     if (port->process_pragma && !port->process_pragma(cp))
501         return 0;
502
503     /* now compare and do what needs to be done */
504     if (strncmp(cp,PRAGMA_SAVE,strlen(PRAGMA_SAVE)) == 0) {
505         doPragma(P_SAVE,cp+strlen(PRAGMA_SAVE));
506         return 0;
507     }
508
509     if (strncmp(cp,PRAGMA_RESTORE,strlen(PRAGMA_RESTORE)) == 0) {
510         doPragma (P_RESTORE,cp+strlen(PRAGMA_RESTORE));
511         return 0;
512     }
513
514     if (strncmp(cp,PRAGMA_NOINDUCTION,strlen(PRAGMA_NOINDUCTION)) == 0) {
515         doPragma (P_NOINDUCTION,cp+strlen(PRAGMA_NOINDUCTION))  ;
516         return 0;
517     }
518
519     if (strncmp(cp,PRAGMA_NOINVARIANT,strlen(PRAGMA_NOINVARIANT)) == 0) {
520         doPragma (P_NOINVARIANT,NULL)   ;
521         return 0;
522     }
523
524     if (strncmp(cp,PRAGMA_INDUCTION,strlen(PRAGMA_INDUCTION)) == 0) {
525         doPragma (P_INDUCTION,NULL)     ;
526         return 0;
527     }
528
529     if (strncmp(cp,PRAGMA_STACKAUTO,strlen(PRAGMA_STACKAUTO)) == 0) {
530         doPragma (P_STACKAUTO,NULL);
531         return 0;
532     }
533
534     if (strncmp(cp,PRAGMA_NOJTBOUND,strlen(PRAGMA_NOJTBOUND)) == 0) {
535         doPragma (P_NOJTBOUND,NULL);
536         return 0;
537     }
538
539     if (strncmp(cp,PRAGMA_NOGCSE,strlen(PRAGMA_NOGCSE)) == 0) {
540         doPragma (P_NOGCSE,NULL);
541         return 0;
542     }
543
544     if (strncmp(cp,PRAGMA_NOOVERLAY,strlen(PRAGMA_NOOVERLAY)) == 0) {
545         doPragma (P_NOOVERLAY,NULL);
546         return 0;
547     }
548     
549     if (strncmp(cp,PRAGMA_CALLEESAVES,strlen(PRAGMA_CALLEESAVES)) == 0) {
550         doPragma(P_CALLEE_SAVES,cp+strlen(PRAGMA_CALLEESAVES));
551         return 0;
552     }
553     
554     if (strncmp(cp,PRAGMA_EXCLUDE,strlen(PRAGMA_EXCLUDE)) == 0) {
555         doPragma(P_EXCLUDE,cp+strlen(PRAGMA_EXCLUDE));
556         return 0;
557     }
558
559     if (strncmp(cp,PRAGMA_NOIV,strlen(PRAGMA_NOIV)) == 0) {
560         doPragma(P_NOIV,cp+strlen(PRAGMA_NOIV));
561         return 0;
562     }
563
564     if (strncmp(cp,PRAGMA_NOLOOPREV,strlen(PRAGMA_NOLOOPREV)) == 0) {
565         doPragma(P_LOOPREV,NULL);
566         return 0;
567     }
568
569     werror(W_UNKNOWN_PRAGMA,cp);
570     return 0;
571 }
572
573 /* will return 1 if the string is a part
574    of a target specific keyword */
575 int isTargetKeyword(char *s)
576 {
577     int i;
578     
579     if (port->keywords == NULL)
580         return 0;
581     for ( i = 0 ; port->keywords[i] ; i++ ) {
582         if (strcmp(port->keywords[i],s) == 0)
583             return 1;
584     }
585     
586     return 0;
587 }
588
589 extern int fatalError;
590
591 int yyerror(char *s)
592 {
593    fflush(stdout);
594
595    if (yylineno && filename) {
596      fprintf(stdout,"\n%s:%d: %s: token -> '%s' ; column %d\n",
597              filename,yylineno,
598              s,yytext,column);
599      fatalError++;
600    } else {
601      // this comes from an empy file, no problem
602    }
603    return 0;
604 }