Mercurial > hg > CbC > old > device
view mc-macro.c @ 436:d92786033042 loprtc-div
loprtc
author | kono |
---|---|
date | Sun, 14 Nov 2004 15:41:05 +0900 |
parents | c29eebf3eaf4 |
children | 818505dd6e1f |
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-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 * mappend(int lists,char **result); static int macro_processing(); static void gen_source(char *s) { printf("%s",s); } /* replace macro term into cheap. ## concatenation requires repeated replace. */ extern void macro_expansion(NMTBL *nptrm) { int i = mode; int macrop = 0; int slfree = lfree; char *macropp; 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; // we can reset cheap, no page wrap in this case mappend(reverse0(macrop),¯opp); cheap->ptr[-1] ='\n'; cheap->ptr[0] =0; while (mconcat) { // ## re-eval macro printf("## %s",macropp); mconcat = 0; macrop = 0; macrop=macro_eval(macrop,macropp,0); cheap = reset_cheap(&scheap); macropp = cheap->ptr; // will not override evaled list mappend(reverse0(macrop),¯opp); cheap->ptr[-1] ='\n'; cheap->ptr[0] =0; } cheap = reset_cheap(&scheap); mconcat = 0; lfree = slfree; if (lsrc && !asmf && nptrm->sc==FMACRO) gen_comment(macropp); chptrsave = glist2((int)chptr,chptrsave); chsave = glist2(ch,chsave); chptr = macropp; ch = *chptr++; mode = i; } /* file inclusion */ /* file name concatenation */ 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 */ static FILE * getfname(void) { int i,end='"',err=0; char *s,*p,**pp,*name; 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 (fp) { p = name; } else { for(pp=(end=='>'||filep->inc=='>') ?l_include_path:include_path; *pp;pp++) { p = expand_file_name(*pp,name); if ((fp = fopen(p,"r"))) break ; } } if(!fp) { error(FILERR); return filep->fcb; } copy_current_file_dir(s=p); // File name determined. Dispose extra copies. cheap = reset_cheap(&scheap); 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 */ static int next_eof; extern void getline(void) { int i; int c; 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 (*(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; int mode_save; ++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) { 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)) { 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': if (macroeq("include")) { if(filep+1 >= filestack + FILES) error(FILERR); if ( ((filep+1)->fcb=getfname()) == NULL) error(FILERR); (filep+1)->ln=lineno; lineno=0; ++filep; *(chptr = linebuf) = '\0'; return 0; } break; #if ASM_CODE case 'a': if (c=='a'&¯oeq("asm")) { if (asmf) error(MCERR); asmf = 1; getline(); while (asmf) { gen_source(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 */ 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); 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) { 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(); } } 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(); } } 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(); } // } 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; sargs = args = cadr(nptr->dsp); values = macro_args(pchptr); if (pchptr==&chptr) { ch = *chptr++; } evalues = 0; while(values) { evalues = list2(macro_eval(0,(char *)car(values),history),evalues); values = cadr(values); } evalues = reverse0(evalues); enter_scope(); while(args) { mappend(reverse0(car(evalues)),¯o); local_define((char *)car(args),macro); args = cadr(args); evalues = cadr(evalues); } macro = (char *)car(nptr->dsp); macrop = macro_eval(macrop,macro,list2((int)macro,history)); args = sargs; 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) */ 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=='#') { // name concatenation. skip ## and re-eval macro line. mconcat = 1; body++; continue; } else if (alpha(c)) { 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); 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; 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 * 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 */