%{ #line 2 "postlang.y" /* * These are token values that needn't have an associated code for the * compiled file */ %} %token F_CASE F_DEFAULT %union { int number; float real; unsigned int address; /* Address of an instruction */ char *string; short type; struct { int key; char block; } case_label; struct function *funp; } %type <number> opt_int assign F_NUMBER constant F_LOCAL_NAME expr_list %type <number> const1 const2 const3 const4 const5 const6 const7 const8 const9 %type <number> lvalue_list argument type basic_type optional_star expr_list2 %type <number> type_modifier type_modifier_list opt_basic_type block_or_semi %type <number> argument_list m_expr_list m_expr_list2 %type <string> identifier fun_identifier opt_inherit_name %type <string> F_IDENTIFIER F_STRING string_con1 string_constant function_name %type <real> F_FLOATC %type <case_label> case_label /* The following symbols return type information */ %type <type> function_call lvalue string cast expr01 comma_expr %type <type> expr2 expr211 expr1 expr212 expr213 expr24 expr22 expr23 expr25 %type <type> expr27 expr28 expr3 expr31 expr4 number expr0 real /* %expect 1 */ /* You can uncomment previous statement if you use bison */ %{ /* has to be here so that F_EXT is defined */ static void store_reloc_data(char, unsigned short, char *name, int, char); static void ins_f_byte(unsigned int ); static int first_default_arg, current_arg; static int is_ctor, is_dtor; static int return_label; #define CTOR_FUNC ((char *)1) #define DTOR_FUNC ((char *)2) %} %% all: { invariant_last_address = 0; } program ; program: program def possible_semi_colon | /* empty */ ; possible_semi_colon: /* empty */ | ';' { yyerror("Extra ';'. Ignored."); }; inheritance: type_modifier_list F_INHERIT F_STRING opt_inherit_name ';' { char *initializer_name; struct object *ob; struct inherit inherit; int initializer; extern char *findstring (char *); if (mem_block[A_VARIABLES].current_size || mem_block[A_FUNCTIONS].current_size) yyerror("Inherit after other definitions\n"); ob = find_object2($3); if (ob == 0) { if (inherit_file) free(inherit_file); inherit_file = $3; free($4); /* Return back to load_object() */ YYACCEPT; } if (ob->prog->flags & PRAGMA_NO_INHERIT) { yyerror("Inheriting bad object.\n"); } if (!check_inherits(ob->prog)) { if (inherit_file) free(inherit_file); inherit_file = $3; free($4); /* Return back to load_object() */ YYACCEPT; } free($3); inherit.prog = ob->prog; inherit.type = $1; copy_inherits (ob->prog, inherit.type, $4); free($4); } opt_inherit_name: /* empty */ { char *n = strrchr($<string>0, '/'); if (n) { $$ = string_copy(n + 1); } else $$ = string_copy($<string>0); } | F_IDENTIFIER { $$ = $1; } ; invariant : '<' '>' ':' { if (invariant_last_address) { if (invariant_last_address + 2 == mem_block[A_PROGRAM].current_size) mem_block[A_PROGRAM].current_size -= 3; else upd_short(invariant_last_address, mem_block[A_PROGRAM].current_size); } else invariant_first_address = mem_block[A_PROGRAM].current_size; } expr0 { ins_f_byte(F_FAIL_INVARIANT); ins_f_byte(F_JUMP); invariant_last_address = mem_block[A_PROGRAM].current_size; ins_short(0); } ; pre_condition : F_LSH ':' { if (pre_cond_last_address) if (pre_cond_last_address + 2 == mem_block[A_PROGRAM].current_size) mem_block[A_PROGRAM].current_size -= 3; else upd_short(pre_cond_last_address, mem_block[A_PROGRAM].current_size); else pre_cond_first_address = mem_block[A_PROGRAM].current_size; if (is_ctor) { yyerror("Constructors may not have preconditions"); } } expr0 { ins_f_byte(F_FAIL_PRECOND); ins_f_byte(F_JUMP); pre_cond_last_address = mem_block[A_PROGRAM].current_size; ins_short(0); } ; post_condition : F_RSH ':' { if (post_cond_last_address) if (post_cond_last_address + 2 == mem_block[A_PROGRAM].current_size) mem_block[A_PROGRAM].current_size -= 3; else upd_short(post_cond_last_address, mem_block[A_PROGRAM].current_size); else post_cond_first_address = mem_block[A_PROGRAM].current_size; if (is_dtor) { yyerror("Destructors may not have postconditions"); } } expr0 { ins_f_byte(F_FAIL_POSTCOND); ins_f_byte(F_JUMP); post_cond_last_address = mem_block[A_PROGRAM].current_size; ins_short(0); } ; opt_int : /* empty */ { $$ = 1; } | constant assertion : '@' opt_int ':' { ins_f_byte(F_ASSERTION); ins_short($2); push_explicit(mem_block[A_PROGRAM].current_size); ins_short(0); } expr0 { ins_f_byte(F_FAIL_ASSERTION); upd_short(pop_address(), mem_block[A_PROGRAM].current_size); } number: F_NUMBER { if ( $1 == 0 ) { ins_f_byte(F_CONST0); $$ = TYPE_ANY; } else if ( $1 == 1 ) { ins_f_byte(F_CONST1); $$ = TYPE_NUMBER; } else { ins_f_byte(F_NUMBER); ins_long($1); $$ = TYPE_NUMBER; } } ; optional_star: /* empty */ { $$ = 0; } | '*' { $$ = TYPE_MOD_POINTER; } ; block_or_semi: block { $$ = 0; } | ';' { $$ = ';'; } | '=' string_con1 ';' { $<string>$ = $<string>2; }; | '=' F_NUMBER ';' { if ($2 != 0) { yyerror("Syntax error"); } $$ = 1; } opt_pre_post_cond : /* empty */ | pre_post_cond ; pre_post_cond : pre_condition ';' | post_condition ';' | pre_post_cond pre_condition ';' | pre_post_cond post_condition ';' ; def: type optional_star fun_identifier { /* Save start of function. */ clear_init_arg_stack(); push_explicit(mem_block[A_PROGRAM].current_size); true_varargs = 0; pre_cond_first_address = pre_cond_last_address = post_cond_first_address = post_cond_last_address = 0; first_default_arg = current_arg = 0; is_ctor = is_dtor = 0; return_label = make_label(); if ($3 == CTOR_FUNC) { $3 = string_copy(".CTOR"); is_ctor = 1; } else if ($3 == DTOR_FUNC) { $3 = string_copy(".DTOR"); is_dtor = 1; } if (is_ctor | is_dtor) { if ($1 | $2) { yyerror("Constructors and destructors doesn't have a type"); $1 = $2 = 0; } if (pragma_strict_types) { $1 = exact_types = TYPE_VOID; } else exact_types = 0; } else if ($1 & TYPE_MASK) { exact_types = $1 | $2; } else { if (pragma_strict_types) yyerror("\"#pragma strict_types\" requires type of function"); exact_types = 0; } } '(' argument ')' { /* * Define a prototype. If it is a real function, then the * prototype will be replaced below. */ if ($6 && is_ctor | is_dtor) { yyerror("Constructors and destructors don't take arguments"); } ins_f_byte(F_JUMP); push_explicit(mem_block[A_PROGRAM].current_size); ins_short(0); } opt_pre_post_cond { int i; unsigned short j; i = pop_address(); push_explicit(mem_block[A_PROGRAM].current_size); dump_init_arg_table($6); j = mem_block[A_PROGRAM].current_size; upd_short(i, mem_block[A_PROGRAM].current_size); ((char *)mem_block[A_PROGRAM].block)[i] = ((char *)&j)[0]; ((char *)mem_block[A_PROGRAM].block)[i + 1] = ((char *)&j)[1]; define_new_function($3, $6, 0, 0, NAME_PROTOTYPE | $1 | $2 | true_varargs, first_default_arg); if (pre_cond_last_address) { ins_f_byte(F_DO_PRECOND); ins_short(pre_cond_first_address); upd_short(pre_cond_last_address, mem_block[A_PROGRAM].current_size); } } block_or_semi { /* Either a prototype or a block */ if ($11 == ';') /* its only a prototype */ { pop_address(); /* Not used here */ mem_block[A_PROGRAM].current_size = pop_address(); } else if ($11 == 0) { define_new_function($3, $6, current_number_of_locals - $6, pop_address(), $1 | $2 | true_varargs, first_default_arg); ins_f_byte(F_CONST0); set_label(return_label, mem_block[A_PROGRAM].current_size); if (post_cond_last_address) { ins_f_byte(F_DO_POSTCOND); ins_short(post_cond_first_address); upd_short(post_cond_last_address, mem_block[A_PROGRAM].current_size); } /* Code for calling invariants */ if (!is_dtor) ins_f_byte(F_DO_INVARIANTS); /* End of invariants */ ins_f_byte(F_RETURN); pop_address(); /* Not used here */ } else if ($11 == 1) { if (is_ctor | is_dtor) yyerror("Constructors and destructors can't be abstract"); define_new_function($3, $6, 0, 0, NAME_ABSTRACT | $1 | $2 | true_varargs, first_default_arg); yyerror("Abstract functions isn't implemented yet"); } else { extern void (* get_C_fun_address(char *, char *))(); void (*func)(); define_new_function($3, $6, current_number_of_locals - $6, pop_address(), $1 | $2 | true_varargs, first_default_arg); ins_f_byte(F_CALL_C); func = get_C_fun_address(current_file, $<string>11); if (!func) { char buf[256]; sprintf(buf,"Undefined interface %s() = \"%s\".\n", $3, $<string>11); yyerror(buf); } free($<string>11); #ifdef __alpha ins_long((int) ((long)func & 0xffffffff)); ins_long((int) ((long)func >> 32)); #else ins_long((long)func); #endif if (!is_dtor) ins_f_byte(F_DO_INVARIANTS); ins_f_byte(F_RETURN); pop_address(); /* Not used here */ } free_all_local_names(); free($3); /* Value was copied above */ is_ctor = is_dtor = 0; } | type name_list ';' { if ($1 == 0) yyerror("Missing type"); } | inheritance ; | invariant ';' new_arg_name: type optional_star F_IDENTIFIER { 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); } if (first_default_arg != current_arg) yyerror("non default argument defined after default one"); else first_default_arg++; push_init_arg_address(mem_block[A_PROGRAM].current_size); } ; | type F_LOCAL_NAME {yyerror("Illegal to redeclare local name"); } ; | type optional_star F_IDENTIFIER { int var_num; if (exact_types && $1 == 0) { yyerror("Missing type for argument"); var_num = add_local_name($3, TYPE_ANY); /* Supress more errors */ } else { var_num = add_local_name($3, $1 | $2); } push_init_arg_address(mem_block[A_PROGRAM].current_size); ins_f_byte(F_PUSH_LOCAL_VARIABLE_LVALUE); ins_byte(var_num); } '=' expr0 { if (!compatible_types((($1 ? $1 : TYPE_ANY) | $2) & TYPE_MASK, $6)){ char buff[100]; sprintf(buff, "Type mismatch %s when initializing %s", get_two_types($1 | $2, $6), $3); yyerror(buff); } ins_f_byte(F_ASSIGN); ins_f_byte(F_POP_VALUE); } ; | type F_LOCAL_NAME '=' expr0 {yyerror("Illegal to redeclare local name"); } ; argument: /* empty */ { $$ = 0;} | argument_list ; | argument_list ',' F_VARARG { true_varargs = TYPE_MOD_TRUE_VARARGS; $$ = $1 + 1; push_init_arg_address(mem_block[A_PROGRAM].current_size); ins_f_byte(F_PUSH_LOCAL_VARIABLE_LVALUE); ins_byte(add_local_name(string_copy("argv"), TYPE_ANY | TYPE_MOD_POINTER)); ins_f_byte(F_AGGREGATE); ins_short(0); ins_f_byte(F_ASSIGN); ins_f_byte(F_POP_VALUE); current_arg++; } argument_list: new_arg_name { $$ = 1; current_arg++; } | argument_list ',' new_arg_name { $$ = $1 + 1; current_arg++; } ; 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; } ; 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 { $$ = TYPE_NUMBER; current_type = $$; } | F_INT { $$ = TYPE_NUMBER; current_type = $$; } | F_STRING_DECL { $$ = TYPE_STRING; current_type = $$; } | F_OBJECT { $$ = TYPE_OBJECT; current_type = $$; } | F_VOID {$$ = TYPE_VOID; current_type = $$; } | F_MIXED { $$ = TYPE_ANY; current_type = $$; } | F_MAPPING { $$ = TYPE_MAPPING; current_type = $$; }; | F_FLOAT { $$ = TYPE_FLOAT; current_type = $$; }; name_list: new_name | new_name ',' name_list; new_name: optional_star F_IDENTIFIER { define_variable($2, current_type | $1); free($2); } | optional_star F_IDENTIFIER { int var_num; define_variable($2, current_type | $1); transfer_init_control(); ins_f_byte(F_PUSH_IDENTIFIER_LVALUE); ins_byte(variable_inherit_found); ins_byte(variable_index_found); } '=' expr0 { if (pragma_strict_types && !compatible_types((current_type | $1) & TYPE_MASK, $5)){ char buff[100]; sprintf(buff, "Type mismatch %s when initializing %s", get_two_types(current_type | $1, $5), $2); yyerror(buff); } ins_f_byte(F_ASSIGN); ins_f_byte(F_POP_VALUE); add_new_init_jump(); free($2); } ; block: '{' local_declarations statements '}' { ; }; local_declarations: /* empty */ | local_declarations basic_type local_name_list ';' ; new_local_name: optional_star F_IDENTIFIER { add_local_name($2, current_type | $1); } ; | optional_star F_IDENTIFIER { int var_num; var_num = add_local_name($2, current_type | $1); ins_f_byte(F_PUSH_LOCAL_VARIABLE_LVALUE); ins_byte(var_num); } '=' expr0 { if (exact_types && !compatible_types((current_type | $1) & TYPE_MASK, $5)){ char buff[100]; sprintf(buff, "Type mismatch %s when initializing %s", get_two_types(current_type | $1, $5), $2); yyerror(buff); } ins_f_byte(F_ASSIGN); ins_f_byte(F_POP_VALUE); } ; local_name_list: new_local_name | new_local_name ',' local_name_list ; statements: /* empty */ | statement statements | error ';' ; statement: comma_expr ';' { ins_f_byte(F_POP_VALUE); if (d_flag & DEBUG_BREAK_POINT) ins_f_byte(F_BREAK_POINT); /* if (exact_types && !TYPE($1,TYPE_VOID)) yyerror("Value thrown away"); */ } | cond | while | do | for | switch | case | default | return ';' | block | assertion ';' | /* empty */ ';' | F_BREAK ';' /* This code is a jump to a jump */ { if (current_break_address == 0) yyerror("break statement outside loop"); if (current_break_address & BREAK_ON_STACK) { ins_f_byte(F_BREAK); } else { ins_f_byte(F_JUMP); ins_short(current_break_address); } } | F_CONTINUE ';' /* This code is a jump to a jump */ { if (current_continue_address == 0) yyerror("continue statement outside loop"); ins_f_byte(F_JUMP); ins_short(current_continue_address); } ; while: { push_explicit(current_continue_address); push_explicit(current_break_address); current_continue_address = mem_block[A_PROGRAM].current_size; } F_WHILE '(' comma_expr ')' { ins_f_byte(F_JUMP_WHEN_NON_ZERO); ins_short(0); /* to block */ current_break_address = mem_block[A_PROGRAM].current_size; ins_f_byte(F_JUMP); ins_short(0); /* Exit loop */ upd_short(current_break_address-2, mem_block[A_PROGRAM].current_size); } statement { ins_f_byte(F_JUMP); ins_short(current_continue_address); upd_short(current_break_address+1, mem_block[A_PROGRAM].current_size); current_break_address = pop_address(); current_continue_address = pop_address(); } do: { int tmp_save; push_explicit(current_continue_address); push_explicit(current_break_address); /* Jump to start of loop. */ ins_f_byte(F_JUMP); tmp_save = mem_block[A_PROGRAM].current_size; ins_short(0); current_break_address = mem_block[A_PROGRAM].current_size; /* Jump to end of loop. All breaks go through this one. */ ins_f_byte(F_JUMP); push_address(); ins_short(0); current_continue_address = mem_block[A_PROGRAM].current_size; upd_short(tmp_save, current_continue_address); push_address(); } F_DO statement F_WHILE '(' comma_expr ')' ';' { ins_f_byte(F_JUMP_WHEN_NON_ZERO); ins_short(pop_address()); /* Fill in the break jump address in the beginning of the loop. */ upd_short(pop_address(), mem_block[A_PROGRAM].current_size); current_break_address = pop_address(); current_continue_address = pop_address(); } for: F_FOR '(' { push_explicit(current_continue_address); push_explicit(current_break_address); } for_expr ';' { ins_f_byte(F_POP_VALUE); push_address(); } for_expr ';' { ins_f_byte(F_JUMP_WHEN_NON_ZERO); ins_short(0); /* Jump to block of block */ current_break_address = mem_block[A_PROGRAM].current_size; ins_f_byte(F_JUMP); ins_short(0); /* Out of loop */ current_continue_address = mem_block[A_PROGRAM].current_size; } for_expr ')' { ins_f_byte(F_POP_VALUE); ins_f_byte(F_JUMP); ins_short(pop_address()); /* Here starts the block. */ upd_short(current_break_address-2, mem_block[A_PROGRAM].current_size); } statement { ins_f_byte(F_JUMP); ins_short(current_continue_address); /* Now, the address of the end of the block is known. */ upd_short(current_break_address+1, mem_block[A_PROGRAM].current_size); current_break_address = pop_address(); current_continue_address = pop_address(); } for_expr: /* EMPTY */ { ins_f_byte(F_CONST1); } | comma_expr {;} ; switch: F_SWITCH '(' comma_expr ')' { /* initialize switch */ push_explicit(current_case_number_heap); push_explicit(current_case_string_heap); push_explicit(zero_case_label); push_explicit(current_break_address); ins_f_byte(F_SWITCH); ins_byte(0xff); /* kind of table */ current_case_number_heap = mem_block[A_CASE_NUMBERS].current_size; current_case_string_heap = mem_block[A_CASE_STRINGS].current_size; zero_case_label = NO_STRING_CASE_LABELS; ins_short(0); /* address of table */ current_break_address = mem_block[A_PROGRAM].current_size | BREAK_FROM_CASE; ins_f_byte(F_JUMP); ins_short(0); /* break address to push, table is entered before */ ins_short(0); /* default address */ } statement { int i; int block_index; int current_case_heap; short default_addr; /* Wrap up switch */ current_break_address &= ~BREAK_FROM_CASE; /* It is not unusual that the last case/default has no break */ /* Default address */ if (!(default_addr = read_short(current_break_address + 3))) { upd_short(current_break_address + 3, /* no default given -> */ mem_block[A_PROGRAM].current_size); /* create one */ default_addr = mem_block[A_PROGRAM].current_size; } ins_f_byte(F_JUMP); ins_short(current_break_address); /* Table address */ upd_short(current_break_address - 2, mem_block[A_PROGRAM].current_size); /* What type of table? */ if (zero_case_label & (NO_STRING_CASE_LABELS|SOME_NUMERIC_CASE_LABELS)) { block_index = A_CASE_NUMBERS; current_case_heap = current_case_number_heap; mem_block[A_PROGRAM].block[current_break_address - 3] = 0; } else { block_index = A_CASE_STRINGS; current_case_heap = current_case_string_heap; mem_block[A_PROGRAM].block[current_break_address - 3] = 1; if (zero_case_label & 0xffff) { ins_long(0); /* not used */ ins_short(zero_case_label); /* the address */ } else { ins_long(0); /* not used */ ins_short(default_addr); /* the address */ } } /* Dump the table */ { struct case_heap_entry *ent, *end; ent = (struct case_heap_entry *) (mem_block[block_index].block + current_case_heap); end = (struct case_heap_entry *) (mem_block[block_index].block + mem_block[block_index].current_size); for (; ent < end; ent++) { ins_long(ent->key); ins_short(ent->addr); } } /* Break address */ upd_short(current_break_address + 1, mem_block[A_PROGRAM].current_size); mem_block[A_CASE_NUMBERS].current_size = current_case_number_heap; mem_block[A_CASE_STRINGS].current_size = current_case_string_heap; current_break_address = pop_address(); zero_case_label = pop_address(); current_case_string_heap = pop_address(); current_case_number_heap = pop_address(); } case: F_CASE case_label ':' { /* Register label */ struct case_heap_entry temp; if ( !( current_break_address & BREAK_FROM_CASE ) ) { yyerror("Case outside switch"); break; } temp.key = $2.key; temp.addr = mem_block[A_PROGRAM].current_size; temp.line = current_line; add_to_case_heap($2.block,&temp, NULL); } | F_CASE case_label F_RANGE case_label ':' { /* Register range label */ struct case_heap_entry temp1, temp2; if ( !( current_break_address & BREAK_FROM_CASE ) ) { yyerror("Case outside switch"); break; } if ($2.block != $4.block) yyerror("Incompatible types in case label range bounds"); else { temp1.key = $2.key; temp1.addr = -1; temp1.line = current_line; temp2.key = $4.key; temp2.addr = mem_block[A_PROGRAM].current_size; temp2.line = current_line; add_to_case_heap($2.block, &temp1, &temp2); } } case_label: constant { if ( !(zero_case_label & NO_STRING_CASE_LABELS) ) yyerror("Mixed case label list not allowed"); if ( $$.key = $1 ) zero_case_label |= SOME_NUMERIC_CASE_LABELS; else zero_case_label |= mem_block[A_PROGRAM].current_size; $$.block = A_CASE_NUMBERS; } | string_constant { if ( zero_case_label & SOME_NUMERIC_CASE_LABELS ) yyerror("Mixed case label list not allowed"); zero_case_label &= ~NO_STRING_CASE_LABELS; $$.key = (unsigned short)store_prog_string($1); $$.block = A_CASE_STRINGS; free($1); } constant: const1 | constant '|' const1 { $$ = $1 | $3; } ; const1: const2 | const1 '^' const2 { $$ = $1 ^ $3; } ; const2: const3 | const2 '&' const3 { $$ = $1 & $3; } ; const3: const4 | const3 F_EQ const4 { $$ = $1 == $3; } | const3 F_NE const4 { $$ = $1 != $3; } ; const4: const5 | const4 '>' const5 { $$ = $1 > $3; } | const4 F_GE const5 { $$ = $1 >= $3; } | const4 '<' const5 { $$ = $1 < $3; } | const4 F_LE const5 { $$ = $1 <= $3; } ; const5: const6 | const5 F_LSH const6 { $$ = $1 << $3; } | const5 F_RSH const6 { $$ = $1 >> $3; } ; const6: const7 | const6 '+' const7 { $$ = $1 + $3; } | const6 '-' const7 { $$ = $1 - $3; } ; const7: const8 | const7 '*' const8 { $$ = $1 * $3; } | const7 '%' const8 { $$ = $1 % $3; } | const7 '/' const8 { $$ = $1 / $3; } ; const8: const9 | '(' constant ')' { $$ = $2; } ; const9: F_NUMBER | '-' F_NUMBER { $$ = -$2; } | F_NOT F_NUMBER { $$ = !$2; } | '~' F_NUMBER { $$ = ~$2; } ; default: F_DEFAULT ':' { if ( !( current_break_address & BREAK_FROM_CASE ) ) { yyerror("Default outside switch"); break; } current_break_address &= ~(BREAK_FROM_CASE); if ( read_short(current_break_address + 3 ) ) yyerror("Duplicate default"); upd_short(current_break_address + 3, mem_block[A_PROGRAM].current_size); current_break_address |= (BREAK_FROM_CASE); } ; comma_expr: expr0 { $$ = $1; } | comma_expr { ins_f_byte(F_POP_VALUE); } ',' expr0 { $$ = $4; } ; expr0: expr01 | lvalue assign expr0 { if (exact_types && !compatible_types($1, $3) && !($1 == TYPE_STRING && $3 == TYPE_NUMBER && $2 == F_ADD_EQ)) { type_error("Bad assignment. Rhs", $3); } ins_f_byte($2); $$ = $3; } | error assign expr01 { yyerror("Illegal LHS"); $$ = TYPE_ANY; }; expr01: expr1 { $$ = $1; } | expr1 '?' { ins_f_byte(F_JUMP_WHEN_ZERO); push_address(); ins_short(0); } expr01 { int i; i = pop_address(); ins_f_byte(F_JUMP); push_address(); ins_short(0); upd_short(i, mem_block[A_PROGRAM].current_size); } ':' expr01 { upd_short(pop_address(), mem_block[A_PROGRAM].current_size); if (exact_types && !compatible_types($4, $7)) { type_error("Different types in ?: expr", $4); type_error(" and ", $7); } if ($4 == TYPE_ANY) $$ = $7; else if ($7 == TYPE_ANY) $$ = $4; else if (TYPE($4, TYPE_MOD_POINTER|TYPE_ANY)) $$ = $7; else if (TYPE($7, TYPE_MOD_POINTER|TYPE_ANY)) $$ = $4; else $$ = $4; }; assign: '=' { $$ = F_ASSIGN; } | F_AND_EQ { $$ = F_AND_EQ; } | F_OR_EQ { $$ = F_OR_EQ; } | F_XOR_EQ { $$ = F_XOR_EQ; } | F_LSH_EQ { $$ = F_LSH_EQ; } | F_RSH_EQ { $$ = F_RSH_EQ; } | F_ADD_EQ { $$ = F_ADD_EQ; } | F_SUB_EQ { $$ = F_SUB_EQ; } | F_MULT_EQ { $$ = F_MULT_EQ; } | F_MOD_EQ { $$ = F_MOD_EQ; } | F_DIV_EQ { $$ = F_DIV_EQ; }; return: F_RETURN { if (exact_types && !TYPE(exact_types, TYPE_VOID)) type_error("Must return a value for a function declared", exact_types); ins_f_byte(F_CONST0); ins_f_byte(F_JUMP); ins_label(return_label); } | F_RETURN comma_expr { if (exact_types && !TYPE($2, exact_types & TYPE_MASK)) type_error("Return type not matching", exact_types); ins_f_byte(F_JUMP); ins_label(return_label); }; expr_list: /* empty */ { $$ = 0; } | expr_list2 { $$ = $1; } | expr_list2 ',' { $$ = $1; } ; /* Allow a terminating comma */ expr_list2: expr0 { $$ = 1; add_arg_type($1); } | expr_list2 ',' expr0 { $$ = $1 + 1; add_arg_type($3); } ; m_expr_list: /* empty */ { $$ = 0; } | m_expr_list2 { $$ = $1; } | m_expr_list2 ',' { $$ = $1; } ; /* Allow a terminating comma */ m_expr_list2: expr0 ':' expr1 { $$ = 2; add_arg_type($1); add_arg_type($3); } | m_expr_list2 ',' expr0 ':' expr1 { $$ = $1 + 2; add_arg_type($3); add_arg_type($5); } expr1: expr2 { $$ = $1; } | expr2 F_LOR { ins_f_byte(F_DUP); ins_f_byte(F_JUMP_WHEN_NON_ZERO); push_address(); ins_short(0); ins_f_byte(F_POP_VALUE); } expr1 { upd_short(pop_address(), mem_block[A_PROGRAM].current_size); if ($1 == $4) $$ = $1; else $$ = TYPE_ANY; /* Return type can't be known */ }; expr2: expr211 { $$ = $1; } | expr211 F_LAND { ins_f_byte(F_DUP); ins_f_byte(F_JUMP_WHEN_ZERO); push_address(); ins_short(0); ins_f_byte(F_POP_VALUE); } expr2 { upd_short(pop_address(), mem_block[A_PROGRAM].current_size); if ($1 == $4) $$ = $1; else $$ = TYPE_ANY; /* Return type can't be known */ } ; expr211: expr212 | expr211 '|' expr212 { if (exact_types && !TYPE($1,TYPE_NUMBER)) type_error("Bad argument 1 to |", $1); if (exact_types && !TYPE($3,TYPE_NUMBER)) type_error("Bad argument 2 to |", $3); $$ = TYPE_NUMBER; ins_f_byte(F_OR); }; expr212: expr213 | expr212 '^' expr213 { if (exact_types && !TYPE($1,TYPE_NUMBER)) type_error("Bad argument 1 to ^", $1); if (exact_types && !TYPE($3,TYPE_NUMBER)) type_error("Bad argument 2 to ^", $3); $$ = TYPE_NUMBER; ins_f_byte(F_XOR); }; expr213: expr22 | expr213 '&' expr22 { int t1 = $1 & TYPE_MASK, t3 = $3 & TYPE_MASK; if (($1 & TYPE_MOD_POINTER && $3 & TYPE_MOD_POINTER) && (t1 == t3)) $$ = $1; else if (((t1 == TYPE_ANY) && $3 & TYPE_MOD_POINTER) || ($1 & TYPE_MOD_POINTER && (t3 == TYPE_ANY))) $$ = TYPE_MOD_POINTER | TYPE_ANY; else if ((t1 == TYPE_ANY) && (t3 == TYPE_ANY)) $$ = TYPE_ANY; else { if (exact_types && !TYPE($1,TYPE_NUMBER)) type_error("Bad argument 1 to &", $1); if (exact_types && !TYPE($3,TYPE_NUMBER)) type_error("Bad argument 2 to &", $3); $$ = TYPE_NUMBER; } ins_f_byte(F_AND); }; expr22: expr23 | expr24 F_EQ expr24 { int t1 = $1 & TYPE_MASK, t2 = $3 & TYPE_MASK; if (exact_types && t1 != t2 && t1 != TYPE_ANY && t2 != TYPE_ANY) { type_error("== always false because of different types", $1); type_error(" compared to", $3); } ins_f_byte(F_EQ); $$ = TYPE_NUMBER; }; | expr24 F_NE expr24 { int t1 = $1 & TYPE_MASK, t2 = $3 & TYPE_MASK; if (exact_types && t1 != t2 && t1 != TYPE_ANY && t2 != TYPE_ANY) { type_error("!= always true because of different types", $1); type_error(" compared to", $3); } ins_f_byte(F_NE); $$ = TYPE_NUMBER; }; expr23: expr24 | expr24 '>' expr24 { $$ = TYPE_NUMBER; ins_f_byte(F_GT); }; | expr24 F_GE expr24 { $$ = TYPE_NUMBER; ins_f_byte(F_GE); }; | expr24 '<' expr24 { $$ = TYPE_NUMBER; ins_f_byte(F_LT); }; | expr24 F_LE expr24 { $$ = TYPE_NUMBER; ins_f_byte(F_LE); }; expr24: expr25 | expr24 F_LSH expr25 { ins_f_byte(F_LSH); $$ = TYPE_NUMBER; if (exact_types && !TYPE($1, TYPE_NUMBER)) type_error("Bad argument number 1 to '<<'", $1); if (exact_types && !TYPE($3, TYPE_NUMBER)) type_error("Bad argument number 2 to '<<'", $3); }; | expr24 F_RSH expr25 { ins_f_byte(F_RSH); $$ = TYPE_NUMBER; if (exact_types && !TYPE($1, TYPE_NUMBER)) type_error("Bad argument number 1 to '>>'", $1); if (exact_types && !TYPE($3, TYPE_NUMBER)) type_error("Bad argument number 2 to '>>'", $3); }; expr25: expr27 | expr25 '+' expr27 /* Type checks of this case is complicated */ { ins_f_byte(F_ADD); $$ = TYPE_ANY; }; | expr25 '-' expr27 { int bad_arg = 0; if (exact_types) { if (!(TYPE($1, TYPE_NUMBER) || TYPE($1, TYPE_FLOAT)) && !($1 & TYPE_MOD_POINTER) ) { type_error("Bad argument number 1 to '-'", $1); bad_arg++; } if (!TYPE($3, $1) && !($3 & TYPE_MOD_POINTER) ) { type_error("Bad argument number 2 to '-'", $3); bad_arg++; } } $$ = TYPE_ANY; if (($1 & TYPE_MOD_POINTER) || ($3 & TYPE_MOD_POINTER)) $$ = TYPE_MOD_POINTER | TYPE_ANY; if (!($1 & TYPE_MOD_POINTER) || !($3 & TYPE_MOD_POINTER)) { if (exact_types && $$ != TYPE_ANY && !bad_arg) yyerror("Arguments to '-' don't match"); $$ = ($1 & TYPE_MOD_POINTER)?$3:$1; } ins_f_byte(F_SUBTRACT); }; expr27: expr28 | expr27 '*' expr3 { if (exact_types && !(TYPE($1, TYPE_NUMBER) || TYPE($1, TYPE_FLOAT))) type_error("Bad argument number 1 to '*'", $1); if (exact_types && !TYPE($1, $3)) { type_error("Bad argument number 2 to '*'", $3); } ins_f_byte(F_MULTIPLY); $$ = $1; }; | expr27 '%' expr3 { if (exact_types && !TYPE($1, TYPE_NUMBER)) type_error("Bad argument number 1 to '%'", $1); if (exact_types && !TYPE($3, TYPE_NUMBER)) type_error("Bad argument number 2 to '%'", $3); ins_f_byte(F_MOD); $$ = TYPE_NUMBER; }; | expr27 '/' expr3 { if (exact_types && !(TYPE($1, TYPE_NUMBER) || TYPE($1, TYPE_FLOAT))) type_error("Bad argument number 1 to '/'", $1); if (exact_types && !TYPE($3, $1)) type_error("Bad argument number 2 to '/'", $3); ins_f_byte(F_DIVIDE); $$ = $1; }; expr28: expr3 | cast expr3 { $$ = $1; if (exact_types && $2 != TYPE_ANY && $2 != TYPE_UNKNOWN && $1 != TYPE_VOID) type_error("Casts are only legal for type mixed, or when unknown", $2); } ; expr3: expr31 | F_INC lvalue { ins_f_byte(F_INC); if (exact_types && !TYPE($2, TYPE_NUMBER)) type_error("Bad argument to ++", $2); $$ = TYPE_NUMBER; }; | F_DEC lvalue { ins_f_byte(F_DEC); if (exact_types && !TYPE($2, TYPE_NUMBER)) type_error("Bad argument to --", $2); $$ = TYPE_NUMBER; }; | F_NOT expr3 { ins_f_byte(F_NOT); /* Any type is valid here. */ $$ = TYPE_NUMBER; }; | '~' expr3 { ins_f_byte(F_COMPL); if (exact_types && !TYPE($2, TYPE_NUMBER)) type_error("Bad argument to ~", $2); $$ = TYPE_NUMBER; }; | '-' expr3 { ins_f_byte(F_NEGATE); if (exact_types && !(TYPE($2, TYPE_NUMBER) || TYPE($2, TYPE_FLOAT))) type_error("Bad argument to unary '-'", $2); $$ = $2; }; expr31: expr4 | lvalue F_INC { ins_f_byte(F_POST_INC); if (exact_types && !TYPE($1, TYPE_NUMBER)) type_error("Bad argument to ++", $1); $$ = TYPE_NUMBER; }; | lvalue F_DEC { ins_f_byte(F_POST_DEC); if (exact_types && !TYPE($1, TYPE_NUMBER)) type_error("Bad argument to --", $1); $$ = TYPE_NUMBER; }; expr4: function_call | lvalue { int pos = mem_block[A_PROGRAM].current_size; /* Some optimization. Replace the push-lvalue with push-value */ if (last_push_identifier == pos - 3) mem_block[A_PROGRAM].block[last_push_identifier] = F_IDENTIFIER - F_OFFSET; else if (last_push_local == pos-2) mem_block[A_PROGRAM].block[last_push_local] = F_LOCAL_NAME - F_OFFSET; else if (last_push_indexed == pos-1) mem_block[A_PROGRAM].block[last_push_indexed] = F_INDEX - F_OFFSET; else if (last_push_indexed != 0) fatal("Should be a push at this point !\n"); $$ = $1; } | expr4 '[' comma_expr F_RANGE comma_expr ']' { ins_f_byte(F_RANGE); last_push_indexed = 0; if (exact_types && !($1 & TYPE_MAPPING)) { if (($1 & TYPE_MOD_POINTER) == 0 && !TYPE($1, TYPE_STRING)) type_error("Bad type to indexed value", $1); if (!TYPE($3, TYPE_NUMBER)) type_error("Bad type of index", $3); if (!TYPE($5, TYPE_NUMBER)) type_error("Bad type of index", $5); } if ($1 == TYPE_ANY) $$ = TYPE_ANY; else if (TYPE($1, TYPE_STRING)) $$ = TYPE_STRING; else if ($1 & TYPE_MOD_POINTER) $$ = $1; else if (exact_types) type_error("Bad type of argument used for range", $1); }; | expr4 '[' F_RANGE { ins_f_byte(F_CONST0); } comma_expr ']' { ins_f_byte(F_RANGE); last_push_indexed = 0; if (exact_types && !($1 & TYPE_MAPPING)) { if (($1 & TYPE_MOD_POINTER) == 0 && !TYPE($1, TYPE_STRING)) type_error("Bad type to indexed value", $1); if (!TYPE($5, TYPE_NUMBER)) type_error("Bad type of index", $5); } if ($1 == TYPE_ANY) $$ = TYPE_ANY; else if (TYPE($1, TYPE_STRING)) $$ = TYPE_STRING; else if ($1 & TYPE_MOD_POINTER) $$ = $1; else if (exact_types) type_error("Bad type of argument used for range", $1); }; | expr4 '[' comma_expr F_RANGE ']' { ins_f_byte(F_NUMBER); ins_long(~(1<<31)); /* MAXINT */ ins_f_byte(F_RANGE); last_push_indexed = 0; if (exact_types && !($1 & TYPE_MAPPING)) { if (($1 & TYPE_MOD_POINTER) == 0 && !TYPE($1, TYPE_STRING)) type_error("Bad type to indexed value", $1); if (!TYPE($3, TYPE_NUMBER)) type_error("Bad type of index", $3); } if ($1 == TYPE_ANY) $$ = TYPE_ANY; else if (TYPE($1, TYPE_STRING)) $$ = TYPE_STRING; else if ($1 & TYPE_MOD_POINTER) $$ = $1; else if (exact_types) type_error("Bad type of argument used for range", $1); }; | string | number | real | '(' comma_expr ')' { $$ = $2; } | catch { $$ = TYPE_ANY; } | sscanf { $$ = TYPE_NUMBER; } | parse_command { $$ = TYPE_NUMBER; } | '(' '{' expr_list '}' ')' { pop_arg_stack($3); /* We don't care about these types */ ins_f_byte(F_AGGREGATE); ins_short($3); $$ = TYPE_MOD_POINTER | TYPE_ANY; } | '(' '[' m_expr_list ']' ')' { pop_arg_stack($3); ins_f_byte(F_M_AGGREGATE); ins_short($3); $$ = TYPE_MAPPING; }; catch: F_CATCH { ins_f_byte(F_CATCH); push_address(); ins_short(0);} '(' comma_expr ')' { ins_f_byte(F_POP_VALUE); ins_f_byte(F_CONST0); ins_f_byte(F_THROW); upd_short(pop_address(), mem_block[A_PROGRAM].current_size); }; sscanf: F_SSCANF '(' expr0 ',' expr0 lvalue_list ')' { ins_f_byte(F_SSCANF); ins_byte($6 + 2); } parse_command: F_PARSE_COMMAND '(' expr0 ',' expr0 ',' expr0 lvalue_list ')' { ins_f_byte(F_PARSE_COMMAND); ins_byte($8 + 3); } lvalue_list: /* empty */ { $$ = 0; } | ',' lvalue lvalue_list { $$ = 1 + $3; } ; identifier: F_IDENTIFIER | F_COLON_COLON identifier { $$ = xalloc(strlen($2) + 3); sprintf($$, "::%s", $2); free($2); } | F_IDENTIFIER F_COLON_COLON identifier { $$ = xalloc(strlen($1) + strlen($3) + 3); sprintf($$, "%s::%s", $1, $3); free($1); free($3); } ; fun_identifier: F_IDENTIFIER | F_LSH { $$ = DTOR_FUNC;} | F_RSH { $$ = CTOR_FUNC;} lvalue: identifier { int i = verify_declared($1); last_push_identifier = mem_block[A_PROGRAM].current_size; ins_f_byte(F_PUSH_IDENTIFIER_LVALUE); ins_byte(variable_inherit_found); ins_byte(variable_index_found); free($1); if (i == -1) $$ = TYPE_ANY; else $$ = i & TYPE_MASK; } | F_LOCAL_NAME { last_push_local = mem_block[A_PROGRAM].current_size; ins_f_byte(F_PUSH_LOCAL_VARIABLE_LVALUE); ins_byte($1); $$ = type_of_locals[$1]; } | expr4 '[' comma_expr ']' { last_push_indexed = mem_block[A_PROGRAM].current_size; ins_f_byte(F_PUSH_INDEXED_LVALUE); if (exact_types && !($1 & TYPE_MAPPING)) { if (($1 & TYPE_MOD_POINTER) == 0 && !TYPE($1, TYPE_STRING)) type_error("Bad type to indexed value", $1); if (!TYPE($3, TYPE_NUMBER)) type_error("Bad type of index", $3); } if ($1 == TYPE_ANY) $$ = TYPE_ANY; else if (TYPE($1, TYPE_STRING)) $$ = TYPE_NUMBER; else if ($1 == TYPE_MAPPING) $$ = TYPE_ANY; else $$ = $1 & TYPE_MASK & ~TYPE_MOD_POINTER; }; real: F_FLOATC { ins_f_byte(F_FLOATC); ins_long(*((int *)&$<real>1)); $$ = TYPE_FLOAT; }; string: F_STRING { ins_f_byte(F_STRING); ins_short(store_prog_string($1)); free($1); $$ = TYPE_STRING; }; string_constant: string_con1 { $$ = $1; }; string_con1: F_STRING | string_con1 '+' F_STRING { $$ = xalloc( strlen($1) + strlen($3) + 1 ); strcpy($$, $1); strcat($$, $3); free($1); free($3); }; function_call: function_name '(' expr_list ')' { /* Note that this code could be made a lot cleaner if some * support functions were added. (efun_call() is a good one) */ int inherited_override = !!strchr($1, ':'); int efun_override = inherited_override && strncmp($1,"efun::", 6) == 0; int is_sfun = 0; int f; $$ = TYPE_ANY; /* in case anything goes wrong we need a default type. /LA */ if (inherited_override && !efun_override) { struct function *funp; /* Find the right function to call This assumes max 255 inherited programs and 32767 functions in one program. */ if (defined_function($1)) { funp = &function_prog_found->functions[function_index_found]; $$ = funp->type_flags & TYPE_MASK; ins_f_byte(F_CALL_NON_VIRT); ins_byte (function_inherit_found); ins_short (function_index_found); ins_byte($3); /* Number of arguments */ } else { char buff[100]; sprintf(buff, "Function %.50s undefined", $1); yyerror(buff); } } /* All simul_efuns are considered defined. */ else if (!efun_override && (defined_function ($1) || (is_sfun = 1) && is_simul_efun ($1)) ) { struct function *funp; unsigned short *arg_indices; unsigned short *arg_types; if (function_prog_found) { funp = &(function_prog_found-> functions[function_index_found]); arg_indices = function_prog_found->type_start; arg_types = function_prog_found->argument_types; } else { funp = FUNCTION(function_index_found); /* Beware... these are pointers to volatile structures */ arg_indices = (unsigned short *) mem_block[A_ARGUMENT_INDEX].block; arg_types = (unsigned short *) mem_block[A_ARGUMENT_TYPES].block; /* Assumption: exact_types implies correct values for arg_types */ } /* Private functions in inherited programs may not be called. */ if (exact_types && function_prog_found && function_type_mod_found & TYPE_MOD_PRIVATE) { char buff[100]; sprintf (buff, "Function %.44s marked 'private'", funp->name); yyerror (buff); } $$ = funp->type_flags & TYPE_MASK; if (is_sfun) { ins_f_byte(F_CALL_SIMUL); store_reloc_data(R_CALL, mem_block[A_PROGRAM].current_size, $1,0,0); } else if (funp->type_flags & TYPE_MOD_NO_MASK) { ins_f_byte(F_CALL_NON_VIRT); } else { ins_f_byte (F_CALL_VIRT); if (function_prog_found) store_reloc_data(R_CALL, mem_block[A_PROGRAM].current_size, $1,0,0); } ins_byte (function_inherit_found); ins_short (function_index_found); /* Insert function name into string list and code its index */ ins_byte ($3); /* * Check number of arguments. */ if ((funp->type_flags & NAME_STRICT_TYPES) && exact_types && funp->num_arg != $3 && /* An old varargs function */ !((funp->type_flags & TYPE_MOD_VARARGS) && $3 < funp->num_arg) && /* A true varargs function? */ !((funp->type_flags & TYPE_MOD_TRUE_VARARGS) && $3 + 1 >= funp->num_arg) && /* A function with default values for arguments? */ !($3 < funp->num_arg && funp->first_default <= $3)) { char buff[100]; sprintf(buff, "Wrong number of arguments to %.60s", $1); yyerror(buff); } /* * Check the argument types. */ if (funp->type_flags & NAME_STRICT_TYPES && exact_types && arg_indices && arg_indices[function_index_found] != INDEX_START_NONE) { int i, first; int num_check = funp->num_arg; if (funp->type_flags & TYPE_MOD_TRUE_VARARGS) num_check--; first = arg_indices[function_index_found]; for (i=0; i < num_check && i < $3; i++) { int tmp = get_argument_type(i, $3); if (!TYPE(tmp, arg_types[first + i])) { char buff[100]; sprintf(buff, "Bad type for argument %d %s", i+1, get_two_types(arg_types[first+i], tmp)); yyerror(buff); } } } } else if (efun_override || (f = lookup_predef($1)) != -1) { int min, max, def, *argp; extern int efun_arg_types[]; if (efun_override) f = lookup_predef($1+6); if (f == -1) /* Only possible for efun_override */ { char buff[100]; sprintf(buff, "Unknown efun: %s", $1+6); yyerror(buff); } else { min = instrs[f-F_OFFSET].min_arg; max = instrs[f-F_OFFSET].max_arg; def = instrs[f-F_OFFSET].Default; $$ = instrs[f-F_OFFSET].ret_type; argp = &efun_arg_types[instrs[f-F_OFFSET].arg_index]; if (def && $3 == min-1) { ins_f_byte(def); max--; min--; } else if ($3 < min) { char bff[100]; sprintf(bff, "Too few arguments to %s", instrs[f-F_OFFSET].name); yyerror(bff); } else if ($3 > max && max != -1) { char bff[100]; sprintf(bff, "Too many arguments to %s", instrs[f - F_OFFSET].name); yyerror(bff); } else if (max != -1 && exact_types) { /* * Now check all types of the arguments to efuns. */ int i, argn; char buff[100]; for (argn=0; argn < $3; argn++) { int tmp = get_argument_type(argn, $3); for(i=0; !TYPE(argp[i], tmp) && argp[i] != 0; i++) ; if (argp[i] == 0) { sprintf(buff, "Bad argument %d type to efun %s()", argn+1, instrs[f-F_OFFSET].name); yyerror(buff); } while(argp[i] != 0) i++; argp += i + 1; } } ins_f_byte(f); /* Only store number of arguments for instructions * that allowed a variable number. */ if (max != min) ins_byte($3); /* Number of actual arguments */ } } else { if (exact_types) { char buff[200]; sprintf (buff, "Undefined function: %.50s", $1); yyerror (buff); } /* Function not found */ ins_f_byte(F_CALL_VIRT); store_reloc_data(R_CALL, mem_block[A_PROGRAM].current_size, $1,0,0); ins_byte (255); ins_short (-1); ins_byte($3); /* Number of arguments */ $$ = TYPE_ANY; /* just a guess */ } free($1); pop_arg_stack($3); /* Argument types not needed more */ } /* ident, not name. Calls to :: functions are not allowed anyway /Dark */ | expr4 F_ARROW F_IDENTIFIER { ins_f_byte(F_STRING); ins_short(store_prog_string($3)); free($3); } '(' expr_list ')' { ins_f_byte(F_CALL_OTHER); ins_byte($6 + 2); $$ = TYPE_ANY; /* TYPE_UNKNOWN forces casts */ pop_arg_stack($6); /* No good need of these arguments */ }; function_name: identifier cond: condStart statement { int i; i = pop_address(); ins_f_byte(F_JUMP); push_address(); ins_short(0); upd_short(i, mem_block[A_PROGRAM].current_size); } optional_else_part { upd_short(pop_address(), mem_block[A_PROGRAM].current_size); } ; condStart: F_IF '(' comma_expr ')' { ins_f_byte(F_JUMP_WHEN_ZERO); push_address(); ins_short(0); } ; optional_else_part: /* empty */ | F_ELSE statement ; %% int link_errors; static void ins_f_byte(unsigned int b) { if (b - F_OFFSET < 256) ins_byte((char)(b - F_OFFSET)); else { ins_byte((char)(F_EXT - F_OFFSET)); ins_short((short)(b - F_OFFSET)); } } void yyerror(char *str) { extern int num_parse_error; char spos[500]; if (num_parse_error > 5) return; (void)fprintf(stderr, "%s: %s line %d\n", current_file, str, current_line); fflush(stderr); smart_log(current_file, current_line, str); num_parse_error++; } static int check_declared(char *str) { struct variable *vp; extern char *findstring (char *); int offset; int inh; char *super_name = 0; char *sub_name; char *real_name; char *search; variable_index_found = variable_inherit_found = 255; real_name = strrchr(str, ':') + 1; sub_name = strchr(str, ':') + 2; if(!(real_name = (findstring((real_name == (char *)1) ? str : real_name)))) return -1; if (sub_name == (char *)2) for (offset = 0; offset < mem_block[A_VARIABLES].current_size; offset += sizeof (struct variable)) { vp = (struct variable *)&mem_block[A_VARIABLES].block[offset]; /* Only index, prog, and type will be defined. */ if (real_name == vp->name) { variable_type_mod_found = vp->type; variable_index_found = offset / sizeof (struct variable); variable_inherit_found = 255; return variable_index_found; } } else if (sub_name - str > 2) { super_name = xalloc(sub_name - str - 1); memcpy(super_name, str, sub_name - str - 2); super_name[sub_name - str - 2] = 0; if (!strcmp(super_name, "this")) return check_declared(sub_name); } else str = sub_name; /* Look for the variable in the inherited programs */ for (inh = mem_block[A_INHERITS].current_size / sizeof (struct inherit) - 1; inh >= 0; inh -= ((struct inherit *)mem_block[A_INHERITS].block)[inh].prog-> num_inherited) { if (super_name && !strcmp(super_name, ((struct inherit *)mem_block[A_INHERITS].block)[inh].name)) search = sub_name; else search = str; if (find_status (((struct inherit *)mem_block[A_INHERITS].block)[inh].prog, search, TYPE_MOD_PRIVATE) != -1) { /* Adjust for inherit-type */ int type = ((struct inherit *)mem_block[A_INHERITS].block)[inh].type; if (variable_type_mod_found & TYPE_MOD_PRIVATE) type &= ~TYPE_MOD_PUBLIC; if (variable_type_mod_found & TYPE_MOD_PUBLIC) type &= ~TYPE_MOD_PRIVATE; variable_type_mod_found |= type & TYPE_MOD_MASK; variable_inherit_found += inh - (((struct inherit *)mem_block[A_INHERITS].block)[inh].prog-> num_inherited - 1); return 1; } } return -1; } static int verify_declared(char *str) { int r; r = check_declared(str); if (r == -1) { char buff[100]; (void)sprintf(buff, "Variable %s not declared !", str); yyerror(buff); return -1; } if (variable_inherit_found == 255) return ((struct variable *)mem_block[A_VARIABLES].block)[variable_index_found]. type; else return ((struct inherit *)mem_block[A_INHERITS].block)[variable_inherit_found]. prog->variable_names[variable_index_found].type; } void free_all_local_names() { int i; for (i=0; i<current_number_of_locals; i++) { free(local_names[i]); local_names[i] = 0; } current_number_of_locals = 0; } int 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; } return current_number_of_locals - 1; } int find_inherit(struct program *prog1, struct program *prog) { int i; for (i = 0; i < (int)prog1->num_inherited; i++) if (prog1->inherit[i].prog == prog) return i; return -1; } static void copy_inherits(struct program *from, int type, char *name) { int i; struct inherit inh; int j[256], k = 0; char buf[256]; access_program(from); for(i = 0; i < from->num_variables; i++) if ((type | from->variable_names[i].type) & TYPE_MOD_NO_MASK && check_declared(from->variable_names[i].name) != -1 && (variable_inherit_found == 255 || ((struct inherit *) (mem_block[A_INHERITS].block))[variable_inherit_found].prog != from)) { sprintf(buf,"Redefinition of no_mask variable %s in program %s.\n", from->variable_names[i].name, from->name); yyerror(buf); } for (i = 0; i < (int) from->num_functions; i++) if ((type | from->functions[i].type_flags) & TYPE_MOD_NO_MASK && defined_function(from->functions[i].name) && function_prog_found != from) { sprintf(buf,"Redefinition of no_mask function %s in program %s.\n", from->functions[i].name, from->name); yyerror(buf); } for (i = from->num_inherited - 2; i >= 0; i -= from->inherit[i].prog->num_inherited) j[k++] = i; for (i = j[--k]; k >= 0; i = j[--k]) { /* Correct the type */ int new_type = type; int old_type = from->inherit[i].type; if (old_type & TYPE_MOD_PRIVATE) new_type &= ~TYPE_MOD_PUBLIC; if (old_type & TYPE_MOD_PUBLIC) new_type &= ~TYPE_MOD_PRIVATE; copy_inherits(from->inherit[i].prog, old_type | new_type, from->inherit[i].name); } inh = from->inherit[from->num_inherited - 1]; /* Make a copy */ /* Adjust the info */ inh.name = make_shared_string(name); inh.type = type; add_to_mem_block (A_INHERITS, (char *)&inh, sizeof inh); } static int check_inherits(struct program *from) { int i, update = 0; struct object *ob; int len = strlen(from->name) - 1; char *ob_name = xalloc(len); strncpy(ob_name, from->name, len - 1); ob_name[len - 1] = 0; ob = find_object2(ob_name); free(ob_name); if (!ob || ob->prog != from) return 0; for (i = from->num_inherited - 2; i >= 0; i -= from->inherit[i].prog->num_inherited) if (!check_inherits(from->inherit[i].prog)) update = 1; if (update) { if (ob) destruct_object(ob); return 0; } return 1; } void hash_func (int size, struct function *from, struct function_hash *to) { int first_hole; /* Keep chained lists through the hash table */ int first_collision; int last_collision, next_collision; int i, probe; int *back; if (size <= 0) return; back = (int *) alloca(sizeof(int) * size); /* Prepare the lists */ for (first_hole = 0, first_collision = -1, i = 0; i < size; i++) { to[i].next_hashed_function = i+1; /* forward */ back[i] = i-1; /* back */ to[i].name = 0; /* free entry */ } to[size-1].next_hashed_function = -1; /* Hash all non-collisions and mark collisions */ for (i = 0, last_collision = -1; i < size; i++) { probe = PTR_HASH(from[i].name, size); if (!to[probe].name) { /* free */ if (back[probe] == -1) first_hole = to[probe].next_hashed_function; else to[back[probe]].next_hashed_function = to[probe].next_hashed_function; if (to[probe].next_hashed_function != -1) back[to[probe].next_hashed_function] = back[probe]; to[probe].name = from[i].name; to[probe].func_index = i; from[i].hash_idx = probe; to[probe].next_hashed_function = -1; } else { /* collision */ if (first_collision == -1) last_collision = first_collision = i; else { from[last_collision].hash_idx = i; last_collision = i; } from[i].hash_idx = -1; } } /* Plug collisions into the holes */ for ( ; first_collision != -1; first_collision = next_collision) { i = first_hole; first_hole = to[i].next_hashed_function; to[i].name = from[first_collision].name; to[i].func_index = first_collision; to[i].next_hashed_function = -1; next_collision = from[first_collision].hash_idx; from[first_collision].hash_idx = i; for (probe = PTR_HASH (to[i].name, size); to[probe].next_hashed_function != -1; probe = to[probe].next_hashed_function) ; to[probe].next_hashed_function = i; } /* Finished */ } /* * This function is called from lex.c for every new line read. */ void store_line_number_info(int ifile, int line) { static int cur_pc, cur_line, cur_file; static int prev_file, prev_line; char delta, tmp; if (ifile == -1) { cur_pc = cur_line = cur_file = 0; prev_file = prev_line = 0; return; } delta = mem_block[A_PROGRAM].current_size - cur_pc; if (delta) { if (prev_file != cur_file || prev_line - cur_line < 1 || prev_line - cur_line > 0xff) { tmp = 0xfe; add_to_mem_block(A_LINENUMBERS, &tmp, 1); tmp = prev_file; add_to_mem_block(A_LINENUMBERS, &tmp, 1); tmp = prev_line >> 8; add_to_mem_block(A_LINENUMBERS, &tmp, 1); tmp = 0xff & prev_line; add_to_mem_block(A_LINENUMBERS, &tmp, 1); } else if (prev_line - cur_line == 2) { tmp = 0; add_to_mem_block(A_LINENUMBERS, &tmp, 1); } else if (prev_line - cur_line > 2) { tmp = 0xff; add_to_mem_block(A_LINENUMBERS, &tmp, 1); tmp = prev_line - cur_line - 1; add_to_mem_block(A_LINENUMBERS, &tmp, 1); } add_to_mem_block(A_LINENUMBERS, &delta, 1); cur_pc = mem_block[A_PROGRAM].current_size; cur_line = prev_line; cur_file = prev_file; } prev_line = line; prev_file = ifile; } void old_store_line_number_info(int ifile, int line) { static int old_offset = -1; unsigned short offset = mem_block[A_PROGRAM].current_size; unsigned short incfilenum = ifile; unsigned short file_line = line; #if 0 if (mem_block[A_LINENUMBERS].current_size >= 3 * sizeof(short) && offset == old_offset) { mem_block[A_LINENUMBERS].current_size -= 3 * sizeof(short); } old_offset = offset; #endif add_to_mem_block(A_LINENUMBERS, (char *)&offset, sizeof offset); add_to_mem_block(A_LINENUMBERS, (char *)&incfilenum, sizeof incfilenum); add_to_mem_block(A_LINENUMBERS, (char *)&file_line, sizeof file_line); } static void store_reloc_data(char type, unsigned short address, char *name, int value, char modifier) { struct reloc rel; rel.type = type; rel.modifier = modifier; rel.address = address; rel.name = string_copy(name); rel.value = value; add_to_mem_block(A_RELOC, (char *)&rel, sizeof(struct reloc)); } static char * get_type_name(int type) { static char buff[100]; static char *type_name[] = { "unknown", "int", "string", "void", "object", "mixed", "mapping", "float" }; 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_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(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); } } int remove_undefined_prototypes (int num_functions, struct function *functions) { int i; for (i = 0; i < num_functions;i++) { if (functions[i].type_flags & NAME_PROTOTYPE) { char buff[500]; sprintf(buff, "Function %s declared but never defined", functions[i].name); yyerror(buff); } } return num_functions; } /* * Compile an LPC file. */ void compile_file() { int yyparse(); prolog(); yyparse(); epilog(); } static char * get_two_types(int type1, int type2) { static char buff[100]; strcpy(buff, "( "); strcat(buff, get_type_name(type1)); strcat(buff, "vs "); strcat(buff, get_type_name(type2)); strcat(buff, ")"); return buff; } /* This is used for two purposes. Both in the BINARIES package to store change dates for includefiles in a compiled program. Also as an index of includefiles for giving correct runtime error messages references. */ void remember_include(char *buf) { struct stat sbuf; char number[128]; if (stat(buf, &sbuf)==-1) fatal("LIB not able to stat open file %s\n",buf); sprintf(number,"%d:", sbuf.st_mtime); add_to_mem_block(A_INCLUDES, number, strlen(number)); add_to_mem_block(A_INCLUDES, buf, strlen(buf) + 1); } /* * The program has been compiled. Prepare a 'struct program' to be returned. */ int current_id_number = 1; #define H_OFFSET(arg) (((char *)&(((struct program *)0)->arg)) -\ ((char *)((struct program *)0))) static struct section_desc sec_hdr[] = { {A_HEADER, -1, -1, sizeof(struct program)}, {A_INHERITS, H_OFFSET(inherit), H_OFFSET(num_inherited), sizeof(struct inherit)}, {A_FUNC_HASH, H_OFFSET(func_hash), -1, sizeof(struct function_hash)}, {-1, 0, 0, 0}, }; static struct section_desc sec_exe[] = { {A_PROGRAM, H_OFFSET(program), H_OFFSET(program_size), 1}, {A_RODATA, H_OFFSET(rodata), H_OFFSET(rodata_size), 1}, {A_FUNCTIONS, H_OFFSET(functions), H_OFFSET(num_functions), sizeof(struct function)}, {A_VARIABLES, H_OFFSET(variable_names), H_OFFSET(num_variables), sizeof(struct variable)}, {A_CFUN, H_OFFSET(cfuns), -1, sizeof(struct cfun_desc)}, {-1, 0, 0, 0}, }; static struct section_desc sec_dbg[] = { {A_LINENUMBERS, H_OFFSET(line_numbers), H_OFFSET(sizeof_line_numbers), 1}, {A_INCLUDES, H_OFFSET(include_files), H_OFFSET(sizeof_include_files), 1}, {-1, 0, 0, 0}, }; struct segment_desc segm_desc[] = { /* S_HDR */ -1, -1, H_OFFSET(total_size),sec_hdr, /* S_EXEC */ H_OFFSET(program), H_OFFSET(swap_num), H_OFFSET(exec_size),sec_exe, /* S_DBG */ H_OFFSET(line_numbers), H_OFFSET(swap_lineno_index), H_OFFSET(debug_size),sec_dbg, -1, -1, -1, (struct section_desc *)NULL, }; char * load_segments(struct segment_desc *seg, struct mem_block *mem_block) { char *hdr = 0; int size; char *block; struct section_desc *sect; for ( ; seg->sections != NULL; seg++) { size = 0; for (sect = seg->sections; sect->section != -1; sect++) size += align(mem_block[sect->section].current_size); if (size) block = xalloc(size); else block = xalloc(1); if (!hdr) hdr = block; if (seg->ptr_offset != -1) *(char **)(hdr + seg->ptr_offset) = block; for (sect = seg->sections; sect->section != -1; sect++) { memcpy(block, mem_block[sect->section].block, mem_block[sect->section].current_size); if (sect->ptr_offset != -1) *(char **)(hdr + sect->ptr_offset) = block; if (sect->num_offset != -1) *(unsigned short *)(hdr + sect->num_offset) = mem_block[sect->section].current_size / sect->ent_size; block += align(mem_block[sect->section].current_size); } if (seg->size_offset != -1) *(int *)(hdr + seg->size_offset) = size; } return hdr; } static int process_reloc(struct reloc *reloc, int num_relocs, int num_inherited) { unsigned int i, j; char *name; unsigned short fix; int psize; psize = mem_block[A_PROGRAM].current_size; link_errors = 0; for (i = 0; i < num_relocs; i++, reloc++) { if (reloc->address >= psize) fatal("Corrupt relocation address.\n"); name = reloc->name; switch (reloc->type) { int call_efun; case R_CALL: call_efun = 0; if (!defined_function(name) || function_type_mod_found & TYPE_MOD_PRIVATE && function_inherit_found != num_inherited) { if (is_simul_efun(name)) { call_efun = F_CALL_SIMUL; function_index_found = store_prog_string(name); function_inherit_found = 0; } else { link_errors++; fprintf(stderr,"%s Function %s doesn't exist.\n", inner_get_srccode_position( reloc->address, mem_block[A_LINENUMBERS].block, mem_block[A_LINENUMBERS].current_size, mem_block[A_INCLUDES].block, current_file), name); fflush(stderr); break; } } else if (strchr(name,':') || function_type_mod_found & TYPE_MOD_NO_MASK) call_efun = F_CALL_NON_VIRT; else call_efun = F_CALL_VIRT; fix = function_index_found; mem_block[A_PROGRAM].block[reloc->address - 1] = call_efun - F_OFFSET; mem_block[A_PROGRAM].block[reloc->address] = function_inherit_found; mem_block[A_PROGRAM].block[reloc->address + 1] = ((char *)&fix)[0]; mem_block[A_PROGRAM].block[reloc->address + 2] = ((char *)&fix)[1]; break; default: fatal("Unsupported reloc data (%d).\n", reloc->type); } } return link_errors; } int link_C_functions(char *name) { int i, j, errors = 0; struct cfun_desc cfun; int num_inherited; num_inherited = mem_block[A_INHERITS].current_size / sizeof(struct inherit); for(i = 0; interface[i]; i++) if (!strcmp(interface[i]->program, name)) for(j = 0; interface[i]->vars[j]; j++) { if (check_declared(interface[i]->vars[j]->name) == -1) { char buf[100]; sprintf(buf, "Variable %s (referenced from cfun) not defined.\n", interface[i]->vars[j]->name); current_line = -1; yyerror(buf); } if (variable_inherit_found == 255) variable_inherit_found = num_inherited; cfun.idx = variable_index_found - num_inherited; cfun.inh = variable_inherit_found; add_to_mem_block(A_CFUN, (char *)&cfun, sizeof(cfun)); } return errors; } void epilog() { int size, i, j, ix, psize; char *p; struct function *funp; extern int pragma_resident; extern int current_time; int functions_left; /* Functions left after removing dangling prototypes */ extern total_program_size; char *l; int has_invariant = -1; int lsize; struct inherit inherit_self; int has_dtor, has_ctor; #ifdef DEBUG if (num_parse_error == 0 && type_of_arguments.current_size != 0) fatal("Failed to deallocate argument type stack\n"); #endif /* * Define the .CTOR function, but only if there was any code * to initialize. */ if (defined_function(".CTOR") && !function_prog_found) { has_ctor = function_index_found; } else has_ctor = -1; if (defined_function(".DTOR") && !function_prog_found) { has_dtor = function_index_found; } else has_dtor = -1; if (first_last_initializer_end != last_initializer_end) { if (has_ctor != -1) { struct function *funp; funp = &((struct function *) mem_block[A_FUNCTIONS].block)[has_ctor]; upd_short(last_initializer_end, funp->offset); funp->offset = 0; } else { has_ctor = mem_block[A_FUNCTIONS].current_size / sizeof(struct function); define_new_function(".CTOR", 0, 0, 0, TYPE_MOD_PRIVATE | TYPE_VOID, 0); /* * Change the last jump after the last initializer into a * return(1) statement. */ mem_block[A_PROGRAM].block[last_initializer_end - 1] = F_DO_INVARIANTS - F_OFFSET; mem_block[A_PROGRAM].block[last_initializer_end] = F_CONST1 - F_OFFSET; mem_block[A_PROGRAM].block[last_initializer_end + 1] = F_RETURN - F_OFFSET; } } if (invariant_last_address) { has_invariant = mem_block[A_FUNCTIONS].current_size / sizeof(struct function); define_new_function(".INV", 0, 0, invariant_first_address, TYPE_MOD_PRIVATE | TYPE_VOID, 0); mem_block[A_PROGRAM].block[invariant_last_address - 1] = F_CONST1 - F_OFFSET; mem_block[A_PROGRAM].block[invariant_last_address] = F_RETURN - F_OFFSET; } else has_invariant = -1; functions_left = remove_undefined_prototypes ( mem_block[A_FUNCTIONS].current_size / sizeof (struct function), (struct function *)mem_block[A_FUNCTIONS].block); /* I don't like doing this, but I see no other way. |D| */ mem_block[A_FUNCTIONS].current_size = functions_left * sizeof (struct function); if (!(num_parse_error || inherit_file)) { link_C_functions(current_file); link_errors = 0; process_reloc((struct reloc *)mem_block[A_RELOC].block, mem_block[A_RELOC].current_size / sizeof(struct reloc), mem_block[A_INHERITS].current_size / sizeof(struct inherit)); num_parse_error += link_errors; } { int c; for (c = 0; c < mem_block[A_RELOC].current_size / sizeof(struct reloc); c++) free(((struct reloc *)mem_block[A_RELOC].block)[c].name); } inherit_self.type = 0; inherit_self.name = make_shared_string("this"); add_to_mem_block(A_INHERITS, (char *) &inherit_self, sizeof(struct inherit)); add_to_mem_block(A_HEADER, (char *)&NULL_program, sizeof(NULL_program)); { int num_func = mem_block[A_FUNCTIONS].current_size / sizeof(struct function); mem_block[A_FUNC_HASH].current_size = num_func * sizeof(struct function_hash); if (num_func) { mem_block[A_FUNC_HASH].block = realloc((char *)mem_block[A_FUNC_HASH].block, num_func * sizeof(struct function_hash)); mem_block[A_FUNC_HASH].max_size = mem_block[A_FUNC_HASH].current_size; } hash_func(num_func, (struct function *)mem_block[A_FUNCTIONS].block, (struct function_hash *)mem_block[A_FUNC_HASH].block); } prog = (struct program *)load_segments(segm_desc, mem_block); prog->ref = 0; prog->swap_num = 0; prog->invariant = has_invariant; prog->ctor_index = has_ctor; prog->dtor_index = has_dtor; prog->mod_time = current_time; prog->name = string_copy(current_file); prog->id_number = current_id_number++; prog->cpu = 0; prog->swap_lineno_index = 0; prog->flags = (pragma_no_inherit ? PRAGMA_NO_INHERIT : 0) | (pragma_no_clone ? PRAGMA_NO_CLONE : 0) | (pragma_resident ? PRAGMA_RESIDENT : 0); prog->inherit[prog->num_inherited - 1].prog = prog; for (i = ix = 0; i < (int)prog->num_inherited; i++) { int inh = find_inherit(prog, prog->inherit[i].prog); if (inh == i) { prog->inherit[i].variable_index_offset = ix; ix += prog->inherit[i].prog->num_variables; prog->inherit[i].type &= ~TYPE_MOD_SECOND; } else { prog->inherit[i].variable_index_offset = prog->inherit[inh].variable_index_offset; prog->inherit[i].type |= TYPE_MOD_SECOND; } } /* don't forget the following: * prog->sizeof_argument_types = * mem_block[A_ARGUMENT_TYPES??].current_size); * if you have fixed it one day .... ok ? :-=) * remember to remove the above change to total_size !!!!!!!! */ prog->sizeof_argument_types=0; /* NOTE: Don't forget to hash the argument types along with the functions */ prog->argument_types = 0; /* For now. Will be fixed someday */ prog->type_start = 0; for (i = 0; i < prog->num_inherited; i++) { reference_prog (prog->inherit[i].prog, "inheritance"); } prog->load_time = current_time; register_program(prog); /* 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 */ total_program_size += prog->exec_size; total_prog_block_size += prog->total_size; total_num_prog_blocks += 1; for (i=0; i < A_NUM; i++) free((char *)mem_block[i].block); if (num_parse_error || inherit_file) { free_prog(prog, 0); prog = 0; } return; } /* * Initialize the environment that the compiler needs. */ static void prolog() { int i; if (type_of_arguments.block == 0) { type_of_arguments.max_size = 100; type_of_arguments.block = xalloc(type_of_arguments.max_size); } type_of_arguments.current_size = 0; approved_object = 0; last_push_indexed = -1; last_push_local = -1; last_push_identifier = -1; prog = 0; /* 0 means fail to load. */ comp_stackp = 0; /* Local temp stack used by compiler */ current_continue_address = 0; current_break_address = 0; 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; } add_new_init_jump(); first_last_initializer_end = last_initializer_end; } /* * Add a trailing jump after the last initialization code. */ void add_new_init_jump() { /* * Add a new jump. */ ins_f_byte(F_JUMP); last_initializer_end = mem_block[A_PROGRAM].current_size; ins_short(0); } int search_for_ext_function(char *name, struct program *prog) { char *ix; int i, res; ix = strchr(name, ':'); if (ix == NULL) { /* its a simple name so search for it the normal way */ return search_for_function(name, prog); } if (ix - name == 4 && !strncmp(name, "this", 4)) return search_for_ext_function(ix + 2, prog); for (i = prog->num_inherited - 2; i >= 0; i--) { if (ix == name || strlen(prog->inherit[i].name) == ix - name && strncmp(prog->inherit[i].name, name, ix - name) == 0) { res = search_for_ext_function(ix + 2, prog->inherit[i].prog); if (res) { int type_mod; /* adjust values and return */ function_inherit_found += i - (prog->inherit[i].prog->num_inherited - 1); type_mod = prog->inherit[function_inherit_found].type; /* Correct function_type_mod_found */ if (function_type_mod_found & TYPE_MOD_PRIVATE) type_mod &= ~TYPE_MOD_PUBLIC; if (function_type_mod_found & TYPE_MOD_PUBLIC) type_mod &= ~TYPE_MOD_PRIVATE; function_type_mod_found |= type_mod; return res; } else { /* skip program and continue */ i -= prog->inherit[i].prog->num_inherited - 1; } } } return 0; }