Mercurial > hg > CbC > old > device
view mc-macro.c @ 589:f095b8507947
*** empty log message ***
author | kono |
---|---|
date | Wed, 18 Jan 2006 16:55:13 +0900 |
parents | 1fcad06b264a |
children | 0497fa2e2414 |
line wrap: on
line source
/* Micro-C Preprocessor Part */ /* $Id$ */ #include <stdio.h> #include "mc.h" #include "mc-parse.h" #include "mc-macro.h" #include "mc-codegen.h" #include "mc-code.h" extern struct {int fd,ln;char *name0;int inc;FILE *fcb;} *filep,filestack[FILES]; int in_macro_if = 0; char *chinput; static int mconcat=0; static void macro_define0(); static int macro_args(char **pchptr); static int macro_function(int macrop,char **pchptr,NMTBL *nptr,int history); static void local_define(char *macro,char *value); static int macro_eval(int macrop,char *body0,int history); static char * mappend0(int lists,char **result); static int macro_processing(); /* macro_expansion(NMTBL *nptrm) innput macro term (and chptr for arguments) result put into cheap, and chptr is set. current ch and chptr are pushed into chptr stack. ## concatenation requires repeated replace. In macro_function and macro_eavl, expand result is put into macrop local variable. list2("replaced string",next) to generate result, mappend/reverse0 is necessary. */ extern void macro_expansion(NMTBL *nptrm) { int i = mode; int macrop = 0; int slfree = lfree; int c; char *macropp,*s,*t; struct cheap scheap; mode = STAT; save_cheap(&scheap,cheap); if (nptrm->sc == FMACRO) { macrop=macro_function(macrop,&chptr,nptrm,0); } else { macrop=macro_eval(macrop,(char *)car(nptrm->dsp),0); } cheap = reset_cheap(&scheap); macropp = cheap->ptr; // append result override, working cheap, but it's OK. mappend0(reverse0(macrop),¯opp); // cheap->ptr[-1] ='\n'; // makes some tokenize happy // ## macro_result needs \n at end cheap->ptr[-1] = 0; // makes some tokenize happy t = cheap->ptr-2; cheap->ptr[0] =0; cheap = increment_cheap(cheap,¯opp); while (mconcat) { // ## re-eval macro // if (lsrc) printf("## before %s",macropp); mconcat = 0; macrop = 0; // remove \s**##\s* // it is difficult to remove previous space on the fly, // so multi path loop is required for(s=t=macropp;*s;) { if ((c=*s++)=='#'&&*s=='#') { if (t>s-3) t=s-2; else t--; while(*t<=' '&&t>macropp) t--; t++; for(s++;*s && *s<=' ';) s++; continue; } *t++=c; } *t++=0; // evaluate generated result again if (lsrc) { printf("### %s\n",macropp); if (t[-2]!='\n') putchar('\n'); } macrop=macro_eval(macrop,macropp,0); cheap = reset_cheap(&scheap); macropp = cheap->ptr; // will not override evaled list mappend0(reverse0(macrop),¯opp); // cheap->ptr[-1] ='\n'; cheap->ptr[-1] =0; cheap->ptr[0] =0; cheap = increment_cheap(cheap,¯opp); } cheap = reset_cheap(&scheap); // genrated macro will be overwrited by cheap, but it's OK, again mconcat = 0; set_lfree(slfree); if (lsrc && !asmf && nptrm->sc==FMACRO) { gen_comment(macropp); if (t[-2]!='\n') putchar('\n'); } // push previous chptr, and change it to the generate macro chptrsave = glist2((int)chptr,chptrsave); chsave = glist2(ch,chsave); chptr = macropp; ch = *chptr++; mode = i; } /* file inclusion */ /* file name concatenation on cheap */ static char * expand_file_name(char *path,char *name) { char *p = cheap->ptr; if (! *path) return name; while(( *cheap->ptr = *path++ )) cheap = increment_cheap(cheap,&p); if (cheap->ptr[-1]!='/') { *cheap->ptr = '/'; cheap = increment_cheap(cheap,&p); } while(( *cheap->ptr = *name++ )) cheap = increment_cheap(cheap,&p); *cheap->ptr = 0; cheap = increment_cheap(cheap,&p); return p; } /* get file name <name> => name current_file_name_dir / name libdir / name "name" => name current_file_name_dir / name include_path / name (no difference?) next flag ignores the first occurence. */ static int nameeq(char *p, char *q) { if (!p) return 0; while(*p) if(*p++ != *q++) return 0; return (*q==0); } static FILE * getfname(int next) { int i,end='"',err=0; char *s,*p,**pp,*name,*prev=0; FILE *fp; struct cheap scheap; name = cheap->ptr; getch(); if(skipspc()=='"') { end = '"'; } else if (ch=='<') { end = '>'; } else { error(INCERR); err=1; } for(i=0;(getch()!=end && ch!='\n');) { *cheap->ptr = ch; cheap = increment_cheap(cheap,&name); } if(ch=='\n') error(INCERR); if (err) return filep->fcb; *cheap->ptr = 0; cheap = increment_cheap(cheap,&name); save_cheap(&scheap,cheap); fp = fopen(name,"r") ; if (next && fp) { fclose(fp); fp=0; next=0; prev=name; } if (fp) { p = name; } else { // no deferenced on "" and <>? for(pp=include_path; *pp;pp++) { p = expand_file_name(*pp,name); if(prev && nameeq(p,prev)) continue; if ((fp = fopen(p,"r"))) { if (next) { fclose(fp); fp=0; next=0; prev=p; continue; } else break ; } } if (!fp /* && (end=='>'||filep->inc=='>') */ ) { // <> case only for(pp=l_include_path; *pp;pp++) { p = expand_file_name(*pp,name); if(prev && nameeq(p,prev)) continue; if ((fp = fopen(p,"r"))) { if (next) { fclose(fp); fp=0; next=0; prev=p; continue; } else break ; } } } } if(!fp) { error(FILERR); return filep->fcb; } // we have so search current directory of the included file // keep track the name copy_current_file_dir(s=p); // File name determined. Dispose extra copies. cheap = reset_cheap(&scheap); // Generated name needs copy. if (p!=name) { name = cheap->ptr; while((*cheap->ptr = *s++)) cheap = increment_cheap(cheap,&name); *cheap->ptr = 0; cheap = increment_cheap(cheap,&name); } (filep+1)->inc = end; (filep+1)->name0 = name; return ( (filep+1)->fcb = fp ); } /* line input and conversion */ static int macro_if_depth ; static int macro_if_current ; static int macro_if_skip ; /* there may extra non-terminate comment after #if/#else directive */ /* #endif / * hoge */ /* */ /* */ static int skip_rest_of_line() { getch(); do { while(ch!='\n'&&ch!='\r') { if (!in_comment) { if (ch=='/') { getch(); if (ch=='/') in_comment=2; else if (ch=='*') { in_comment=1; } else continue; } } else if (ch=='*') { getch(); if (ch=='/') { in_comment=0; return macro_if_skip?0:1; } else continue; } getch(); } if (in_comment==1) { getline(); getch(); } } while(in_comment==1); in_comment=0; return 0; } /* getline from chptr or chinput (for internal source) with macro processing generate comment generate ST_COMMENT parse tree, in inline mode In getch, if chptr is empty, pop chptr stack, if stack is empy read from fp. */ static int next_eof; struct cheap *st_cheap, *cheap1; // ST_COMMENT may interfere with other inrement_cheap, so we use // another cheap area. extern void getline(void) { int i; int c; char num[10]; if (next_eof) { next_eof=0; error(EOFERR); } do { if (chinput) { if (! *chinput) { chinput=0; continue; } chptr=linebuf; i=0; while((*chptr++=c=*chinput++)&&(c!='\n')) { if (++i > LBUFSIZE-2) error(LNERR); } } else { lineno++; glineno++; chptr=linebuf; i=0; while ((*chptr++ = c = getc(filep->fcb)) != '\n') { if (++i > LBUFSIZE-2) error(LNERR); if (c==EOF) { next_eof=1; --chptr; break; } } } *chptr = '\0'; if (lsrc && !asmf && !macro_if_skip && linebuf[0]) { gen_comment(linebuf); if (inmode) { // inline mode int i=0; int c; char *p; // should be done in some init if (!st_cheap) { st_cheap = cheap1 = new_cheap(); } p = st_cheap->ptr; sprintf(num,"%d: ",lineno); parse = list3(ST_COMMENT,parse,(int)p); // should contain file name c = 0; while((*st_cheap->ptr = num[c++])) st_cheap = increment_cheap(st_cheap,&p); while((c = *st_cheap->ptr = linebuf[i++])) { st_cheap = increment_cheap(st_cheap,&p); if (c=='\n') { *st_cheap->ptr = 0; st_cheap = increment_cheap(st_cheap,&p); p = st_cheap->ptr; // parse = list3(ST_COMMENT,parse,(int)p); sprintf(num,"%d: ",lineno); c = 0; while((*cheap->ptr = num[c++])) st_cheap = increment_cheap(st_cheap,&p); } } } } if (*(chptr = linebuf) == '#' && !in_comment && !in_quote) { if (macro_processing()) return; } } while(!in_quote && (macro_if_skip || linebuf[0] == '#')); } /* preprocessor directive */ /* line continuation \\ */ extern void check_macro_eof() { int c; // can't be in macro expansion for(c=0;c<LBUFSIZE-3&&chptr[c];c++); if (c>0&&chptr[c-1]=='\\') { return; } else if (c>0&&chptr[c-1]=='\n') { if (c>0&&chptr[c-2]=='\\') { return; } else { c--; } } chptr[c] = ';'; chptr[c+1] = '\n'; chptr[c+2] = 0; } /* #if hoge case */ static void macro_if() { int i; ch= *chptr; in_macro_if = 1; check_macro_eof(); getsym(0); /* i=cexpr(expr(1)); #if allow undefined symbols.. */ i=expr(1); in_macro_if = 0; if (car(i)==CONST) i=cadr(i); else i=0; if (ch) { if (chptr[-1]==ch) { /* we are fall into getch(), which lost the last ch */ /* chptr[-1]==ch check is fanatic, but ... */ chptr--; } else error(-1); } macro_if_depth = macro_if_current; macro_if_skip = !i; } static int macro_processing() { int i; int c=0; int mode_save; int next; ++chptr; while (*chptr==' '||*chptr=='\t') ++chptr; switch(chptr[0]*chptr[1]) { case 'i'*'f': if ((macroeq("ifdef") || macroeq("ifndef"))) { c = (chptr[-4]=='n'); macro_if_current++; if (!macro_if_skip) { // try getsym in IFDEF mode to avoid symbol define mode_save = mode; mode = IFDEF; ch= *chptr; i = getsym(0); mode = mode_save; macro_if_depth = macro_if_current; macro_if_skip = (!i)^c; } return 0; } else if (macroeq("if")) { macro_if_current++; if (!macro_if_skip) { macro_if(); } return 0; } break; case 'e'*'l': if (macroeq("elif")) { if (macro_if_current==0) { error(MCERR); /* extra #else */ return 0; } if (macro_if_current == macro_if_depth) { if (!macro_if_skip || macro_if_skip==2) { macro_if_skip=2; return 0; } macro_if(); } return 0; } else if (macroeq("else")) { if (macro_if_current==0) { error(MCERR); /* extra #else */ return 0; } if (macro_if_current == macro_if_depth) { if (macro_if_skip==2) ; else if (macro_if_skip) macro_if_skip=0; else macro_if_skip=1; } return skip_rest_of_line(); } break; case 'e'*'n': if (macroeq("endif")) { if (macro_if_current == macro_if_depth) { macro_if_skip = 0; macro_if_depth = --macro_if_current; } else { if (macro_if_current<=0) { error(MCERR); /* extra #if */ return 0; } macro_if_current--; } return skip_rest_of_line(); } } if (macro_if_skip) return 0; switch(chptr[0]) { case 'd': if (macroeq("define")) { ch= *chptr; macro_define0(); *(chptr = linebuf) = '\0'; return 0; } break; case 'u': if (macroeq("undef")) { i=mode; mode=IFDEF; ch= *chptr; if (getsym(0)) { // make it EMPTY if (nptr->sc == MACRO) { nptr->sc = EMPTY; } else if (nptr->sc == FMACRO) { nptr->sc = EMPTY; /* we cannot reclaim it's arg */ } else error(MCERR); } mode=i; return 0; } break; case 'i': next = 1; if (macroeq("include_next")|| (next=0, macroeq("include"))) { if(filep+1 >= filestack + FILES) error(FILERR); if ( ((filep+1)->fcb=getfname(next)) == NULL) error(FILERR); (filep+1)->ln=lineno; lineno=0; ++filep; *(chptr = linebuf) = '\0'; return 0; } break; #if ASM_CODE // deprecated, use asm function case 'a': if (c=='a'&¯oeq("asm")) { if (asmf) error(MCERR); asmf = 1; getline(); while (asmf) { printf("%s",linebuf); getline(); } return 0; } break; case 'e': if (macroeq("endasm")) { if (!asmf) error(MCERR); asmf = 0; return 0; } break; #endif case ' ': case '\t': getline(); return 0; } error(MCERR); return 0; } extern int macroeq(char *s) { char *p; for (p = chptr; *s;) if (*s++ != *p++) return 0; chptr = p; return 1; } /* macro interpreter */ /* generate macro define */ extern void macro_define(char *macro) { char *chptr_save; int chsave; chptr_save = chptr; chsave = ch; chptr = macro; ch= *chptr++; macro_define0(); chptr = chptr_save; ch = chsave; } /* macro define from chptr */ static void macro_define0() { int i,args,c; char **body; i=mode; mode=MDECL; // ch= *chptr; ?? // fprintf(stderr,"macro def: ch %c *chptr %c\n",ch,*chptr); getsym(0); // fprintf(stderr,"macro def: %s =>",name); if (nptr->sc != EMPTY) { /* override existing macro */ } args = 0; if (ch=='(') { nptr->sc = FMACRO; args = macro_args(&chptr); } else { nptr->sc = MACRO; nptr->ty = -1; } // equal is allowed for -Dhoge=aho option // if (ch=='=') chptr++; while((c=*chptr)==' '||c=='\t') chptr++; nptr->dsp = list2((int)cheap->ptr,args); /* macro body */ body = (char **)&car(nptr->dsp); // now copy it to the body while ((*cheap->ptr = c = *chptr++) && c != '\n') { cheap = increment_cheap(cheap,body); if (c=='/'&&chptr[0]=='/') { cheap->ptr--; *cheap->ptr = '\0'; while(*chptr++); break; } else if (c=='/'&&chptr[0]=='*') { cheap->ptr--; chptr++; while((c = *chptr++)) { if (c=='*'&&chptr[0]=='/') { c = *chptr++; break; } } if (!c) break; } else if (c=='\\' && (*chptr=='\n'||*chptr==0)) { chptr++; cheap->ptr--; getline(); } } if (c=='\n') { *cheap->ptr = '\0'; } cheap = increment_cheap(cheap,body); // fprintf(stderr,"%s\n",(char *)car(nptr->dsp)); mode=i; } // create function macro argument list // return list2((char*)arg,next) static int macro_args(char **pchptr) { int c; int in_quote = 0; int in_wquote = 0; int plevel = 0; char **body; char *chptr = *pchptr; int args = list2((int)cheap->ptr,0); body = (char **)&car(args); for(;;) { *cheap->ptr = c = *chptr++; cheap = increment_cheap(cheap,body); if (c=='\\') { if (*chptr=='\n') { cheap->ptr--; getline(); chptr = *pchptr; continue; } } if (!c) { chptr--; error(MCERR); *pchptr = chptr; return reverse0(args); } if (in_quote) { if (c=='\\') { if (*chptr != '\n') { *cheap->ptr = *chptr++; cheap = increment_cheap(cheap,body); } else { getline(); chptr = *pchptr; } } else if (c=='\'') { in_quote = 0; } } else if (in_wquote) { if (c=='\\') { if (*chptr !='\n') { *cheap->ptr = *chptr++; cheap = increment_cheap(cheap,body); } else { *cheap->ptr = '\n'; getline(); chptr = *pchptr; } } else if (c=='"') { in_wquote = 0; } } else if (c=='"') { in_wquote = 1; } else if (c=='\'') { in_quote = 1; } if (plevel==0) { if (c==',') { cheap->ptr[-1] = 0; args = list2((int)cheap->ptr,args); body = (char **)&car(args); } else if (c==')') { cheap->ptr[-1] = 0; break; } else if (c=='(') { plevel++; } else if (c=='\\') { if (*chptr=='\n') { cheap->ptr--; getline(); chptr = *pchptr; } // } else if (c==' '||c=='\t') { // cheap->ptr--; } else if (c=='\n') { cheap->ptr--; getline(); chptr = *pchptr; } } else if (c==')') { plevel--; } else if (c=='(') { plevel++; } else if (c=='\n') { cheap->ptr--; getline(); chptr = *pchptr; } } *pchptr = chptr; return reverse0(args); } /* output macro expansion result into macrobuf (macropp) */ static int macro_function(int macrop,char **pchptr,NMTBL *nptr,int history) { int args,sargs,values,evalues; char *macro; // make argument list sargs = args = cadr(nptr->dsp); values = macro_args(pchptr); if (pchptr==&chptr) { ch = *chptr++; } // eval all argument list evalues = 0; while(values) { evalues = list2(macro_eval(0,(char *)car(values),history),evalues); values = cadr(values); } // define all arguments locally // #define arg0 arg0_value // #define arg1 arg2_value .... evalues = reverse0(evalues); enter_scope(); while(args) { mappend0(reverse0(car(evalues)),¯o); local_define((char *)car(args),macro); args = cadr(args); evalues = cadr(evalues); } // process body replacement macro = (char *)car(nptr->dsp); macrop = macro_eval(macrop,macro,list2((int)macro,history)); args = sargs; // unbind arguments leave_scope(); return macrop; } static void local_define(char *macro,char *value) { NMTBL *nptr0,*nlist; while(*macro==' '||*macro=='\t') macro++; nptr0 = name_space_search(nlist=get_name(macro,0,DEF),MACRO); nptr0 = make_local_scope(nlist,nptr0,MACRO); nptr0->nm = value; } /* Evaluate macro string. reuslt: list2("replaced string",next) history is necessary to avoid recursion */ static int macro_eval(int macrop,char *body0,int history) { int c,len; int in_quote = 0; int in_wquote = 0; char *macro; char *body = body0; char **expand; NMTBL *nptrm; macrop = list2((int)cheap->ptr,macrop); expand = (char **)&car(macrop); for(; (c = *body++) ;) { if (in_quote) { if (c=='\\') { *cheap->ptr = c; c = *body++; cheap = increment_cheap(cheap,expand); } else if (c=='\'') { in_quote = 0; } } else if (in_wquote) { if (c=='\\') { *cheap->ptr = c; c = *body++; cheap = increment_cheap(cheap,expand); } else if (c=='"') { in_wquote = 0; } } else if (c=='"') { in_wquote = 1; } else if (c=='\'') { in_quote = 1; } else if (c=='#' && *body=='#') { mconcat = 1; // name concatenation. flag only. remove and re-evaluate // in the top level. (and skip space) } else if (alpha(c)) { // find a name body--; // ungetc nptrm = get_name(body,&len,NONDEF); if (!nptrm) { while((*cheap->ptr = *body++) && len--) cheap = increment_cheap(cheap,expand); body--; continue; } body += len; c = *body; nptrm = name_space_search(nptrm,MACRO); macro = (char *)car(nptrm->dsp); // if (check_recurse(macro,history)) goto skip; switch(nptrm->sc) { case FMACRO: if (c==' '||c=='\t') { while (c==' '||c=='\t') c=*body++; body--; } if(c!='(') error(MCERR); *cheap->ptr = 0; cheap = increment_cheap(cheap,expand); body++; macrop = macro_function(macrop,&body,nptrm, list2((int)macro,history)); macrop = list2((int)cheap->ptr,macrop); expand = (char **)&(car(macrop)); break; case MACRO: if (neqname(nptrm->nm,macro)) { if (macro[0]==0) continue; *cheap->ptr = 0; cheap = increment_cheap(cheap,expand); macrop=macro_eval(macrop,macro,list2((int)macro,history)); macrop = list2((int)cheap->ptr,macrop); expand = (char **)&(car(macrop)); break; } default: macro = nptrm->nm; // skip: case LMACRO: while((*cheap->ptr = *macro++)/* && len-- */) cheap = increment_cheap(cheap,expand); } continue; } *cheap->ptr = c; cheap = increment_cheap(cheap,expand); } *cheap->ptr = 0; cheap = increment_cheap(cheap,expand); return macrop; } /* cancat list2("string",next) into cheap. result overwrited by next cheap allocation */ static char * mappend0(int lists,char **result) { char *p; *result = cheap->ptr; for(;lists;lists = cadr(lists)) { p = (char *)car(lists); for(;(*cheap->ptr=*p++);cheap = increment_cheap(cheap,0)) { // in_quote + \n case ? should be \n. if (p[-1]=='\n') cheap->ptr[0]=' '; } } cheap = increment_cheap(cheap,0); return *result; } // do not replace \n extern char * mappend(int lists,char **result) { char *p; *result = cheap->ptr; for(;lists;lists = cadr(lists)) { p = (char *)car(lists); for(;(*cheap->ptr=*p++);cheap = increment_cheap(cheap,0)) { // in_quote + \n case ? should be \n. // if (p[-1]=='\n') cheap->ptr[0]=' '; } } cheap = increment_cheap(cheap,0); return *result; } /* end */