Mercurial > hg > CbC > old > device
view mc-parse.c @ 935:7672a37e7545 default tip
Raspbery PI ARM support begin
author | kono |
---|---|
date | Sat, 24 Dec 2016 03:02:57 +0000 |
parents | 949ed26efba9 |
children |
line wrap: on
line source
/************************************************************************ ** Copyright (C) 2006 Shinji Kono ** 連絡先: 琉球大学情報工学科 河野 真治 ** (E-Mail Address: kono@ie.u-ryukyu.ac.jp) ** ** このソースのいかなる複写,改変,修正も許諾します。ただし、 ** その際には、誰が貢献したを示すこの部分を残すこと。 ** 再配布や雑誌の付録などの問い合わせも必要ありません。 ** 営利利用も上記に反しない範囲で許可します。 ** バイナリの配布の際にはversion messageを保存することを条件とします。 ** このプログラムについては特に何の保証もしない、悪しからず。 ** ** Everyone is permitted to do anything on this program ** including copying, modifying, improving, ** as long as you don't try to pretend that you wrote it. ** i.e., the above copyright notice has to appear in all copies. ** Binary distribution requires original version messages. ** You don't have to ask before copying, redistribution or publishing. ** THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. ***********************************************************************/ #include <stdio.h> #include <stdlib.h> // for malloc // this in ./stdio.h //extern void * malloc(size_t size); //extern void * realloc(void *ptr, size_t size); #include "mc.h" #include "mc-parse.h" #include "mc-codegen.h" #include "mc-switch.h" #include "mc-macro.h" #include "mc-inline.h" #include "conv/conv.h" extern Converter *conv; #define FILES 10 #define OUTPUT_FILE_NAME "mcout.s" extern void exit(int); /* to avoid stdlib.h inclusion */ #if LONGLONG_CODE #if 0 extern long long strtoll(char * nptr, char ** endptr, int base); #endif #endif #if FLOAT_CODE extern double strtod(const char *nptr, char **endptr); #endif int parse_mode = 1; // generate parse tree for all code static int HEAP_REPORT = 0; static int lfree_type_limit; // debugging purpose // list of local declared type have to be // keep NMTBL null_nptr; NMTBL *fnptr; // current compiling function NMTBL *nptr,*gnptr; // current name ptr NMTBL *local_nptr; // local struct initialzation in static area int local_struct_offset; // local struct initialzation offset static NMTBL *htable0[GSYMS]; // hash table NMTBL **htable = htable0; // string pool struct cheap *cheap,*cheap0; static struct cheap *nptr_pool,*nptr_pool0; static NMTBL *free_nptr_list; int current_scope; // scope unwinder int attribute; // current attribte list int inline_funcs; // list of inline functions (for pfdecl) // current linebuffer and pointer char linebuf[LBUFSIZE]; char *chptr; int ch; // pre-read character int chptrsave,chsave; // linebuffer stack (for macro) int chk; int args; // function argument list int init_vars; // list of local variable initialize /* heap 0---global----gfree-> <-lfree--local----TOP (heapsize) lfree is reset in top level */ int *heap; // heap pointer int lfree; // local heap top int gfree; // global heap top int heapsize = HEAPSIZE; int asmf; // in asm (no longer used) int bit_field_disp; int blabel,dlabel; // break label, default label int clabel; // continue label int cslabel; // case label list int csvalue1; int cslist; int control; // execution will be reached here int debug; int fields; // struct field list int gtypedefed; // global typedef list (for mc-tree.c) int typedefed; // local typedef list (for mc-tree.c) int in_comment; // getsym mode int in_quote; // getsym mode int labelno; // label number int disp; // local variable offset int gpc; // global variable count (nolonger used) static int stat_no; // local static unique number int lastexp; // delayed last expression in a statement int lineno; // lineno in a file int glineno; // total lineno int lsrc; // source listing flag int retlabel,retpending,retcont; // return label int pending_jmp; // previous jump (not yet generated) int struct_return; // function returns struct int sym,type; // current symbol and type int mode,stmode,ctmode,inmode; // mode, storage mode, constant mode, inline int decl_str_init; // delayed local struct initialize int parse; // parse tree list for inline int lp64; // LP64 mode (long = (int *) = 8) NMTBL *local_static_list,*global_list; // list of static, global variable // file pointers struct {int fd,ln;char *name0;int inc;FILE *fcb;} *filep,filestack[FILES]; // function for Recursive decent nodes static NMTBL *decl0(void),*decl1(void); static int append3(int p,int a1,int a2); static int expr0(void); static int expr1(void); static int expr10(void); static int expr11(void); static int expr12(void); static int expr13(void); static int expr14(void); static int expr15(int e1); static int expr16(int e1); static int expr2(void); static int expr3(void); static int expr4(void); static int expr5(void); static int expr6(void); static int expr7(void); static int expr8(void); static int expr9(void); extern int getfree(int n); static int ndecl0(void); static int ndecl1(void); static int postequ(int s1, int s2); static int sdecl(int s); static int edecl(); static int adecl(NMTBL *n); static void code_decl(NMTBL *n); static void decl(void); static int typespec(); static void docase(void); static void docomp(int); static void dodefault(void); static void dodo(void); static void dofor(void); static void dogoto(void); static void doif(void); static void dolabel(void); static void doreturn(void); static void doswitch(void); static void dowhile(void); #if ASM_CODE static void doasm(); #endif static void errmsg(void); static void fdecl(NMTBL *n); static int getstring(void); static void init(void); static void newfile(void); static void reserve(char *s, int d, int sc); static void reverse(int t1); static void set_converter(char *s); static int escape(void); static void statement(int); static int typename(void); static int decl_data_field(int type,int v,int offset); static int decl_data_def(NMTBL *n, int t, int v,int offset,int skip); static int decl_data(int t, int v,int offset,int skip); static int typeid(int s); extern NMTBL * get_name_from_chptr(); static NMTBL * hash_search(char *name,struct cheap *scheap,int len,unsigned int hash,int mode); extern NMTBL * make_local_scope(NMTBL *nlist,NMTBL *nptr1,int sc); static NMTBL * make_top_scope(NMTBL *nlist,NMTBL *nptr1,int sc); static void extrn_use(NMTBL *nptr); static void top_init(); static void qualifiers(); static void attributes(); static void macro_convert(); extern void sym_print(int,FILE *); static void copy_attributes(NMTBL *n) ; int types_compatible(int t, int t1); // current value of constant symbol #if FLOAT_CODE static double dsymval; #endif #if LONGLONG_CODE static long long lsymval; #endif static int symval; static int sdecl_f = 1; // in struct defenition (for converter) static int stypedecl; // in type defenition (for converter) Converter *conv = &null_converter; /* Converter *conv = &c_converter; */ static char *ccout = 0; // output file name // include file search path #define MAX_INCLUDE_PATH_COUNT 10 char *include_path[MAX_INCLUDE_PATH_COUNT]; int include_path_count; extern char *l_include_path[]; static char current_file_dir[LBUFSIZE]; // keep track include file directory static int ac,ac2; static char **av; int main(int argc, char **argv) { /* option handling */ if(argc==1) exit(1); lsrc = chk = asmf = 0; ac=argc; av=argv; current_file_dir[0] = 0; include_path[include_path_count++] = current_file_dir; for (ac2=1; (ac2 < ac) && (*av[ac2] == '-'); ++ac2) { switch (*(av[ac2]+1)) { case 's': lsrc = 1; break; case 'o': ccout = av[ac2]+2; break; case 'c': chk = 1; break; case 'E': ac2++; macro_convert(); break; case 'd': debug = 1; break; case 'v': HEAP_REPORT = 1; break; case 'p': parse_mode = !parse_mode; break; case 'D': // define macro option. processed by macro break; case 'C': if (av[ac2+1]) set_converter(av[ac2]+2); chk = 1; ccout=0; break; case 'I': include_path[include_path_count++] = av[ac2]+2; if (include_path_count<MAX_INCLUDE_PATH_COUNT) break; default: error(OPTION); exit(1); } } if (!chk && ccout) if ( (freopen(ccout,"w",stdout)) == NULL ) error(FILERR); init(); /* top level */ while(1) { top_init(); while(getsym(0)==SM) conv->sm_(); mode=GDECL; stmode=0; inmode=0; attribute = 0; args=0; decl(); } /*NOTREACHED*/ } static void top_init() { // int i; mode=TOP; if (gfree > heapsize-HEAPSIZE) { heapsize *= 2; if (HEAP_REPORT) fprintf(stderr,"** heap extended to %d\n",heapsize); heap = (int*)realloc((void*)heap,heapsize*sizeof(int)); if(!heap) { error(MMERR); exit(1); } } set_lfree(heapsize); codegen_decl_init(); #if 0 while (chptrsave!=0) { i = cadr(chptrsave); free_glist2(chptrsave); chptrsave = i; } while (chsave!=0) { i = cadr(chsave); free_glist2(chsave); chsave = i; } #endif // a in previous extern f(a) is in current scope, release it leave_scope(); } static void print_string(char *s, int i) { int c; printf("\""); while(--i>0) { c=*s++; if(c=='\n') printf("\\n"); else if(c=='\r') printf("\\r\\n"); else if(c=='\t') printf("\\t"); else if(c==033) printf("\\033"); else if(c=='"') printf("\\\""); else if(c=='\\') printf("\\\\"); else if(!(' '<=c&&c<=0x7f)) printf("\\%03o",c); else printf("%c",c); } printf("\""); } static void macro_convert() { init(); top_init(); while(getsym(0)) { // how to insert comment and new line? switch (sym) { case IDENT: printf("%s",nptr->nm); break; case CONST: printf("%d",symval); break; #if FLOAT_CODE case FCONST: printf("%g",dsymval); break; case DCONST: printf("%g",dsymval); break; #endif #if LONGLONG_CODE case LCONST: printf("%lld",lsymval); break; #endif case STRINGS: { int i; for(i = nptr->dsp;i; i = cadr(i)) { print_string(scaddr(i), car(i)); printf("\n"); } break; } case STRING: print_string(nptr->nm, nptr->dsp); break; default: sym_print(sym,stdout); } while (ch<=' ') { putchar(ch); getch(); } } /* NOT REACHED */ } /* error handler when EOF, process next file */ static int serious(int n) { switch(n) { case DCERR: // "Declaration syntax" : case STERR: // "Statement syntax" : case EXERR: // "Expression syntax" : case CNERR: // "Constant required" : case CHERR: // "Illegal character" : case MCERR: // "Macro syntax" : case INCERR: // "Include syntax" : case TYERR: // "Type mismatch" : case LVERR: // "Lvalue required" : case UDERR: // "Undeclared identifier" : case OPTION: // "Illegal option" : case INERR: // "bad initialization" : case AGERR: // "wrong number of arguments" : case CODE_ERR: // "goto is necessary" : case ILERR: // "inline error" : case SIERR: // "non brace in struct init error" : case GTERR: // "cannot goto to a function" : case FNERR: // "calling a code segement, use goto" : case UCERR: // "already used as code segement" : case UFERR: // "already used as function" : case ENERR: // function has return value but reached to the end case RETERR: // return in code segement is not allowed return 0; } return 1; } extern void error(int n) { char *file; if(n == EOFERR) { if(filep!=filestack) { fclose(filep->fcb); lineno=filep->ln; --filep; copy_current_file_dir(filep->name0); return; } else if(ac2!=ac) { fclose(filep->fcb); newfile(); return; } else if(mode == TOP) { closing(); if (chk) { fprintf(stderr, "Total internal labels : %u.\n",labelno-1); fprintf(stderr, "Total global variables: %u bytes.\n",gpc); } exit(0); } } if (conv->error_(n)) return; if (!filep) file = ""; else file = filep->name0; fprintf(stderr,"%s:%d:%s\n",file,lineno, (n==FILERR) ? "Can't open specified file" : (n==DCERR) ? "Declaration syntax" : (n==RDERR) ? "Redefined" : (n==STERR) ? "Statement syntax" : (n==EXERR) ? "Expression syntax" : (n==CNERR) ? "Constant required" : (n==CHERR) ? "Illegal character" : (n==GSERR) ? "Too many global symbols" : (n==HSERR) ? "Too many string or symbols" : (n==LSERR) ? "Too many local symbols" : (n==MSERR) ? "Too many macro symbols" : (n==STRERR) ? "Too many strings or macros" : (n==LNERR) ? "Line too long" : (n==NMERR) ? "Name too long" : (n==MMERR) ? "malloc error" : (n==EOFERR) ? "Unexpected end of file" : (n==MCERR) ? "Macro syntax" : (n==INCERR) ? "Include syntax" : (n==HPERR) ? "Too long expression" : (n==TYERR) ? "Type mismatch" : (n==LVERR) ? "Lvalue required" : (n==UDERR) ? "Undeclared identifier" : (n==OPTION) ? "Illegal option" : (n==RGERR) ? "too many register usage (internal error)" : (n==REG_ERR) ? "illegal register var" : (n==INERR) ? "bad initialization" : (n==AGERR) ? "wrong number of arguments" : (n==CODE_ERR) ? "goto is necessary" : (n==ILERR) ? "inline error" : (n==SIERR) ? "warning: missing braces around initializer" : (n==GTERR) ? "cannot goto to a function" : (n==FNERR) ? "calling a code segement, use goto" : (n==UCERR) ? "already used as code segement" : (n==UFERR) ? "already used as function" : (n==ENERR) ? "function has return value but reached to the end" : (n==CSERR) ? "no excutable code in switch" : (n==UFLDERR) ? "unknown field in struct/union" : (n==RETERR) ? "return in code segement is not allowed" : "Bug of compiler"); errmsg(); if (serious(n)) exit(1); } static void errmsg(void) { char *p,*lim; if(lineno==0) return; fprintf(stderr,"%s",linebuf); lim=chptr; while (chptrsave) { lim = scaddr(chptrsave); chptrsave = cadr(chptrsave); } if (lim<linebuf||linebuf+BUFSIZ<lim) { fprintf (stderr,"\n"); return; } for (p=linebuf; p < lim;) fprintf(stderr,(*p++ == '\t') ? "\t" : " "); fprintf (stderr,"^\n"); } /* required symbol check */ static void checksym(int s) { char *p; if (sym != s) { p=(s==RPAR) ? "')'": (s==RBRA) ? "']'": (s==SM) ? "';'": (s==LPAR) ? "'('": (s==WHILE) ? "'while'": (s==ASS) ? "'='": (s==RC) ? "'}'": (s==LC) ? "'{'": (s==COMMA) ? "','": (s==COLON) ? "':'": "Identifier"; fprintf(stderr,"%d:%s expected.\n",lineno,p); errmsg(); } getsym(0); } /* heap array memory pool initialize init before reserve() this can be called twice or more. */ static void heap_init() { gpc=glineno=0; if (!heap) { heap = (int *)malloc(heapsize*sizeof(int)); heap[0] = 0; // car(0) case } if (!heap) error(MMERR); gfree=1; labelno=2; set_lfree(heapsize); } void set_lfree(int save) { lfree = save; if (lfree_type_limit && lfree_type_limit < lfree) error(-1); } /* Par file initialization. */ static int free_glist2_list = 0; static int free_glist3_list = 0; static void reinit(void) { int i; struct cheap *p; global_list = &null_nptr; cheap=cheap0; st_cheap = cheap1; for(p=cheap;p;p=p->next) p->ptr=p->first; nptr_pool = nptr_pool0; for(p=nptr_pool;p;p=p->next) p->ptr=p->first; free_nptr_list = 0; for(i=0;i<GSYMS;i++) htable[i] = 0; free_glist2_list = 0; free_glist3_list = 0; parse = 0; inline_funcs = 0; inmode = 0; heap_init(); reserve("int",INT,RESERVE); reserve("void",VOID,RESERVE); reserve("char",CHAR,RESERVE); reserve("const",KONST,RESERVE); reserve("__const__",KONST,RESERVE); reserve("__const",KONST,RESERVE); reserve("struct",STRUCT,RESERVE); reserve("union",UNION,RESERVE); reserve("unsigned",UNSIGNED,RESERVE); reserve("signed",SIGNED,RESERVE); reserve("static",STATIC,RESERVE); reserve("goto",GOTO,RESERVE); reserve("return",RETURN,RESERVE); reserve("__return",RETURN,RESERVE); reserve("_CbC_return",RETURN,RESERVE); reserve("break",BREAK,RESERVE); reserve("continue",CONTINUE,RESERVE); reserve("if",IF,RESERVE); reserve("else",ELSE,RESERVE); reserve("for",FOR,RESERVE); reserve("do",DO,RESERVE); reserve("while",WHILE,RESERVE); reserve("switch",SWITCH,RESERVE); reserve("case",CASE,RESERVE); reserve("default",DEFAULT,RESERVE); reserve("typedef",TYPEDEF,RESERVE); reserve("sizeof",SIZEOF,RESERVE); reserve("long",LONG,RESERVE); reserve("short",SHORT,RESERVE); reserve("extern",EXTRN,RESERVE); reserve("defined",DEFINED,RESERVE); reserve("register",REGISTER,RESERVE); #ifdef USE_CODE_KEYWORD reserve("code",CODE,RESERVE); #endif reserve("__code",CODE,RESERVE); reserve("environment",ENVIRONMENT,RESERVE); reserve("_CbC_environment",ENVIRONMENT,RESERVE); reserve("float",FLOAT,RESERVE); reserve("double",DOUBLE,RESERVE); reserve("inline",INLINE,RESERVE); reserve("enum",ENUM,RESERVE); reserve("volatile",VOLATILE,RESERVE); reserve("__volatile__",VOLATILE,RESERVE); reserve("restrict",RESTRICT,RESERVE); reserve("__restrict",RESTRICT,RESERVE); reserve("typeof",TYPEOF,RESERVE); reserve("__typeof__",TYPEOF,RESERVE); reserve("__builtin_alloca",ALLOCA,RESERVE); reserve("__builtin_constant_p",BUILTINP,RESERVE); reserve("__builtin_expect",BUILTIN_EXPECT,RESERVE); reserve("__builtin_fabs",BUILTIN_FABS,RESERVE); reserve("__builtin_fabsf",BUILTIN_FABSF,RESERVE); reserve("__builtin_fabsl",BUILTIN_FABSL,RESERVE); reserve("__builtin_inf",BUILTIN_INF,RESERVE); reserve("__builtin_inff",BUILTIN_INFF,RESERVE); reserve("__builtin_infl",BUILTIN_INFL,RESERVE); reserve("__builtin_types_compatible_p",BUILTIN_TYPES_COMPATIBLE_P,RESERVE); reserve("__attribute__",ATTRIBUTE,RESERVE); reserve("__attribute",ATTRIBUTE,RESERVE); reserve("__label__",LABEL,RESERVE); reserve("__FILE__",C_FILE,RESERVE); reserve("__FUNCTION__",C_FUNCTION,RESERVE); reserve("__func__",C_FUNCTION,RESERVE); reserve("__LINE__",C_LINE,RESERVE); #if ASM_CODE reserve("asm",ASM,RESERVE); reserve("__asm",ASM,RESERVE); // ? reserve("__asm__",ASM,RESERVE); #endif // attributes ( in different name space ) reserve("aligned",ALIGNED,ATTRIBUTE); reserve("noreturn",NORETURN,ATTRIBUTE); reserve("__always_inline__",ALWAYS_INLINE,ATTRIBUTE); codegen_reinit(); // macro_define("__restrict\n"); macro_define("__micro_c__ 1\n"); #ifdef __APPLE__ macro_define("__APPLE__ 1\n"); #endif #ifdef bsd macro_define("bsd 1\n"); #endif for(i=0;av[i];i++) { if (av[i][0]=='-'&&av[i][1]=='D') macro_define(av[i]+2); } current_scope = 0; enter_scope(); } /* one time initialization */ static void init(void) { cheap0 = new_cheap(); nptr_pool0 = new_cheap(); codegen_init(); reinit(); filep=filestack; newfile(); getch(); } /* keep track current directory */ extern void copy_current_file_dir(char *name) { char *s = name; char *d = current_file_dir; char *p; for(p = d;d<current_file_dir+LBUFSIZE && *s; ) { if (*s=='/') p = d+1; *d++ = *s++; } *p = 0; } /* search possible exisiting file name with new extension hoge.c -> hoge.s */ static int first_newfile = 1; extern char * make_filename_with_extension(char *filename,char *ext) { char *p=cheap->ptr; char *s,*t; struct cheap scheap,scheap1; save_cheap(&scheap,cheap); save_cheap(&scheap1,cheap); // make gcc happy if (! *filename) filename="mcout"; for (t=0,s=filename;(*cheap->ptr = *s);cheap=increment_cheap(cheap,&p)) { if (*s++ =='.') { t=cheap->ptr; save_cheap(&scheap1,cheap); } } if (t) { cheap = reset_cheap(&scheap1); cheap->ptr = t; *cheap->ptr='.'; } else { cheap->ptr[-1]='.'; cheap->ptr--; } cheap = increment_cheap(cheap,&p); for(s = ext; *s; s++) { *cheap->ptr = *s; cheap = increment_cheap(cheap,&p); } *cheap->ptr = 0; // by T.Matsu *cheap->ptr = *s; cheap = increment_cheap(cheap,&p); // by T.Matsu cheap = reset_cheap(&scheap); return p; } /* start new file in argument list create filep */ static void newfile(void) { char *s; if (!first_newfile) { closing(); reinit(); } else first_newfile = 0; lineno=0; if (chk) fprintf(stderr,"%s:\n",av[ac2]); if ( (filep->fcb = fopen(av[ac2++],"r")) == NULL ) error(FILERR); s = av[ac2-1]; copy_current_file_dir(s); filep->name0 = cheap->ptr; filep->inc = 0; while((*cheap->ptr = *s++)) cheap = increment_cheap(cheap,&filep->name0); *cheap->ptr = 0; cheap = increment_cheap(cheap,&filep->name0); conv->open_(filep->name0); if(!ccout && !chk) { ccout = make_filename_with_extension(filep->name0,"s"); if ( (freopen(ccout,"w",stdout)) == NULL ) error(FILERR); ccout=0; } opening(filep->name0); if (init_src) { // before reading any file, perform initialization source chinput = init_src; } getline1(); } static void set_converter(char *s) { chptr = s; if (0) ; #if !UDPCL else if (macroeq("c2cbc")) conv=&c2cbc_converter; else if (macroeq("cbc2c")) conv=&cbc2c_converter; else if (macroeq("c")) conv=&c_converter; #else else if (macroeq("udpcl")) conv=&udpcl_converter; #endif else conv=&null_converter; } /* regist reserved word */ static void reserve(char *s, int d, int sc) { NMTBL *nptr; if (d==0) error(-1); (nptr = name_space_search(get_name(s,0,DEF),0))->sc = sc; nptr->dsp = d; } /* Parse part */ /* storage class volatile, static, extern.. */ static void storage_class() { qualifiers(); switch(sym) { case STATIC: if(mode==LDECL) { getsym(0); conv->static_(); mode=STADECL; stmode=LDECL; // これかよ... } else if(mode==GDECL) { getsym(0); conv->static_(); stmode=STATIC; } else error(DCERR); break; case REGISTER: //if(mode!=LDECL) // error(DCERR); stmode=REGISTER; getsym(0); conv->register_(); break; case EXTRN: if(mode==LDECL) { getsym(0); conv->static_(); mode=GDECL; stmode=EXTRN; } else if(mode==GDECL) { getsym(0); conv->extern_(); stmode=EXTRN; } else error(DCERR); break; case LABEL: /* GNU extension */ if(mode==LDECL) { getsym(0); mode = LLDECL; } else error(DCERR); break; case TYPEDEF: if(mode==GDECL) { getsym(0); conv->typedef_(); mode=GTDECL; } else if(mode==LDECL) { getsym(0); conv->typedef_(); mode=LTDECL; } else error(DCERR); break; } if(sym==INLINE) { getsym(0); inmode = INLINE; } } /* declaration int i; int f(arg) {...} STORAGE_CLASS TYPESPEC name () { } STORAGE_CLASS TYPESPEC name , STORAGE_CLASS TYPESPEC name = value, */ static void decl(void) { NMTBL *n; int t,sd,attr; ctmode=0; if (mode==GDECL) { typedefed=0; } storage_class(); if((t=typespec())==0) return; if(sym==SM) { conv->return_type_(t,0,stypedecl); conv->sm_(); return; } storage_class(); type=t;sd=stypedecl; attr = attribute; // decl0 will clear it n=decl0(); reverse(t); if (n == &null_nptr) { /* only bit field allows null identifier */ if (!(type>0&&car(type)==BIT_FIELD)) { error(DCERR); return; } } else set_attributes(n,attr); while (sym==ATTRIBUTE||sym==ASM) { int sym0 = sym; getsym(0); attributes(sym0); } set_attributes(n,attribute); if(sym==LC || ( sym!=SM && sym!=COMMA && sym!=ASS)) { /* function body */ if (mode!=GDECL) { error(DCERR); return; // we cannot trust it's arguments } stypedecl=sd; if (type<0) error(DCERR); else if (car(type)==CODE) { if (is_function(n)) error(UFERR); code_decl(n); return; } else if (car(type)==FUNCTION) { if (is_code(n)) error(UCERR); fdecl(n); return; } else error(DCERR); } else { int init = 0; int v; conv->return_type_(type,n,sd); n = def(n,ctmode); v = list3n(n->sc,n->dsp,n); if (sym==ASS && n!=&null_nptr) { conv->op_(sym); init = decl_data_def(n, type,v,0,0); data_closing(v,type); } if (inmode && (mode==LDECL||mode==LLDECL||mode==STADECL)) { parse = list5n(ST_DECL,parse,list3(mode,stmode,ctmode),init,n); } while(sym==COMMA) { init = 0; conv->comma_(); getsym(0); type=t; n=decl0(); reverse(t); if(n == &null_nptr) { /* only bitfield allow null field name */ if (!(type>0&&car(type)==BIT_FIELD)) error(DCERR); } conv->return_type_(type,n,1); n = def(n,ctmode); v = list3n(n->sc,n->dsp,n); if (sym==ASS && n!=&null_nptr) { conv->op_(sym); init = decl_data_def(n, type,v,0,0);data_closing(v,type); } if (inmode && mode==LDECL) { parse = list5n(ST_DECL,parse, list3(mode,stmode,ctmode),init,n); } } if(sym!=SM) error(DCERR); conv->sm_(); if(mode==GTDECL) mode=GDECL; if(mode==STADECL||mode==LTDECL) mode=LDECL; } } static void attributes(int attr) { int smode = mode; mode=ATTRIBUTE; checksym(LPAR); if (attr==ASM) { // int r __asm("r0") if (sym==STRING) { attribute = list3n(ASM,attribute,nptr); getsym(0); } mode = smode; checksym(RPAR); return; } while(sym!=RPAR) { if (sym==LPAR) { attributes(0); // __attibte(()) } else if (sym==IDENT) { attribute = list3n(IDENT,attribute,nptr); getsym(ATTRIBUTE); } else if (sym==STRING) { attribute = list3n(STRING,attribute,nptr); getsym(ATTRIBUTE); } else { attribute = list3(sym,attribute,0); getsym(ATTRIBUTE); if (sym==LPAR) { getsym(ATTRIBUTE); while(sym!=RPAR) { caddr(attribute) = list3(sym,caddr(attribute),symval); getsym(ATTRIBUTE); } getsym(ATTRIBUTE); } } } mode = smode; getsym(0); } static void qualifiers() { for(;;) { switch (sym) { case KONST: ctmode |= KONST_BIT; break; case VOLATILE: ctmode |= VOLATILE_BIT; break; case RESTRICT: ctmode |= RESTRICT_BIT; break; case ATTRIBUTE: getsym(0); attributes(ATTRIBUTE); continue; case INLINE: inmode = INLINE; getsym(0); continue; default: return; } getsym(0); } /* not reached */ } /* type specification */ static int typespec() { int t = INT; int slfree; int smode,stype; stypedecl = 0; qualifiers(); switch(sym) { case CHAR: if ((char)-1 == 255) { t = UCHAR; getsym(0); break; } case VOID: case INT: case CODE: case FLOAT: case DOUBLE: t= sym; getsym(0); break; case ENUM: t = edecl(); break; case STRUCT: case UNION: t=sdecl(sym); break; case SIGNED: t = INT; // default if(getsym(0)==INT) getsym(0); else if (sym==CHAR) { getsym(0); t = CHAR; } else if (sym==SHORT) { t = SHORT; if(getsym(0)==INT) getsym(0); // signed short int } else if (sym==LONG) { // signed long getsym(0); t = lp64?LONGLONG:INT; if(sym==LONG) { // signed long long if(getsym(0)==INT) getsym(0); t=LONGLONG; } else if(sym==INT) { // signed long int getsym(0); t = lp64?LONGLONG:INT; } } break; case UNSIGNED: t = UNSIGNED; if(getsym(0)==INT) { t = UNSIGNED; // unsigend int getsym(0); } else if (sym==CHAR) { getsym(0); t = UCHAR; } else if (sym==SHORT) { // unsigend short t = USHORT; if(getsym(0)==INT) getsym(0); } else if (sym==LONG) { // unsigned long getsym(0); t = lp64?ULONGLONG:UNSIGNED; if(sym==LONG) { // unsigned long long if(getsym(0)==INT) getsym(0); // unsigend long long int t=ULONGLONG; } else if(sym==INT) { // unsigend long int getsym(0); t = lp64?ULONGLONG:UNSIGNED; } } break; case SHORT: t=SHORT; if(getsym(0)==INT) getsym(0); else if(sym==UNSIGNED) { getsym(0); t = USHORT; } break; case LONG: t = lp64?LONGLONG:INT; getsym(0); if(sym==LONG) { getsym(0); t=LONGLONG; if (sym==INT) getsym(0); else if (sym==UNSIGNED) { if(getsym(0)==INT) getsym(0); t=ULONGLONG; break; } // } else if(sym==DOUBLE) { getsym(0); t=DOUBLE; } else if(sym==INT) { getsym(0); } else if(sym==UNSIGNED) { if(getsym(0)==INT) getsym(0); // long unsigend int t = lp64?ULONGLONG:UNSIGNED; } // break; case TYPEOF: getsym(0); slfree=lfree; stype=type; smode = mode; mode = STAT; checksym(LPAR); mode = LDECL; // typespec required this if((t=typename())==0) { mode = STAT; // too late for expression expr(0); t = type; } set_lfree(slfree); type=stype; mode = smode; checksym(RPAR); return t; break; default: if(sym==IDENT) { if (nptr->sc==TYPE) { t=nptr->ty; typedefed=glist3n(TYPEDEF,typedefed,nptr); // have to be type attribute copy_attributes(nptr); getsym(0); break; } else if(nptr->sc==EMPTY && gnptr->sc==TYPE) { // ??? getsym(0); break; } } if(mode==LDECL) return 0; // not a type t= INT; // empty typespec } qualifiers(); if (ctmode) { t = gset_type_attr(t,ctmode); } return t; } /* indirect * type prefix */ static struct nametable * decl0(void) { NMTBL *n; if(sym==MUL) { attribute = 0; // do not inherite type attributes getsym(0); qualifiers(); n=decl0(); type=list2(POINTER,type); return n; } return decl1(); } /* type postfix a() a[] (type) */ static NMTBL * decl1(void) { NMTBL *n; int i,array_type,arg; if(sym==LPAR) { getsym(0); n=decl0(); checksym(RPAR); } else if (sym == IDENT||sym==ALLOCA) { n=nptr; getsym(0); } else { /* error(DCERR); */ n= &null_nptr; } while(1) { if(sym==LBRA) { /* array */ if(getsym(0)==RBRA) { getsym(0); type=list3(ARRAY,type,0); } else { array_type=type; i=inmode?cexpr(pexpr(expr(1))):cexpr(expr(1)); checksym(RBRA); type=list3(ARRAY,array_type,i); } } else if(sym==LPAR) { /* function or code segment */ if(mode==GDECL) { mode=ADECL;getsym(0);mode=GDECL; /* ??? */ } else getsym(0); n->dsp=0; if(stmode==EXTRN) n->sc=EXTRN; else if(stmode==STATIC) n->sc=STATIC; if (type==CODE) { // n->ty=CODE; if(sym==RPAR) { getsym(0);arg=0; } else { if (mode==ADECL) { int sargs=args; enter_scope(); arg=adecl(n); leave_scope(); args=sargs; } else arg=adecl(n); } type=glist3(CODE,CODE,arg); } else { if(sym==RPAR) { getsym(0);arg=0; } else { if (mode==ADECL) { int sargs=args; enter_scope(); arg=adecl(n); leave_scope(); args=sargs; } else arg=adecl(n); } type=glist3(FUNCTION,type,arg); } /* Do not set n->ty here. It could be K&R style arguments or struct field names */ /* in GDECL n->dsp contains real parameter, if not, it contains arg type list. Real parameter list is compatible with arg type list. See def/ADECL */ if (mode!=GDECL) n->dsp=arg; } else if(sym==COLON) { /* bit-field */ if (mode==GSDECL||mode==GUDECL||mode==LSDECL||mode==LUDECL) { if (scalar(type) || type==LONGLONG || type==ULONGLONG) { getsym(0); type = list3(BIT_FIELD,type, list3(type /*store type*/,0 /*bit offset*/,symval)); getsym(0); } } else error(DCERR); return n; } else { return n; } } /* NOT REACHED */ } /* argument declaration (ANSI) argtypes=list2(type,argtypes); */ static int adecl(NMTBL *n) { NMTBL *arg,*sfnptr; int t; int stype,smode,sd,sargs,sstmode; int argtypes; int sctmode = ctmode; int sinmode = inmode; ctmode=0; if (parse_mode) inmode = INLINE; sstmode=stmode; stmode=REGISTER; /* nobody use this? */ stype=type; sfnptr=fnptr; fnptr=n; sd = sdecl_f; sdecl_f = 0; argtypes = 0; smode = mode; mode=ADECL; args = 0; n->dsp=0; for(;;) { if(sym==IDENT && nptr->sc!=TYPE) { type=INT; /* naked argument, old K&R C */ def(nptr,ctmode); getsym(0); if(sym==RPAR) break; } else { if(sym==DOTS) { argtypes=list2(DOTS,argtypes); attribute = 0; getsym(0); break; } if((t=typespec())==0) { attribute = 0; error(DCERR); break; } type=t; if(sym!=COMMA && sym!=RPAR) { sargs = args; arg=decl0(); args = sargs; reverse(t); // this sets type also if (arg != &null_nptr) { if (smode==GDECL) { def(arg,ctmode); } } } attribute = 0; argtypes=list2(type,argtypes); if(sym==RPAR) break; } if (sym!=COMMA) error(DCERR); ctmode=0; getsym(0); } argtypes=reverse0(argtypes); n->dsp=reverse0(n->dsp); checksym(RPAR); mode=smode; fnptr=sfnptr; type=stype; sdecl_f = sd; ctmode = sctmode; stmode=sstmode; inmode = sinmode; return argtypes; } /* reverse modifies type also */ static void reverse(int t1) { int t2,t3; t2=t1; while(type!=t1) { t3=cadr(type); cadr(type) = t2; t2=type; type=t3; } type = t2; } /* destructive reverse */ int reverse0(int t1) { int t2,t3; t2=0; while(t1) { t3=cadr(t1); cadr(t1) = t2; t2=t1; t1=t3; } return t2; } NMTBL * reversen(NMTBL *t1) { NMTBL *t2,*t3; t2= &null_nptr; while(t1 != &null_nptr) { t3=t1->next; t1->next = t2; t2=t1; t1=t3; } return t2; } /* calcurate size of type */ extern int size(int t) { t = type_value(t); if (t<0) { switch(t) { case CHAR: return 1; case UCHAR: return 1; case VOID: return 1; /* not 0 */ case SHORT: return size_of_short; case USHORT: return size_of_short; case REGISTER: return size_of_int; case DREGISTER: return size_of_double; case FREGISTER: return size_of_float; case LREGISTER: return size_of_longlong; case FLOAT: return size_of_float; case DOUBLE: return size_of_double; case LONGLONG: return size_of_longlong; case ULONGLONG: return size_of_longlong; case ENUM: return size_of_int; case POINTER: return size_of_pointer; default: if(scalar(t)) return size_of_int; error(DCERR); } } /* type represented in a list */ switch(car(t)) { case STRUCT: case UNION: if(cadr(t)==-1) error(DCERR); return(cadr(t)); case ARRAY: return(size(cadr(t))*caddr(t)); case CODE: return size_of_pointer; case FUNCTION: return size_of_pointer; case POINTER: return size_of_pointer; default: error(DCERR); } return 0; } #define hash_value(hash,ch) (hash = (37*hash)^(11*(unsigned char)(ch))) // #define hash_value(hash,ch) (hash = (37*hash)^((unsigned char)(ch))) /* new name for static global variable delimitor _ */ extern NMTBL * new_static_name(char *name,int delimit) { int ndsp,ch,len=0; char *p = cheap->ptr; char *q = name; unsigned int hash = 0; struct cheap scheap; NMTBL *n; #if 1 NMTBL *nlist; #endif while((ch = *name++)) { hash_value(hash,*cheap->ptr = ch); increment_cheap(cheap,&p);len++; } ndsp = ++stat_no; *cheap->ptr = delimit; increment_cheap(cheap,&p); if (delimit=='_') len++; while(ndsp>0) { ch = ndsp%10+'0'; if (delimit=='_') hash_value(hash,*cheap->ptr = ch); else *cheap->ptr = ch; increment_cheap(cheap,&p);if (delimit=='_') len++; ndsp /= 10; } *cheap->ptr = 0; increment_cheap(cheap,&p); save_cheap(&scheap,cheap); n = name_space_search(nlist=hash_search(delimit=='_'?p:q,&scheap,len,hash,DEF),0); n->nm = p; return n; } /* data declaration a[] = {,,,,}; */ #define LOCAL_STRUCT_INIT_STATIC 0 static int decl_data_field(int type1,int v,int offset) { int t1,t2,period=0; // int offset0 = offset+size(type); int mode_save=mode; int type0=type_value(type1); NMTBL *nptr1; if(cadr(type0)==-1) { // no struct field defenition error(DCERR); return offset; } t1 = caddr(type0); /* list of fields */ if (sym==LC) { mode = STAT; getsym(0); } else if (sym != PERIOD ) { // have to be a value, no comma cascading values // int mode_save = mode; int stype = type; // mode=STAT; do it in GDECL mode // expr1 may contain (sturct hoge){...}. it will call local_struct_static. tell him about offset local_struct_offset = offset; if (mode!=SFDINIT) mode = STAT; int e=expr1(); mode = mode_save; int t2 = type; type = stype; if (size(t2)==size(type0)) { // direct assingn case , including (struct hoge){ ... } if (inmode || mode==SFDINIT) { return e; } type = type0; offset = assign_data(e,type0,v,offset); type = stype; return offset; } // missing brace case error(SIERR); if (inmode) { offset = list4(DECL_DATA_LIST,offset,list3(DECL_DATA,e,t2),car(t1)); } else { type = car(t1); offset = assign_data(e,car(t1),v,offset); type = stype; } t1 = cadr(t1); if (! ( t1 && sym==COMMA)) return offset; conv->comma_(); getsym(0); // fall through } mode=SFDINIT; while(1) { if (sym==PERIOD) { /* struct/union field initializaer */ period=1; getsym(0); if (sym==IDENT) { int foffset; nptr1 = nptr; t2 = search_struct_type(type1,nptr1->nm,&foffset); if (!t2) error(UFLDERR); getsym(0); if (sym==ASS) { if (inmode) { int offset1 = decl_data(t2,v,0,0); offset = list4n(DECL_DATA_FIELD,offset,offset1,nptr1); } else { decl_data(t2,v,offset+foffset,0); } } else error(INERR); } else error(INERR); } else { if(period) { if (sym==RC) break; /* {.hoge=v,} case */ error(INERR); } if(!t1) break; // empty field case (it can happen...) // next decl_data must skip getsym if (inmode) { int offset1 = decl_data(car(t1),v,0,1); offset = list4(DECL_DATA_LIST,offset,offset1,car(t1)); } else { offset = decl_data(car(t1),v,offset,1); } t1 = cadr(t1); } if ( t1 && sym==COMMA) { conv->comma_(); getsym(0); continue; } // if (!t1 && sym==COMMA) getsym(0); /* extra comma */ if (sym==RC) break; // premature end } mode = mode_save; return offset; } #if LOCAL_STRUCT_INIT_STATIC // should be in mc-codegen.c static void local_struct_static(int v) { NMTBL *nptr0,*n = ncaddr(v); int offset=0; int smode = mode; int v0; // uninitialized part should be 0. // local var init cannot postponed because of assign_expr0/type // if initialization contains expressions, // we cannot do it in STADECL, but we can assign later in this mode if (local_nptr || mode==SFDINIT || inmode ) { decl_data_field(type,v,local_struct_offset); return; } local_nptr = n; // will be clear in flush local_struct_offset = offset; mode=STADECL; nptr0=new_static_name("__lstruct",'_'); nptr = def(nptr0,0); mode=smode; v0 = list3n(GVAR,0,nptr0); decl_data_field(type,v0,offset); // do struct assignment before flushed assignment expression // int sz = size(n->ty); //init_vars = list2( // list4(STASS, // inmode?( // offset?( // lp64?list3(LADD,list3n(IVAR,n->dsp,0),llist2(LCONST,offset)): // list3(ADD,list3n(IVAR,n->dsp,0),list2(CONST,offset))): // list3n(IVAR,n->dsp,0)): // list3n(LVAR,n->dsp+offset,0), // list3(RSTRUCT,v0,sz),sz), // init_vars); mode=STADECL; gen_delayed_decl_data(v,0); mode = smode; } #endif /* data structure initialization int a = 1; int b[] = {1,2,3}; struct s s = {1,2,{2,3}}; struct s s = {.a=1,.b=2}; struct s s = {.a=(struct b){1,2,.b=3}}; list item list4(DECL_DATA_LIST,next,value,type); // coarsed later list item with struct tag or array tag list4n(DECL_DATA_FIELD,next,decl_data,(NMTBL*)nptr); data initializer (array or struct) // data type for field list3(DECL_DATA,value,type); cast があるかどうかの区別 */ static int decl_data_def(NMTBL *n, int t, int v,int offset,int skip) { NMTBL *slocal_nptr = local_nptr; local_nptr = n; int slocal_struct_offset = local_struct_offset ; int e = decl_data(t,v,offset,skip); local_struct_offset = slocal_struct_offset ; local_nptr = slocal_nptr; return e; } static int decl_data(int t, int v,int offset,int skip) { int t0,t1=0,e,i,mode_save,lc=0; int offset0; NMTBL *n = ncaddr(v); emit_init_vars(); conv->decl_data_(); t0 = type_value(t); mode_save = mode; mode=STAT; if (offset==0) { if (n->sc==GVAR && n->dsp==-1) { /* duplicate initialization */ error(INERR); } else { if (mode_save==GDECL && has_attr(n,KONST)) { mode=GDECL; } } } if (!skip) getsym(0); if (sym==RC) { /* premature end (not necessary?) */ conv->decl_data_end_(); mode = mode_save; return offset; } else if (scalar(t)) { if (sym==LC) { lc=1; getsym(0); } e=expr1(); if (lc) checksym(RC); mode = mode_save; if (inmode) { offset = list3(DECL_DATA,e,type); type=t; return offset; } //if(car(e)!=CONST && t==CHAR) // error(TYERR); // correct_type is too weak, should handle ADDRESS/ARRAY // assign_data call rvalue, this is a duplicate rvalue call (correct?) if (!scalar(type) && (type>0 && (car(type)!=ADDRESS && car(type)!=ARRAY))) e = correct_type(rvalue(e),t0); offset = assign_data(e,t,v,offset); type=t; return offset; } else if (t0==FLOAT||t0==DOUBLE||t0==LONGLONG||t0==ULONGLONG) { if (sym==LC) { lc=1; getsym(0); } e=expr1(); if (lc) checksym(RC); mode = mode_save; if (inmode) { offset = list3(DECL_DATA,e,type); type=t; return offset; } e = correct_type(rvalue(e),t0); offset = assign_data(e,t,v,offset); type=t; return offset; } else if (t0>0 && (t1 = car(t0)) && t1==ARRAY) { if (sym==LC) { int offset1 = 0; // int a[] = {... } conv->lc_(); conv->decl_data_begin_(); mode = mode_save; t1 = cadr(t); i = 0; for(;;) { if (sym!=RC) { if (inmode) { int e=decl_data(t1,v,0,0); offset1 = list4(DECL_DATA_ARRAY,offset1,e,t1); } else { offset0 = offset; /* array of some thing */ offset=decl_data(t1,v,offset,0); if (offset0!=offset) i++; } } if (sym==COMMA) { conv->comma_(); continue; } else if (sym==RC) { conv->decl_data_end_(); conv->rc_(); if (inmode) { getsym(0); offset1 = reverse0(offset1); offset = list3(DECL_DATA,offset1,t); return offset; } if (caddr(t)==0) { /* size not defined */ caddr(t)=i; /* define array size */ } else if (caddr(t)!=i) { /* size match? */ if (caddr(t) < i ) { /* too many data */ // this check is sligtly odd (fix me) // error(INERR); } else if (!decl_str_init) assign_data(list2(CONST,caddr(t)-i),EMPTY,v,offset); } getsym(0); return offset; } } /* NOT REACHED */ } else if ((t=type_value(cadr(t0)))==CHAR||t==UCHAR) { e=expr1(); mode = mode_save; if(car(e)!=STRING && car(e)!=STRINGS) error(TYERR); if (inmode) { offset = list3(DECL_DATA,e,type); return offset; } offset=assign_data(e,list3(ARRAY,t,size(type)),v,offset); if (caddr(t0)==0) { /* size not defined */ caddr(t0)=size(type); /* define array size */ } else if (caddr(t0)!=size(type)) { /* size match? */ if (caddr(t0)>size(type)) { // shorter string needs filler return offset; } error(TYERR); } return offset; } } else if (t1==BIT_FIELD) { /* Calculation of bitfiled in compile runtime is too difficult. */ if(mode==GDECL) error(INERR); e=expr1(); mode = mode_save; // e = correct_type(e,t); correct me if (inmode) { offset = list3(DECL_DATA,e,type); type=t; return offset; } offset = assign_data(e,t,v,offset); type=t; return offset; } else if (t1==STRUCT||t1==UNION) { // struct hoge a = {...} if (sym==LC) lc=1; conv->lc_(); conv->decl_data_begin_(); mode = mode_save; #if LOCAL_STRUCT_INIT_STATIC if(mode==LDECL && !inmode) { local_struct_offset = offset; local_struct_static(v); // change mode to STADECL // decl_data_field(t,n,offset) is called inside; } else #endif // we cannot handle direct struct assign ( struct hoge a = f(); ) here, because of missing brace case if (inmode) { int offset1=decl_data_field(t,v,0); if (car(offset1)==DECL_DATA_FIELD||car(offset1)==DECL_DATA_LIST) offset1 = reverse0(offset1); offset=list3(DECL_DATA,offset1,t); } else { offset=decl_data_field(t,v,offset); } conv->decl_data_end_(); conv->rc_(); if (lc) { while (sym==COMMA) getsym(0); // why we need this?! checksym(RC); } return offset; } mode = mode_save; error(TYERR); /* should be initialization error */ return offset; /* not reached */ } /* declaration in struct/union */ static void sdecl_field(int smode) { while (getsym(0) != RC) { decl(); } if (sdecl_f) conv->rc_(); mode = smode; getsym(0); fields = reverse0(fields); } #if 0 static void print_fields(int fields,char *s) { for(;fields;fields=cadr(fields)) { fprintf(stderr,"%s %s %d %d\n",s,(char*)caddr(fields),car(fields),cadddr(fields)); } fprintf(stderr,"\n"); } #endif /* struct/union tag ... struct/union name nptr0->sc = TAG; nptr0->ty = list4(...) type ... list4(STRUCT,disp,fields,(int)nptr0); filed ... assoc list defined in def(); */ static int sdecl(int s) { int smode,sdisp,mymode,sbit_field_disp,type0=0; NMTBL *nptr0,*gnptr0; int sfields = fields; fields = 0; smode=mode; if (mode==GDECL || mode==GSDECL || mode==GUDECL || mode==GTDECL) mode=(s==STRUCT?GSDECL:GUDECL); else mode=(s==STRUCT?LSDECL:LUDECL); mymode = mode; sdisp=disp; sbit_field_disp=bit_field_disp; disp=0; bit_field_disp=0; if (sdecl_f) conv->sdecl_(s); if (getsym(TAG) == IDENT) { /* struct tag name */ nptr0 = nptr; gnptr0 = gnptr; if (sdecl_f) conv->id_(sym,nptr); mode = smode; // return to (possibly) LDECL for next getsym if (getsym(0) == LC) { /* struct define case */ mode=mymode; if (sdecl_f) conv->lc_(); if (nptr0->sc == EMPTY) nptr0=gnptr0; if (nptr0->sc!=TAG && nptr0->sc != EMPTY) error(DCERR); nptr0->sc = TAG; nptr0->ty = list4n(s,-1,0,nptr0); sdecl_field(smode); caddr(nptr0->ty)=fields; cadr((type0 = nptr0->ty))=disp; /* type0 = list4(s,disp,fields,0); now ... */ } else { /* struct reference case */ mode=mymode; if(nptr0->sc == EMPTY) nptr0=gnptr0; if(nptr0->sc == EMPTY) nptr0->sc = TAG; if(nptr0->sc != TAG) error(TYERR); if (nptr0->ty) { fields = caddr(nptr0->ty); disp = cadr(nptr0->ty); } conv->comment_(' '); type0 = glist4n(s,disp,fields,nptr0); } } else if(sym==LC) { /* no tag name */ if (sdecl_f) conv->lc_(); sdecl_field(smode); type0 = glist4n(s,disp,fields,0); // mode is now previous mode } else error(DCERR); stypedecl=1; disp=sdisp; bit_field_disp=sbit_field_disp; mode=smode; fields = sfields; return type0; } /* enum */ static int edecl() { int smode=mode; int sdisp=disp; NMTBL *nptr0; if (mode==GDECL || mode==GTDECL) mode=GEDECL; else mode=LEDECL; if (getsym(0) == IDENT) { nptr->sc = TAG; getsym(0); } if(sym==LC) { while (getsym(0) == IDENT) { nptr->sc = ENUM; nptr->ty = INT; nptr0 = nptr; if (getsym(0) == ASS) { getsym(0); disp = inmode?cexpr(pexpr(expr1())):cexpr(expr1()); } nptr0->dsp = disp; if (sym!=COMMA) break; disp++; } checksym(RC); } type = ENUM; disp=sdisp; mode=smode; return type; } /* local decl can be used, after {} */ /* but it's lexical scope remains after {} */ /* my be in for(int i=....) not yet (fixed already?) */ /* After this call, emit_init_vars() is required */ static void local_decl(int scope) { if (scope) enter_scope(); init_vars=0; /* local variable declaration */ stmode=0; mode=STAT; while (typeid(getsym(0)) || sym==STATIC || sym==EXTRN || sym==LABEL || sym==REGISTER || sym==TYPEDEF) { mode=LDECL; stmode=0; decl(); mode=STAT; } conv->localvar_end_(); } extern void code_arguments_fix(NMTBL *fnptr) { arg_register(fnptr, inmode); } /* code sgement simpler than fdecl, because it does not have return value. */ static void code_decl(NMTBL *n) { int arglist; int sinmode = 0; int arg_disp; if (parse_mode) { sinmode = inmode; inmode = INLINE; } if (!inmode) { if (stmode==0 && n->sc==STATIC) { // static proto type, no storage class in definition stmode=n->sc; } if(!chk) gen_code_enter(n->nm); extrn_use(n); } else { if (parse && (car(parse)!=ST_DECL&&car(parse)!=ST_COMMENT)) error(-1); // What kind of error? if (parse && car(parse)==ST_COMMENT) cadr(parse)=0; else parse = 0; } local_static_list = &null_nptr; fnptr=n; // n->sc = CODE; n->ty = type; fcheck(n); disp = -args; mode=ADECL; if (sym!=LC) { arglist=fnptr->dsp; args=fnptr->dsp=0; while (sym!=LC) { /* argument declaration !ANSI */ decl(); getsym(0); } disp = -args; fnptr->dsp = arg_reorder(arglist,fnptr->dsp); // fnptr->dsp = reverse0(fnptr->dsp); } if (!inmode) code_arguments_fix(fnptr); arg_disp = args; typedefed=0; conv->code_(fnptr); conv->lc_(); /* local variable declaration */ control=1; cslabel = -1; local_decl(0); if(!inmode && !chk) gen_code_enter1(args); emit_init_vars(); // lfree_type_limit = lfree; while(sym!=RC) statement(0); if(control) error(CODE_ERR); control=0; conv->code_end_(); if (inmode) { set_attr(n,INLINE, list4n(reverse0(parse),arg_disp,disp,local_static_list)); if (parse_mode && ! sinmode) { set_attr(n,NOINLINE,-1); } parse = 0; inline_funcs = list3n(INLINE,inline_funcs,n); } else { if(!chk) gen_code_leave(fnptr->nm); } args = 0; // lfree_type_limit = 0; if (parse_mode) { // do not generate static inline function if (sinmode && n->sc==STATIC) return; inmode = 0; pcode_decl(fnptr); inmode = 0; } } static NMTBL *tmp_struct; /* function define */ static void fdecl(NMTBL *n) { int sd = stypedecl; int arglist,arg_disp; int sinmode = inmode; if (has_attr(n,ALWAYS_INLINE)) { inmode = INLINE; } if (parse_mode) { inmode = INLINE; } if (!inmode) { if (stmode==0 && n->sc==STATIC) { // static proto type, no storage class in definition stmode=n->sc; } if(!chk) gen_enter(n->nm); extrn_use(n); retlabel=fwdlabel(); } else { if (parse && (car(parse)!=ST_DECL&&car(parse)!=ST_COMMENT)) error(-1); // What kind of error? if (parse && car(parse)==ST_COMMENT) cadr(parse)=0; else parse = 0; } local_static_list = &null_nptr; fnptr=n; retcont = 0; // if (tmp_struct) { tmp_struct->sc = 0; tmp_struct->nm = 0; } // why? tmp_struct = 0; /* a = f().field */ n->ty = type; fcheck(n); // n->sc = FUNCTION; // static information? mode=ADECL; if (sym!=LC) { arglist = fnptr->dsp; fnptr->dsp =args=0; while (sym!=LC) { /* K&R sytle argument declaration */ stmode=0; decl(); getsym(0); } // This order can be different from proto type. Proto type is correct. // Recalculate offset using prototype list. // arglist is set by adecl() and is reversed. fnptr->dsp = arg_reorder(arglist,fnptr->dsp); } fnptr->dsp=reverse0(fnptr->dsp); fdecl_struct(fnptr->ty); /* insert extra argument for struct passing */ arg_disp = args; args = 0; disp=0; arg_register(fnptr,inmode); // arg_register changes first arguments offset, we have to follow. // In inmode case, we don't have to do this, because it was IVAR. if (!inmode && struct_return) { cadr(car(struct_return)) = ncadddr(fnptr->dsp)->dsp;} typedefed=0; conv->function_(fnptr,sd); conv->lc_(); control=1; cslabel = -1; /* local variable declaration */ local_decl(0); if (!inmode && !chk) gen_enter1(); emit_init_vars(); lfree_type_limit = lfree; while(sym!=RC) statement(0); leave_scope(); conv->function_end_(); conv->rc_(); if (inmode) { set_attr(n,INLINE, list4n(reverse0(parse),arg_disp,disp,local_static_list)); if (parse_mode && ! sinmode) { set_attr(n,NOINLINE,-1); } parse = 0; inline_funcs = list3n(INLINE,inline_funcs,n); inmode = 0; } else { #if 0 if (type_value(cadr(fnptr->ty))!=VOID) { if (control && !retpending && !pending_jmp) error(ENERR); // function has return value but reached to the end } #endif if(!chk) gen_leave(control,n->nm); } retpending = 0; control=0; arglist=0; lfree_type_limit = 0; if (parse_mode) { // do not generate static inline function inmode = sinmode; if (sinmode && n->sc==STATIC) return; if (has_attr(n,ALWAYS_INLINE)) return; inmode = 0; pfdecl(fnptr); inmode = 0; } inmode = sinmode; } /* copy function argment for inline function */ /* calcurate argument offset here */ static int copy_arg(int arg, int is_code) { NMTBL *a,*n1; int offset=0; int nargs; for(nargs=0;arg;arg=cadr(arg)) { int t; int sz ; n1 = get_nptr(); a = ncadddr(arg); n1->ty = a->ty; n1->nm = a->nm; n1->sc = a->sc==IVAR?LVAR:a->sc; n1->attr = a->attr; t = type_value(n1->ty); sz = size(t); offset = arg_alignment(offset,n1,t,sz, is_code); nargs=list4n(car(arg),nargs,caddr(arg),n1); } args = offset; return nargs; } /* generate function from parse tree */ /* some inline functions are external or indirectly called */ /* even if it is a static. Generate these in closing(); */ /* should be in mc-inline.c? */ extern void pfdecl(NMTBL *n) { int e; int args,nargs,cargs; NMTBL *a; if (has_attr(n,ALWAYS_INLINE)) return; if (has_attr(n,GENERATED)) return; set_attr(n,GENERATED,0); top_init(); stmode = STATIC; if (is_code(n)||is_function(n)) { if (n->sc==EXTRN1||n->sc==EXTRN) { stmode = EXTRN; } } if(!chk) gen_enter(n->nm); extrn_use(n); local_static_list = &null_nptr; retlabel=fwdlabel(); fnptr=get_nptr(); fnptr->ty=n->ty; fnptr->nm=n->nm; fnptr->sc=n->sc; fnptr->attr=n->attr; fnptr->next=0; // make copied called function argment nargs = copy_arg(n->dsp, 0); // fdecl_struct(fnptr->ty); already done by fdecl before fnptr->dsp=reverse0(nargs); retcont = 0; tmp_struct = 0; disp=0; arg_register(fnptr,0); // should fix n1->dsp // make calling argments for(args=fnptr->dsp,cargs=0;args;args=cadr(args)) { a = ncadddr(args); // make call function argment for gen_inline e=list3n(a->sc==IVAR?LVAR:a->sc,a->dsp,a); cargs = list3(e,cargs,a->ty); } // build inline function call e = list4(INLINE,list3n(FNAME,0,n),cargs, list3(car(fnptr->ty),cadr(fnptr->ty),caddr(fnptr->ty))); typedefed=0; init_vars=0; if(!chk) gen_enter1(); control=1; cslabel = -1; mode = STAT; if(!chk) gen_inline(e,1); if(!chk) gen_leave(control,n->nm); retpending = 0; control=0; } /* static inline function is not generated, but global inline fuction may called directlry. so we have to generated this. this is also called from parse mode. */ extern void pcode_decl(NMTBL *n) { int e; int arg,nargs,cargs; NMTBL *a; if (has_attr(n,GENERATED)) return; set_attr(n,GENERATED,0); top_init(); stmode = STATIC; if (is_code(n)||is_function(n)) { if (n->sc==EXTRN1||n->sc==EXTRN) { stmode = EXTRN; } } if(!chk) gen_code_enter(n->nm); extrn_use(n); local_static_list = &null_nptr; retlabel=fwdlabel(); fnptr=get_nptr(); fnptr->ty=n->ty; fnptr->nm=n->nm; fnptr->sc=n->sc; fnptr->attr=n->attr; fnptr->next=0; // make copied called function argment nargs = copy_arg(n->dsp,1); // fdecl_struct(fnptr->ty); already done by fdecl before fnptr->dsp=reverse0(nargs); code_arguments_fix(fnptr); retcont = 0; tmp_struct = 0; disp = -args; arg_register(fnptr, 0); // should fix n1->dsp // make calling argments for(arg=fnptr->dsp,cargs=0;arg;arg=cadr(arg)) { a = ncadddr(arg); // make call function argment for gen_inline e=list3n(a->sc==IVAR?LVAR:a->sc,a->dsp,a); cargs = list3(e,cargs,a->ty); } // build inline function call e = list4(INLINE,list3n(FNAME,0,n),cargs, list3(car(fnptr->ty),cadr(fnptr->ty),caddr(fnptr->ty))); typedefed=0; init_vars=0; if(!chk) gen_code_enter1(args); control=1; cslabel = -1; mode = STAT; if(!chk) gen_inline(e,1); if(!chk) gen_code_leave(n->nm); retpending = 0; control=0; } /* basic C statement */ static void statement(int use) { int slfree,e; loop: if(sym==SM) { conv->sm_(); getsym(0); return; } else if (typeid(sym) || sym==REGISTER ) { // anytime local declaration... mode=LDECL; stmode=0; lfree_type_limit = lfree; decl(); mode=STAT; checkret(); emit_init_vars(); goto loop; } switch(sym) { case IF: doif(); return; case WHILE: dowhile(); return; case DO: dodo(); return; case FOR: dofor(); return; case SWITCH: doswitch(); return; case LC: docomp(use); return; case BREAK: checkret(); conv->break_(); if (control) { if (inmode) { parse = list2(ST_BREAK,parse); } else { gen_jmp(blabel); } } getsym(0); checksym(SM); return; case CONTINUE: checkret(); conv->continue_(); if (inmode) { parse = list2(ST_CONTINUE,parse); } else if (control) gen_jmp(clabel); getsym(0); checksym(SM); return; case CASE: docase(); goto loop; case DEFAULT: dodefault(); goto loop; case RETURN: doreturn(); return; case GOTO: dogoto(); return; #if ASM_CODE case ASM: doasm(); return; #endif default: checkret(); if(sym==IDENT&&skipspc()==':') { dolabel(); if (sym==RC) { fprintf(stderr," error: label at end of compound statement\n"); return; } goto loop; } else { // ({... ; value}) requires delayed handling of lastexp. // lastexp will be flushed in checkret(), or used by // statement expression. if (use) { lastexp = expr(0); } else if (inmode) { e = expr(0); parse = list3(ST_COMP,parse,e); } else { slfree=lfree; gexpr(expr(0),use); set_lfree(slfree); } conv->sm_(); checksym(SM); } } } static void doif(void) { int l1,l2=0,slfree,pparse=0; int if0; getsym(0); checksym(LPAR); conv->if_(); slfree=lfree; checkret(); if (inmode) { pparse = parse; parse = 0; l1 = if0 = expr(0); } else { l1 = bexpr((if0 = expr(0)),0,fwdlabel()); } set_lfree(slfree); conv->if_then_(if0); checksym(RPAR); statement(0); checkret(); if (inmode) { l2 = reverse0(parse); parse = 0; } if(sym==ELSE) { conv->if_else_(); if (inmode) { getsym(0); statement(0); checkret(); parse = list3(ST_IF,pparse,list3(l1,l2,reverse0(parse))); } else { if ((l2 = control)) gen_jmp(l2=fwdlabel()); fwddef(l1); getsym(0); statement(0); checkret(); if (l2) fwddef(l2); } } else { if (inmode) { parse = list3(ST_IF,pparse,list3(l1,l2,0)); } else { fwddef(l1); } } conv->if_endif_(); } static void dowhile(void) { int sbreak,scontinue,slfree,e,pparse=0; sbreak=blabel; scontinue=clabel; if (inmode) { checkret(); pparse = parse; parse=0; } else { blabel=fwdlabel(); control=1; checkret(); clabel=backdef(); } conv->while_(); getsym(0); checksym(LPAR); slfree=lfree; e=expr(0); checksym(RPAR); conv->while_body_(e); if(sym==SM) { if (inmode) { parse = list4(ST_WHILE,pparse,e,0); } else { bexpr(e,1,clabel); } set_lfree(slfree); conv->sm_(); getsym(0); } else { if (!inmode) { bexpr(e,0,blabel); } set_lfree(slfree); statement(0); checkret(); if (inmode) { parse = list4(ST_WHILE,pparse,e,reverse0(parse)); } else { if(control) gen_jmp(clabel); } } conv->while_end_(); if (!inmode) fwddef(blabel); clabel=scontinue; blabel=sbreak; } static void dodo(void) { int sbreak,scontinue,l=0,slfree,pparse=0,e; sbreak=blabel; scontinue=clabel; if (inmode) { checkret(); pparse = parse; parse = 0; } else { blabel=fwdlabel(); clabel=fwdlabel(); control=1; checkret(); l=backdef(); } conv->dowhile_(); getsym(0); statement(0); checkret(); if (inmode) { l = reverse0(parse); parse =0; } else { fwddef(clabel); } checksym(WHILE); checksym(LPAR); slfree=lfree; conv->dowhile_cond_(); if (inmode) { e = expr(0); parse = list4(ST_DO,pparse,e,l); } else { bexpr((e=expr(0)),1,l); } conv->dowhile_end_(e); set_lfree(slfree); checksym(RPAR); checksym(SM); if (!inmode) fwddef(blabel); clabel=scontinue; blabel=sbreak; } static void dofor(void) { int pparse=0,p0=0,p1=0; int l=0,e=0,slfree,dflag=0; int sbreak=blabel; int slimit = lfree_type_limit; int sinit_vars = init_vars; int scontinue=clabel; init_vars = 0; if (inmode) { pparse = parse; parse=0; } else { blabel=fwdlabel(); } conv->for_(); getsym(0); checksym(LPAR); slfree=lfree; // // for(int hge;hge<0;hge--) {... } // if (typeid(sym) || sym==REGISTER ) { // initializer with declaration // for has strange scope rule enter_scope(); dflag = 1; mode=LDECL; stmode=0; lfree_type_limit = lfree; decl(); mode=STAT; checkret(); if (chk) { // why? kono p0 = list3(ST_COMP,reverse0(init_vars),0); } else { emit_init_vars(); } if (inmode) { p0 = reverse0(parse); parse = 0; } getsym(0); } else if(sym!=SM) { // initial expression (without declartion) checkret(); if (inmode) { p0 = expr(0); } else { gexpr(expr(0),0); } checksym(SM); conv->for1_(); } else { p0 = 0; conv->for1_(); getsym(0); } set_lfree(slfree); control=1; checkret(); if (!inmode) { l=backdef(); } if(sym!=SM) { // loop condition expression if (inmode) { p1 = expr(0); } else { bexpr((p1=expr(0)),0,blabel); } checksym(SM); conv->for2_(p1); } else { conv->for2_(0); p1 = 0; getsym(0); } set_lfree(slfree); e = 0; if(sym==RPAR) { // no continue expression clabel=l; conv->for_body_(0); getsym(0); statement(0); checkret(); } else { // continue expression clabel=fwdlabel(); e=expr(0); conv->for_body_(e); checksym(RPAR); statement(0); checkret(); if (!inmode) { fwddef(clabel); gexpr(e,0); } set_lfree(slfree); } conv->for_end_(p0,p1,e); if (dflag) leave_scope(); if (inmode) { parse = list3(ST_FOR,pparse,list4(p0,p1,e,reverse0(parse))); // parse = list3(ST_FOR,pparse,list4(p0,p1,e,parse)); } else { gen_jmp(l); fwddef(blabel); } lfree_type_limit = slimit ; clabel=scontinue; blabel=sbreak; init_vars=sinit_vars; } /* compound statement {} may contain declaration */ static void docomp(int use) { int slimit = lfree_type_limit ; int sinit_vars = init_vars; conv->lc_(); local_decl(1); emit_init_vars(); lfree_type_limit = lfree; while(sym!=RC) statement(use); conv->rc_(); lfree_type_limit = slimit; init_vars = sinit_vars; leave_scope(); getsym(0); } /* CASE_CODE generates table jump CASCADE switch(c) { compute c jmp cslabel0 case 5; cslabel0: cmp c,5 jne cslabel1 ..... break; jmp blabel default: dlabel: } clsabel1: if (defalut) jmp dlabel blabel: CASE_CODE switch(c) { compute c case 5; cslabel0: cmp c,5 jne jtable_JMP <-- at least one case required ..... break; jmp blabel default: dlabel: } clsabel1: if (defalut) jmp dlabel table_JMP: table_jmp blabel: cslist keeps list of case/label pair */ static void doswitch(void) { int sbreak=0,scase=0,sdefault=0,slfree=0,svalue=0,slist=0; int pparse = parse,v,cst=0; checkret(); if (inmode) { parse = 0; } if (!inmode) { slist = cslist; cslist = 0; sbreak=blabel; /* save parents break label */ blabel=fwdlabel(); sdefault=dlabel; /* save parents default label */ dlabel=0; scase=cslabel; /* save parents next case label */ conv->switch_(); getsym(0); checksym(LPAR); slfree=lfree; svalue=csvalue1; /* save parents switch value */ v = expr(0); if (!scalar(type)) error(EXERR); if (car(v)!=CONST) gexpr(v,1); } else { conv->switch_(); getsym(0); checksym(LPAR); v = expr(0); if (!scalar(type)) error(EXERR); } cst = (car(v)==CONST); if (!inmode) { csvalue1=cst ? glist2(CONST,cadr(v)): csvalue() ; set_lfree(slfree); checksym(RPAR); conv->switch_body_(v); if (cst) { gen_jmp( cslabel = fwdlabel()); } else { cslabel = control = 0; } } else { conv->switch_body_(v); checksym(RPAR); } /* next syntax should be a case statement but... main() { int i=3,j=1,k=0; switch(i) { for(;j<10;j++) { case 3: k++; case 2: k++; case 1: k++; case 0: k++; } } printf("%d\n",k); } In this case, we have to jump into the first case label. Can be done in checkret(); */ statement(0); conv->switch_end_(cslist); checkret(); if (inmode) { parse = list4(ST_SWITCH,pparse,v,reverse0(parse)); } else { #if CASE_CODE if (!cst) { if (control) gen_jmp(blabel); genswitch(cslist,cslabel); } else if (!cslist) { if(dlabel) { df_label(cslabel,dlabel); cslist=1; } else { // no matched value, but some statement may haave control if(pending_jmp!=cslabel) fwddef(cslabel); else pending_jmp=0; // cslabel is here } } #else if (!(cst && cslit)) { if(dlabel) df_label(cslabel,dlabel); else fwddef(cslabel); } #endif free_glist2(csvalue1); } if (!inmode) { fwddef(blabel); csvalue1=svalue; cslabel=scase; dlabel=sdefault; blabel=sbreak; cslist = slist; } } #if CASE_CODE /* used in insert ascend */ extern int docase_eq() { error(-1); // duplicate case value return 0; // remove duplicate value } #endif static void docase(void) { #if CASE_CODE int l=0,clist=0,c,cst = (csvalue1 && car(csvalue1)==CONST); // if (cst) clist means there is a matching constant if (!inmode && !cst) l = fwdlabel(); while(sym==CASE) { conv->case_begin_(0,0); getsym(0); // we have to make it global? c = inmode?cexpr(pexpr(expr1())):cexpr(expr1()); if (!inmode && cst) { clist |= (cadr(csvalue1)==c); conv->case_(list2(c,0),0); } else { clist=glist3(c,clist,inmode?0:l); conv->case_(clist,0); } checksym(COLON); } if (cst && !clist) return; if (inmode) { parse = glist3(ST_CASE,parse,clist); control=1; return; } if (retpending) { ret(); retpending=0; } if (cst) { if (cslist) { // error(CSERR); return; // duplicate value } cslist=1; fwddef(cslabel); return; } if (!cslabel) { if (!control) { // immediate after switch(i) (usual case) // use it for jump to table lookup cmpdimm(car(clist),csvalue1,cslabel=fwdlabel(),1); // Insert anyway to check duplicate case value. // Mark it already used. caddr(clist)=0; } else { // checkret() sequence inconsistent // This can't happen, because checkret() force table lookup jump // before any executable instruction in switch such as switch-for. error(-1); } } // Make ascend order list of case value while(clist) { clist = cadr(c=clist); cadr(c) = 0; // insert destroy cadr of clist cslist=insert_ascend(cslist,c,docase_eq); } fwddef(l); control=1; #else /* casading branch implementation */ int c,clist,l,slfree; int cst = (csvalue1 && car(csvalue1)==CONST); if (!inmode && !cst) { if (retpending) { ret(); retpending=0; } } else { l = 0; slfree=lfree; c=0; } while(sym==CASE) { conv->case_begin_(c,0); getsym(0); c = inmode?cexpr(pexpr(expr1(1))):cexpr(expr1(1)); if (!inmode && cst) clist |= (c==cadr(csvalue1)); else clist=list2(c,clist); conv->case_(clist,0); checksym(COLON); } if (inmode) { parse = list3(ST_CASE,parse,clist); control=1; return; } if (cst && ! clist) { set_lfree(slfree); return; } if (cst) { if (!cslist) { if (retpending) { ret(); retpending=0; } fwddef(cslabel); cslist=1; } set_lfree(slfree); return; } if (retpending) { ret(); retpending=0; } l=fwdlabel(); if (control) { control=0; gen_jmp(l); } if (cslabel) fwddef(cslabel); while(cadr(clist)) { cmpdimm(car(clist),csvalue1,l,0); clist=cadr(clist); } cmpdimm(car(clist),csvalue1,cslabel=fwdlabel(),1); if (l) fwddef(l); set_lfree(slfree); /* control==1? */ #endif } static void dodefault(void) { // int cst = (car(csvalue1)==CONST); we cannot ommit this... control=1; checkret(); getsym(0); checksym(COLON); if (inmode) { parse = list2(ST_DEFAULT,parse); } else { if (dlabel) error(STERR); // double default: dlabel = backdef(); } conv->case_(0,1); } // return statement // return values in a fixed register (architecture dependent) // struct value is copied to the place passed by the caller, // by called function, and return it's pointer to the caller. // // current register is moved to corret one in checkret(); // other complex stack work will be done at the last of // generated function. (retpending flag) static void doreturn(void) { int slfree,e,e1; if (is_code(fnptr)) { error(RETERR); } if (!inmode && !cslabel) gen_jmp(cslabel = fwdlabel()); if(getsym(0)==SM) { // should check fnptr have no return value conv->return_(); conv->return_end_(0); getsym(0); if (inmode) parse = list3(ST_RETURN,parse,0); retpending = 1; return; } conv->return_(); slfree=lfree; if (struct_return) { e = expr(0); if ((car(type)==STRUCT || car(type)==UNION)&& size(type)==cadr(struct_return)) { if(car(e)==FUNCTION) { /* CASCADING struct return */ /* return struct_return_f(); case */ /* pass the return pointer to the called function */ replace_return_struct(e, rvalue_t(car(struct_return),caddr(struct_return))); if (inmode) { parse = list3(ST_RETURN,parse,e); } else gexpr(e,0); } else { type = caddr(struct_return); // e1 = rvalue_t(cadr(struct_return),INT); /* size */ e1 = cadr(struct_return); /* size */ if (inmode) { parse = list3(ST_RETURN,parse, list4(STASS,rvalue(car(struct_return)),e,e1)); } else gexpr(list4(STASS,rvalue(car(struct_return)),e,e1),0); } } else { error(TYERR); /* should check compatible */ } } else { // normal value if (inmode) { e = correct_type(expr(0),cadr(fnptr->ty)); parse = list3(ST_RETURN,parse,e); } else { gexpr(correct_type((e=expr(0)),cadr(fnptr->ty)),1); } } conv->return_end_(e); set_lfree(slfree); checksym(SM); /* control = 0; still control continue until pending return emission */ retpending = 1; } /* CbC continuation */ static void dojump(int e1,int env) { int e2 = cadr(e1); NMTBL *nptr0; conv->jump_(env); if (car(e2) == FNAME) { nptr0=ncaddr(e2); if (nptr0->sc==EMPTY) nptr0->sc = EXTRN1; else if(nptr0->sc==FUNCTION) nptr0->sc = CODE; if (nptr0->ty>0&&car(nptr0->ty)==FUNCTION) error(GTERR); // car(nptr0->ty)=CODE; } if (inmode) { parse = list3(ST_GOTO,parse,list3(JUMP,e1,env)); } else { gexpr(list3(JUMP,e1,env),0); } control=0; conv->sm_(); checksym(SM); return; } static void dogoto(void) { NMTBL *nptr0; int t,e1,env; int sstmode=stmode; checkret(); conv->goto_(); stmode=GOTO; getsym(0); e1 = expr(0); stmode=sstmode; t=car(e1); if (type==VOID) { /* indirect goto */ if (car(e1)==RINDIRECT) { if (inmode) { parse = list3(ST_GOTO,parse,e1); } else { gen_indirect_goto(cadr(e1)); } } else error(TYERR); checksym(SM); return; } if (t==FNAME) { /* classical goto */ nptr0 = ncaddr(e1); t = nptr0->sc; if (t==EMPTY||t==EXTRN1||t==EXTRN) { // error check? nptr0->sc=EMPTY; nptr0=l_top_search(nptr0->nm,0); nptr0->sc = FLABEL; if (!inmode) nptr0->dsp = fwdlabel(); else nptr0->dsp = --disp; } else if (!(t==FLABEL||t==BLABEL)) { error(STERR); } if (!inmode) gen_jmp(nptr0->dsp); else parse = list3(ST_GOTO,parse,list3n(IVAR,nptr0->dsp,nptr0)); control=0; conv->sm_(); checksym(SM); conv->goto_label_(nptr0); return; } if (t==COMMA) { error(STERR); /* CbC environment option */ env = caddr(e1); e1 = cadr(e1); t = car(e1); } else { env = 0; } if (t==CODE) { /* CbC continuation */ dojump(e1,env); return; } error(STERR); return; } static void dolabel(void) { NMTBL *nptr1; control=1; checkret(); if(nptr->sc == FLABEL) { // already used by goto with fwdlabel // or this is a local label defined by __label__ if (!inmode) fwddef(nptr->dsp); else parse = list3(ST_LABEL,parse,list3n(IVAR,nptr->dsp,nptr)); } else if(nptr->sc != EMPTY && nptr->sc != EXTRN1) { error(TYERR); // duplicate label } else { nptr->sc=EMPTY; // define this label in top level scope nptr1=l_top_search(nptr->nm,0); nptr1->sc = BLABEL; if (!inmode) nptr1->dsp = backdef(); else { nptr1->dsp = --disp; parse = list3(ST_LABEL,parse,list3n(IVAR,nptr1->dsp,nptr1)); } } conv->label_(); getsym(0); checksym(COLON); } #if ASM_CODE /* asm( asm_string : output expr : input expr : option_string ) */ static void doasm() { int e1 = 0, asm0 = 0, input = 0, out = 0, opt = 0; int e; checkret(); getsym(0); qualifiers(); checksym(LPAR); // asm string if (sym!=STRING && sym!=STRINGS) error(DCERR); asm0=list3n(sym,nptr->dsp,nptr); getsym(0); if (sym!=COLON) { #if 0 if (sym==RPAR) { // old type asm statement goto output; } #endif error(DCERR); } do { // output expression getsym(0); if (sym==COLON) break; if (sym!=STRING && sym!=STRINGS) error(DCERR); out=list2(list3n(sym,nptr->dsp,nptr),out); getsym(0); e1=list2(e=expr1(),e1); lcheck(e); } while(sym==COMMA); if (sym==COLON) { do { // input expression getsym(0); if (sym==COLON) break; if (sym!=STRING && sym!=STRINGS) error(DCERR); input=list2(list3n(sym,nptr->dsp,nptr),input); getsym(0); e1=list2(expr1(),e1); } while(sym==COMMA); } if (sym==COLON) { do { // option string getsym(0); if (sym!=STRING && sym != STRINGS) error(DCERR); opt=list2(list3n(sym,nptr->dsp,nptr),opt); getsym(0); } while(sym==COMMA); } checksym(RPAR); input = reverse0(input); out = reverse0(out); if (inmode) { parse = list4(ST_ASM,parse,list4(asm0,input,out,opt),e1); } else { gexpr(list3(ASM,list4(asm0,input,out,opt),e1),0); } checksym(SM); } #endif /* C expression */ extern int expr(int noconv) // noconv=1 suppress convsion output { int r; conv->noconv_(noconv); r=rvalue(expr0()); if (noconv) conv->conv_(); return r; } static int expr0(void) { int e; e=expr1(); while(sym==COMMA) { conv->op_(sym); getsym(0);e=list3(COMMA,e,rvalue(expr1())); } return e; } static int expr1(void) { int e1,e2,t,op,no_float; e1=expr2(); no_float = 0; switch (sym) { case ASS: conv->op_(sym); lcheck(e1); t=type; getsym(0); e2=rvalue(expr1()); e1 = assign_expr(e1,e2,t); return e1; case RSHIFT+AS: case LSHIFT+AS: case BAND+AS: case EOR+AS: case BOR+AS: case MOD+AS: no_float = 1; case ADD+AS: case SUB+AS: case MUL+AS: case DIV+AS: conv->op_(sym); op = sym-AS; lcheck(e1); t=type; getsym(0); e2=rvalue(expr1()); return assop(e1,e2,op,t,no_float); default: return(e1); } } static int expr2(void) { int e1,e2,e3,t; e1=expr3(); if(sym==COND) { // e1?e2:e3 conv->cond_(); e1=rvalue(e1); getsym(0); if (sym==COLON) { e2 = 0; // dumb extension of gcc t=type; getsym(0); } else { conv->cond1_(); e2=rvalue(expr0()); t=type; conv->cond2_(); checksym(COLON); } e3=rvalue(expr2()); conv->cond_end_(); return cond(t,e1,e2,e3); } return(e1); } static int expr3(void) { int e,e1; e=expr4(); while(sym==LOR) { /* || */ conv->op_(sym); e=rvalue(e); getsym(0); e1=rvalue(expr4()); if(car(e)==CONST) e = cadr(e )?e:e1; else if(car(e1)==CONST) e = cadr(e1)?e1:e; else e=list3(LOR,e,e1); type = INT; } return(e); } static int expr4(void) { int e,e1; e=expr5(); while(sym==LAND) { /* && */ conv->op_(sym); e=rvalue(e); getsym(0); e1=rvalue(expr5()); if(car(e)==CONST) e = cadr(e )?e1:e; else if(car(e1)==CONST) e = cadr(e1)?e:e1; else e=list3(LAND,e,e1); type = INT; } return(e); } static int expr5(void) { int e1,e2,t; e1=expr6(); while(sym==BOR) { /* | */ conv->op_(sym); e1=rvalue(e1); t=type; getsym(0); e2=rvalue(expr6()); e1=binop(BOR,e1,e2,t,type); } return(e1); } static int expr6(void) { int e1,e2,t; e1=expr7(); while(sym==EOR) { /* ^ */ conv->op_(sym); e1=rvalue(e1); t=type; getsym(0); e2=rvalue(expr7()); e1=binop(EOR,e1,e2,t,type); } return(e1); } static int expr7(void) { int e1,e2,t; e1=expr8(); while(sym==BAND) { /* & */ conv->op_(sym); e1=rvalue(e1); t=type; getsym(0); e2=rvalue(expr8()); e1=binop(BAND,e1,e2,t,type); } return(e1); } static int expr8(void) { int e1,e2,op,t; e1=expr9(); while((op=sym)==EQ||op==NEQ) { conv->op_(sym); e1=rvalue(e1); t=type; getsym(0); e2=rvalue(expr9()); e1=binop(op,e1,e2,t,type); type= INT; } return e1; } static int expr9(void) { int e1,e2,t,op; e1=expr10(); while((op=sym)==GT||op==GE||op==LT||op==LE) { conv->op_(sym); e1=rvalue(e1); t=type; getsym(0); e2=rvalue(expr10()); e1=binop(op,e1,e2,t,type); type= INT; } return e1; } static int expr10(void) { int e1,e2,t,op; e1=expr11(); while((op=sym)==RSHIFT||op==LSHIFT) { conv->op_(sym); e1=rvalue(e1); t=type; getsym(0); e2=rvalue(expr11()); e1=binop(op,e1,e2,t,type); } return e1; } static int expr11(void) { int e1,e2,t,op; e1=expr12(); while((op=sym)==ADD||op==SUB) { conv->op_(sym); e1=rvalue(e1); t=type; getsym(0); e2=rvalue(expr12()); e1=binop(op,e1,e2,t,type); } return e1; } static int expr12(void) { int e1,e2,t,op; e1=expr13(); while((op=sym)==MUL||op==DIV||op==MOD) { conv->op_(sym); e1=rvalue(e1); t=type; getsym(0); e2=rvalue(expr13()); e1=binop(op,e1,e2,t,type); } return e1; } /* unary operators */ static int expr13(void) { int e,op,dir,t; NMTBL *nptr1; switch (op = sym) { case INC: case DEC: conv->prefix_(sym); getsym(0); lcheck(e=expr13()); dir = op==INC?1:-1; switch(type) { case CHAR: type= INT; return(list4(PREINC,e,dir,1)); case UCHAR: type= UNSIGNED; return(list4(UPREINC,e,dir,1)); case SHORT: type= INT; return(list4(PREINC,e,dir,size_of_short)); case USHORT: type= UNSIGNED; return(list4(UPREINC,e,dir,size_of_short)); case INT: return(list4(PREINC,e,dir,size_of_int)); case UNSIGNED: return(list4(UPREINC,e,dir,size_of_int)); #if LONGLONG_CODE case LONGLONG: return(list4(LPREINC,e,dir,size_of_longlong)); case ULONGLONG: return(list4(LUPREINC,e,dir,size_of_longlong)); #endif #if FLOAT_CODE case FLOAT: return(list3(FPREINC,e,dir)); case DOUBLE: return(list3(DPREINC,e,dir)); #endif } if(integral(type)) return(list4(PREINC,e,dir,size_of_int)); if(type>0 && car(type)==BIT_FIELD) { e = list4(BPREINC,e,dir,type); type = cadr(type); /* value type */ return e; } if(car(type)!=POINTER) error(TYERR); return(list4(UPREINC,e,dir*size(cadr(type)),size_of_pointer )); case MUL: /* *p */ conv->prefix_(sym); getsym(0); e=rvalue(expr13()); return(indop(e)); case BAND: /* &p */ conv->prefix_(sym); getsym(0); switch(car(e=expr13())) { case INDIRECT: e=cadr(e); break; case DREGISTER: /* should be error? */ case FREGISTER: case LREGISTER: case REGISTER: case GVAR: case LVAR: case ARRAY: case ARROW: case PERIOD: e=list2(ADDRESS,e); break; case IVAR: if ((nptr1=ncaddr(e))) { set_attr(nptr1,HAS_ADDRESS,1); } e=list2(ADDRESS,e); break; case FNAME: break; case CAST: if (car(cadr(e))== DECL_DATA) break; default:error(LVERR); } type=list2(POINTER,type); return e; case ADD: /* +p */ conv->prefix_(sym); getsym(0); return expr13(); case SUB: /* -p */ conv->prefix_(sym); getsym(0); e=rvalue(expr13()); #if FLOAT_CODE if(type==FLOAT) { return(car(e)==FCONST?dlist2(FCONST,-dcadr(e)):list2(FMINUS,e)); } else if(type==DOUBLE) { return(car(e)==DCONST?dlist2(DCONST,-dcadr(e)):list2(DMINUS,e)); } #endif #if LONGLONG_CODE if(type==LONGLONG||type==ULONGLONG) { // return list2(LMINUS,e); if (car(e)==LCONST) { if (lcadr(e)>0 && type==ULONGLONG) { type=LONGLONG; } else if (lcadr(e)<=0 && type==LONGLONG) { type=ULONGLONG; } return llist2(LCONST,-lcadr(e)); } return list2(LMINUS,e); } #endif if(!integral(type)) error(TYERR); if (car(e)==CONST) { if (cadr(e)>0 && type==UNSIGNED) { type=INT; } if (cadr(e)<=0 && type==INT) { type=UNSIGNED; } return list2(CONST,-cadr(e)); } return list2(MINUS,e); case BNOT: /* ~p */ conv->prefix_(sym); getsym(0); e=rvalue(expr13()); // LONGLONG? if(!integral(type)) error(TYERR); return(car(e)==CONST?list2(CONST,~cadr(e)):list2(BNOT,e)); case LNOT: /* !p */ conv->prefix_(sym); getsym(0); e=rvalue(expr13()); #if FLOAT_CODE if (car(e)==DCONST||car(e)==FCONST) return list2(CONST,!dcadr(e)); #endif #if LONGLONG_CODE if (car(e)==LCONST) return list2(CONST,!lcadr(e)); #endif if (car(e)==CONST) return list2(CONST,!cadr(e)); if (scalar(type)) return list2(LNOT,e); if (type==LONGLONG||type==ULONGLONG) return binop(EQ,e,llist2(LCONST,0),type,LONGLONG); if (type==FLOAT||type==DOUBLE) return binop(EQ,e,dlist2(FCONST,0),type,FLOAT); error(TYERR); return list2(CONST,1); case ALLOCA: conv->prefix_(sym); getsym(0); checksym(LPAR); e=rvalue(expr0()); checksym(RPAR); type=list2(POINTER,VOID); return list2(ALLOCA,e); case BUILTINP: /* __builtin_constant_p GNU extenstion */ conv->prefix_(sym); getsym(0); checksym(LPAR); e=expr0(); checksym(RPAR); type=INT; if (inmode) return list2(BUILTINP,rvalue(e)); /* evalue it later */ else return list2(CONST,is_const(e)); case BUILTIN_TYPES_COMPATIBLE_P: { int t, t1; getsym(0); int slfree=lfree; int stype=type; int smode = mode; mode = STAT; checksym(LPAR); mode = LDECL; // typespec required this if((t=typename())==0) { mode = STAT; // too late for expression expr(0); t = type; } checksym(COMMA); mode = LDECL; // typespec required this if((t1=typename())==0) { mode = STAT; // too late for expression expr(0); t1 = type; } set_lfree(slfree); type=stype; mode = smode; checksym(RPAR); return types_compatible(t,t1); } case BUILTIN_EXPECT: /* builtin_expect(x,c) used in branch. x is expectet to be c */ conv->prefix_(sym); getsym(0); checksym(LPAR); e=expr1(); t=type; checksym(COMMA); expr0(); /* ingore */ checksym(RPAR); type=t; return e; case BUILTIN_FABSF: conv->prefix_(sym); getsym(0); checksym(LPAR); e=expr0(); checksym(RPAR); e = list2(op,rvalue_t(e,FLOAT)); type = FLOAT; if (is_const(e)) { #if FLOAT_CODE return (dcadr(e)>0.0) ? e : dlist2(FCONST,-dcadr(e)); #endif } return e; case BUILTIN_FABS: case BUILTIN_FABSL: conv->prefix_(sym); getsym(0); checksym(LPAR); e=expr0(); checksym(RPAR); e = list2(op,rvalue_t(e,DOUBLE)); type = DOUBLE; if (is_const(e)) { #if FLOAT_CODE return (dcadr(e)>0.0) ? e : dlist2(DCONST,-dcadr(e)); #endif } return e; case BUILTIN_INFF: conv->prefix_(sym); getsym(0); checksym(LPAR); checksym(RPAR); type = FLOAT; e = list2(op,0); return e; case BUILTIN_INF: case BUILTIN_INFL: conv->prefix_(sym); getsym(0); checksym(LPAR); checksym(RPAR); type = DOUBLE; e = list2(op,0); return e; case SIZEOF: conv->prefix_(sym); if(getsym(0)==LPAR) { conv->lpar_(); if(typeid(getsym(0))) { e=list2(CONST,size(t=typename())); type=INT; checksym(RPAR); conv->type_(t); conv->rpar_(); return e; } else { e=expr0(); checksym(RPAR); expr16(e); if(sym==INC||sym==DEC) { /* after this operation, type is extended */ getsym(0); switch(type) { case CHAR: type=INT; break; case SHORT: type=INT; break; case UCHAR: type=UNSIGNED; break; case USHORT: type=UNSIGNED; break; case FLOAT: case DOUBLE: break; default: if(!scalar(type)) error(TYERR); } } conv->rpar_(); } } else expr13(); e=list2(CONST,size(type)); type=INT; return e; case LAND: /* &&p gcc extension label value */ getsym(0); if (sym!=IDENT) error(TYERR); #if 0 e = expr13(); type = car(e); if (type!=FNAME) { error(TYERR); } nptr1 = ncaddr(e); #else nptr1 = nptr; getsym(0); #endif type = nptr1->sc; if (type==EMPTY||type==EXTRN1||type==EXTRN) { nptr1->sc=EMPTY; nptr1=l_top_search(nptr->nm,0); nptr1->sc = FLABEL; if (inmode!=INLINE) nptr1->dsp = fwdlabel(); else nptr1->dsp = --disp; } type = list2(POINTER,VOID); // can be global?! return list2(LABEL, list3n(inmode==INLINE?IVAR:LVAR,nptr1->dsp,nptr1)); } e=expr14(); /* postfix unary operators */ if((op=sym)==INC||op==DEC) { conv->postfix_(sym); lcheck(e); getsym(0); dir = op==INC?1:-1; switch(type) { case CHAR: type= INT; return(list4(POSTINC,e,dir,1)); case UCHAR: type= UNSIGNED; return(list4(UPOSTINC,e,dir,1)); case SHORT: type= INT; return(list4(POSTINC,e,dir,size_of_short)); case USHORT: type= UNSIGNED; return(list4(UPOSTINC,e,dir,size_of_short)); case INT: return(list4(POSTINC,e,dir,size_of_int)); case UNSIGNED: return(list4(UPOSTINC,e,dir,size_of_int)); #if FLOAT_CODE case FLOAT: return(list3(FPOSTINC,e,dir)); case DOUBLE: return(list3(DPOSTINC,e,dir)); #endif #if LONGLONG_CODE case LONGLONG: return(list3(LPOSTINC,e,dir)); case ULONGLONG: return(list3(LUPOSTINC,e,dir)); #endif } if(integral(type)) return(list4(POSTINC,e,dir,size_of_int)); if(type>0 && car(type)==BIT_FIELD) { e = list4(BPOSTINC,e,dir,type); type = cadr(type); /* value type */ return e; } if(car(type)!=POINTER) error(TYERR); return(list4(UPOSTINC,e, op==INC?size(cadr(type)):-size(cadr(type)),size_of_pointer )); } return e; } /* mark extern symbol is used */ static void extrn_use(NMTBL *nptr) { /* EXTRN1 means that defined extern is used in this source */ if(nptr->sc==EXTRN) { nptr->sc=EXTRN1; } if (!nptr->next) { nptr->next = global_list; global_list = nptr; } } /* define function name as extern */ static int fname(NMTBL *nptr) { int e1; e1=list3n(FNAME,0,nptr); if (nptr->ty>0) { // should be function or code // type=list3(FUNCTION,type,arg); type=list3(car(nptr->ty),cadr(nptr->ty),caddr(nptr->ty)); } else { // label type=nptr->ty; } getsym(0); // extrn_use(nptr); can be static return expr16(e1); } /* term */ static int expr_identifier() { int e1; conv->id_(sym,nptr); switch(nptr->sc) { case EXTRN: case EXTRN1: extrn_use(nptr); case STATIC: if(is_code(nptr)||is_function(nptr)) { return fname(nptr); } case GVAR: e1=list3n(GVAR,0,nptr); type=nptr->ty; getsym(0); extrn_use(nptr); break; case FLABEL: case BLABEL: return fname(nptr); case LVAR: case IVAR: case LREGISTER: case DREGISTER: case FREGISTER: case REGISTER: e1=list3n(nptr->sc,nptr->dsp,nptr); type=nptr->ty; getsym(0); break; case ENUM: e1=list2(CONST,nptr->dsp); type=INT; getsym(0); break; case EMPTY: if(getsym(0)==LPAR) { type= glist3(stmode==GOTO?CODE:FUNCTION,INT,0); nptr->sc = EXTRN1; nptr->ty= type; extrn_use(nptr); e1=expr15(list3n(FNAME,0,nptr)); break; } else if (in_macro_if) { type = INT; e1= list2(CONST,0); break; } else { if (stmode!=GOTO) // undefined on goto statement is OK error(UDERR); int smode = mode; mode = GDECL; // type = nptr->ty= glist3(FUNCTION,INT,0); type = INT; def(nptr,0); nptr->sc = EXTRN1; mode = smode; e1=list3n(FNAME,0,nptr); // type=list3(nptr->sc,nptr->ty,nptr->dsp); break; } default:error(UDERR); e1 = 0; } return expr16(e1); } static int typecast() { int e1; NMTBL *nptr0; int t=typename(); conv->type_(t,0,0); conv->rpar_(); checksym(RPAR); if (sym==LC && (t>0 && (car(t)==STRUCT||car(t)==UNION))) { // initializer // q->lock = (spinlock_t) { }; conv->lc_(); nptr0 = get_nptr(); nptr0->nm = ""; nptr0->sc = EMPTY; nptr0->attr = 0; type = nptr0->ty = t; int local_offset; if (mode==GDECL||inmode) { int e2,e3; e2 = list3n(GVAR,0,nptr0); e3 = decl_data_field(type,e2,0); if (!inmode) { e1 = e2; } else { e1 = reverse0(e3); e1 = list3(DECL_DATA,e1,t); e1 = list4(CAST,e1,t,t); // only for cast syntax } } else { if (!local_nptr) { // struct initialization for this variable // (struct hoge) { .fuga = 5 } local_nptr = nptr0; int smode = mode; mode = LDECL; def(nptr0,0); mode = smode; local_struct_offset = 0; } e1 = list3n(local_nptr->sc,local_nptr->dsp,local_nptr); #if LOCAL_STRUCT_INIT_STATIC local_struct_static(e1); #else local_offset = local_struct_offset; int offset = decl_data_field(type,e1,local_struct_offset); if (offset==local_struct_offset) { // empty case, let's zero clear now int sz = size(type); zfill(e1,offset,sz); local_struct_offset = offset + sz; } else local_struct_offset = offset; #endif } if (mode==STAT && decl_str_init) gen_delayed_decl_data(e1,local_offset); if (init_vars && mode!=LDECL) { emit_init_vars(); } if (nptr0==local_nptr) { // I have created this, sanitize local_nptr = 0; local_struct_offset = 0; } conv->rc_(); checksym(RC); type = t; return e1; } e1=expr13(); // (type) expr if (inmode) { e1 = list4(CAST,e1,t,type); type = t; return e1; } else { if (integral(t) || t==DOUBLE || t==FLOAT || t==LONGLONG || t==ULONGLONG) e1 = rvalue(e1); // left value should not be rvalued e1 = correct_type(e1,t); type = t; return e1; } } static int statement_expression() { // statement in expression (GNU extension) // a = {hoge(); 1;} // In docomp, last expression is kept in lastexp. // int e1; if (inmode) { int sparse = parse; parse=0; docomp(1); // wrong parse tree fix me! e1 = list3(COMMA,reverse0(parse),lastexp); parse = sparse; lastexp = 0; } else { int l,b,l2,cntl=control; // if COMMA expr is not gexpred by !control, // l2 is not defined and generates undefined error. // cntl prevents this. if (cntl) { gen_jmp(l=fwdlabel()); } else l = 0; b = backdef(); // control=1 docomp(1); if (cntl) { gen_jmp(l2=fwdlabel()); } else l2 = 0; // make it a simple call (by jmp) // register stack save now e1 = list3(COMMA,list3(LCALL,b,l2),lastexp); lastexp = 0; if (l) fwddef(l); control=cntl; } conv->rpar_(); checksym(RPAR); return expr16(e1); } static int strlen1(char *s) { int i = 0; while(*s++) i++; return i; } /** * basic term */ static int expr14(void) { int e1=0,t,t1; switch(sym) { case IDENT: return expr_identifier(); case STRINGS: e1=list3n(STRINGS,nptr->dsp,nptr); type=list3(ARRAY,CHAR,symval); getsym(0); break; case STRING: conv-> string_(nptr->nm,nptr->dsp); e1=list3n(STRING,nptr->dsp,nptr); type=list3(ARRAY,CHAR,nptr->dsp); getsym(0); break; case CONST: conv-> const_(symval); type= symval>=0?UNSIGNED:INT; e1=list2(CONST,symval); getsym(0); break; #if FLOAT_CODE case FCONST: conv-> const_(symval); type= FLOAT; e1=dlist2(FCONST,dsymval); getsym(0); break; case DCONST: conv-> const_(symval); type= DOUBLE; e1=dlist2(DCONST,dsymval); getsym(0); break; #endif #if LONGLONG_CODE case LCONST: conv-> const_(symval); type= ULONGLONG; e1=llist2(LCONST,lsymval); getsym(0); break; #endif case RETURN: conv-> return_f_(); if (!is_function(fnptr)) { error(STERR); } // this is wrong... should be // code (*)(return_type); type=list2(POINTER,list3(CODE,VOID,cadr(fnptr->ty))); // type arg e1=list3n(RETURN,0,fnptr); getsym(0); break; case DEFINED: t = mode; mode = IFDEF; getsym(0); if (sym==LPAR) { t1 = 1; getsym(0); } else t1 = 0; conv-> defined_(nptr->nm); mode = t; type= INT; e1=list2(CONST,symval); getsym(0); if (t1) checksym(RPAR); break; case ENVIRONMENT: // return current frame pointer (or equivalent) conv-> environment_(); type=list2(POINTER,VOID); e1=list2(ENVIRONMENT,0); getsym(0); break; case C_FILE: // return current file name nptr=name_space_search(get_name(filep->name0,0,0),STRING); nptr->dsp = strlen1(nptr->nm)+1; type=list3(ARRAY,CHAR,nptr->dsp); e1=list3n(STRING,nptr->dsp,nptr); getsym(0); break; case C_FUNCTION: // return current function name nptr=get_name(fnptr->nm,0,0); nptr=name_space_search(nptr,STRING); nptr->dsp = strlen1(nptr->nm)+1; type=list3(ARRAY,CHAR,nptr->dsp); e1=list3n(STRING,nptr->dsp,nptr); getsym(0); break; case C_LINE: // return current lineno in int type=UNSIGNED; e1=list2(CONST,lineno); getsym(0); break; case LPAR: conv->lpar_(); getsym(0); qualifiers(); if(typeid(sym)) { return typecast(); } else if (sym==LC) { return statement_expression(); } else { e1=expr0(); } conv->rpar_(); checksym(RPAR); break; default:error(EXERR); e1=list2(CONST,0); } return expr16(e1); } /* post fix binary operator (struct . -> or array[] */ static int expr16(int e1) { int e2,t,ind; while(1) { if(sym==LBRA) { /* a[3] */ conv->lbra_(sym); e1=rvalue(e1); t=type; getsym(0); e2=rvalue(expr0()); checksym(RBRA); conv->rbra_(sym); if (inmode || chk) { e1 = list5(ARRAY,e1,e2,t,type); if (car(t)!=POINTER) error(-1); type = cadr(t); } else { e1=binop(ADD,e1,e2,t,type); e1=indop(e1); } } else if(sym==LPAR) { e1=expr15(e1); /* f() */ } else if(sym==PERIOD||sym==ARROW) { ind = sym; conv->op_(sym); getsym(0); if (sym!=IDENT) error(TYERR); conv->id_(sym,nptr); e1=strop(e1,ind==ARROW); getsym(0); } else break; } if(car(e1)==FNAME) { set_attr(ncaddr(e1),FNAME,1); type=list2(POINTER,type); } return e1; } /* function call */ static NMTBL * make_tmp_struct() { int sz; /* checks type */ /* make temporary struct for return value */ /* but it is better to see we can reuse old one */ /* a = f().a case */ if (tmp_struct && !inmode) { sz = size(tmp_struct->ty); if (sz>=size(type)) { /* reuse it */ } else if (tmp_struct->dsp-sz==disp) { /* extendable */ disp -= tmp_struct->dsp-sz; tmp_struct->dsp = disp; } else { tmp_struct = def(0,0); } } else if (tmp_struct && inmode) { if (size(type)>size(tmp_struct->ty)) { tmp_struct->ty = type; } } else { tmp_struct = def(0,0); if (inmode) { set_attr(tmp_struct,HAS_ADDRESS,1); parse = list5n(ST_DECL,parse,list3(LDECL,0,0),0,tmp_struct); } } return tmp_struct; } /* function call */ static int expr15(int e1) { int t,arglist,e,argtypes,at,ftype; int type0 = type_value(type); int dots; /* function call target */ if(type0>0 && car(type0)==POINTER) { if (car(cadr(type0))==FUNCTION||car(cadr(type0))==CODE) { e1=rvalue(e1); type=set_type_with_attr(cadr(type0),type); type0 = type_value(type); } /* else error */ } if(integral(type0)||type0<0||((car(type0)!=FUNCTION)&&(car(type0)!=CODE))){ error(TYERR); } ftype = type; conv->funcall_(type); /* function argments */ function_type(ftype,&dots); if (type0<=0) { getsym(0); return INT; } argtypes = caddr(type0); if (!argtypes) dots=1; if ((t=type_value(cadr(type0)))>=0 && (car(t)==STRUCT||car(t)==UNION)) { /* skip return struct pointer */ if (argtypes==0) error(-1); argtypes = cadr(argtypes); } arglist=0; getsym(0); while(sym!=RPAR) { e=rvalue(expr1()); if(argtypes==0) { at=DOTS; if (!dots) { error(AGERR); } } else if(car(argtypes)==DOTS) at=DOTS; else { at=car(argtypes); argtypes=cadr(argtypes); } if (at>0&&car(at)==ARRAY) at = list2(POINTER,cadr(at)); e = correct_type(e,at); arglist=list3(e,arglist,type); if(sym!=COMMA) break; conv->comma_(); getsym(0); } if (!dots && argtypes && car(argtypes)!=VOID) { error(AGERR); } checksym(RPAR); conv->funcall_args_(e1,ftype,arglist); if(t==CODE) { if (stmode!=GOTO) error(FNERR); // code segment has no return type type = ftype; return list4(CODE,e1,arglist,ftype); // should be CODE? } else if (stmode==GOTO) { // symbol is undefined at this time // error(GTERR); } /* return type */ NMTBL *tmp = 0; type = cadr(ftype); type0 = type_value(type); if(type0==CHAR||type0==SHORT) type=set_type_with_attr(INT,type); else if(type0==UCHAR||type0==USHORT) type=set_type_with_attr(UNSIGNED,type); else if(type0>0 && (car(type0)==STRUCT||car(type0)==UNION)) { /* temporal struct is required */ tmp = make_tmp_struct(); e = list3n(inmode?IVAR:LVAR,tmp->dsp,tmp); /* pass the pointer as an argument */ /* this is recognized by called function declaration */ /* but I don't know this sequence is compatible with gcc */ arglist = append3(arglist,list2(ADDRESS,e),list2(POINTER,type)); } if (car(e1)==FNAME) { // recursive inline is not allowed if (ncaddr(e1)!=fnptr && is_inline(ncaddr(e1))) { if (tmp) return list2(INDIRECT,(list4(INLINE,e1,arglist,ftype))); else return list4(INLINE,e1,arglist,ftype); } } if (tmp) return list2(INDIRECT,list4(stmode==GOTO?CODE:FUNCTION,e1,arglist,ftype)); else return list4(stmode==GOTO?CODE:FUNCTION,e1,arglist,ftype); } static int typeid(int s) { switch(s) { case CODE : case SHORT : case LONG : case STRUCT : case UNION : case ENUM : case LONGLONG : case FLOAT : case DOUBLE : case VOID : case ULONGLONG : case TYPEOF : case KONST: case VOLATILE: return 1; case IDENT: return nptr->sc==TYPE; } return (integral(s)); } static int typename(void) { int t; int sctmode=ctmode; int sd = sdecl_f; sdecl_f = 0; ctmode=0; sdecl_f = 0; type=t=typespec(); // undefine case? ctmode = sctmode; ndecl0(); reverse(t); sdecl_f = sd; return type; } /* type prefix in cast (type definition)expre */ static int ndecl0(void) { if(sym==MUL) { attribute = 0; // do not inherite type attributes getsym(0); return type=list2(POINTER,ndecl0()); } return ndecl1(); } /* type postfix in cast */ static int ndecl1(void) { int i,t,arglist; if(sym==LPAR) { if(getsym(0)==RPAR) { type=list3(FUNCTION,type,0); getsym(0); } else { ndecl0(); checksym(RPAR); } } while(1) { if(sym==LBRA) { getsym(0); t=type; i = inmode?cexpr(pexpr(expr(1))):cexpr(expr(1)); checksym(RBRA); type=list3(ARRAY,t,i); } else if(sym==LPAR) { t = type; getsym(0); arglist=0; while(sym!=RPAR) { ndecl0(); arglist=list2(type,arglist); if(sym!=COMMA) break; getsym(0); } checksym(RPAR); type=list3(FUNCTION,t,arglist); } else return type; } } int types_compatible(int t, int t1) { int eq = 0; if (t==t1) eq = 1; type = INT; return list2(CONST,eq); } /* string cheap management compiler keeps string data (name, string etc.) new_cheap() increment cheap memory increment_cheap(cheap, &pointer_top) before this pointer_top = cheap->ptr is necessary. increment cheap->ptr, if cheap is increased, pointer_top is updated. Note. Inline comments use cheap during getc(). If getch() cross the new line, continuous cheap is not assured. save_cheap(struct cheap *scheap,struct cheap *cheap) saved point for reseting cheap. reset_cheap(struct cheap *scheap) abandone cheap to save_cheap point. To avoid interference, allocate new cheap pool and struct. */ extern struct cheap * new_cheap() { struct cheap *p = (struct cheap *)malloc(sizeof(struct cheap)); if (!p) error(MMERR); // fatal p->ptr = p->first = (char *)malloc(CHEAPSIZE); if (HEAP_REPORT) fprintf(stderr,"** new cheap %d\n",(int)CHEAPSIZE); p->last = p->first + CHEAPSIZE; if (!p->ptr) error(MMERR); // fatal p->next = 0; return p; } extern struct cheap * increment_cheap(struct cheap *cheap,char **save) { char *p,*q,*from,*to; int i; if (cheap->ptr >= cheap->last-1) { // running out of cheap area if (!cheap->next) { // no previously freed cheap create new one cheap->next = new_cheap(); } if (save) { // string in cheap have to be continuous. // prepare move from old cheap cheap->ptr = from = *save; i = cheap->last - from; to = *save = cheap->next->first; if (i>CHEAPSIZE) error(NMERR); // a string is larger than cheap size if (to<=chptr && chptr<=to+i) { // we are going to destory the line just we are // reading... move reading line to the next cheap if (!cheap->next->next) { cheap->next->next = new_cheap(); } q = chptr; p = chptr = cheap->next->next->ptr; while((*p++ = *q++)); // now save to move overflowed string } while(i-->0) { *to++ = *from++; } cheap->next->ptr = to-1; } cheap = cheap->next; } cheap->ptr++; return cheap; } /* mark string cheap */ extern void save_cheap(struct cheap *scheap,struct cheap *cheap) { // keep curret cheap pointer scheap->ptr = cheap->ptr; scheap->next = cheap; } /* discard string heap until marked string */ extern struct cheap * reset_cheap(struct cheap *scheap) { // go back to the kept curret cheap pointer // (should be while loop if (cheap==scheap->next) { cheap->ptr = scheap->ptr; } else { cheap->ptr = cheap->first; cheap = scheap->next; cheap->ptr = scheap->ptr; } return cheap; } /* Symbol table handling hash table lexical scope structure for macro and local variable, goto label, string */ static int neqnamel(char *p,char *q,int len) { while(len-->0 && *p++ == *q++); return len!=-1; } /** hash table search *char name cheap heap len length hash hash value mode NONDEF search only, DEF define return NMTBL in hash entry */ static NMTBL * hash_search(char *name,struct cheap *scheap,int len,unsigned int hash,int mode) { NMTBL *hptr,**iptr,**eptr; int i,j; eptr = iptr= &htable[hash % GSYMS]; for(i=0;(hptr=*iptr) && hptr->sc!=0 && neqnamel(hptr->nm,name,len);i++) { // open hash if (++iptr== &htable[GSYMS]) iptr=&htable[0]; if (eptr==iptr) error(GSERR); } // we cannot extend hash now if (HEAP_REPORT && i>3) { for(j=0,eptr=htable;eptr<htable+GSYMS;eptr++) { if (*eptr) j++; } fprintf(stderr,"# bad hash %d hash=%d/%d %02d%% %s\n", i, hash%GSYMS,GSYMS,j*100/GSYMS,name); } if (!hptr) { // not found if (mode==NONDEF) return 0; hptr = get_nptr(); hptr->nm = name; /* name should be in the safe place (cheap) */ *iptr = hptr; } if (hptr->sc == 0) { // newly created entry hptr->sc=EMPTY; } else { // already defined cheap = reset_cheap(scheap); } return hptr; } /** register general data in hash for long long or double data is copied into cheap when it is created typedef union { double d; float f; int i; long l; long long ll; } Value, *ValuePtr; */ extern NMTBL * get_data(ValuePtr name,int len,int mode) { /* no name copy */ unsigned int c; unsigned int hash0 = 0; int i = len; char *n = (char*)name; struct cheap scheap; save_cheap(&scheap,cheap); char *top = cheap->ptr; while(len-->0) { c = *n++; hash_value(hash0,*cheap->ptr = c); cheap = increment_cheap(cheap,&top); } return name_space_search(hash_search(top,&scheap,i,hash0,DEF),STRING); } extern int get_data_label(ValuePtr name,int len, void emit(ValuePtr, int, void * ), void *arg) { int lb; NMTBL * n = get_data(name,len,DEF); if ((lb=attr_value(n,LABEL))) return lb; lb=fwdlabel(); set_attr(n,LABEL,lb); emit(name, lb, arg); return lb; } /** get name from already stored in cheap */ extern NMTBL * get_name(char *name,int *len,int mode) { /* no name copy */ unsigned int c,i = 0; unsigned int hash0 = 0; char *n = name; struct cheap scheap; save_cheap(&scheap,cheap); c = *n++; for(i=0;alpha(c) || digit(c);i++) { hash_value(hash0,c); c = *n++; } if (len) *len = i; return hash_search(name,&scheap,i,hash0,mode); } /** get name from input */ extern NMTBL * get_name_from_chptr() { int i = 0; unsigned int hash0 = 0; char *name = cheap->ptr; struct cheap scheap; save_cheap(&scheap,cheap); for(i=0;alpha(ch) || digit(ch);i++) { hash_value(hash0,*cheap->ptr = ch); cheap = increment_cheap(cheap,&name); getch(); } *cheap->ptr = 0; cheap = increment_cheap(cheap,&name); return hash_search(name,&scheap,i,hash0,DEF); } // call this right after '/' static void skip_comment(int space) { for(;;getch()) { if (ch=='/') { in_comment = 1; conv->comment_('/'); conv->comment_('/'); while(ch!='\n') { getch(); conv->comment_(ch); } in_comment = 0; if (space) skipspc(); else return; if (ch!='/') break; continue; } if(ch!='*') { ch = *--chptr; // we already read '/', this is safe return ; } in_comment = 1; conv->comment_('/'); conv->comment_('*'); int c; do { c=ch; getch(); conv->comment_(ch); } while(!(c=='*'&&ch=='/')); in_comment = 0; getch(); if (space) skipspc(); else return; if (ch!='/') break; } } /* All strings are kept in hash table, and shared. float/long long should be shared too. concatenate "..." comment "..." */ static int getstring(void) { char *name = cheap->ptr; int c; unsigned int hash = 0; int strings = 0; struct cheap scheap; save_cheap(&scheap,cheap); do { while (ch == '"') { in_quote = 1; getch(); while (ch != '"') { if (cheap->ptr - scheap.ptr >STRSIZE-1) { *cheap->ptr = 0; cheap = increment_cheap(cheap,&name); strings = glist3s(cheap->ptr - scheap.ptr-1 ,strings,name); save_cheap(&scheap,cheap); name = cheap->ptr; } if ((c = escape())==0 && ch=='"') { in_quote = 0; getch(); goto possible_string_concatenate; } hash_value(hash, *cheap->ptr = c); cheap = increment_cheap(cheap,&name); } in_quote = 0; getch(); } possible_string_concatenate: *cheap->ptr = 0; cheap = increment_cheap(cheap,&name); char *s = cheap->ptr; skipspc(); if (ch=='/') skip_comment(1); if (ch=='"') { // concatenated string does not terminated by 0 if (s != cheap->ptr) { // discontinuous cheap case strings = glist3s(s - scheap.ptr -1,strings,name); save_cheap(&scheap,cheap); name = cheap->ptr; } else { cheap->ptr--; } } } while (ch=='"'); if (strings) { // too long string is stored in glist3 strings = glist3s(cheap->ptr - scheap.ptr,strings,name); nptr = get_nptr(); nptr->dsp = strings = reverse0(strings); int i,j; for(j = strings, i = 0; j ; j = cadr(j)) { i += car(j); } symval = i; return STRINGS; } int i = cheap->ptr - scheap.ptr; nptr = name_space_search(hash_search(name,&scheap,i,hash,DEF),STRING); // if we already have this, hash_search will reset cheap // should do the same thing for float/double constant nptr->dsp = i; symval = i; return STRING; } /* long long posfix (0ULL etc.) */ static int is_ll() { if (ch=='U' || ch=='u') { getch(); } if (ch=='L'||ch=='l') { if (getch()=='L'||ch=='l') { getch(); return 1; } if (lp64) return 1; } return 0; } static int get_numerical() { int d; struct cheap scheap; char *num; /* numerical */ save_cheap(&scheap,cheap); symval=0; d=0; num = cheap->ptr; sym = 0; if(ch=='.') { getch(); if(ch=='.') { getch(); if (ch=='.') { getch(); return sym=DOTS; } error(CHERR); return getsym(0); } else if (!digit(ch)) return sym=PERIOD; d=1; *cheap->ptr = '.'; /* .0 case */ cheap = increment_cheap(cheap,&num); } else if (ch == '0') { *cheap->ptr = ch; cheap = increment_cheap(cheap,&num); if (getch() == 'x' || ch == 'X') { *cheap->ptr = ch; cheap = increment_cheap(cheap,&num); /* hexadicimal */ while(1) { getch(); *cheap->ptr = ch; cheap = increment_cheap(cheap,&num); if(digit(ch)) symval=symval*16+ch-'0'; else if('a'<=ch&&ch<='f') symval=symval*16+ch-'a'+10; else if('A'<=ch&&ch<='F') symval=symval*16+ch-'A'+10; else break; } if (is_ll()) { #if LONGLONG_CODE cheap->ptr[-1] = 0; lsymval = strtoll(num,0,0); // we should keep this value? like string? cheap = reset_cheap(&scheap); sym=LCONST; #endif } else sym=CONST; } else if (digit(ch)) { /* octal */ while(1) { getch(); *cheap->ptr = ch; cheap = increment_cheap(cheap,&num); if(digit(ch)) symval=symval*8+ch-'0'; else break; } if (is_ll()) { #if LONGLONG_CODE cheap->ptr[-1] = 0; cheap = increment_cheap(cheap,&num); lsymval = strtoll(num,0,0); cheap = reset_cheap(&scheap); sym=LCONST; #endif } else sym=CONST; } else if (ch=='L'||ch=='U') { /* 0L or 0LL case */ if (is_ll()) { #if LONGLONG_CODE lsymval = 0; sym=LCONST; #endif } } else if (ch=='.'||ch=='e') { d=1; *cheap->ptr = '0'; /* 0. case */ cheap = increment_cheap(cheap,&num); } else { cheap = reset_cheap(&scheap); symval = 0; sym=CONST; } } else { while(digit(ch)) { *cheap->ptr = ch; cheap = increment_cheap(cheap,&num); symval=symval*10+ch-'0';getch(); } if (ch=='.'||ch=='e'||ch=='f') d=1; } if (!sym) { if (!d) { if (is_ll()) { #if LONGLONG_CODE *cheap->ptr = 0; cheap = increment_cheap(cheap,&num); lsymval = strtoll(num,0,0); sym=LCONST; #endif } else sym=CONST; } else { #if FLOAT_CODE /* floating point case */ while(digit(ch)|| ch=='.'||ch=='e'||ch=='f') { *cheap->ptr = ch; cheap = increment_cheap(cheap,&num); getch(); if ((ch=='-' && (cheap->ptr[-1]=='e'|| cheap->ptr[-1]=='f'))|| (ch=='+' && (cheap->ptr[-1]=='e'|| cheap->ptr[-1]=='f'))) { *cheap->ptr = ch; cheap = increment_cheap(cheap,&num); getch(); } } /* C99 */ if (ch=='F' || ch=='L') { // float or long double *cheap->ptr = ch; cheap = increment_cheap(cheap,&num); getch(); } *cheap->ptr = 0; cheap = increment_cheap(cheap,&num); dsymval = strtod(num,0); sym=DCONST; #else symval = 0; sym=CONST; #endif } } cheap = reset_cheap(&scheap); return sym; } /* Tokenizer output sym symval nptr gnptr */ extern int getsym(int sc) { NMTBL *nlist,*nptr0,*nptrm; char c; retry: if (alpha(skipspc())) { nptrm=name_space_search(nlist = get_name_from_chptr(),MACRO); if (mode==MDECL) { nptr = nptrm; return (sym==MACRO); } if (mode==IFDEF) { nptr = nptrm; if (nptrm->sc == MACRO||nptrm->sc==FMACRO) { return (symval=1); } else { return (symval=0); } } if ((nptrm->sc==MACRO&&neqname(scaddr(nptrm->dsp),nptrm->nm)) || (nptrm->sc==FMACRO&&skipspc()=='(')) { char *s; if (in_macro_if && (s = scaddr(nptrm->dsp)) && *s==0) { symval = 0; return (sym=CONST); } if (!check_recurse(nptrm->nm,macro_history)) { macro_expansion(nptrm); sc=0; goto retry; } } /* global variable name table */ nptr0 = name_space_search(nlist,sc); if (nptr0->sc == RESERVE) return sym = nptr0->dsp; if (mode==ATTRIBUTE && nptr0->sc == ATTRIBUTE) return sym = nptr0->dsp; sym = IDENT; gnptr=nptr=nptr0; switch(mode) { case ADECL: if (nptr0->sc ==TYPE) return sym; break; case GDECL: case GSDECL: case GUDECL: case LSDECL: case LUDECL: case GTDECL: case TOP: case GEDECL: case SFDINIT: return sym; } if (nptr->sc == TYPE) return sym; if (nptr->sc == TAG) return sym; if (mode==STAT) { /* can be undeclared global variable */ return sym; } /* define case LDECL ony? */ nptr = make_local_scope(nlist,nptr,sc); return sym; } else if (digit(ch)||ch=='.') { return get_numerical(); } else if(ch=='\'') { getch(); symval=escape(); if(ch!='\'') error(CHERR); getch(); return sym=CONST; } else if(ch=='"') { return sym= getstring(); } /* 2 letters literal */ c=ch; getch(); switch(c) { case '*': return postequ(MUL,MUL+AS); case '&': if(ch=='&') {getch();return sym=LAND;} return postequ(BAND,BAND+AS); case '-': if(ch=='>') {getch();return sym=ARROW;} if(ch=='-') {getch();return sym=DEC;} return postequ(SUB,SUB+AS); case '!': return postequ(LNOT,NEQ); case '~': return sym=BNOT; case '+': if(ch=='+') {getch();return sym=INC;} return postequ(ADD,ADD+AS); case '%': return postequ(MOD,MOD+AS); case '^': return postequ(EOR,EOR+AS); case '|': if(ch=='|') {getch();return sym=LOR;} return postequ(BOR,BOR+AS); case '=': return postequ(ASS,EQ); case '>': if(ch=='>') {getch();return postequ(RSHIFT,RSHIFT+AS);} return postequ(GT,GE); case '<': if(ch=='<') {getch();return postequ(LSHIFT,LSHIFT+AS);} return postequ(LT,LE); case '(': return sym=LPAR; case ')': return sym=RPAR; case '[': return sym=LBRA; case ']': return sym=RBRA; case '{': return sym=LC; case '}': return sym=RC; case ',': return sym=COMMA; case ':': return sym=COLON; case '?': return sym=COND; case ';': return sym=SM; case '/': if(ch!='*'&&ch!='/') return postequ(DIV,DIV+AS); skip_comment(1); sc=0; goto retry; case 0: case '\n': case '\f': case '\\': sc = 0; goto retry; default: error(CHERR); sc = 0; goto retry; } } static int postequ(int s1, int s2) { if(ch=='=') {getch();return sym=s2;} return sym=s1; } extern int alpha(int c) { return(('a'<=c&&c<='z')||('A'<=c&&c<='Z')||c=='_'); } extern int digit(int c) { return('0'<=c&&c<='9'); } extern void free_nptr(NMTBL *n) { n->u.nptr = free_nptr_list; free_nptr_list = n; } /* nptr pool (for resue) */ extern NMTBL * get_nptr() { NMTBL *ret; if (free_nptr_list) { // we can use free list ret = free_nptr_list; free_nptr_list = free_nptr_list->u.nptr; ret->sc = 0; ret->ty = 0; ret->dsp = 0; ret->dsp = 0; ret->u.nptr = 0; ret->attr = 0; ret->next = 0; return ret; } if (nptr_pool->ptr >= nptr_pool->last) { if (nptr_pool->next) { // we can reuse previous nptr_pool nptr_pool = nptr_pool->next; } else { // allocate new one if (HEAP_REPORT) fprintf(stderr,"** nptr extended\n"); nptr_pool->next = new_cheap(); nptr_pool = nptr_pool->next; } } ret = (NMTBL *)nptr_pool->ptr; nptr_pool->ptr += sizeof(NMTBL); ret->sc = 0; ret->ty = 0; ret->dsp = 0; ret->u.nptr = 0; ret->attr = 0; ret->next = 0; return ret; } /* dummy name table element */ int dummy_count = 0; extern NMTBL * anonymous_nptr() { NMTBL *nptr; int i,j; nptr= get_nptr(); j = dummy_count++; for(i=0;j>0;j/=10); nptr->nm = cheap->ptr; cheap->ptr += i-1+3; increment_cheap(cheap,&nptr->nm); nptr->nm[0]='_'; nptr->nm[1]='a'; nptr->nm[2]='n'; j = dummy_count; for(;i>=0;i--) { nptr->nm[i+3]='0'+j%10; j/=10; } nptr->sc=EMPTY; nptr->dsp=0; nptr->u.nptr=0; return nptr; } /* lexical name scope handler enter_scope leave_scope nptr->dsp glist3n(ScopeID,next,nptr) ScopeID MACRO,NAME,TYPEDEF,FIELD */ extern NMTBL * name_space_search(NMTBL *hash,int sc) { int ns = 0; NMTBL *n = 0; for(ns=hash->dsp;ns;ns=cadr(ns)) { // iterate on possible scope if (car(ns)==sc) { return ncaddr(ns); } } if (ns==0) { n = get_nptr(); hash->dsp = glist3n(sc,hash->dsp,n); // make a scope for sc } // else error ? n->nm = hash->nm; n->sc = EMPTY; n->dsp = 0; n->attr = 0; return n; } // search local nptr by name and storage class extern NMTBL * lsearch(char *name,int sc) { NMTBL *nlist,*nptr1; nptr1 = name_space_search(nlist=get_name(name,0,DEF),sc); return make_local_scope(nlist,nptr1,sc); } // search top level local name (for label) extern NMTBL * l_top_search(char *name,int sc) { NMTBL *nlist,*nptr1; nptr1 = name_space_search(nlist=get_name(name,0,DEF),sc); return make_top_scope(nlist,nptr1,sc); } extern NMTBL * make_local_scope(NMTBL *nlist,NMTBL *nptr1,int sc) { int ns; for(ns=nlist->dsp;ns;ns=cadr(ns)) { // iterate on possible scope if (car(ns)==sc) { // memorize previous nptr for this name for leave_scope car(current_scope) = glist3n(ns,car(current_scope),nptr1); ncaddr(ns) = nptr1 = get_nptr(); nptr1->nm = nlist->nm; nptr1->sc=EMPTY; nptr1->dsp = 0; break; } } return nptr1; } static NMTBL * make_top_scope(NMTBL *nlist,NMTBL *nptr1,int sc) { int ns; int scope; for(scope=current_scope;cadr(scope);scope=cadr(scope)); for(ns=nlist->dsp;ns;ns=cadr(ns)) { // memorize previous nptr for this name for leave_scope if (car(ns)==sc) { car(scope) = glist3n(ns,car(scope),nptr1); ncaddr(ns) = nptr1 = get_nptr(); nptr1->nm = nlist->nm; nptr1->sc=EMPTY; nptr1->dsp = 0; break; } } return nptr1; } extern void enter_scope() { current_scope = glist2(0,current_scope); } extern void leave_scope() { NMTBL *ns; int scope,next; if (!current_scope) error(-1); // restore nptr of current scope name to the previous nptr scope = car(current_scope); while(scope) { ns = ncaddr(car(scope)); switch(ns->sc) { case GVAR: case STATIC: case IVAR: break; default: if (!inmode) free_nptr(ns); } ncaddr(car(scope)) = ncaddr(scope); next = cadr(scope); free_glist2(scope); // will destroy cadr scope = next; } if ((next=cadr(current_scope))) { free_glist2(current_scope); current_scope = next; } else car(current_scope) = 0; } extern NMTBL * extern_define(char *s,int d,int type,int use) { NMTBL *nptr0; (nptr0 = name_space_search(get_name(s,0,DEF),0))->sc = EXTRN; nptr0->dsp = d; nptr0->ty=type; if (use) extrn_use(nptr0); return nptr0; } /* Character handling */ extern int neqname(char *p,char *q) { if (!p) return 0; while(*p && *p!='.') if(*p++ != *q++) return 1; return (*q!=0); } extern int skipspc(void) { static int topspc = 0; while(ch=='\t'||ch=='\n'||ch==' '||ch=='\r') { if (ch=='\n'||ch=='\r') topspc=1; if (topspc) conv->comment_(ch); getch(); } topspc=0; return ch; } static int prev_macro_end; extern int getch(void) { int i,j; if (prev_macro_end) { int history = 0; if (macro_history_save) { history = car(macro_history_save); int save = cadr(macro_history_save); free_glist2(macro_history_save); macro_history_save = save; while(macro_history!=history) { int next = cadr(macro_history); free_glist3(macro_history); macro_history = next; } } prev_macro_end = 0; } if(*chptr) return ch = *chptr++; else if (chptrsave) { prev_macro_end = 1; chptr = scaddr(chptrsave); ch = car(chsave); i = cadr(chptrsave); j = cadr(chsave); free_glist2s(chptrsave); free_glist2(chsave); chptrsave = i; chsave = j; return ch; } if (!filep) return ch=0; // command line case; getline1(); if (in_macro_if) check_macro_eof(); return getch(); } static int escape(void) { char c; // Unicode? if ((c=ch) == '\\') { if (digit(c=getch())) { c = ch-'0'; if (digit(getch())) { c = c*8+ch-'0'; if (digit(getch())) { c=c*8+ch-'0';getch(); } } return c; } getch(); switch(c) { case 'n': return '\n'; case 't': return '\t'; case 'b': return '\b'; case 'r': return '\r'; case 'f': return '\f'; case '\\': return '\\'; case '\n': if (ch=='"') { return 0; } return escape(); default: return c; } } // if (c == '\n') error(EXERR); getch(); return c; } /* node management (cdr coding ) */ #if LONGLONG_CODE extern int llist2(int e1, long long d1) { int e; e=getfree((sizeof(int)+size_of_longlong)/sizeof(int)); heap[e]=e1; lcadr(e)=d1; return e; } extern int llist3(int e1, int e2,long long d1) { int e; e=getfree((sizeof(int)+size_of_longlong)/sizeof(int)); heap[e]=e1; heap[e+1]=e2; lcaddr(e)=d1; return e; } #endif #if FLOAT_CODE extern int dlist2(int e1, double d1) { int e; e=getfree((sizeof(int)+sizeof(double))/sizeof(int)); heap[e]=e1; dcadr(e)=d1; return e; } extern int dlist3(int e1, int e2,double d1) { int e; e=getfree((sizeof(int)*2+sizeof(double))/sizeof(int)); heap[e]=e1; heap[e+1]=e2; dcaddr(e)=d1; return e; } #endif extern int list2(int e1, int e2) { int e; e=getfree(2); heap[e]=e1; heap[e+1]=e2; return e; } extern int list3(int e1, int e2, int e3) { int e; e=getfree(3); heap[e]=e1; heap[e+1]=e2; heap[e+2]=e3; return e; } extern int list3n(int e1, int e2, NMTBL *e3) { int e; e=getfree(2+(sizeof(void*)/sizeof(int))); heap[e]=e1; heap[e+1]=e2; vcaddr(e) = e3; return e; } extern int list3s(int e1, int e2, char *e3) { int e; e=getfree(2+(sizeof(void*)/sizeof(int))); heap[e]=e1; heap[e+1]=e2; scaddr(e) = e3; return e; } extern int list4(int e1, int e2, int e3, int e4) { int e; e=getfree(4); heap[e]=e1; heap[e+1]=e2; heap[e+2]=e3; heap[e+3]=e4; return e; } extern int list4n(int e1, int e2, int e3, NMTBL * e4) { int e; e=getfree(3+(sizeof(void*)/sizeof(int))); heap[e]=e1; heap[e+1]=e2; heap[e+2]=e3; ncadddr(e) = e4; return e; } extern int list4s(int e1, int e2, int e3, char * e4) { int e; e=getfree(3+(sizeof(void*)/sizeof(int))); heap[e]=e1; heap[e+1]=e2; heap[e+2]=e3; scadddr(e) = e4; return e; } extern int list5(int e1, int e2, int e3, int e4,int e5) { int e; e=getfree(5); heap[e]=e1; heap[e+1]=e2; heap[e+2]=e3; heap[e+3]=e4; heap[e+4]=e5; return e; } extern int list5n(int e1, int e2, int e3, int e4,NMTBL * e5) { int e; e=getfree(4+(sizeof(void*)/sizeof(int))); heap[e]=e1; heap[e+1]=e2; heap[e+2]=e3; heap[e+3]=e4; ncaddddr(e) = e5; return e; } extern int getfree(int n) { int e; switch (mode) { case GDECL: case GSDECL: case GUDECL: case GTDECL: case MDECL: case ADECL: case LSDECL: case LUDECL: case GEDECL: case ATTRIBUTE: e=gfree; gfree+=n; break; default: if (inmode) { e=gfree; gfree+=n; } else { lfree-=n; e=lfree; } } if(lfree<gfree) error(HPERR); return e; } extern int glist2(int e1,int e2) { int ret; if (free_glist2_list) { ret = free_glist2_list; free_glist2_list = cadr(free_glist2_list); car(ret)=e1; cadr(ret)=e2; return ret; } ret = gfree; gfree+=2 ; heap[ret]=e1; heap[ret+1]=e2; if(lfree<gfree) error(HPERR); return ret; } extern int glist2s(int e1,char *e2) { int ret; ret = gfree; gfree+=(1+sizeof(void*)/sizeof(int)) ; heap[ret]=e1; scaddr(ret) = e2; if(lfree<gfree) error(HPERR); return ret; } extern int glist3s(int e1,int e2, char *e3) { int ret; ret = gfree; gfree+=(2+sizeof(void*)/sizeof(int)) ; heap[ret]=e1; heap[ret+1]=e2; scaddr(ret) = e3; if(lfree<gfree) error(HPERR); return ret; } extern void free_glist2(int e1) { if (e1>gfree) return; /* freeing local heap */ if (e1==gfree) { gfree-=2; } else { cadr(e1) = free_glist2_list; free_glist2_list = e1; } } extern int glist3(int e1,int e2,int e3) { int ret; if (free_glist3_list) { ret = free_glist3_list; free_glist3_list = cadr(free_glist3_list); car(ret)=e1; cadr(ret)=e2; caddr(ret)=e3; return ret; } ret = gfree; gfree+=3 ; heap[ret]=e1; heap[ret+1]=e2; heap[ret+2]=e3; if(lfree<gfree) error(HPERR); return ret; } extern int glist3n(int e1,int e2,NMTBL *e3) { int ret; ret = gfree; gfree+=(2+sizeof(void*)/sizeof(int)) ; heap[ret]=e1; heap[ret+1]=e2; ncaddr(ret) = e3; // heap[ret+2]=e3; if(lfree<gfree) error(HPERR); return ret; } extern int glist4(int e1,int e2,int e3,int e4) { int ret; ret = gfree; gfree+=4 ; heap[ret]=e1; heap[ret+1]=e2; heap[ret+2]=e3; heap[ret+3]=e4; if(lfree<gfree) error(HPERR); return ret; } extern int glist4n(int e1,int e2,int e3,NMTBL * e4) { int ret; ret = gfree; gfree+=(3+sizeof(void*)/sizeof(int)) ; heap[ret]=e1; heap[ret+1]=e2; heap[ret+2]=e3; ncadddr(ret) = e4; if(lfree<gfree) error(HPERR); return ret; } extern int glist5(int e1,int e2,int e3,int e4,int e5) { int ret; ret = gfree; gfree+=4 ; heap[ret]=e1; heap[ret+1]=e2; heap[ret+2]=e3; heap[ret+3]=e4; heap[ret+4]=e5; if(lfree<gfree) error(HPERR); return ret; } extern void free_glist2s(int e1) { // fix me } extern void free_glist3(int e1) { /* list3n is larger than length 3, but it's Ok */ if (e1>gfree) return; /* freeing local heap */ if (e1==gfree) { gfree-=3; } else { cadr(e1) = free_glist3_list; free_glist3_list = e1; } } extern void free_glist3_a(int e1) // free all chain of glist3 { int next; while(e1) { if (e1>gfree) continue; /* freeing local heap */ next = cadr(e1); if (e1==gfree) { gfree-=3; } else { cadr(e1) = free_glist3_list; free_glist3_list = e1; } e1 = next; } } extern int length(int list) { int n=0; for(;list;n++) { list = cadr(list); } return n; } extern int nth(int n, int list) { while(n-->0) { list = cadr(list); } return list; } extern int insert_ascend(int p,int e,int eq()) { int p1,p2,dup; if(!p) return e; if (car(p)==car(e)) { if ((dup=eq())==0) // duplicate value is not override return p; else if (dup==2) { // keep unique allow override cadr(e) = cadr(p); // skip one return e; } // any other value allows duplicate } else if (car(p)>car(e)) { cadr(e) = p; return e; } p1=p; while(cadr(p)) { p = cadr(p2=p); if (car(p)==car(e)) { if ((dup=eq())==0) // duplicate value is not override return p1; else if (dup==2) { // keep unique allow override cadr(e) = cadr(p); // skip one cadr(p2) = e; return p1; } // any other value allows duplicate } else if (car(p)>=car(e)) { cadr(e) = cadr(p2); cadr(p2) = e; return p1; } } cadr(p) = e; return p1; } extern int append5(int p,int a1,int a2,int a3,int a4) { int p1; if(!p) return list5(a1,0,a2,a3,a4); p1=p; while(cadr(p)) p = cadr(p); cadr(p) = list5(a1,0,a2,a3,a4); return p1; } extern int append4(int p,int a1,int a2,int a3) { int p1; if(!p) return list4(a1,0,a2,a3); p1=p; while(cadr(p)) p = cadr(p); cadr(p) = list4(a1,0,a2,a3); return p1; } extern int append3(int p,int a1,int a2) { int p1; if(!p) return list3(a1,0,a2); p1=p; while(cadr(p)) p = cadr(p); cadr(p) = list3(a1,0,a2); return p1; } /* attribute list for nptr->attr */ extern int has_attr(NMTBL *n,int attr) { int e; if (!n) return 0; e = n->attr; for(;e;e=cadr(e)) { if (car(e)==attr) return 1; } return 0; } extern int attr_value(NMTBL *n,int attr) { int e; if (!n) return 0; e = n->attr; for(;e;e=cadr(e)) { if (car(e)==attr) return caddr(e); } return 0; } extern void set_attr(NMTBL *n,int attr,int value) { int e; if (!n) error(-1); e = n->attr; for(;e;e=cadr(e)) { if (car(e)==attr) { caddr(e) = value; return; } } switch (n->sc) { case LVAR: n->attr = list3(attr,n->attr,value); break; default: n->attr = glist3(attr,n->attr,value); break; } return; } /* transfer attribtes() value to nptr; */ extern void set_attributes(NMTBL *n,int attr) { int e; for(e = attr; e ; e = cadr(e)) { set_attr(n,car(e),caddr(e)); } } extern int attr_value_in_list(int list,int attr) { int e; e = list; for(;e;e=cadr(e)) { if (car(e)==attr) return caddr(e); } return 0; } static void copy_attributes(NMTBL *n) { int attr; for(attr=n->attr;attr;attr=cadr(attr)) { attribute = list3(car(attr),attribute,caddr(attr)); } } extern void display_ntable(NMTBL *n, char *s) { fprintf(stderr,"\n%s ",s); fprintf(stderr,"nptr->sc %d ",n->sc); fprintf(stderr,"nptr->dsp %d ",n->dsp); fprintf(stderr,"nptr->ty %d ",n->ty); fprintf(stderr,"nptr->nm %s\n",n->nm); } /* type attribute type = list3(ATTRIBUTE,type,attr); use type_value to remove this */ extern int set_type_attr(int type,int attr) { if (type>0 && car(type)==ATTRIBUTE) { caddr(type) = attr; } else { type = list3(ATTRIBUTE,type,attr); } return type; } extern int gset_type_attr(int type,int attr) { if (type>0 && car(type)==ATTRIBUTE) { caddr(type) = attr; } else { type = glist3(ATTRIBUTE,type,attr); } return type; } extern int get_type_attr(int type) { if (type>0 && car(type)==ATTRIBUTE) { return caddr(type); } else { return 0; } } extern int type_value(int type) { if (type>0 && car(type)==ATTRIBUTE) { return cadr(type); } else { return type; } } extern int set_type_with_attr(int type,int type_with_attr) { if (type_with_attr>0 && car(type_with_attr)==ATTRIBUTE) { return list3(ATTRIBUTE,type_value(type),caddr(type_with_attr)); } else { return type; } } extern int gset_type_with_attr(int type,int type_with_attr) { if (type_with_attr>0 && car(type_with_attr)==ATTRIBUTE) { return glist3(ATTRIBUTE,type_value(type),caddr(type_with_attr)); } else { return type; } } /* for gdb... */ extern int c0(int d) { fprintf(stderr,"heap[%d]=",d);return car(d); } extern int c1(int d) { fprintf(stderr,"heap[%d]=",d);return cadr(d); } extern int c2(int d) { fprintf(stderr,"heap[%d]=",d);return caddr(d); } extern int c3(int d) { fprintf(stderr,"heap[%d]=",d);return cadddr(d); } extern int c4(int d) { fprintf(stderr,"heap[%d]=",d);return caddddr(d); } extern char *cc2(int d) { fprintf(stderr,"heap[%d]=",d);return scaddr(d); } extern NMTBL *nc2(int d) { fprintf(stderr,"heap[%d]=",d);return ncaddr(d); } /* end */