View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0000394 | LDMud 3.3 | Compilation, Installation | public | 2005-06-24 07:37 | 2018-01-29 21:57 |
Reporter | Gnomi | Assigned To | |||
Priority | normal | Severity | minor | Reproducibility | always |
Status | closed | Resolution | fixed | ||
Platform | i686 | OS | Debian GNU/Linux | OS Version | 3.1 |
Product Version | 3.3 | ||||
Fixed in Version | 3.3.714 | ||||
Summary | 0000394: Types mixed up | ||||
Description | Hi, this is an interesting one. The line int i = to_int(({float})0); which initializes a global variable yields (in 3.2, 3.3 and 3.4) Type mismatch ( private float vs int ) when initializing i. The reason is, that the driver keeps the last type in the global variable current_type and thinks, this is the type of the variable that should be initialized. But ({float}) also overwrites current_type, which then results in this error. Handling '({ })' specially wont help, because in 3.3 and 3.4 the error occurs also with the following line: closure cl = (: int i = 10; :); The cleanest solution would be to get rid of this global variable, but that requires a rewrite of the grammar (drag 'type' from 'def := type name_list' into 'new_name' from 'name_list'). If you're interested I could try to come up with such a patch. Greetings, Gnomi. | ||||
Tags | No tags attached. | ||||
Attached Files | 3.3currenttype.diff (35,135 bytes)
Index: src/prolang.y =================================================================== --- src/prolang.y (Revision 22) +++ src/prolang.y (Arbeitskopie) @@ -871,10 +871,6 @@ */ #endif /* USE_STRUCTS */ -static fulltype_t current_type; - /* The current basic type (reference not counted). - */ - static p_uint last_expression; /* If >= 0, the address of the last instruction which by itself left * a value on the stack. If there is no such instruction, the value @@ -987,6 +983,8 @@ /* Forward declarations */ struct lvalue_s; /* Defined within YYSTYPE aka %union */ +static void define_local_variable (ident_t* name, fulltype_t actual_type, typeflags_t opt_star, struct lvalue_s *lv, Bool redeclare, Bool with_init); +static void init_local_variable (ident_t* name, struct lvalue_s *lv, int assign_op, fulltype_t type2); static Bool add_lvalue_code ( struct lvalue_s * lv, int instruction); static void insert_pop_value(void); static void arrange_protected_lvalue(p_int, int, p_int, int); @@ -3406,7 +3404,175 @@ } /* verify_declared() */ /*-------------------------------------------------------------------------*/ +static int +define_global_variable (ident_t* name, fulltype_t actual_type, typeflags_t opt_star, Bool with_init) +/* This is called directly from a parser rule: <type> [*] <name> + * if with_init is true, then an initialization of this variable will follow. + * It creates the global variable and returns its index. + */ +{ + int i; + + variables_defined = MY_TRUE; + + if (!(actual_type.typeflags & (TYPE_MOD_PRIVATE | TYPE_MOD_PUBLIC + | TYPE_MOD_PROTECTED))) + { + actual_type.typeflags |= default_varmod; + } + + if (actual_type.typeflags & TYPE_MOD_VARARGS) + { + yyerror("can't declare a variable as varargs"); + actual_type.typeflags &= ~TYPE_MOD_VARARGS; + } + + actual_type.typeflags |= opt_star; + + if (!pragma_share_variables) + actual_type.typeflags |= VAR_INITIALIZED; + + define_variable(name, actual_type); + i = verify_declared(name); /* Is the var declared? */ + + /* Initialize float values with 0.0. */ + if (with_init + || (!(actual_type.typeflags & TYPE_MOD_POINTER) + && (actual_type.typeflags & PRIMARY_TYPE_MASK) == TYPE_FLOAT + )) + { + + /* Prepare the init code */ + transfer_init_control(); + + /* If this is the first variable initialization and + * pragma_share_variables is in effect, insert + * the check for blueprint/clone initialisation: + * if (clonep(this_object())) return 1; + */ + if (!variables_initialized && pragma_share_variables) + { + ins_f_code(F_THIS_OBJECT); + ins_f_code(F_CLONEP); + ins_f_code(F_BRANCH_WHEN_ZERO); + ins_byte(2); + ins_f_code(F_CONST1); + ins_f_code(F_RETURN); + } + + /* Initialize floats with 0.0 */ + if(!with_init) + { + PREPARE_INSERT(5) + /* Must come after the non-local program code inserts! */ + + add_f_code(F_FCONST0); + +#ifdef DEBUG + if (i & VIRTUAL_VAR_TAG) + { + /* When we want to allow 'late' initializers for + * inherited variables, it must have a distinct syntax, + * lest name clashs remain undetected, making LPC code + * hard to debug. + */ + fatal("Newly declared variable is virtual\n"); + } +#endif + variables_initialized = MY_TRUE; /* We have __INIT code */ + if (!pragma_share_variables) + VARIABLE(i)->type.typeflags |= VAR_INITIALIZED; + + /* Push the variable reference and create the assignment */ + + if (i + num_virtual_variables > 0xff) + { + add_f_code(F_PUSH_IDENTIFIER16_LVALUE); + add_short(i + num_virtual_variables); + CURRENT_PROGRAM_SIZE += 1; + } + else + { + add_f_code(F_PUSH_IDENTIFIER_LVALUE); + add_byte(i + num_virtual_variables); + } + + /* Ok, assign */ + add_f_code(F_VOID_ASSIGN); + CURRENT_PROGRAM_SIZE += 4; + add_new_init_jump(); + } /* PREPARE_INSERT() block */ + } /* if (float variable) */ + + return i; +} /* define_global_variable() */ + +/*-------------------------------------------------------------------------*/ static void +init_global_variable (int i, ident_t* name, fulltype_t actual_type, typeflags_t opt_star, int assign_op, fulltype_t exprtype) +/* This is called directly from a parser rule: <type> [*] <name> = <expr> + * It will be called after the call to define_global_variable(). + * It assigns the result of <expr> to the variable. + */ +{ + PREPARE_INSERT(4) + + if (!(actual_type.typeflags & (TYPE_MOD_PRIVATE | TYPE_MOD_PUBLIC + | TYPE_MOD_PROTECTED))) + { + actual_type.typeflags |= default_varmod; + } + + actual_type.typeflags |= opt_star; + +#ifdef DEBUG + if (i & VIRTUAL_VAR_TAG) + { + /* When we want to allow 'late' initializers for + * inherited variables, it must have a distinct syntax, + * lest name clashs remain undetected, making LPC code + * hard to debug. + */ + fatal("Newly declared variable is virtual\n"); + } +#endif + variables_initialized = MY_TRUE; /* We have __INIT code */ + + /* Push the variable reference and create the assignment */ + + if (i + num_virtual_variables > 0xff) + { + add_f_code(F_PUSH_IDENTIFIER16_LVALUE); + add_short(i + num_virtual_variables); + CURRENT_PROGRAM_SIZE += 1; + } + else + { + add_f_code(F_PUSH_IDENTIFIER_LVALUE); + add_byte(i + num_virtual_variables); + } + + /* Only simple assigns are allowed */ + if (assign_op != F_ASSIGN) + yyerror("Illegal initialization"); + + /* Do the types match? */ + actual_type.typeflags &= TYPE_MOD_MASK; + if (!compatible_types(actual_type, exprtype, MY_TRUE)) + { + yyerrorf("Type mismatch %s when initializing %s" + , get_two_types(actual_type, exprtype) + , get_txt(name->name)); + } + + /* Ok, assign */ + add_f_code(F_VOID_ASSIGN); + CURRENT_PROGRAM_SIZE += 3; + add_new_init_jump(); +} /* init_global_variable() */ + +/*-------------------------------------------------------------------------*/ +static void store_function_header ( p_int start , string_t * name, fulltype_t returntype , int num_args, int num_vars @@ -5450,6 +5616,7 @@ %type <fulltype> type %type <fulltype> opt_basic_type basic_type %type <fulltype> non_void_type opt_basic_non_void_type basic_non_void_type +%type <fulltype> name_list member_name_list local_name_list %type <inh_flags> inheritance_qualifier inheritance_qualifiers %type <typeflags> inheritance_modifier_list inheritance_modifier %ifdef USE_NEW_INLINES @@ -5470,7 +5637,6 @@ %type <lrvalue> parse_command %endif %type <lvalue> lvalue name_lvalue local_name_lvalue foreach_var_lvalue -%type <lvalue> new_local_name %type <index> index_range index_expr %type <case_label> case_label %type <address> optional_else @@ -5617,10 +5783,8 @@ #endif /* USE_NEW_INLINES */ } - | type name_list ';' /* Variable definition */ + | name_list ';' /* Variable definition */ { - if ($1.typeflags == 0) - yyerror("Missing type"); #ifndef USE_NEW_INLINES if (first_inline_fun) insert_inline_fun_now = MY_TRUE; @@ -5817,7 +5981,7 @@ context_decl: - basic_type local_name_list + local_name_list { /* Empty action to void value from local_name_list */ } ; /* context_decl */ @@ -5933,32 +6097,43 @@ ; /* member_list */ member: - basic_non_void_type member_name_list ';' + member_name_list ';' { - /* The member_name_list adds the struct members, using - * the value of current_type set by basic_non_void_type. - */ + /* The member_name_list adds the struct members. */ } ; /* member */ member_name_list: - member_name - | member_name_list ',' member_name -; /* member_name_list */ - -member_name: - optional_star L_IDENTIFIER + basic_non_void_type optional_star L_IDENTIFIER { + fulltype_t actual_type = $1; vartype_t type; - current_type.typeflags |= $1; - assign_full_to_vartype(&type, current_type); - add_struct_member($2->name, type, NULL); - if ($2->type == I_TYPE_UNKNOWN) - free_shared_identifier($2); + + actual_type.typeflags |= $2; + + assign_full_to_vartype(&type, actual_type); + add_struct_member($3->name, type, NULL); + if ($3->type == I_TYPE_UNKNOWN) + free_shared_identifier($3); + + $$ = $1; } -; /* member_name */ + | member_name_list ',' optional_star L_IDENTIFIER + { + fulltype_t actual_type = $1; + vartype_t type; + + actual_type.typeflags |= $3; + + assign_full_to_vartype(&type, actual_type); + add_struct_member($4->name, type, NULL); + if ($4->type == I_TYPE_UNKNOWN) + free_shared_identifier($4); + + $$ = $1; + } +; /* member_name_list */ - %endif /* USE_STRUCTS */ /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ @@ -6373,14 +6548,12 @@ type: type_modifier_list opt_basic_type { set_fulltype($$, $1 | $2.typeflags, $2.t_struct); - current_type = $$; } ; non_void_type: type_modifier_list opt_basic_non_void_type { set_fulltype($$, $1 | $2.typeflags, $2.t_struct); - current_type = $$; } ; @@ -6411,15 +6584,15 @@ basic_non_void_type: - L_STATUS { $$ = Type_Number; current_type = $$; } - | L_INT { $$ = Type_Number; current_type = $$; } - | L_STRING_DECL { $$ = Type_String; current_type = $$; } - | L_OBJECT { $$ = Type_Object; current_type = $$; } - | L_CLOSURE_DECL { $$ = Type_Closure; current_type = $$; } - | L_SYMBOL_DECL { $$ = Type_Symbol; current_type = $$; } - | L_FLOAT_DECL { $$ = Type_Float; current_type = $$; } - | L_MAPPING { $$ = Type_Mapping; current_type = $$; } - | L_MIXED { $$ = Type_Any; current_type = $$; } + L_STATUS { $$ = Type_Number; } + | L_INT { $$ = Type_Number; } + | L_STRING_DECL { $$ = Type_String; } + | L_OBJECT { $$ = Type_Object; } + | L_CLOSURE_DECL { $$ = Type_Closure; } + | L_SYMBOL_DECL { $$ = Type_Symbol; } + | L_FLOAT_DECL { $$ = Type_Float; } + | L_MAPPING { $$ = Type_Mapping; } + | L_MIXED { $$ = Type_Any; } %ifdef USE_STRUCTS | L_STRUCT identifier { @@ -6438,7 +6611,6 @@ } free_mstring($2); - current_type = $$; } %endif /* USE_STRUCTS */ ; /* basic_non_void_type */ @@ -6446,7 +6618,7 @@ basic_type: basic_non_void_type - | L_VOID { $$ = Type_Void; current_type = $$; } + | L_VOID { $$ = Type_Void; } ; /* basic_type */ @@ -6561,209 +6733,55 @@ ; /* new_arg_name */ + name_list: - new_name - | name_list ',' new_name; - - -new_name: /* Simple variable definition */ - optional_star L_IDENTIFIER + type optional_star L_IDENTIFIER { %line - fulltype_t actual_type = current_type; + if ($1.typeflags == 0) + yyerror("Missing type"); - variables_defined = MY_TRUE; + define_global_variable($3, $1, $2, MY_FALSE); + $$ = $1; + } - if (!(actual_type.typeflags & (TYPE_MOD_PRIVATE | TYPE_MOD_PUBLIC - | TYPE_MOD_PROTECTED))) - { - actual_type.typeflags |= default_varmod; - } + /* Variable definition with initialization */ - if (actual_type.typeflags & TYPE_MOD_VARARGS) - { - yyerror("can't declare a variable as varargs"); - actual_type.typeflags &= ~TYPE_MOD_VARARGS; - } + | type optional_star L_IDENTIFIER + { + if ($1.typeflags == 0) + yyerror("Missing type"); - actual_type.typeflags |= $1; + $<number>$ = define_global_variable($3, $1, $2, MY_TRUE); + } - if (!pragma_share_variables) - actual_type.typeflags |= VAR_INITIALIZED; + L_ASSIGN expr0 + { + init_global_variable($<number>4, $3, $1, $2, $5, $6.type); + $$ = $1; + } - define_variable($2, actual_type); - - if (!(actual_type.typeflags & TYPE_MOD_POINTER) - && (actual_type.typeflags & PRIMARY_TYPE_MASK) == TYPE_FLOAT - ) - { - int i = verify_declared($2); /* Is the var declared? */ - - /* Prepare the init code */ - transfer_init_control(); - - /* If this is the first variable initialization and - * pragma_share_variables is in effect, insert - * the check for blueprint/clone initialisation: - * if (clonep(this_object())) return 1; - */ - if (!variables_initialized && pragma_share_variables) - { - ins_f_code(F_THIS_OBJECT); - ins_f_code(F_CLONEP); - ins_f_code(F_BRANCH_WHEN_ZERO); - ins_byte(2); - ins_f_code(F_CONST1); - ins_f_code(F_RETURN); - } - - { - PREPARE_INSERT(5) - /* Must come after the non-local program code inserts! */ - - add_f_code(F_FCONST0); - -#ifdef DEBUG - if (i & VIRTUAL_VAR_TAG) - { - /* When we want to allow 'late' initializers for - * inherited variables, it must have a distinct syntax, - * lest name clashs remain undetected, making LPC code - * hard to debug. - */ - fatal("Newly declared variable is virtual\n"); - } -#endif - variables_initialized = MY_TRUE; /* We have __INIT code */ - if (!pragma_share_variables) - VARIABLE(i)->type.typeflags |= VAR_INITIALIZED; - - /* Push the variable reference and create the assignment */ - - if (i + num_virtual_variables > 0xff) - { - add_f_code(F_PUSH_IDENTIFIER16_LVALUE); - add_short(i + num_virtual_variables); - CURRENT_PROGRAM_SIZE += 1; - } - else - { - add_f_code(F_PUSH_IDENTIFIER_LVALUE); - add_byte(i + num_virtual_variables); - } - - /* Ok, assign */ - add_f_code(F_VOID_ASSIGN); - CURRENT_PROGRAM_SIZE += 4; - add_new_init_jump(); - } /* PREPARE_INSERT() block */ - } /* if (float variable) */ + | name_list ',' optional_star L_IDENTIFIER + { + define_global_variable($4, $1, $3, MY_FALSE); + $$ = $1; } /* Variable definition with initialization */ - | optional_star L_IDENTIFIER + | name_list ',' optional_star L_IDENTIFIER { - fulltype_t actual_type = current_type; - - variables_defined = MY_TRUE; - - if (!(actual_type.typeflags & (TYPE_MOD_PRIVATE | TYPE_MOD_PUBLIC - | TYPE_MOD_PROTECTED))) - { - actual_type.typeflags |= default_varmod; - } - - actual_type.typeflags |= $1; - - define_variable($2, actual_type); - $<number>$ = verify_declared($2); /* Is the var declared? */ - - /* Prepare the init code */ - transfer_init_control(); - - /* If this is the first variable initialization and - * pragma_share_variables is in effect, insert - * the check for blueprint/clone initialisation: - * if (clonep(this_object())) return 1; - */ - if (!variables_initialized && pragma_share_variables) - { - ins_f_code(F_THIS_OBJECT); - ins_f_code(F_CLONEP); - ins_f_code(F_BRANCH_WHEN_ZERO); - ins_byte(2); - ins_f_code(F_CONST1); - ins_f_code(F_RETURN); - } + $<number>$ = define_global_variable($4, $1, $3, MY_TRUE); } L_ASSIGN expr0 - { - fulltype_t actual_type = current_type; - fulltype_t exprtype = $5.type; - int i = $<number>3; - PREPARE_INSERT(4) - - if (!(actual_type.typeflags & (TYPE_MOD_PRIVATE | TYPE_MOD_PUBLIC - | TYPE_MOD_PROTECTED))) - { - actual_type.typeflags |= default_varmod; - } - - actual_type.typeflags |= $1; - -#ifdef DEBUG - if (i & VIRTUAL_VAR_TAG) - { - /* When we want to allow 'late' initializers for - * inherited variables, it must have a distinct syntax, - * lest name clashs remain undetected, making LPC code - * hard to debug. - */ - fatal("Newly declared variable is virtual\n"); - } -#endif - variables_initialized = MY_TRUE; /* We have __INIT code */ - if (!pragma_share_variables) - VARIABLE(i)->type.typeflags |= VAR_INITIALIZED; - - /* Push the variable reference and create the assignment */ - - if (i + num_virtual_variables > 0xff) - { - add_f_code(F_PUSH_IDENTIFIER16_LVALUE); - add_short(i + num_virtual_variables); - CURRENT_PROGRAM_SIZE += 1; - } - else - { - add_f_code(F_PUSH_IDENTIFIER_LVALUE); - add_byte(i + num_virtual_variables); - } - - /* Only simple assigns are allowed */ - if ($4 != F_ASSIGN) - yyerror("Illegal initialization"); - - /* Do the types match? */ - actual_type.typeflags &= TYPE_MOD_MASK; - if (!compatible_types(actual_type, exprtype, MY_TRUE)) - { - yyerrorf("Type mismatch %s when initializing %s" - , get_two_types(actual_type, exprtype) - , get_txt($2->name)); - } - - /* Ok, assign */ - add_f_code(F_VOID_ASSIGN); - CURRENT_PROGRAM_SIZE += 3; - add_new_init_jump(); + init_global_variable($<number>5, $4, $1, $3, $6, $7.type); + $$ = $1; } -; /* new_name */ +; /* name_list */ /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ @@ -6803,224 +6821,81 @@ statements: /* empty */ - | statements basic_type local_name_list ';' + | statements local_name_list ';' | statements statement ; local_name_list: - new_local - | local_name_list ',' new_local -; - - -new_local: - new_local_name + basic_type optional_star L_IDENTIFIER { - /* If this is a float variable, we need to insert an appropriate - * initializer, as the default svalue-0 is not a valid float value. - */ - - Bool need_value = MY_FALSE; -%line - -#ifdef USE_NEW_INLINES - /* When parsing context variables, the context_closure instruction - * expects a value on the stack. If we do a float initialization, - * we leave the 0.0 on the stack, otherwise we'll push a 0. - * For normal float locals, we'll create the bytecode to assign - * the float 0. - */ - need_value = current_inline && current_inline->parse_context; -#endif /* USE_NEW_INLINES */ - - if (!($1.type.typeflags & TYPE_MOD_POINTER) - && ($1.type.typeflags & PRIMARY_TYPE_MASK) == TYPE_FLOAT - ) - { - ins_f_code(F_FCONST0); - - if (!need_value) - { - if (!add_lvalue_code(&$1, F_VOID_ASSIGN)) - YYACCEPT; - } - - need_value = MY_FALSE; - } /* if (float variable) */ - - if (need_value) /* If we still need a value... */ - { - ins_number(0); - } + struct lvalue_s lv; + define_local_variable($3, $1, $2, &lv, MY_FALSE, MY_FALSE); + + $$ = $1; } - - | new_local_name L_ASSIGN expr0 + | basic_type optional_star L_LOCAL { - /* We got a "<name> = <expr>" type declaration. */ - - fulltype_t type2 = $3.type; - -%line -#ifdef USE_NEW_INLINES -#ifdef DEBUG_INLINES -if (current_inline && current_inline->parse_context) printf("DEBUG: inline context decl: name = expr, program_size %d\n", CURRENT_PROGRAM_SIZE); -#endif /* DEBUG_INLINES */ -#endif /* USE_NEW_INLINES */ - type2.typeflags &= TYPEID_MASK; - - /* Check the assignment for validity */ - if (exact_types.typeflags && !compatible_types($1.type, type2, MY_TRUE)) - { - yyerrorf("Bad assignment %s", get_two_types($1.type, type2)); - } - - if ($2 != F_ASSIGN) - { - yyerror("Only plain assignments allowed here"); - } - - if (type2.typeflags & TYPE_MOD_REFERENCE) - yyerror("Can't trace reference assignments"); - - /* If we're parsing a context variable, just leave the - * value on the stack for the context_closure instruction. - * For normal locals, add the bytecode to create the lvalue - * and do the assignment. - */ -#ifdef USE_NEW_INLINES - if (!current_inline || !current_inline->parse_context) -#endif /* USE_NEW_INLINES */ - { - if (!add_lvalue_code(&$1, F_VOID_ASSIGN)) - YYACCEPT; - } /* parsed context var */ + struct lvalue_s lv; + define_local_variable($3, $1, $2, &lv, MY_TRUE, MY_FALSE); + + $$ = $1; } -; /* new_local */ - -new_local_name: - optional_star L_IDENTIFIER + | basic_type optional_star L_IDENTIFIER { - /* A new local variable */ - - block_scope_t *scope = block_scope + block_depth - 1; - ident_t *q; - fulltype_t actual_type = current_type; - - actual_type.typeflags |= $1; - -#ifdef USE_NEW_INLINES - if (current_inline && current_inline->parse_context) - { -#ifdef DEBUG_INLINES -printf("DEBUG: context name '%s'\n", get_txt($2->name)); -#endif /* DEBUG_INLINES */ - q = add_context_name($2, actual_type, -1); - $$.u.simple[0] = F_PUSH_CONTEXT_LVALUE; - $$.u.simple[1] = q->u.local.context; - } - else - { - q = add_local_name($2, actual_type, block_depth); - if (use_local_scopes && scope->num_locals == 1) - { - /* First definition of a local, so insert the - * clear_locals bytecode and remember its position - */ - scope->addr = mem_block[A_PROGRAM].current_size; - ins_f_code(F_CLEAR_LOCALS); - ins_byte(scope->first_local); - ins_byte(0); - } - - $$.u.simple[0] = F_PUSH_LOCAL_VARIABLE_LVALUE; - $$.u.simple[1] = q->u.local.num; - } -#else /* USE_NEW_INLINES */ - q = add_local_name($2, actual_type, block_depth, MY_FALSE); - - if (use_local_scopes && scope->num_locals == 1) - { - /* First definition of a local, so insert the - * clear_locals bytecode and remember its position - */ - scope->addr = mem_block[A_PROGRAM].current_size; - ins_f_code(F_CLEAR_LOCALS); - ins_byte(scope->first_local); - ins_byte(0); - } - - $$.u.simple[0] = F_PUSH_LOCAL_VARIABLE_LVALUE; - $$.u.simple[1] = q->u.local.num; -#endif /* USE_NEW_INLINES */ - $$.length = 0; - $$.type = actual_type; + define_local_variable($3, $1, $2, &$<lvalue>$, MY_FALSE, MY_TRUE); } - - | optional_star L_LOCAL + L_ASSIGN expr0 { - /* A local name is redeclared. If this happens on a deeper - * level, it is even legal. - */ - - ident_t *q; - block_scope_t *scope = block_scope + block_depth - 1; - fulltype_t actual_type = current_type; - - actual_type.typeflags |= $1; - -#ifdef USE_NEW_INLINES - if (current_inline && current_inline->parse_context) - { -#ifdef DEBUG_INLINES -printf("DEBUG: context name '%s'\n", get_txt($2->name)); -#endif /* DEBUG_INLINES */ - if (current_inline->block_depth+1 <= $2->u.local.depth) - yyerrorf("Illegal to redeclare local name '%s'" - , get_txt($2->name)); - - q = add_context_name($2, actual_type, -1); - $$.u.simple[0] = F_PUSH_CONTEXT_LVALUE; - $$.u.simple[1] = q->u.local.context; - } - else - { - q = redeclare_local($2, actual_type, block_depth); - if (use_local_scopes && scope->num_locals == 1) - { - /* First definition of a local, so insert the - * clear_locals bytecode and remember its position - */ - scope->addr = mem_block[A_PROGRAM].current_size; - ins_f_code(F_CLEAR_LOCALS); - ins_byte(scope->first_local); - ins_byte(0); - } - - $$.u.simple[0] = F_PUSH_LOCAL_VARIABLE_LVALUE; - $$.u.simple[1] = q->u.local.num; - } -#else /* USE_NEW_INLINES */ - q = redeclare_local($2, actual_type, block_depth); - - if (use_local_scopes && scope->num_locals == 1) - { - /* First definition of a local, so insert the - * clear_locals bytecode and remember its position - */ - scope->addr = mem_block[A_PROGRAM].current_size; - ins_f_code(F_CLEAR_LOCALS); - ins_byte(scope->first_local); - ins_byte(0); - } - - $$.u.simple[0] = F_PUSH_LOCAL_VARIABLE_LVALUE; - $$.u.simple[1] = q->u.local.num; -#endif /* USE_NEW_INLINES */ - $$.length = 0; - $$.type = actual_type; + init_local_variable($3, &$<lvalue>4, $5, $6.type); + + $$ = $1; } -; /* new_local_name */ + | basic_type optional_star L_LOCAL + { + define_local_variable($3, $1, $2, &$<lvalue>$, MY_TRUE, MY_TRUE); + } + L_ASSIGN expr0 + { + init_local_variable($3, &$<lvalue>4, $5, $6.type); + + $$ = $1; + } + | local_name_list ',' optional_star L_IDENTIFIER + { + struct lvalue_s lv; + define_local_variable($4, $1, $3, &lv, MY_FALSE, MY_FALSE); + + $$ = $1; + } + | local_name_list ',' optional_star L_LOCAL + { + struct lvalue_s lv; + define_local_variable($4, $1, $3, &lv, MY_TRUE, MY_FALSE); + + $$ = $1; + } + | local_name_list ',' optional_star L_IDENTIFIER + { + define_local_variable($4, $1, $3, &$<lvalue>$, MY_FALSE, MY_TRUE); + } + L_ASSIGN expr0 + { + init_local_variable($4, &$<lvalue>5, $6, $7.type); + + $$ = $1; + } + | local_name_list ',' optional_star L_LOCAL + { + define_local_variable($4, $1, $3, &$<lvalue>$, MY_TRUE, MY_TRUE); + } + L_ASSIGN expr0 + { + init_local_variable($4, &$<lvalue>5, $6, $7.type); + + $$ = $1; + } +; /* local_name_list */ statement: @@ -11516,8 +11391,14 @@ local_name_lvalue: - basic_type new_local_name - { $$ = $2; } + basic_type optional_star L_IDENTIFIER + { + define_local_variable($3, $1, $2, &$$, MY_FALSE, MY_TRUE); + } + | basic_type optional_star L_LOCAL + { + define_local_variable($3, $1, $2, &$$, MY_TRUE, MY_TRUE); + } ; /* local_name_lvalue */ @@ -13820,6 +13701,173 @@ /*=========================================================================*/ /*-------------------------------------------------------------------------*/ +static void +define_local_variable (ident_t* name, fulltype_t actual_type, typeflags_t opt_star, struct lvalue_s *lv, Bool redeclare, Bool with_init) +/* This is called directly from a parser rule: <type> [*] <name> + * if with_init is true, then an initialization of this variable will follow. + * if redeclare is true, then a local name is redeclared. + * It creates the local variable and returns the corresponding lvalue + * in lv. + */ +{ + /* redeclare: + * MY_FALSE: A new local variable + * MY_TRUE: A local name is redeclared. If this happens + * on a deeper level, it is even legal. + */ + + block_scope_t *scope = block_scope + block_depth - 1; + ident_t *q; + + actual_type.typeflags |= opt_star; + +#ifdef USE_NEW_INLINES + if (current_inline && current_inline->parse_context) + { +#ifdef DEBUG_INLINES +printf("DEBUG: context name '%s'\n", get_txt(name->name)); +#endif /* DEBUG_INLINES */ + + if (redeclare && current_inline->block_depth+1 <= name->u.local.depth) + yyerrorf("Illegal to redeclare local name '%s'" + , get_txt(name->name)); + + q = add_context_name(name, actual_type, -1); + lv->u.simple[0] = F_PUSH_CONTEXT_LVALUE; + lv->u.simple[1] = q->u.local.context; + } + else + { + if(redeclare) + q = redeclare_local(name, actual_type, block_depth); + else + q = add_local_name(name, actual_type, block_depth); + if (use_local_scopes && scope->num_locals == 1) + { + /* First definition of a local, so insert the + * clear_locals bytecode and remember its position + */ + scope->addr = mem_block[A_PROGRAM].current_size; + ins_f_code(F_CLEAR_LOCALS); + ins_byte(scope->first_local); + ins_byte(0); + } + + lv->u.simple[0] = F_PUSH_LOCAL_VARIABLE_LVALUE; + lv->u.simple[1] = q->u.local.num; + } +#else /* USE_NEW_INLINES */ + if (redeclare) + q = redeclare_local(name, actual_type, block_depth); + else + q = add_local_name(name, actual_type, block_depth, MY_FALSE); + + if (use_local_scopes && scope->num_locals == 1) + { + /* First definition of a local, so insert the + * clear_locals bytecode and remember its position + */ + scope->addr = mem_block[A_PROGRAM].current_size; + ins_f_code(F_CLEAR_LOCALS); + ins_byte(scope->first_local); + ins_byte(0); + } + + lv->u.simple[0] = F_PUSH_LOCAL_VARIABLE_LVALUE; + lv->u.simple[1] = q->u.local.num; +#endif /* USE_NEW_INLINES */ + lv->length = 0; + lv->type = actual_type; + + if (!with_init) + { + /* If this is a float variable, we need to insert an appropriate + * initializer, as the default svalue-0 is not a valid float value. + */ + + Bool need_value = MY_FALSE; +%line + +#ifdef USE_NEW_INLINES + /* When parsing context variables, the context_closure instruction + * expects a value on the stack. If we do a float initialization, + * we leave the 0.0 on the stack, otherwise we'll push a 0. + * For normal float locals, we'll create the bytecode to assign + * the float 0. + */ + need_value = current_inline && current_inline->parse_context; +#endif /* USE_NEW_INLINES */ + + if (!(actual_type.typeflags & TYPE_MOD_POINTER) + && (actual_type.typeflags & PRIMARY_TYPE_MASK) == TYPE_FLOAT + ) + { + ins_f_code(F_FCONST0); + + if (!need_value) + { + if (!add_lvalue_code(lv, F_VOID_ASSIGN)) + return; + } + + need_value = MY_FALSE; + } /* if (float variable) */ + + if (need_value) /* If we still need a value... */ + { + ins_number(0); + } + } +} + +/*-------------------------------------------------------------------------*/ +static void +init_local_variable (ident_t* name, struct lvalue_s *lv, int assign_op, fulltype_t type2) +/* This is called directly from a parser rule: <type> [*] <name> = <expr> + * It will be called after the call to define_local_variable(). + * It assigns the result of <expr> to the variable. + */ +{ + /* We got a "<name> = <expr>" type declaration. */ + +%line +#ifdef USE_NEW_INLINES +#ifdef DEBUG_INLINES +if (current_inline && current_inline->parse_context) printf("DEBUG: inline context decl: name = expr, program_size %d\n", CURRENT_PROGRAM_SIZE); +#endif /* DEBUG_INLINES */ +#endif /* USE_NEW_INLINES */ + + type2.typeflags &= TYPEID_MASK; + + /* Check the assignment for validity */ + if (exact_types.typeflags && !compatible_types(lv->type, type2, MY_TRUE)) + { + yyerrorf("Bad assignment %s", get_two_types(lv->type, type2)); + } + + if (assign_op != F_ASSIGN) + { + yyerror("Only plain assignments allowed here"); + } + + if (type2.typeflags & TYPE_MOD_REFERENCE) + yyerror("Can't trace reference assignments"); + + /* If we're parsing a context variable, just leave the + * value on the stack for the context_closure instruction. + * For normal locals, add the bytecode to create the lvalue + * and do the assignment. + */ +#ifdef USE_NEW_INLINES + if (!current_inline || !current_inline->parse_context) +#endif /* USE_NEW_INLINES */ + { + if (!add_lvalue_code(lv, F_VOID_ASSIGN)) + return; + } /* parsed context var */ +} + +/*-------------------------------------------------------------------------*/ static Bool add_lvalue_code ( struct lvalue_s * lv, int instruction) | ||||
Date Modified | Username | Field | Change |
---|---|---|---|
2005-06-24 07:37 | Gnomi | New Issue | |
2005-08-25 12:26 | Gnomi | File Added: 3.3currenttype.diff | |
2005-08-25 12:29 | Gnomi | Note Added: 0000384 | |
2006-03-14 23:08 |
|
Status | new => resolved |
2006-03-14 23:08 |
|
Fixed in Version | => 3.3.714 |
2006-03-14 23:08 |
|
Resolution | open => fixed |
2006-03-14 23:08 |
|
Assigned To | => lars |
2006-03-14 23:08 |
|
Note Added: 0000498 | |
2007-10-06 19:55 |
|
Status | resolved => closed |
2010-11-16 09:42 |
|
Source_changeset_attached | => ldmud.git master 1b6d3ffe |
2018-01-29 18:59 |
|
Source_changeset_attached | => ldmud.git master 1b6d3ffe |
2018-01-29 21:57 |
|
Source_changeset_attached | => ldmud.git master 1b6d3ffe |