/* this one should make sure that this token has the first number */ %token F_ADD_256 /* This comment inserts extra tokens from make_func after next line * the empty lines below will be filled with %token statements, * they are left empty so that line numbering will be correct * (even if the file will be wrong) */ /* MAGIC MARKER */ /* * These are token values that needn't have an associated code for the * compiled file */ %token F_MAX_OPCODE %token F_ADD_EQ %token F_AND_EQ %token F_ARG_LIST %token F_ARROW %token F_BREAK %token F_CALL_OTHER %token F_CASE %token F_CAST %token F_COLON_COLON %token F_COMMA %token F_CONTINUE %token F_DEFAULT %token F_DIV_EQ %token F_DO %token F_DOT_DOT %token F_DOT_DOT_DOT %token F_EFUN %token F_EFUN_CALL %token F_EFUN_NAME %token F_ELSE %token F_FLOAT_TOKEN %token F_FOR %token F_FUNCTION %token F_FUNCTION_NAME %token F_GAUGE %token F_IDENTIFIER %token F_IF %token F_INHERIT %token F_INLINE %token F_INT %token F_LAMBDA %token F_LIST %token F_LIST_END %token F_LOCAL %token F_LSH_EQ %token F_LVALUE_LIST %token F_MAPPING %token F_MIXED %token F_MOD_EQ %token F_MULT_EQ %token F_NO_MASK %token F_OBJECT %token F_OR_EQ %token F_PRIVATE %token F_PROTECTED %token F_PUBLIC %token F_REGULAR_EXPRESSION %token F_RSH_EQ %token F_STATIC %token F_STATUS %token F_STRING_DECL %token F_SUBSCRIPT %token F_SUB_EQ %token F_VARARGS %token F_VOID %token F_WHILE %token F_XOR_EQ %token F_MAX_INSTR %right '=' %right '?' %left F_LOR %left F_LAND %left '|' %left '^' %left '&' %left F_EQ F_NE %left '>' F_GE '<' F_LE /* nonassoc? */ %left F_LSH F_RSH %left '+' '-' %left '*' '%' '/' %right F_NOT '~' %nonassoc F_INC F_DEC %{ /* * This is the grammar definition of LPC. The token table is built * automatically by make_func. The lang.y is constructed from this file, * the generated token list and post_lang.y. The reason of this is that there * is no #include-statment that yacc recognizes. */ #include "global.h" #ifdef HAVE_MEMORY_H #include <memory.h> #endif #if defined(sun) #include <alloca.h> #endif #include <setjmp.h> #include "simul_efun.h" #include "interpret.h" #include "array.h" #include "object.h" #include "exec.h" #include "instrs.h" #include "incralloc.h" #include "operators.h" #include "stralloc.h" #include "main.h" #include "las.h" #include "simulate.h" #include "interpret.h" #include "lex.h" extern struct program fake_prog; #define YYMAXDEPTH 600 int islocal PROT((char *)); extern struct mem_block mem_block[NUMAREAS]; #define align(x) (((x) + 3) & ~3) #define FUN_IS_VARARGS 0x40000000 /* * If the type of the function is given, then strict types are * checked and required. */ int exact_types; extern int pragma_strict_types; /* Maintained by lex.c */ extern int pragma_save_types; /* Also maintained by lex.c */ int approved_object; /* How I hate all these global variables */ int total_num_prog_blocks, total_prog_block_size; extern int lasdebug; extern struct vector *current_switch_mapping; extern int *break_stack; extern int current_break,break_stack_size; extern int *continue_stack; extern int current_continue,continue_stack_size; extern int comp_stackp; extern int num_parse_error; extern int d_flag; static int current_type; node *init_node=0; static struct program NULL_program; /* marion - clean neat empty struct */ void push_locals(); void pop_locals(); void push_break_stack(); void pop_break_stack(int); void push_continue_stack(); void pop_continue_stack(int); void epilog(); int check_declared PROT((char *str)); static void prolog(); void free_all_local_names(), add_local_name PROT((char *, int)), smart_log PROT((char *, int, char *)); extern int yylex(); int verify_declared PROT((char *)); static void copy_variables(); static void copy_functions PROT((struct program *, int type,int offset)); void type_error PROT((char *, int)); int insert_efun_call(int f,int args); void insert_pop_stack(); void pop_local_names(); char *get_type_name(int); extern int current_line; /* * 'inherit_file' is used as a flag. If it is set to a string * after yyparse(), this string should be loaded as an object, * and the original object must be loaded again. */ extern char *current_file, *inherit_file; /* * The names and types of arguments and auto variables. */ char **local_names; unsigned short *type_of_locals; int current_number_of_locals = 0; struct program *prog; /* Is returned to the caller of yyparse */ /* * Return the index of the function found, otherwise -1. */ int defined_function(char *s) { int e; struct function_p *funp; struct function *fun; #ifdef DEBUG if(s!=debug_findstring(s)) fatal("defined_function on nonshared string.\n"); #endif for (e=mem_block[A_FUNCTION_PTRS].current_size/sizeof(struct function_p)-1 ;e>=0;e--) { funp=FUNCTIONP(e); if (funp->flags & NAME_HIDDEN) continue; fun=INHERIT(funp->prog)->prog->functions+funp->fun; /* Pointer comparison is possible since we use unique strings */ if (fun->name == s) return e; } return -1; } int low_reference_inherited_function(int e,char *function_name) { struct function_p funp; struct program *p; int i,d; p=fake_prog.inherit[e].prog; i=find_shared_string_function(function_name,p); if(i==-1) return i; if(p->function_ptrs[i].flags & (NAME_UNDEFINED|NAME_HIDDEN)) return -1; funp=p->function_ptrs[i]; funp.prog=e; funp.flags|=NAME_HIDDEN; for(d=0;d<fake_prog.num_function_ptrs;d++) { struct function_p *fp; fp=fake_prog.function_ptrs+d; if(!MEMCMP((char *)fp,(char *)&funp,sizeof funp)) return d; } add_to_mem_block(A_FUNCTION_PTRS,(char *)&funp,sizeof funp); return fake_prog.num_function_ptrs; } int reference_inherited_function(char *super_name,char *function_name) { struct program *p; int e,i; #ifdef DEBUG if(function_name!=debug_findstring(function_name)) fatal("defined_function on nonshared string.\n"); #endif setup_fake_program(); for(e=fake_prog.num_inherited-1;e>0;e--) { if(fake_prog.inherit[e].inherit_level!=1) continue; p=fake_prog.inherit[e].prog; if(super_name) { int l; l=strlen(p->name); if(l<strlen(super_name)) continue; if(strncmp(super_name,p->name+l-strlen(super_name),strlen(super_name))) continue; } i=low_reference_inherited_function(e,function_name); if(i==-1) continue; return i; } return -1; } /* * Define a new function. Note that this function is called at least twice * for alll function definitions. First as a prototype, then as the real * function. Thus, there are tests to avoid generating error messages more * than once by looking at (flags & NAME_PROTOTYPE). */ static int define_new_function(char *name, int num_arg, int num_local, int offset, int flags, int type) { int num; struct function fun,*func; struct function_p fun_p,*funp; unsigned short argument_start_index; extern int pragma_all_inline; #ifdef DEBUG if(name!=debug_findstring(name)) fatal("defined_new_function on nonshared string.\n"); #endif num = defined_function(name); if(pragma_all_inline) type|=TYPE_MOD_INLINE; if (num >= 0) { /* * The function was already defined. It may be one of several reasons: * * 1. There has been a prototype. * 2. There was the same function defined by inheritance. * 3. This function has been called, but not yet defined. * 4. The function is doubly defined. * 5. A "late" prototype has been encountered. */ funp = FUNCTIONP(num); if (!(funp->flags & NAME_UNDEFINED) && !(flags & NAME_PROTOTYPE) && !(funp->flags & NAME_INHERITED)) { char *p = (char *)alloca(80 + strlen(name)); sprintf(p, "Redeclaration of function %s.", name); yyerror(p); return num; } /* * It was either an undefined but used funtion, or an inherited * function. In both cases, we now consider this to be THE new * definition. It might also have been a prototype to an already * defined function. * * Check arguments only when types are supposed to be tested, * and if this function really has been defined already. * * 'nomask' functions may not be redefined. */ if ((funp->type & TYPE_MOD_NO_MASK) && !(funp->flags & NAME_PROTOTYPE) && !(flags & NAME_PROTOTYPE)) { char *p = (char *)alloca(80 + strlen(name)); sprintf(p, "Illegal to redefine 'nomask' function \"%s\"",name); yyerror(p); } func=INHERIT(funp->prog)->prog->functions+funp->fun; if (exact_types && funp->type != TYPE_UNKNOWN) { int i; if (func->num_arg != num_arg && !(funp->type & TYPE_MOD_VARARGS)) { yyerror("Incorrect number of arguments."); }else if (!(funp->flags & NAME_STRICT_TYPES)){ yyerror("Called function not compiled with type testing."); }else{ /* Now check that argument types wasn't changed. */ for (i=0; i < num_arg; i++) { /* oops, gotta do something here */ } } } /* If it was yet another prototype, then simply return. */ if (flags & NAME_PROTOTYPE) return num; #ifdef DEBUG if(lasdebug) { fprintf(stderr,"Defining function '%s'\n",name); } #endif if(funp->prog!=0) { fun.name=copy_shared_string(name); funp->fun=mem_block[A_FUNCTIONS].current_size/sizeof(struct function); funp->prog=0; add_to_mem_block(A_FUNCTIONS,(char *)&fun,sizeof fun); func=INHERIT(funp->prog)->prog->functions+funp->fun; } func->num_arg=num_arg; func->num_local=num_local; func->offset=offset; funp->flags = flags; funp->type = type; funp->prog=0; if (exact_types) funp->flags |= NAME_STRICT_TYPES; return num; } fun.name = copy_shared_string(name); fun.offset = offset; fun.num_arg = num_arg; fun.num_local = num_local; num = mem_block[A_FUNCTIONS].current_size / sizeof fun; /* Number of local variables will be updated later */ add_to_mem_block(A_FUNCTIONS, (char *)&fun, sizeof fun); fun_p.flags = flags; fun_p.type = type; fun_p.fun=num; fun_p.prog=0; if (exact_types) fun_p.flags |= NAME_STRICT_TYPES; num = mem_block[A_FUNCTION_PTRS].current_size / sizeof fun_p; /* Number of local variables will be updated later */ add_to_mem_block(A_FUNCTION_PTRS, (char *)&fun_p, sizeof fun_p); if (exact_types == 0 || num_arg == 0) { argument_start_index = INDEX_START_NONE; } else { int i; /* * Save the start of argument types. */ argument_start_index = mem_block[A_ARGUMENT_TYPES].current_size / sizeof (unsigned short); for (i=0; i < num_arg; i++) { add_to_mem_block(A_ARGUMENT_TYPES, (char *)&type_of_locals[i], sizeof type_of_locals[i]); } } add_to_mem_block(A_ARGUMENT_INDEX, (char *)&argument_start_index, sizeof argument_start_index); return num; } unsigned short compile_type_to_runtime_type(unsigned short type) { if(type & TYPE_MOD_POINTER) return T_POINTER; switch(type & TYPE_MOD_MASK) { case TYPE_NUMBER: return T_NUMBER; case TYPE_STRING: return T_STRING; case TYPE_OBJECT: return T_OBJECT; case TYPE_MAPPING: return T_MAPPING; case TYPE_LIST: return T_LIST; case TYPE_FUNCTION: return T_FUNCTION; case TYPE_FLOAT: return T_FLOAT; case TYPE_REGULAR_EXPRESSION: return T_REGEXP; default: return T_ANY; } } /* argument must be a shared string */ static void define_variable(char *name,int type,int flags) { struct variable dummy; int n; #ifdef DEBUG if(name!=debug_findstring(name)) fatal("define_variable on nonshared string.\n"); #endif if(type==TYPE_VOID) return; n = check_declared(name); if (n != -1 && (VARIABLE(n)->type & TYPE_MOD_NO_MASK)) { char *p = (char *)alloca(80 + strlen(name)); sprintf(p, "Illegal to redefine 'nomask' variable \"%s\"", name); yyerror(p); } dummy.name = copy_shared_string(name); dummy.type = type; dummy.flags = flags; dummy.rttype=compile_type_to_runtime_type(type); switch(dummy.rttype) { case T_FUNCTION: dummy.rttype=T_ANY; case T_ANY: add_to_mem_block(A_VARIABLES, (char *)&dummy, sizeof dummy); /* add a dummy variable to allocate some extra space */ dummy.name=make_shared_string("dummy"); dummy.type=TYPE_VOID; dummy.flags=NAME_HIDDEN; dummy.rttype=T_NOTHING; add_to_mem_block(A_VARIABLES, (char *)&dummy, sizeof dummy); break; default: add_to_mem_block(A_VARIABLES, (char *)&dummy, sizeof dummy); } } void fix_comp_stack(int sp) { if(comp_stackp>sp) { yyerror("Compiler stack fixed."); comp_stackp=sp; }else if(comp_stackp<sp){ fatal("Compiler stack frame underflow."); } } %} %union { int number; float fnum; unsigned int address; /* Address of an instruction */ char *string; unsigned short type; struct node_s *n; } %type <fnum> F_FLOAT %type <number> F_FUNCTION_NAME F_EFUN_NAME argument_list %type <number> assign F_NUMBER F_LOCAL %type <number> optional_varargs optional_varargs2 %type <number> argument type basic_type optional_star cast %type <number> type_modifier type_modifier_list opt_basic_type %type <string> F_IDENTIFIER F_STRING string_constant %type <string> any_identifier ident_or_function_name /* The following symbos return type information */ %type <n> function_call string expr01 expr00 comma_expr fnumber %type <n> expr2 expr1 expr3 number expr0 expr4 catch lvalue_list %type <n> lambda for_expr block assoc_pair new_local_name %type <n> expr_list2 m_expr_list m_expr_list2 statement gauge sscanf %type <n> for do cond optional_else_part while statements %type <n> local_name_list call_other expr_list3 swap %type <n> unused2 foreach unused switch case return expr_list default %type <n> continue break block_or_semi %% all: program; program: program def possible_semi_colon | /* empty */ ; possible_semi_colon: /* empty */ | ';' { yyerror("Extra ';'. Ignored."); }; string_constant: F_STRING { $$=string_copy($1); free_string($1); } | string_constant '+' F_STRING { $$ = xalloc( strlen($1) + strlen($3) + 1 ); strcpy($$, $1); strcat($$, $3); free($1); free_string($3); }; inheritance: type_modifier_list F_INHERIT string_constant ';' { struct program *p; struct inherit inherit; int variable_index_offset; int function_index_offset; int inherit_offset,e; char *s; p = find_program2($3); if (p == 0) { inherit_file = $3; /* Return back to load_object() */ YYACCEPT; } free($3); if (p->flags & O_APPROVES) approved_object = 1; inherit_offset = mem_block[A_INHERITS].current_size / sizeof (struct inherit); function_index_offset = mem_block[A_FUNCTION_PTRS].current_size / sizeof (struct function_p); variable_index_offset = mem_block[A_VARIABLES].current_size / sizeof (struct variable); for(e=0;e<p->num_inherited;e++) { inherit=p->inherit[e]; inherit.inherit_level++; inherit.function_index_offset+=function_index_offset; inherit.variable_index_offset+=variable_index_offset; add_to_mem_block(A_INHERITS,(char *) &inherit, sizeof inherit); } copy_variables(p, $1); copy_functions(p, $1, inherit_offset); if((s=findstring("__INIT"))) { if(-1!=find_shared_string_function(s,p)) { e=reference_inherited_function(NULL,s); init_node=mknode('{',init_node,mkcastnode(TYPE_VOID, mkefunnode(F_CALL_FUNCTION,mkconstfunnode(e)))); } } }; fnumber: F_FLOAT { $$=mkfloatnode($1); } number: F_NUMBER { $$=mkintnode($1); } ; optional_star: /* empty */ { $$ = 0; } | '*' { $$ = TYPE_MOD_POINTER; } ; block_or_semi: block { $$ = mknode('{',$1,mknode(F_RETURN,mkintnode(0),0)); } | ';' { $$ = NULL;} ; def: type optional_star any_identifier { if ($1 & TYPE_MOD_MASK) { exact_types = $1 | $2; }else{ if (pragma_strict_types) yyerror("No return type given for function."); exact_types = 0; } } '(' argument ')' { /* * Define a prototype. If it is a real function, then the * prototype will be replaced below. */ define_new_function($3, $6 & ~FUN_IS_VARARGS , 0, 0, NAME_UNDEFINED|NAME_PROTOTYPE, $1 | $2 ); } block_or_semi { int tmp,args; tmp=mem_block[A_PROGRAM].current_size; args=$6 & ~FUN_IS_VARARGS; /* Either a prototype or a block */ if ($9!=NULL) { dooptcode($9,args); define_new_function($3,args, current_number_of_locals-args, tmp, 0, $1 | $2 | get_opt_info() | (($6 & FUN_IS_VARARGS)?TYPE_MOD_VA_ARGS:0) ); } free_all_local_names(); free_string($3); /* Value was copied above */ } | type name_list ';' { if ($1 == 0) yyerror("Missing type"); } | inheritance | error { if(num_parse_error>5) YYACCEPT; } ; new_arg_name: type optional_star any_identifier { #if 0 if(islocal($3)) { yyerror("Illigal to redefine local name.\n"); } #endif if (exact_types && $1 == 0) { yyerror("Missing type for argument"); add_local_name($3, TYPE_ANY); /* Supress more errors */ } else { add_local_name($3, $1 | $2); } }; optional_varargs: ',' F_DOT_DOT_DOT { $$=FUN_IS_VARARGS; } | /* empty */ { $$=0; } ; optional_varargs2: F_DOT_DOT_DOT { $$=FUN_IS_VARARGS; } | /* empty */ { $$=0; } ; argument: optional_varargs2 | argument_list optional_varargs { $$= $1 | $2; } ; argument_list: new_arg_name { $$ = 1; } | argument_list ',' new_arg_name { $$ = $1 + 1; } ; type_modifier: F_NO_MASK { $$ = TYPE_MOD_NO_MASK; } | F_STATIC { $$ = TYPE_MOD_STATIC; } | F_PRIVATE { $$ = TYPE_MOD_PRIVATE; } | F_PUBLIC { $$ = TYPE_MOD_PUBLIC; } | F_VARARGS { $$ = TYPE_MOD_VARARGS; } | F_PROTECTED { $$ = TYPE_MOD_PROTECTED; } | F_INLINE { $$ = TYPE_MOD_INLINE; } ; type_modifier_list: /* empty */ { $$ = 0; } | type_modifier type_modifier_list { $$ = $1 | $2; } ; type: type_modifier_list opt_basic_type { $$ = $1 | $2; current_type = $$; } ; cast: '(' basic_type optional_star ')' { $$ = $2 | $3; } ; opt_basic_type: basic_type | /* empty */ { $$ = TYPE_UNKNOWN; } ; basic_type: F_STATUS { $$=current_type=TYPE_NUMBER; } | F_INT { $$=current_type=TYPE_NUMBER; } | F_STRING_DECL { $$=current_type=TYPE_STRING; } | F_OBJECT { $$=current_type=TYPE_OBJECT; } | F_VOID { $$=current_type=TYPE_VOID; } | F_MIXED { $$=current_type=TYPE_ANY; } | F_MAPPING { $$=current_type=TYPE_MAPPING; } | F_REGULAR_EXPRESSION { $$=current_type=TYPE_REGULAR_EXPRESSION; } | F_LIST { $$=current_type=TYPE_LIST; } | F_FUNCTION { $$=current_type=TYPE_FUNCTION; } | F_FLOAT_TOKEN { $$=current_type=TYPE_FLOAT; } ; name_list: new_name | name_list ',' new_name; new_name: optional_star F_IDENTIFIER { define_variable($2, current_type | $1, 0); free_string($2); } | optional_star F_IDENTIFIER '=' { define_variable($2, current_type | $1, 0); } expr0 { int var_num; var_num = verify_declared($2); init_node=mknode('{',init_node, mkcastnode(TYPE_VOID,mknode(F_ASSIGN,$5,mkglobalnode(var_num)))); free_string($2); } ; new_local_name: optional_star ident_or_function_name { add_local_name($2, current_type | $1); $$=0; } | optional_star ident_or_function_name '=' expr0 { add_local_name($2, current_type | $1); $$=mkcastnode(TYPE_VOID, mknode(F_ASSIGN,$4, mklocalnode(islocal($2)))); }; block:'{' { $<number>$=current_number_of_locals; } statements '}' { int e; for(e=($<number>2)+1;e<current_number_of_locals;e++) { if(local_names[e]) free_string(local_names[e]); local_names[e]=NULL; } $$=$3; } ; local_name_list: new_local_name | local_name_list ',' new_local_name { $$=mknode('{',$1,$3); } ; statements: { $$=0; } | statements statement { $$=mknode('{',$1,$2); } ; statement: unused2 ';' { $$=$1; } | basic_type local_name_list ';' { $$=$2; } | cond | while | do | for | switch | case | default | return ';' | block {} | foreach | break | continue | error ';' { $$=0; } | ';' { $$=0; } ; break: F_BREAK { $$=mknode(F_BREAK,0,0); } ; default: F_DEFAULT ':' { $$=mknode(F_DEFAULT,0,0); } ; continue: F_CONTINUE { $$=mknode(F_CONTINUE,0,0); } ; lambda: F_LAMBDA { push_locals(); exact_types=1; $<number>$=comp_stackp; } '(' argument ')' block { char buf[40],*name; int f,i,args; fix_comp_stack($<number>2); args=$4 & ~FUN_IS_VARARGS; i=mem_block[A_PROGRAM].current_size; dooptcode(mknode('{',$6,mknode(F_RETURN,mkintnode(0),0)),args); sprintf(buf,"__lambda_%d", (int)(mem_block[A_FUNCTION_PTRS].current_size/ sizeof(struct function_p))); name=make_shared_string(buf); f=define_new_function(name,args, current_number_of_locals - args, i, 0, TYPE_ANY | get_opt_info() | (($4 & FUN_IS_VARARGS)?TYPE_MOD_VA_ARGS:0) ); free_string(name); pop_locals(); $$=mkconstfunnode(f); } ; cond: F_IF '(' comma_expr ')' statement optional_else_part { $$=mkcastnode(TYPE_VOID,mknode('?',$3,mknode(':',$5,$6))); } ; optional_else_part: { $$=0; } | F_ELSE statement { $$=$2; } ; foreach: F_FOREACH '(' expr0 ',' expr4 ')' statement { $$=mknode(F_FOREACH,mknode(' ',$3,$5),$7); } ; do: F_DO statement F_WHILE '(' comma_expr ')' ';' { $$=mknode(F_DO,$2,$5); } ; for: F_FOR '(' unused ';' for_expr ';' unused ')' statement { $$=mknode('{',$3,mknode(F_FOR,$5,mknode(':',$9,$7))); } ; while: F_WHILE '(' comma_expr ')' statement { $$=mknode(F_FOR,$3,mknode(':',$5,NULL)); } ; for_expr: /* EMPTY */ { $$=mkintnode(1); } | comma_expr; switch: F_SWITCH '(' comma_expr ')' statement { $$=mknode(F_SWITCH,$3,$5); } ; case: F_CASE comma_expr ':' { $$=mknode(F_CASE,$2,0); } | F_CASE comma_expr F_DOT_DOT comma_expr ':' { $$=mknode(F_CASE,$2,$4); } ; return: F_RETURN { $$=mknode(F_RETURN,mkintnode(0),0); } | F_RETURN comma_expr { $$=mknode(F_RETURN,$2,0); }; unused: { $$=0; } | unused2 ; unused2: comma_expr { $$=mkcastnode(TYPE_VOID,$1); } ; comma_expr: expr0 | unused2 ',' expr0 { $$ = mknode(F_ARG_LIST,mkcastnode(TYPE_VOID,$1),$3); } ; expr00: expr0 | '@' expr0 { $$=mknode(F_PUSH_ARRAY,$2,0); }; expr0: expr01 | expr4 '=' expr0 { $$=mknode(F_ASSIGN,$3,$1); } | expr4 assign expr0 { $$=mknode(F_ASSIGN,mknode($2,copy_node($1),$3),$1); } | error assign expr01 { $$=0; }; expr01: expr1 { $$ = $1; } | expr1 '?' expr01 ':' expr01 { $$=mknode('?',$1,mknode(':',$3,$5)); }; assign: F_AND_EQ { $$=F_AND; } | F_OR_EQ { $$=F_OR ; } | F_XOR_EQ { $$=F_XOR; } | F_LSH_EQ { $$=F_LSH; } | F_RSH_EQ { $$=F_RSH; } | F_ADD_EQ { $$=F_ADD; } | F_SUB_EQ { $$=F_SUBTRACT; } | F_MULT_EQ { $$=F_MULTIPLY; } | F_MOD_EQ { $$=F_MOD; } | F_DIV_EQ { $$=F_DIVIDE; } ; optional_comma: | ',' ; expr_list: { $$=0; } | expr_list2 optional_comma { $$=$1; } ; expr_list2: expr00 | expr_list2 ',' expr00 { $$=mknode(F_ARG_LIST,$1,$3); } ; m_expr_list: { $$=0; } | m_expr_list2 optional_comma { $$=$1; } ; m_expr_list2: assoc_pair | m_expr_list2 ',' assoc_pair { $$=mknode(F_ARG_LIST,$1,$3); } ; assoc_pair: expr0 ':' expr1 { $$=mknode(F_ARG_LIST,$1,$3); } ; expr1: expr2 | expr1 F_LOR expr1 { $$=mknode(F_LOR,$1,$3); } | expr1 F_LAND expr1 { $$=mknode(F_LAND,$1,$3); } | expr1 '|' expr1 { $$=mknode(F_OR,$1,$3); } | expr1 '^' expr1 { $$=mknode(F_XOR,$1,$3); } | expr1 '&' expr1 { $$=mknode(F_AND,$1,$3); } | expr1 F_EQ expr1 { $$=mknode(F_EQ,$1,$3); } | expr1 F_NE expr1 { $$=mknode(F_NE,$1,$3); } | expr1 '>' expr1 { $$=mknode(F_GT,$1,$3); } | expr1 F_GE expr1 { $$=mknode(F_GE,$1,$3); } | expr1 '<' expr1 { $$=mknode(F_LT,$1,$3); } | expr1 F_LE expr1 { $$=mknode(F_LE,$1,$3); } | expr1 F_LSH expr1 { $$=mknode(F_LSH,$1,$3); } | expr1 F_RSH expr1 { $$=mknode(F_RSH,$1,$3); } | expr1 '+' expr1 { $$=mknode(F_ADD,$1,$3); } | expr1 '-' expr1 { $$=mknode(F_SUBTRACT,$1,$3); } | expr1 '*' expr1 { $$=mknode(F_MULTIPLY,$1,$3); } | expr1 '%' expr1 { $$=mknode(F_MOD,$1,$3); } | expr1 '/' expr1 { $$=mknode(F_DIVIDE,$1,$3); } ; expr2: expr3 | cast expr2 { $$=mkcastnode($1,$2); } | F_INC expr4 { $$=mknode(F_INC,$2,0); } | F_DEC expr4 { $$=mknode(F_DEC,$2,0); } | F_NOT expr2 { $$=mknode(F_NOT,$2,0); } | '~' expr2 { $$=mknode(F_COMPL,$2,0); } | '-' expr2 { $$=mknode(F_NEGATE,$2,0); } ; expr3: expr4 | expr4 F_INC { $$=mknode(F_POST_INC,$1,0); } | expr4 F_DEC { $$=mknode(F_POST_DEC,$1,0); } ; expr4: function_call | string | number | fnumber | catch | gauge | sscanf | swap | call_other | lambda | F_IDENTIFIER { int i; if((i=islocal($1))>=0) { $$=mklocalnode(i); }else if((i=check_declared($1))>=0){ $$=mkglobalnode(i); }else if((i=find_simul_efun($1))>=0){ $$=mksimulefunnode(i); }else{ char *e=(char *)alloca(strlen($1)+20); sprintf(e,"'%s' undefined.",$1); yyerror(e); $$=0; } free_string($1); } | expr4 '[' expr0 ']' { $$=mknode(F_INDEX,$1,$3); } | expr4 '[' comma_expr F_DOT_DOT comma_expr ']' { $$=mkefunnode(F_RANGE,mknode(F_ARG_LIST,$1,mknode(F_ARG_LIST,$3,$5))); } | '(' comma_expr ')' { $$=$2; } | '(' '{' expr_list '}' ')' { $$=mkefunnode(F_AGGREGATE,$3); } | '(' '[' m_expr_list ']' ')' { $$=mkefunnode(F_M_AGGREGATE,$3); }; | '(' '<' expr_list F_LIST_END { $$=mkefunnode(F_L_AGGREGATE,$3); } | F_FUNCTION_NAME { struct function_p *fun; fun=FUNCTIONP($1); if((fun->flags & NAME_UNDEFINED) && !(fun->flags & NAME_PROTOTYPE)) { char *p,*name; name=INHERIT(fun->prog)->prog->functions[fun->fun].name; p=(char *)alloca(80+strlen(name)); sprintf(p,"Undefined function '%s'",name); yyerror(p); } $$=mkconstfunnode($1); } | expr4 F_ARROW any_identifier { $$=mkefunnode(F_GET_FUNCTION,mknode(F_ARG_LIST,$1,mkstrnode($3))); } | any_identifier F_COLON_COLON any_identifier { int f; struct function_p *funp; f=reference_inherited_function($1,$3); if (f<0 || (funp=FUNCTIONP(f))->flags & NAME_UNDEFINED) { char *buff; buff=(char *)alloca(80+strlen($1)+strlen($3)); sprintf(buff, "Undefined function %s::%s", $1,$3); yyerror(buff); } free_string($1); free_string($3); $$=mkconstfunnode(f); } | F_COLON_COLON any_identifier { int e,i; $$=0; setup_fake_program(); for(e=1;e<fake_prog.num_inherited;e++) { if(fake_prog.inherit[e].inherit_level!=1) continue; i=low_reference_inherited_function(e,$2); if(i==-1) continue; if($$) { $$=mknode(F_ARG_LIST,$$,mkconstfunnode(i)); }else{ $$=mkconstfunnode(i); } } if(!$$) { $$=mkintnode(0); }else{ if($$->token==F_ARG_LIST) $$=mkefunnode(F_AGGREGATE,$$); } free_string($2); } ; expr_list3: { $$=0; } | ',' expr_list { $$=$2; } ; call_other: F_CALL_OTHER '(' expr0 ',' expr0 expr_list3 ')' { $$=mkefunnode(F_CALL_FUNCTION,mknode(F_ARG_LIST, mkefunnode(F_GET_FUNCTION, mknode(F_ARG_LIST, mkcastnode(TYPE_OBJECT,$3), $5)),$6)); } gauge: F_GAUGE '(' unused ')' { $$=mknode(F_GAUGE,$3,0); } ; catch: F_CATCH '(' unused ')' { $$=mknode(F_CATCH,$3,NULL); } ; sscanf: F_SSCANF '(' expr0 ',' expr0 lvalue_list ')' { $$=mknode(F_SSCANF,mknode(F_ARG_LIST,$3,$5),$6); } swap: F_SWAP_VARIABLES '(' expr4 ',' expr4 ')' { $$=mknode(F_SWAP_VARIABLES,mknode(F_LVALUE_LIST,$3,$5),0); } lvalue_list: /* empty */ { $$ = 0; } | ',' expr4 lvalue_list { $$ = mknode(F_LVALUE_LIST,$2,$3); } ; string: F_STRING { $$=mkstrnode($1); } ; function_call: expr4 '(' expr_list ')' { $$=mkefunnode(F_CALL_FUNCTION,mknode(F_ARG_LIST,$1,$3)); } | F_EFUN F_COLON_COLON any_identifier '(' expr_list ')' { int i; i=lookup_predef($3); if(i<=0) { char *p=(char *)alloca(strlen($3)+20); sprintf(p,"Unknown efun: %s.",$3); yyerror(p); i=0; } free_string($3); $$=mkefunnode(i,$5); } | F_EFUN_NAME '(' expr_list ')' { $$=mkefunnode($1,$3); } ; ident_or_function_name: F_IDENTIFIER | F_FUNCTION_NAME { struct function_p *funp; struct function *fun; funp=FUNCTIONP($1); fun=INHERIT(funp->prog)->prog->functions+funp->fun; $$=copy_shared_string(fun->name); } any_identifier: ident_or_function_name | F_EFUN_NAME { $$=copy_shared_string(instrs[$1-F_OFFSET].name); } ; %% void yyerror(char *str) { extern int num_parse_error; if (num_parse_error > 5) return; (void)fprintf(stderr, "%s:%d: %s\n", current_file,current_line,str); fflush(stderr); smart_log(current_file, current_line, str); /* This should be done in some other way in the future /Profezzorn if (num_parse_error == 0) save_error(str, current_file, current_line); */ num_parse_error++; } /* argument must be a shared string */ int check_declared(char *str) { struct variable *vp; int offset; #ifdef DEBUG if(str!=debug_findstring(str)) fatal("check_declared on nonshared string.\n"); #endif for (offset=0; offset < mem_block[A_VARIABLES].current_size; offset += sizeof (struct variable)) { vp = (struct variable *)&mem_block[A_VARIABLES].block[offset]; if (vp->flags & NAME_HIDDEN) continue; /* Pointer comparison is possible since we use unique strings */ if (vp->name == str) return offset / sizeof (struct variable); } return -1; } int verify_declared(char *str) { int r; r = check_declared(str); if (r < 0) { char buff[100]; (void)sprintf(buff, "Variable %s not declared !", str); yyerror(buff); return -1; } return r; } /* argument must be a shared string (no need to free it) */ void add_local_name(char *str,int type) { if (current_number_of_locals == MAX_LOCAL) { yyerror("Too many local variables"); }else { type_of_locals[current_number_of_locals] = type; local_names[current_number_of_locals++] = str; } } /* argument must be a shared string */ int islocal(char *str) { int e; for(e=current_number_of_locals-1;e>=0;e--) if(local_names[e]==str) return e; return -1; } void free_all_local_names() { int i; for (i=0; i<current_number_of_locals; i++) { if(local_names[i]) free_string(local_names[i]); local_names[i] = 0; } current_number_of_locals = 0; } /* * Copy all function definitions from an inherited object. They are added * as undefined, so that they can be redefined by a local definition. * If they are not redefined, then they will be updated, so that they * point to the inherited definition. See epilog(). Types will be copied * at that moment (if available). * * A call to an inherited function will not be * done through this entry (because this entry can be replaced by a new * definition). If an function defined by inheritance is called, then one * special definition will be made at first call. */ static void copy_functions(struct program *from,int type,int offset) { int i; for (i=0; i < from->num_function_ptrs; i++) { /* Do not call define_new_function() from here, as duplicates would * be removed. */ struct function_p fun; int new_type; char *name; fun = from->function_ptrs[i]; /* Make a copy */ /* Prepare some data to be used if this function will not be * redefined. */ name=from->inherit[fun.prog].prog->functions[fun.fun].name; fun.prog+=offset; if (fun.type & TYPE_MOD_NO_MASK) { int n; n = defined_function(name); if (n != -1 && !(FUNCTIONP(n)->flags & NAME_UNDEFINED)) { char *p = (char *)alloca(80 + strlen(name)); sprintf(p, "Illegal to redefine 'nomask' function \"%s\"",name); yyerror(p); } } /* * public functions should not become private when inherited * 'private' */ new_type = type; if (fun.type & TYPE_MOD_PUBLIC) new_type &= ~TYPE_MOD_PRIVATE; fun.type |= new_type; if(fun.type & TYPE_MOD_PRIVATE) fun.flags|=NAME_HIDDEN; fun.flags |= NAME_INHERITED; add_to_mem_block(A_FUNCTION_PTRS, (char *)&fun, sizeof fun); } } /* * Copy all variabel names from the object that is inherited from. * It is very important that they are stored in the same order with the * same index. */ static void copy_variables(struct program *from,int type) { int i; for (i=0; i<from->num_variables; i++) { int new_type = type; int n = check_declared(from->variable_names[i].name); if (n != -1 && (VARIABLE(n)->type & TYPE_MOD_NO_MASK)) { char *p = (char *)alloca(80+strlen(from->variable_names[i].name)); sprintf(p, "Illegal to redefine 'nomask' variable \"%s\"", VARIABLE(n)->name); yyerror(p); } /* * 'public' variables should not become private when inherited * 'private'. */ if (from->variable_names[i].type & TYPE_MOD_PUBLIC) new_type &= ~TYPE_MOD_PRIVATE; define_variable(from->variable_names[i].name, from->variable_names[i].type | new_type, from->variable_names[i].type & TYPE_MOD_PRIVATE ? NAME_HIDDEN : 0); } } char *get_type_name(int type) { static char buff[100]; static char *type_name[] = { "unknown", "mixed", "void", "int", "string", "object", "mapping", "list", "function", "float", "regular_expression" }; int pointer = 0; buff[0] = 0; if (type & TYPE_MOD_STATIC) strcat(buff, "static "); if (type & TYPE_MOD_NO_MASK) strcat(buff, "nomask "); if (type & TYPE_MOD_PRIVATE) strcat(buff, "private "); if (type & TYPE_MOD_PROTECTED) strcat(buff, "protected "); if (type & TYPE_MOD_PUBLIC) strcat(buff, "public "); if (type & TYPE_MOD_VARARGS) strcat(buff, "varargs "); type &= TYPE_MOD_MASK; if (type & TYPE_MOD_POINTER) { pointer = 1; type &= ~TYPE_MOD_POINTER; } if (type >= sizeof type_name / sizeof type_name[0]) fatal("Bad type\n"); strcat(buff, type_name[type]); strcat(buff," "); if (pointer) strcat(buff, "* "); return buff; } void type_error(str, type) char *str; int type; { static char buff[100]; char *p; p = get_type_name(type); if (strlen(str) + strlen(p) + 5 >= sizeof buff) { yyerror(str); } else { strcpy(buff, str); strcat(buff, ": \""); strcat(buff, p); strcat(buff, "\""); yyerror(buff); } } #ifdef DEBUG void dump_program_desc(struct program *p) { int e,d,q; fprintf(stderr,"Program '%s':\n",p->name); fprintf(stderr,"All inherits:\n"); for(e=0;e<p->num_inherited;e++) { fprintf(stderr,"%3d:",e); for(d=0;d<p->inherit[e].inherit_level;d++) fprintf(stderr," "); fprintf(stderr,"%s\n",p->inherit[e].prog->name); } fprintf(stderr,"All functions:\n"); for(e=0;e<p->num_function_ptrs;e++) { fprintf(stderr,"%3d:",e); for(d=0;d<p->inherit[p->function_ptrs[e].prog].inherit_level;d++) fprintf(stderr," "); fprintf(stderr,"%s::%s();\n", p->inherit[p->function_ptrs[e].prog].prog->name, FUNC(p,e)->name); } fprintf(stderr,"All sorted functions:\n"); for(q=0;q<p->num_funindex;q++) { e=p->funindex[q]; fprintf(stderr,"%3d (%3d):",e,q); for(d=0;d<p->inherit[p->function_ptrs[e].prog].inherit_level;d++) fprintf(stderr," "); fprintf(stderr,"%s::%s();\n", p->inherit[p->function_ptrs[e].prog].prog->name, FUNC(p,e)->name); } } #endif /* * Compile an LPC file. */ void compile_file() { int yyparse(); prolog(); yyparse(); epilog(); } int funcmp(const void *a,const void *b) { struct function_p *fpa,*fpb; struct function *fa,*fb; fpa=prog->function_ptrs+*(unsigned short *)a; fpb=prog->function_ptrs+*(unsigned short *)b; fa=prog->inherit[fpa->prog].prog->functions+fpa->fun; fb=prog->inherit[fpb->prog].prog->functions+fpb->fun; return fa->name - fb->name; } /* * The program has been compiled. Prepare a 'struct program' to be returned. */ void epilog() { static int current_program_id=1; int size, i,e,t; char *p; #if 0 #ifdef DEBUG if (num_parse_error == 0 && type_of_argumentp != 0) fatal("Failed to deallocate argument type stack\n",0,0,0,0,0,0,0,0,0); #endif #endif /* * Define the __INIT function, but only if there was any code * to initialize. */ if (init_node) { char *s; int pc=mem_block[A_PROGRAM].current_size; s=make_shared_string("__INIT"); define_new_function(s,0,0,0,NAME_UNDEFINED | NAME_PROTOTYPE, TYPE_VOID|TYPE_MOD_STATIC); dooptcode(mknode('{',init_node,mknode(F_RETURN,mkintnode(0),0)),0); define_new_function(s, 0, 0,pc, 0, TYPE_VOID|TYPE_MOD_STATIC | get_opt_info()); free_string(s); } if (num_parse_error > 0) { char **grog; struct function *grfun; struct variable *grvar; int grogs; struct vector **foo; struct svalue *s; prog = 0; grog=(char **)(mem_block[A_STRINGS].block); grogs=mem_block[A_STRINGS].current_size/sizeof(char *); for(i=0;i<grogs;i++) free_string(grog[i]); foo=(struct vector **)(mem_block[A_SWITCH_MAPPINGS].block); grogs=mem_block[A_SWITCH_MAPPINGS].current_size/sizeof(struct vector *); for(i=0;i<grogs;i++) free_vector(foo[i]); grfun=(struct function *)(mem_block[A_FUNCTIONS].block); grogs=mem_block[A_FUNCTIONS].current_size/sizeof(struct function); for(i=0;i<grogs;i++) free_string(grfun[i].name); grvar=(struct variable *)(mem_block[A_VARIABLES].block); grogs=mem_block[A_VARIABLES].current_size/sizeof(struct variable); for(i=0;i<grogs;i++) free_string(grvar[i].name); s=(struct svalue *)(mem_block[A_CONSTANTS].block); grogs=mem_block[A_CONSTANTS].current_size/sizeof(struct svalue); for(i=0;i<grogs;i++) free_svalue(s+i); for (i=0; i<NUMAREAS; i++) { free(mem_block[i].block); mem_block[i].current_size=0; } return; } size = align(sizeof (struct program)); for (i=0; i<NUMAREAS; i++) size += align(mem_block[i].current_size); size+=align(sizeof(short)*num_lfuns); size+=align((mem_block[A_FUNCTION_PTRS].current_size/ sizeof (struct function_p))* sizeof(unsigned short)); p = (char *)xalloc(size); prog = (struct program *)p; *prog = NULL_program; prog->total_size = size; prog->ref = 0; prog->id=current_program_id++; prog->name = fake_prog.name; total_prog_block_size += prog->total_size; total_num_prog_blocks += 1; p += align(sizeof (struct program)); #define INS_BLOCK(PTR,PTRS,TYPE,AREA) \ if((prog->PTRS = mem_block[AREA].current_size/sizeof(TYPE))) \ { \ prog->PTR = (TYPE *)p; \ MEMCPY(p,mem_block[AREA].block,mem_block[AREA].current_size); \ p+=align(mem_block[AREA].current_size); \ }else{ \ prog->PTR = (TYPE *) NULL; \ } INS_BLOCK(program,program_size,char,A_PROGRAM); INS_BLOCK(line_numbers,num_line_numbers,unsigned char,A_LINENUMBERS); INS_BLOCK(functions,num_functions,struct function,A_FUNCTIONS); INS_BLOCK(function_ptrs,num_function_ptrs,struct function_p,A_FUNCTION_PTRS); INS_BLOCK(strings,num_strings,char *,A_STRINGS); INS_BLOCK(variable_names,num_variables,struct variable,A_VARIABLES); INS_BLOCK(switch_mappings,num_switch_mappings,struct vector *,A_SWITCH_MAPPINGS); INS_BLOCK(inherit,num_inherited,struct inherit,A_INHERITS); /* Ok, sort for binsearch */ prog->funindex=(unsigned short *)p; for(e=i=0;i<prog->num_function_ptrs;i++) { struct function_p *funp; struct function *fun; funp=prog->function_ptrs+i; if(funp->flags & (NAME_HIDDEN|NAME_UNDEFINED)) continue; if(funp->flags & NAME_INHERITED) { if(funp->type & TYPE_MOD_PRIVATE) continue; fun=prog->inherit[funp->prog].prog->functions+funp->fun; for(t=0;t>=0 && t<prog->num_function_ptrs;t++) { struct function_p *funpb; struct function *funb; if(t==i) continue; funpb=prog->function_ptrs+t; if(funpb->flags & (NAME_HIDDEN|NAME_UNDEFINED)) continue; if((funpb->flags & NAME_INHERITED) && t<i) continue; funb=prog->inherit[funpb->prog].prog->functions+funpb->fun; if(fun->name==funb->name) t=-10; } if(t<0) continue; } prog->funindex[e]=i; e++; } prog->num_funindex=e; fsort((void *)prog->funindex, e,sizeof(unsigned short),funcmp); p+=align(prog->num_funindex*sizeof(unsigned short)); prog->constants = (struct svalue *)p; prog->num_constants = mem_block[A_CONSTANTS].current_size / sizeof (struct svalue); if (mem_block[A_CONSTANTS].current_size) { int e; MEMCPY(p, mem_block[A_CONSTANTS].block, mem_block[A_CONSTANTS].current_size); /* see to it that all strings in constants are shared */ /* for speed and memory effinciency reasons /Hubbe */ /* hmm, I wonder why I copy the svalues.... /Hubbe */ for(e=0;e<prog->num_constants;e++) { struct svalue tmp; copy_svalue(&tmp,prog->constants+e); free_svalue(prog->constants+e); prog->constants[e]=tmp; } } p += align(mem_block[A_CONSTANTS].current_size); prog->lfuns=(short *)p; for(e=0;e<num_lfuns;e++) prog->lfuns[e]=find_function(lfuns[e],prog); prog->num_lfuns=num_lfuns; p += align(sizeof(short)*num_lfuns); prog->argument_types = 0; /* For now. Will be fixed someday */ prog->type_start = 0; for (i=0; i<NUMAREAS; i++) free((char *)mem_block[i].block); /* marion Do referencing here - avoid multiple referencing when an object inherits more than one object and one of the inherited is already loaded and not the last inherited */ reference_prog (prog, "epilog"); /* profezzorn The first item in the inherit_list should be ourselves, so don't reference that one */ prog->inherit[0].prog=prog; for (i = 1; i < prog->num_inherited; i++) reference_prog (prog->inherit[i].prog, "inheritance"); #ifdef DEBUG if(d_flag>3 && !inherit_file) { fprintf(stderr,"Functions in program '%s':\n",prog->name); for(e=0;e<prog->num_function_ptrs;e++) { struct function_p *funp; struct function *fun; funp=prog->function_ptrs+e; fun=prog->inherit[funp->prog].prog->functions+funp->fun; fprintf(stderr,"Function [%c%c%c%c%c] %10s [%c%c%c%c%c%c%c%c] %s %d %d\n", funp->flags&NAME_INHERITED?'I':' ', funp->flags&NAME_HIDDEN?'H':' ', funp->flags&NAME_UNDEFINED?'U':' ', funp->flags&NAME_STRICT_TYPES?'S':' ', funp->flags&NAME_PROTOTYPE?'P':' ', get_type_name(funp->type&TYPE_MOD_MASK), funp->type&TYPE_MOD_STATIC?'S':' ', funp->type&TYPE_MOD_NO_MASK?'N':' ', funp->type&TYPE_MOD_POINTER?'*':' ', funp->type&TYPE_MOD_PRIVATE?'-':' ', funp->type&TYPE_MOD_PROTECTED?'p':' ', funp->type&TYPE_MOD_PUBLIC?'+':' ', funp->type&TYPE_MOD_VARARGS?'V':' ', funp->type&TYPE_MOD_CONSTANT?'C':' ', fun->name, fun->num_arg, fun->num_local ); } printf("SORTED Functions in program '%s':\n",prog->name); for(i=0;i<prog->num_funindex;i++) { struct function_p *funp; struct function *fun; e=prog->funindex[i]; funp=prog->function_ptrs+e; fun=prog->inherit[funp->prog].prog->functions+funp->fun; fprintf(stderr,"Function [%c%c%c%c%c] %10s [%c%c%c%c%c%c%c%c] %s %d %d\n", funp->flags&NAME_INHERITED?'I':' ', funp->flags&NAME_HIDDEN?'H':' ', funp->flags&NAME_UNDEFINED?'U':' ', funp->flags&NAME_STRICT_TYPES?'S':' ', funp->flags&NAME_PROTOTYPE?'P':' ', get_type_name(funp->type&TYPE_MOD_MASK), funp->type&TYPE_MOD_STATIC?'S':' ', funp->type&TYPE_MOD_NO_MASK?'N':' ', funp->type&TYPE_MOD_POINTER?'*':' ', funp->type&TYPE_MOD_PRIVATE?'-':' ', funp->type&TYPE_MOD_PROTECTED?'p':' ', funp->type&TYPE_MOD_PUBLIC?'+':' ', funp->type&TYPE_MOD_VARARGS?'V':' ', funp->type&TYPE_MOD_CONSTANT?'C':' ', fun->name, fun->num_arg, fun->num_local ); } if(d_flag>4) dump_program_desc(prog); } #endif } /* * Initialize the environment that the compiler needs. */ static void prolog() { int i; struct inherit inherit; extern struct program fake_prog; start_line_numbering(); approved_object = 0; prog = 0; /* 0 means fail to load. */ comp_stackp = 0; /* Local temp stack used by compiler */ num_parse_error = 0; free_all_local_names(); /* In case of earlier error */ /* Initialize memory blocks where the result of the compilation * will be stored. */ for (i=0; i < NUMAREAS; i++) { mem_block[i].block = xalloc(START_BLOCK_SIZE); mem_block[i].current_size = 0; mem_block[i].max_size = START_BLOCK_SIZE; } inherit.prog=&fake_prog; inherit.inherit_level=0; inherit.function_index_offset=0; inherit.variable_index_offset=0; add_to_mem_block(A_INHERITS,(char *)&inherit,sizeof inherit); fake_prog.name=make_shared_string(current_file); setup_fake_program(); init_node=0; } void push_locals() { push_explicit(current_type); push_explicit(exact_types); push_explicit((int)local_names); push_explicit((int)type_of_locals); push_explicit(current_number_of_locals); local_names=(char **)malloc(sizeof(char *)*MAX_LOCAL); type_of_locals=(unsigned short *)malloc(sizeof(unsigned short)*MAX_LOCAL); current_number_of_locals=0; exact_types=0; } void pop_locals() { int i; for (i=0; i<current_number_of_locals; i++) { if(local_names[i]) free_string(local_names[i]); local_names[i] = 0; } free((char *)type_of_locals); free((char *)local_names); current_number_of_locals=(int)pop_address(); type_of_locals=(unsigned short *)pop_address(); local_names=(char **)pop_address(); exact_types=pop_address(); current_type=pop_address(); }