Mercurial > hg > CbC > old > device
annotate mc-macro.c @ 872:11abda130b91
struct init on going ...
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 01 Apr 2014 16:57:16 +0900 |
parents | e253ffedf947 |
children | f7803d618f36 |
rev | line source |
---|---|
607 | 1 /* Micro-C Preprocessor Part */ |
327 | 2 |
607 | 3 /************************************************************************ |
4 ** Copyright (C) 2006 Shinji Kono | |
5 ** 連絡先: 琉球大学情報工学科 河野 真治 | |
6 ** (E-Mail Address: kono@ie.u-ryukyu.ac.jp) | |
7 ** | |
8 ** このソースのいかなる複写,改変,修正も許諾します。ただし、 | |
9 ** その際には、誰が貢献したを示すこの部分を残すこと。 | |
10 ** 再配布や雑誌の付録などの問い合わせも必要ありません。 | |
11 ** 営利利用も上記に反しない範囲で許可します。 | |
12 ** バイナリの配布の際にはversion messageを保存することを条件とします。 | |
13 ** このプログラムについては特に何の保証もしない、悪しからず。 | |
14 ** | |
15 ** Everyone is permitted to do anything on this program | |
16 ** including copying, modifying, improving, | |
17 ** as long as you don't try to pretend that you wrote it. | |
18 ** i.e., the above copyright notice has to appear in all copies. | |
19 ** Binary distribution requires original version messages. | |
20 ** You don't have to ask before copying, redistribution or publishing. | |
21 ** THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. | |
22 ***********************************************************************/ | |
327 | 23 #include <stdio.h> |
24 #include "mc.h" | |
25 #include "mc-parse.h" | |
26 #include "mc-macro.h" | |
456 | 27 #include "mc-codegen.h" |
327 | 28 #include "mc-code.h" |
705 | 29 #include "mc-inline.h" |
327 | 30 |
31 extern struct {int fd,ln;char *name0;int inc;FILE *fcb;} *filep,filestack[FILES]; | |
32 | |
33 int in_macro_if = 0; | |
34 char *chinput; | |
721 | 35 int macro_history = 0; |
36 int macro_history_save = 0; | |
327 | 37 |
38 static int mconcat=0; | |
39 | |
40 static void macro_define0(); | |
346 | 41 static int macro_args(char **pchptr); |
327 | 42 static int macro_function(int macrop,char **pchptr,NMTBL *nptr,int history); |
855 | 43 static void local_define(char *macro,char *value, char *name); |
327 | 44 static int macro_eval(int macrop,char *body0,int history); |
553 | 45 static char * mappend0(int lists,char **result); |
327 | 46 static int macro_processing(); |
47 | |
561 | 48 /* |
712 | 49 nptr->dsp |
50 list3s(MACRO,arg,char*) | |
51 | |
52 list3s(STRING,next,char*) | |
53 */ | |
54 | |
55 /* | |
561 | 56 |
57 macro_expansion(NMTBL *nptrm) | |
58 innput macro term (and chptr for arguments) | |
59 result put into cheap, and chptr is set. | |
60 current ch and chptr are pushed into chptr stack. | |
327 | 61 |
561 | 62 ## concatenation requires repeated replace. |
63 | |
64 In macro_function and macro_eavl, | |
65 expand result is put into macrop local variable. | |
861 | 66 list3s(STRING,next,char*) |
561 | 67 to generate result, mappend/reverse0 is necessary. |
68 | |
363 | 69 */ |
70 | |
861 | 71 void |
327 | 72 macro_expansion(NMTBL *nptrm) |
73 { | |
74 int i = mode; | |
75 int macrop = 0; | |
76 int slfree = lfree; | |
540 | 77 int c; |
78 char *macropp,*s,*t; | |
346 | 79 struct cheap scheap; |
327 | 80 mode = STAT; |
81 | |
346 | 82 save_cheap(&scheap,cheap); |
721 | 83 // save recursive macro list |
84 macro_history_save = glist2(macro_history,macro_history_save); | |
346 | 85 |
625 | 86 // call macro evaluation interpreter |
327 | 87 if (nptrm->sc == FMACRO) { |
721 | 88 macrop=macro_function(macrop,&chptr,nptrm,macro_history); |
327 | 89 } else { |
721 | 90 macrop=macro_eval(macrop,scaddr(nptrm->dsp),macro_history); |
327 | 91 } |
625 | 92 |
93 // copy output from resulted listed string | |
94 | |
347 | 95 cheap = reset_cheap(&scheap); |
346 | 96 macropp = cheap->ptr; |
561 | 97 // append result override, working cheap, but it's OK. |
553 | 98 mappend0(reverse0(macrop),¯opp); |
564 | 99 // cheap->ptr[-1] ='\n'; // makes some tokenize happy |
100 // ## macro_result needs \n at end | |
101 cheap->ptr[-1] = 0; // makes some tokenize happy | |
102 t = cheap->ptr-2; | |
346 | 103 cheap->ptr[0] =0; |
540 | 104 cheap = increment_cheap(cheap,¯opp); |
625 | 105 |
106 // if we have ## (concatenation), | |
107 // remove \s**##\s* | |
108 // it is difficult to remove former space on the fly, | |
109 // so multi path loop is required | |
110 | |
327 | 111 while (mconcat) { |
112 // ## re-eval macro | |
861 | 113 if (lsrc) printf("## before %s",macropp); |
327 | 114 mconcat = 0; |
115 macrop = 0; | |
861 | 116 for(s=t=macropp;*s;) { |
117 if ((c=*s++)=='#'&&*s=='#') { | |
118 if (t>s-3) t=s-2; else t--; | |
119 while(*t<=' '&&t>macropp) t--; t++; | |
120 for(s++;*s && *s<=' ';) s++; | |
121 continue; | |
122 } else if (c==STRING) { | |
123 c = '"'; | |
124 } | |
125 *t++=c; | |
126 } | |
127 *t++=0; | |
859 | 128 #if 0 |
861 | 129 if (1 && lsrc) { |
130 printf("\n### %s\n",macropp); | |
131 if (t[-2]!='\n') putchar('\n'); | |
132 } | |
859 | 133 #endif |
861 | 134 // evaluate generated result again |
721 | 135 macrop=macro_eval(macrop,macropp,macro_history); |
861 | 136 cheap = reset_cheap(&scheap); |
137 macropp = cheap->ptr; | |
138 // will not override evaled list | |
553 | 139 mappend0(reverse0(macrop),¯opp); |
861 | 140 // cheap->ptr[-1] ='\n'; |
141 cheap->ptr[-1] =0; | |
142 cheap->ptr[0] =0; | |
143 cheap = increment_cheap(cheap,¯opp); | |
327 | 144 } |
346 | 145 cheap = reset_cheap(&scheap); |
561 | 146 // genrated macro will be overwrited by cheap, but it's OK, again |
327 | 147 mconcat = 0; |
447 | 148 set_lfree(slfree); |
690 | 149 #if 0 |
150 if (lsrc && !asmf && nptrm->sc==FMACRO) { | |
861 | 151 gen_comment(macropp); |
152 if (0 && t[-2]!='\n') putchar('\n'); | |
690 | 153 } |
154 #endif | |
561 | 155 // push previous chptr, and change it to the generate macro |
712 | 156 chptrsave = glist3s(STRING,chptrsave,chptr); // push old one into the stack |
327 | 157 chsave = glist2(ch,chsave); |
346 | 158 chptr = macropp; |
327 | 159 ch = *chptr++; |
160 mode = i; | |
161 } | |
162 | |
163 /* file inclusion */ | |
164 | |
363 | 165 /* |
166 file name concatenation | |
861 | 167 on cheap |
363 | 168 */ |
169 | |
327 | 170 static char * |
346 | 171 expand_file_name(char *path,char *name) |
327 | 172 { |
346 | 173 char *p = cheap->ptr; |
174 if (! *path) return name; | |
175 while(( *cheap->ptr = *path++ )) cheap = increment_cheap(cheap,&p); | |
176 if (cheap->ptr[-1]!='/') { | |
861 | 177 *cheap->ptr = '/'; cheap = increment_cheap(cheap,&p); |
346 | 178 } |
179 while(( *cheap->ptr = *name++ )) cheap = increment_cheap(cheap,&p); | |
351 | 180 *cheap->ptr = 0; |
181 cheap = increment_cheap(cheap,&p); | |
327 | 182 return p; |
183 } | |
184 | |
363 | 185 /* |
625 | 186 internal string compare routine |
187 nameeq in mc-parse.c relies on | |
188 global name variable | |
189 */ | |
190 | |
191 static int | |
192 nameeq(char *p, char *q) | |
193 { | |
194 if (!p) | |
195 return 0; | |
196 while(*p) | |
197 if(*p++ != *q++) return 0; | |
198 return (*q==0); | |
199 } | |
200 | |
201 /* | |
202 file name expansion | |
203 | |
204 Get file name from input stream. | |
205 Result is store in filep structure. | |
206 included file is put on the filep stack | |
207 return filep | |
208 | |
209 filename is copied into cheap | |
210 | |
211 possibly expanded by search path (including current | |
212 directory ). | |
213 | |
363 | 214 get file name |
215 <name> => name | |
216 current_file_name_dir / name | |
217 libdir / name | |
218 "name" => name | |
219 current_file_name_dir / name | |
220 include_path / name | |
861 | 221 (no difference?) |
561 | 222 next flag ignores the first occurence. |
363 | 223 */ |
224 | |
540 | 225 |
327 | 226 static FILE * |
469 | 227 getfname(int next) |
327 | 228 { |
229 int i,end='"',err=0; | |
673 | 230 char *s,*p,**pp,*name,*prev=0; |
327 | 231 FILE *fp; |
346 | 232 struct cheap scheap; |
233 name = cheap->ptr; | |
327 | 234 |
235 getch(); | |
236 if(skipspc()=='"') { end = '"'; | |
237 } else if (ch=='<') { end = '>'; | |
238 } else { error(INCERR); err=1; | |
239 } | |
240 for(i=0;(getch()!=end && ch!='\n');) { | |
861 | 241 *cheap->ptr = ch; |
242 cheap = increment_cheap(cheap,&name); | |
327 | 243 } |
244 if(ch=='\n') error(INCERR); | |
245 if (err) return filep->fcb; | |
351 | 246 *cheap->ptr = 0; |
247 cheap = increment_cheap(cheap,&name); | |
248 save_cheap(&scheap,cheap); | |
327 | 249 fp = fopen(name,"r") ; |
540 | 250 if (next && fp) { fclose(fp); fp=0; next=0; prev=name; } |
713 | 251 p = name; |
252 if (!fp) { | |
861 | 253 // no deferenced on "" and <>? |
254 for(pp=include_path; *pp;pp++) { | |
255 p = expand_file_name(*pp,name); | |
256 if(prev && nameeq(p,prev)) continue; | |
257 if ((fp = fopen(p,"r"))) { | |
258 if (next) { | |
259 fclose(fp); fp=0; next=0; prev=p; | |
260 continue; | |
261 } else | |
262 break ; | |
263 } | |
264 } | |
556 | 265 if (!fp /* && (end=='>'||filep->inc=='>') */ ) { // <> case only |
861 | 266 for(pp=l_include_path; *pp;pp++) { |
267 p = expand_file_name(*pp,name); | |
268 if(prev && nameeq(p,prev)) continue; | |
269 if ((fp = fopen(p,"r"))) { | |
270 if (next) { | |
271 fclose(fp); fp=0; next=0; prev=p; | |
272 continue; | |
273 } else | |
274 break ; | |
275 } | |
276 } | |
277 } | |
327 | 278 } |
279 if(!fp) { error(FILERR); return filep->fcb; } | |
561 | 280 // we have so search current directory of the included file |
281 // keep track the name | |
327 | 282 copy_current_file_dir(s=p); |
351 | 283 // File name determined. Dispose extra copies. |
284 cheap = reset_cheap(&scheap); | |
561 | 285 // Generated name needs copy. |
346 | 286 if (p!=name) { |
861 | 287 name = cheap->ptr; |
288 while((*cheap->ptr = *s++)) cheap = increment_cheap(cheap,&name); | |
289 *cheap->ptr = 0; | |
290 cheap = increment_cheap(cheap,&name); | |
346 | 291 } |
625 | 292 // should check filep over flow (sigh...) |
327 | 293 (filep+1)->inc = end; |
346 | 294 (filep+1)->name0 = name; |
327 | 295 return ( (filep+1)->fcb = fp ); |
296 } | |
297 | |
298 /* line input and conversion */ | |
299 | |
300 static int macro_if_depth ; | |
301 static int macro_if_current ; | |
302 static int macro_if_skip ; | |
303 | |
363 | 304 /* there may extra non-terminate comment after #if/#else directive */ |
861 | 305 /* #endif / * hoge */ |
363 | 306 /* */ |
307 /* */ | |
308 | |
327 | 309 static int |
310 skip_rest_of_line() | |
311 { | |
312 getch(); | |
313 do { | |
861 | 314 while(ch!='\n'&&ch!='\r') { |
315 if (!in_comment) { | |
316 if (ch=='/') { | |
317 getch(); | |
318 if (ch=='/') in_comment=2; | |
319 else if (ch=='*') { | |
320 in_comment=1; | |
321 } else continue; | |
322 } | |
323 } else if (ch=='*') { | |
324 getch(); | |
325 if (ch=='/') { | |
326 in_comment=0; | |
327 return macro_if_skip?0:1; | |
328 } | |
329 else continue; | |
330 } | |
331 getch(); | |
332 } | |
333 if (in_comment==1) { getline1(); getch(); } | |
327 | 334 } while(in_comment==1); |
335 in_comment=0; | |
336 return 0; | |
337 } | |
338 | |
363 | 339 /* |
852 | 340 getline1 from chptr or chinput (for internal source) |
363 | 341 with macro processing |
861 | 342 generate comment |
343 generate ST_COMMENT parse tree, in inline mode | |
561 | 344 In getch, if chptr is empty, pop chptr stack, if stack is empy |
345 read from fp. | |
363 | 346 */ |
347 | |
343 | 348 static int next_eof; |
560 | 349 struct cheap *st_cheap, *cheap1; |
350 // ST_COMMENT may interfere with other inrement_cheap, so we use | |
351 // another cheap area. | |
343 | 352 |
327 | 353 extern void |
852 | 354 getline1(void) |
327 | 355 { |
356 int i; | |
648 | 357 int c = 0; |
625 | 358 char num[10]; // for 32bit |
609 | 359 char *p; |
327 | 360 |
343 | 361 if (next_eof) { |
861 | 362 next_eof=0; |
363 error(EOFERR); | |
343 | 364 } |
327 | 365 do { |
861 | 366 if (chinput) { |
367 // some another input source ( init string ) | |
368 if (! *chinput) { | |
369 chinput=0; | |
370 continue; | |
371 } | |
372 chptr=linebuf; | |
373 i=0; | |
374 while((*chptr++=c=*chinput++)&&(c!='\n')) { | |
375 if (++i > LBUFSIZE-2) error(LNERR); | |
376 } | |
377 } else { | |
378 // get the line from input stream | |
379 lineno++; | |
380 glineno++; | |
381 chptr=linebuf; | |
382 i=0; | |
383 while ((*chptr++ = c = getc(filep->fcb)) != '\n') { | |
384 if (++i > LBUFSIZE-2) error(LNERR); | |
385 if (c=='\r') { | |
386 c = getc(filep->fcb); | |
387 if (c == '\n') { | |
388 chptr[-1]='\n'; break; | |
389 } else { | |
390 // single cr equal to nl | |
391 ungetc(c,filep->fcb); | |
392 chptr[-1]=c='\n'; i--; break; | |
393 } | |
394 } | |
395 if (c==EOF) { | |
396 next_eof=1; | |
397 --chptr; | |
398 break; | |
399 } | |
400 } | |
401 } | |
625 | 402 |
861 | 403 *chptr = '\0'; |
404 if (lsrc && !asmf && !macro_if_skip && linebuf[0]) { | |
405 if (!inmode) | |
406 gen_comment(linebuf); // #if ed line will not be commented | |
407 if (inmode) { | |
408 // inline mode | |
625 | 409 |
861 | 410 // generate inlined line in assembler output |
625 | 411 |
861 | 412 int i=0; |
413 int c; | |
414 // should be done in some init | |
415 if (!st_cheap) { | |
416 st_cheap = cheap1 = new_cheap(); | |
417 } | |
560 | 418 |
861 | 419 p = st_cheap->ptr; |
420 sprintf(num,"%d: ",lineno); | |
421 parse = list4n(ST_COMMENT,parse,lineno,(NMTBL*)p); | |
422 // should contain file name | |
423 c = 0; | |
424 while((*st_cheap->ptr = num[c++])) | |
425 st_cheap = increment_cheap(st_cheap,&p); | |
426 while((c = *st_cheap->ptr = linebuf[i++])) { | |
427 st_cheap = increment_cheap(st_cheap,&p); | |
428 if (c=='\n') { | |
429 *st_cheap->ptr = 0; | |
430 st_cheap = increment_cheap(st_cheap,&p); | |
431 p = st_cheap->ptr; | |
432 // parse = list3n(ST_COMMENT,parse,(NMTBL*)p); | |
433 sprintf(num,"%d: ",lineno); | |
434 c = 0; | |
435 while((*cheap->ptr = num[c++])) | |
436 st_cheap = increment_cheap(st_cheap,&p); | |
437 } | |
438 } | |
439 } | |
440 } | |
441 p = chptr = linebuf; while(*p==' '||*p=='\t') p++; | |
442 if (*p == '#' && !in_comment && !in_quote) { | |
443 // macro directive | |
444 chptr = p; | |
445 if (macro_processing()) return; | |
446 } | |
447 if (c==EOF) break; | |
327 | 448 } while(!in_quote && (macro_if_skip || linebuf[0] == '#')); |
449 } | |
450 | |
451 /* preprocessor directive */ | |
452 | |
453 /* line continuation \\ */ | |
454 | |
455 extern void | |
456 check_macro_eof() | |
457 { | |
458 int c; | |
346 | 459 // can't be in macro expansion |
327 | 460 for(c=0;c<LBUFSIZE-3&&chptr[c];c++); |
461 if (c>0&&chptr[c-1]=='\\') { | |
861 | 462 return; |
327 | 463 } else if (c>0&&chptr[c-1]=='\n') { |
861 | 464 if (c>0&&chptr[c-2]=='\\') { |
465 return; | |
466 } else { | |
467 c--; | |
468 } | |
327 | 469 } |
470 chptr[c] = ';'; | |
471 chptr[c+1] = '\n'; | |
472 chptr[c+2] = 0; | |
473 } | |
474 | |
363 | 475 /* #if hoge case */ |
476 | |
327 | 477 static void |
478 macro_if() | |
479 { | |
599 | 480 int i,stype=type; // expr destroy type |
327 | 481 ch= *chptr; |
599 | 482 in_macro_if = 1; // makes undefined symbol==list2(CONST,0) |
327 | 483 check_macro_eof(); |
484 getsym(0); | |
485 /* i=cexpr(expr(1)); #if allow undefined symbols.. */ | |
486 i=expr(1); | |
705 | 487 if (inmode) i = pexpr(i); // it contain const value only |
327 | 488 in_macro_if = 0; |
489 if (car(i)==CONST) i=cadr(i); | |
490 else i=0; | |
491 if (ch) { | |
861 | 492 if (chptr[-1]==ch) { |
493 /* we are fall into getch(), which lost the last ch */ | |
494 /* chptr[-1]==ch check is fanatic, but ... */ | |
495 chptr--; | |
496 } else error(-1); | |
327 | 497 } |
498 macro_if_depth = macro_if_current; | |
499 macro_if_skip = !i; | |
591 | 500 type=stype; |
327 | 501 } |
502 | |
625 | 503 /* |
504 Macro directive | |
505 | |
506 implemented in simple hash | |
507 | |
508 */ | |
509 | |
327 | 510 static int |
511 macro_processing() | |
512 { | |
513 int i; | |
569 | 514 int c=0; |
327 | 515 int mode_save; |
469 | 516 int next; |
327 | 517 |
518 ++chptr; | |
519 while (*chptr==' '||*chptr=='\t') ++chptr; | |
361 | 520 switch(chptr[0]*chptr[1]) { |
521 case 'i'*'f': | |
861 | 522 if ((macroeq("ifdef") || macroeq("ifndef"))) { |
523 c = (chptr[-4]=='n'); | |
524 macro_if_current++; | |
525 if (!macro_if_skip) { | |
526 // try getsym in IFDEF mode to avoid symbol define | |
527 mode_save = mode; mode = IFDEF; | |
528 ch= *chptr; | |
529 i = getsym(0); | |
530 mode = mode_save; | |
531 macro_if_depth = macro_if_current; | |
532 macro_if_skip = (!i)^c; | |
533 } | |
534 return 0; | |
535 } else if (macroeq("if")) { | |
536 macro_if_current++; | |
537 if (!macro_if_skip) { | |
538 macro_if(); | |
539 } | |
540 return 0; | |
541 } | |
542 break; | |
361 | 543 case 'e'*'l': |
861 | 544 if (macroeq("elif")) { |
545 if (macro_if_current==0) { | |
546 error(MCERR); /* extra #else */ | |
547 return 0; | |
548 } | |
549 if (macro_if_current == macro_if_depth) { | |
550 if (!macro_if_skip || macro_if_skip==2) { | |
551 macro_if_skip=2; | |
552 return 0; | |
553 } | |
554 macro_if(); | |
555 } | |
556 return 0; | |
557 } else if (macroeq("else")) { | |
558 if (macro_if_current==0) { | |
559 error(MCERR); /* extra #else */ | |
560 return 0; | |
561 } | |
562 if (macro_if_current == macro_if_depth) { | |
563 if (macro_if_skip==2) ; | |
564 else if (macro_if_skip) macro_if_skip=0; | |
565 else macro_if_skip=1; | |
566 } | |
567 return skip_rest_of_line(); | |
568 } | |
569 break; | |
361 | 570 case 'e'*'n': |
861 | 571 if (macroeq("endif")) { |
572 if (macro_if_current == macro_if_depth) { | |
573 macro_if_skip = 0; | |
574 macro_if_depth = --macro_if_current; | |
575 } else { | |
576 if (macro_if_current<=0) { | |
577 error(MCERR); /* extra #if */ | |
578 return 0; | |
579 } | |
580 macro_if_current--; | |
581 } | |
582 return skip_rest_of_line(); | |
583 } | |
327 | 584 } |
585 if (macro_if_skip) return 0; | |
361 | 586 switch(chptr[0]) { |
587 case 'd': | |
861 | 588 if (macroeq("define")) { |
589 ch= *chptr; | |
590 macro_define0(); | |
591 *(chptr = linebuf) = '\0'; | |
592 return 0; | |
593 } | |
594 break; | |
361 | 595 case 'u': |
861 | 596 if (macroeq("undef")) { |
597 i=mode; | |
598 mode=IFDEF; | |
599 ch= *chptr; | |
600 if (getsym(0)) { | |
601 // make it EMPTY | |
602 if (nptr->sc == MACRO) { | |
603 nptr->sc = EMPTY; | |
604 } else if (nptr->sc == FMACRO) { | |
605 nptr->sc = EMPTY; | |
606 /* we cannot reclaim it's arg */ | |
607 } else error(MCERR); | |
608 } | |
609 mode=i; | |
610 return 0; | |
611 } | |
612 break; | |
361 | 613 case 'i': |
861 | 614 next = 1; |
615 if (macroeq("include_next")|| (next=0, macroeq("include"))) { | |
616 if(filep+1 >= filestack + FILES) error(FILERR); | |
617 if ( ((filep+1)->fcb=getfname(next)) == NULL) error(FILERR); | |
618 (filep+1)->ln=lineno; | |
619 lineno=0; | |
620 ++filep; | |
621 *(chptr = linebuf) = '\0'; | |
622 return 0; | |
623 } | |
624 break; | |
609 | 625 case 'p': |
861 | 626 if (macroeq("pragma")) { |
627 getline1(); | |
628 return 0; | |
629 } | |
630 break; | |
327 | 631 #if ASM_CODE |
561 | 632 // deprecated, use asm function |
361 | 633 case 'a': |
861 | 634 if (macroeq("asm")) { |
635 if (asmf) error(MCERR); | |
636 asmf = 1; | |
637 getline1(); | |
638 while (asmf) { | |
639 printf("%s",linebuf); | |
640 getline1(); | |
641 } | |
642 return 0; | |
643 } | |
644 break; | |
361 | 645 case 'e': |
861 | 646 if (macroeq("endasm")) { |
647 if (!asmf) error(MCERR); | |
648 asmf = 0; | |
649 return 0; | |
650 } | |
651 break; | |
327 | 652 #endif |
609 | 653 case ' ': case '\t': case '\n': case 0: |
861 | 654 getline1(); |
655 return 0; | |
361 | 656 } |
657 error(MCERR); | |
327 | 658 return 0; |
659 } | |
660 | |
661 extern int | |
662 macroeq(char *s) | |
663 { | |
664 char *p; | |
665 | |
666 for (p = chptr; *s;) if (*s++ != *p++) return 0; | |
667 chptr = p; | |
668 return 1; | |
669 } | |
670 | |
671 /* macro interpreter */ | |
672 | |
561 | 673 /* generate macro define */ |
674 | |
327 | 675 extern void |
676 macro_define(char *macro) | |
677 { | |
678 char *chptr_save; | |
679 int chsave; | |
680 | |
681 chptr_save = chptr; | |
682 chsave = ch; | |
683 chptr = macro; | |
684 ch= *chptr++; | |
685 macro_define0(); | |
686 chptr = chptr_save; | |
687 ch = chsave; | |
688 } | |
689 | |
625 | 690 /* macro define from chptr |
691 | |
692 body will be copied and stored in nptr->dsp | |
861 | 693 list3s( STRING, list of argments (if any), char *) |
625 | 694 We don't expand macro here, it just copied. |
695 | |
696 */ | |
363 | 697 |
327 | 698 static void |
699 macro_define0() | |
700 { | |
701 int i,args,c; | |
346 | 702 char **body; |
327 | 703 |
704 i=mode; | |
705 mode=MDECL; | |
706 // ch= *chptr; ?? | |
707 // fprintf(stderr,"macro def: ch %c *chptr %c\n",ch,*chptr); | |
708 getsym(0); | |
709 // fprintf(stderr,"macro def: %s =>",name); | |
710 if (nptr->sc != EMPTY) { /* override existing macro */ | |
711 } | |
712 args = 0; | |
713 if (ch=='(') { | |
861 | 714 nptr->sc = FMACRO; |
715 args = macro_args(&chptr); | |
327 | 716 } else { |
861 | 717 nptr->sc = MACRO; |
718 nptr->ty = -1; | |
327 | 719 } |
720 // equal is allowed for -Dhoge=aho option | |
534 | 721 // if (ch=='=') chptr++; |
327 | 722 while((c=*chptr)==' '||c=='\t') chptr++; |
712 | 723 nptr->dsp = list3s(MACRO,args,cheap->ptr); /* macro body */ |
724 body = (char **)&scaddr(nptr->dsp); | |
561 | 725 |
726 // now copy it to the body | |
346 | 727 while ((*cheap->ptr = c = *chptr++) |
861 | 728 && c != '\n') { |
729 cheap = increment_cheap(cheap,body); | |
730 if (c=='/'&&chptr[0]=='/') { | |
731 cheap->ptr--; | |
732 *cheap->ptr = '\0'; | |
733 while(*chptr++) | |
734 ; | |
735 break; | |
736 } else if (c=='/'&&chptr[0]=='*') { | |
737 cheap->ptr--; chptr++; | |
738 for(;;) { | |
739 c = *chptr++; | |
740 if (!c) { | |
741 getline1(); | |
742 continue; | |
743 } | |
744 if (c=='*'&&chptr[0]=='/') { | |
745 c = *chptr++; break; | |
746 } | |
747 } | |
748 if (!c) break; | |
749 } else if (c=='\\' && (*chptr=='\n'||*chptr==0)) { | |
750 chptr++; | |
751 cheap->ptr--; | |
752 getline1(); | |
753 } | |
327 | 754 } |
346 | 755 if (c=='\n') { |
861 | 756 *cheap->ptr = '\0'; |
346 | 757 } |
758 cheap = increment_cheap(cheap,body); | |
327 | 759 // fprintf(stderr,"%s\n",(char *)car(nptr->dsp)); |
760 mode=i; | |
761 } | |
762 | |
763 // create function macro argument list | |
764 // return list2((char*)arg,next) | |
625 | 765 // it can be sepearted by \ or comments |
766 // no expansion | |
327 | 767 |
768 static int | |
346 | 769 macro_args(char **pchptr) |
327 | 770 { |
771 int c; | |
772 int in_quote = 0; | |
773 int in_wquote = 0; | |
774 int plevel = 0; | |
346 | 775 char **body; |
327 | 776 char *chptr = *pchptr; |
712 | 777 int args = glist3s(STRING,0,cheap->ptr); |
778 body = (char **)&scaddr(args); | |
327 | 779 for(;;) { |
346 | 780 *cheap->ptr = c = *chptr++; |
861 | 781 cheap = increment_cheap(cheap,body); |
782 if (c=='\\') { | |
783 if (*chptr=='\n') { | |
784 cheap->ptr--; | |
785 getline1(); | |
786 chptr = *pchptr; | |
787 continue; | |
788 } | |
789 } | |
790 if (!c) { | |
791 chptr--; | |
792 error(MCERR); | |
793 *pchptr = chptr; | |
794 return reverse0(args); | |
795 } | |
796 if (in_quote) { | |
797 if (c=='\\') { | |
798 if (*chptr != '\n') { | |
799 *cheap->ptr = *chptr++; | |
800 cheap = increment_cheap(cheap,body); | |
801 } else { | |
802 getline1(); | |
803 chptr = *pchptr; | |
804 } | |
805 } else if (c=='\'') { | |
806 in_quote = 0; | |
807 } | |
808 } else if (in_wquote) { | |
809 if (c=='\\') { | |
810 if (*chptr !='\n') { | |
811 *cheap->ptr = *chptr++; | |
812 cheap = increment_cheap(cheap,body); | |
813 } else { | |
814 *cheap->ptr = '\n'; | |
815 getline1(); | |
816 chptr = *pchptr; | |
817 } | |
818 } else if (c=='"') { | |
819 in_wquote = 0; | |
820 } | |
821 } else if (c=='"') { | |
822 in_wquote = 1; | |
823 } else if (c=='\'') { | |
824 in_quote = 1; | |
825 } if (plevel==0) { | |
826 if (c==',') { | |
827 cheap->ptr[-1] = 0; | |
828 args = list3s(STRING,args,cheap->ptr); | |
829 body = (char **)&scaddr(args); | |
830 } else if (c==')') { | |
831 cheap->ptr[-1] = 0; | |
832 break; | |
833 } else if (c=='(') { | |
834 plevel++; | |
835 } else if (c=='\\') { | |
836 if (*chptr=='\n') { | |
837 cheap->ptr--; | |
838 getline1(); | |
839 chptr = *pchptr; | |
840 } | |
841 // } else if (c==' '||c=='\t') { | |
842 // cheap->ptr--; | |
843 } else if (c=='\n') { | |
844 cheap->ptr--; | |
845 getline1(); | |
846 chptr = *pchptr; | |
847 } | |
848 } else if (c==')') { | |
849 plevel--; | |
850 } else if (c=='(') { | |
851 plevel++; | |
852 } else if (c=='\n') { | |
853 cheap->ptr--; | |
854 getline1(); | |
855 chptr = *pchptr; | |
856 } | |
327 | 857 } |
858 *pchptr = chptr; | |
859 return reverse0(args); | |
860 } | |
861 | |
625 | 862 /* output macro expansion |
863 | |
864 This is a recursive interpreter. | |
865 | |
866 result into macrobuf (macropp) */ | |
327 | 867 |
868 static int | |
869 macro_function(int macrop,char **pchptr,NMTBL *nptr,int history) | |
870 { | |
853
280815f3111a
fix macro ( not working yet ...)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
852
diff
changeset
|
871 int args,sargs,values; |
327 | 872 char *macro; |
873 | |
561 | 874 // make argument list |
327 | 875 sargs = args = cadr(nptr->dsp); |
346 | 876 values = macro_args(pchptr); |
327 | 877 if (pchptr==&chptr) { |
861 | 878 getch(); |
879 // ch = *chptr++; | |
327 | 880 } |
855 | 881 // eval all argument list |
882 int evalues = 0; | |
883 int values0 = values; | |
884 while(values) { | |
885 evalues = list2(macro_eval(0,scaddr(values),history),evalues); | |
886 values = cadr(values); | |
887 } | |
888 evalues = reverse0(evalues); | |
889 values = values0; | |
561 | 890 // define all arguments locally |
891 // #define arg0 arg0_value | |
892 // #define arg1 arg2_value .... | |
359 | 893 enter_scope(); |
327 | 894 while(args) { |
855 | 895 mappend0(reverse0(car(evalues)),¯o); |
896 local_define(scaddr(args),macro, scaddr(values)); | |
861 | 897 args = cadr(args); |
898 evalues = cadr(evalues); | |
899 values = cadr(values); | |
327 | 900 } |
561 | 901 // process body replacement |
712 | 902 macro = scaddr(nptr->dsp); |
721 | 903 macrop = macro_eval(macrop,macro,glist3s(STRING,history,nptr->nm)); |
327 | 904 args = sargs; |
561 | 905 // unbind arguments |
359 | 906 leave_scope(); |
327 | 907 return macrop; |
908 } | |
909 | |
625 | 910 /* |
911 define name in the local scope | |
912 */ | |
913 | |
327 | 914 static void |
855 | 915 local_define(char *macro,char *value, char *name) |
327 | 916 { |
359 | 917 NMTBL *nptr0,*nlist; |
327 | 918 while(*macro==' '||*macro=='\t') macro++; |
359 | 919 nptr0 = name_space_search(nlist=get_name(macro,0,DEF),MACRO); |
920 nptr0 = make_local_scope(nlist,nptr0,MACRO); | |
921 nptr0->nm = value; | |
855 | 922 nptr0->u.nm = name; // shallow value for concatenation |
327 | 923 } |
924 | |
855 | 925 static void |
854
f283fc68137f
intel64 on Lion conv.c conv1.c worked.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
853
diff
changeset
|
926 string_mark(char **expand) |
f283fc68137f
intel64 on Lion conv.c conv1.c worked.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
853
diff
changeset
|
927 { |
f283fc68137f
intel64 on Lion conv.c conv1.c worked.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
853
diff
changeset
|
928 mconcat = 1; |
f283fc68137f
intel64 on Lion conv.c conv1.c worked.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
853
diff
changeset
|
929 *cheap->ptr = STRING; // special value for string |
f283fc68137f
intel64 on Lion conv.c conv1.c worked.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
853
diff
changeset
|
930 cheap = increment_cheap(cheap,expand); |
f283fc68137f
intel64 on Lion conv.c conv1.c worked.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
853
diff
changeset
|
931 } |
f283fc68137f
intel64 on Lion conv.c conv1.c worked.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
853
diff
changeset
|
932 |
855 | 933 static int |
934 next_concat(int c, char *body) | |
935 { | |
936 if (c=='#' && body[0]=='#') return 1; | |
937 while((c=*body++)) { | |
861 | 938 if (c=='#' && body[0]=='#') return 1; |
939 if (c!=' ' && c!='\t' && c!='\n') return 0; | |
855 | 940 } |
941 return 0; | |
942 } | |
943 | |
363 | 944 /* |
945 Evaluate macro string. | |
625 | 946 |
947 This is a recursive interpreter. | |
948 | |
363 | 949 reuslt: list2("replaced string",next) |
861 | 950 history is necessary to avoid recursion |
363 | 951 */ |
952 | |
327 | 953 static int |
954 macro_eval(int macrop,char *body0,int history) | |
955 { | |
350 | 956 int c,len; |
327 | 957 int in_quote = 0; |
958 int in_wquote = 0; | |
623 | 959 int string_flag = 0; |
855 | 960 int prev_concat = 0; |
327 | 961 char *macro; |
962 char *body = body0; | |
346 | 963 char **expand; |
327 | 964 NMTBL *nptrm; |
721 | 965 |
966 macro_history = history; | |
712 | 967 macrop = list3s(STRING,macrop,cheap->ptr); |
968 expand = (char **)&scaddr(macrop); | |
327 | 969 for(; (c = *body++) ;) { |
861 | 970 if (in_quote) { |
971 if (c=='\\') { | |
972 *cheap->ptr = c; c = *body++; | |
973 cheap = increment_cheap(cheap,expand); | |
974 } else if (c=='\'') { | |
975 in_quote = 0; | |
976 } | |
977 } else if (in_wquote) { | |
978 if (c=='\\') { | |
979 *cheap->ptr = c; c = *body++; | |
980 cheap = increment_cheap(cheap,expand); | |
981 } else if (c=='"') { | |
982 in_wquote = 0; | |
983 } | |
984 } else if (c=='"') { | |
985 in_wquote = 1; prev_concat = 0; | |
986 } else if (c=='\'') { | |
987 in_quote = 1; prev_concat = 0; | |
988 } else if (c=='#' && *body=='#') { | |
989 mconcat = 1; | |
990 prev_concat = 1; | |
991 // name concatenation. flag only. remove and re-evaluate | |
992 // in the top level. (and skip space) | |
993 } else if (!mconcat && c=='#' && alpha(*body)) { | |
994 // turn into string next macro literal | |
995 string_flag = 1; | |
996 string_mark(expand); | |
997 prev_concat = 0; | |
623 | 998 goto names; |
861 | 999 } else if (alpha(c)) { |
1000 // find a name | |
1001 body--; // ungetc | |
623 | 1002 names: |
861 | 1003 nptrm = get_name(body,&len,NONDEF); |
1004 if (!nptrm) { | |
1005 while((*cheap->ptr = *body++) && len--) | |
1006 cheap = increment_cheap(cheap,expand); | |
1007 body--; | |
1008 if (string_flag) { | |
1009 string_flag = 0; | |
1010 string_mark(expand); | |
1011 } | |
1012 continue; | |
1013 } | |
1014 body += len; | |
1015 c = *body; | |
1016 nptrm = name_space_search(nptrm,MACRO); | |
1017 if (nptrm->dsp) | |
1018 macro = scaddr(nptrm->dsp); | |
1019 else | |
1020 macro=""; | |
1021 if (check_recurse(nptrm->nm,history)) { | |
1022 // should return the most original one, but how? | |
1023 // save_cheap/reset_cheap and return here? | |
1024 macro = nptrm->nm; | |
1025 goto skip; | |
1026 } | |
1027 switch(nptrm->sc) { | |
1028 case FMACRO: | |
1029 if (c==' '||c=='\t') { | |
1030 while (c==' '||c=='\t') c=*body++; | |
1031 body--; | |
1032 } | |
1033 if(c!='(') { | |
1034 macro = nptrm->nm; | |
1035 goto skip; // error(MCERR); this isn't error | |
1036 } | |
1037 *cheap->ptr = 0; | |
1038 cheap = increment_cheap(cheap,expand); | |
1039 body++; | |
1040 macrop = macro_function(macrop,&body,nptrm, | |
1041 glist3s(STRING,history,nptrm->nm)); | |
1042 macrop = list3s(STRING,macrop,cheap->ptr); | |
1043 expand = (char **)&(scaddr(macrop)); | |
1044 break; | |
1045 default: | |
1046 if (prev_concat) { | |
1047 prev_concat = 0; | |
1048 macro = nptrm->u.nm; | |
1049 } else if (next_concat(c,body)) { | |
1050 prev_concat = 1; | |
1051 macro = nptrm->u.nm; | |
1052 } | |
1053 if (macro==0 || !macro[0]) | |
1054 macro = nptrm->nm; | |
1055 goto skip; | |
1056 case MACRO: | |
1057 if (neqname(nptrm->nm,macro)) { | |
1058 if (macro[0]==0) { | |
1059 if (string_flag) { | |
1060 string_flag = 0; | |
1061 string_mark(expand); | |
1062 } | |
1063 continue; | |
1064 } | |
1065 *cheap->ptr = 0; | |
1066 cheap = increment_cheap(cheap,expand); | |
1067 macrop=macro_eval(macrop,macro,glist3s(STRING,history,nptrm->nm)); | |
1068 macrop = list3s(STRING,macrop,cheap->ptr); | |
1069 expand = (char **)&(scaddr(macrop)); | |
1070 break; | |
1071 } | |
1072 macro = nptrm->nm; | |
721 | 1073 skip: |
861 | 1074 case LMACRO: |
1075 while((*cheap->ptr = *macro++)/* && len-- */) | |
1076 cheap = increment_cheap(cheap,expand); | |
1077 } | |
1078 if (string_flag) { | |
1079 string_flag = 0; | |
1080 string_mark(expand); | |
1081 } | |
1082 continue; | |
1083 } | |
1084 *cheap->ptr = c; | |
1085 cheap = increment_cheap(cheap,expand); | |
327 | 1086 } |
346 | 1087 *cheap->ptr = 0; |
1088 cheap = increment_cheap(cheap,expand); | |
327 | 1089 return macrop; |
1090 } | |
1091 | |
363 | 1092 /* |
1093 cancat list2("string",next) into cheap. | |
1094 result overwrited by next cheap allocation | |
1095 */ | |
327 | 1096 |
553 | 1097 static char * |
1098 mappend0(int lists,char **result) | |
327 | 1099 { |
1100 char *p; | |
346 | 1101 *result = cheap->ptr; |
348 | 1102 for(;lists;lists = cadr(lists)) { |
712 | 1103 p = scaddr(lists); |
609 | 1104 for(;(*cheap->ptr = *p++);cheap = increment_cheap(cheap,result)) { |
861 | 1105 // in_quote + \n case ? should be \n. |
1106 if (p[-1]=='\n') cheap->ptr[0]=' '; | |
1107 } | |
327 | 1108 } |
609 | 1109 cheap = increment_cheap(cheap,result); |
346 | 1110 return *result; |
327 | 1111 } |
1112 | |
553 | 1113 // do not replace \n |
1114 extern char * | |
1115 mappend(int lists,char **result) | |
1116 { | |
1117 char *p; | |
1118 *result = cheap->ptr; | |
1119 for(;lists;lists = cadr(lists)) { | |
712 | 1120 p = scaddr(lists); |
609 | 1121 for(;(*cheap->ptr=*p++);cheap = increment_cheap(cheap,result)) { |
861 | 1122 // in_quote + \n case ? should be \n. |
1123 // if (p[-1]=='\n') cheap->ptr[0]=' '; | |
1124 } | |
553 | 1125 } |
609 | 1126 cheap = increment_cheap(cheap,result); |
553 | 1127 return *result; |
1128 } | |
1129 | |
721 | 1130 extern int |
1131 check_recurse(char *macro,int history) | |
1132 { | |
863
e253ffedf947
recursive macro fix ( at last )
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
861
diff
changeset
|
1133 int len; |
e253ffedf947
recursive macro fix ( at last )
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
861
diff
changeset
|
1134 char *name = macro; |
e253ffedf947
recursive macro fix ( at last )
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
861
diff
changeset
|
1135 while(1) { |
e253ffedf947
recursive macro fix ( at last )
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
861
diff
changeset
|
1136 NMTBL *nptrm = get_name(name,&len,NONDEF); |
e253ffedf947
recursive macro fix ( at last )
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
861
diff
changeset
|
1137 if (!nptrm) break; |
e253ffedf947
recursive macro fix ( at last )
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
861
diff
changeset
|
1138 nptrm = name_space_search(nptrm,MACRO); |
e253ffedf947
recursive macro fix ( at last )
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
861
diff
changeset
|
1139 if (!nptrm) break; |
e253ffedf947
recursive macro fix ( at last )
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
861
diff
changeset
|
1140 if (nptrm->dsp) |
e253ffedf947
recursive macro fix ( at last )
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
861
diff
changeset
|
1141 name = scaddr(nptrm->dsp); |
e253ffedf947
recursive macro fix ( at last )
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
861
diff
changeset
|
1142 else break; |
e253ffedf947
recursive macro fix ( at last )
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
861
diff
changeset
|
1143 if ( nameeq(macro,name) ) return 1; |
e253ffedf947
recursive macro fix ( at last )
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
861
diff
changeset
|
1144 } |
e253ffedf947
recursive macro fix ( at last )
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
861
diff
changeset
|
1145 |
721 | 1146 for(;history;history = cadr(history)) { |
861 | 1147 if (macro==scaddr(history)) { |
721 | 1148 // fprintf(stderr,"check_recurse: %s %s = ",macro,scaddr(history)); |
1149 // fprintf(stderr,"1\n"); | |
861 | 1150 return 1; |
1151 } | |
721 | 1152 } |
1153 // fprintf(stderr,"0\n"); | |
1154 return 0; | |
1155 } | |
1156 | |
327 | 1157 /* end */ |