X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=src%2Fexpressp.c;h=906eed160e4dd7810d609aadfe3828c5d524f3bc;hb=HEAD;hp=c5577db6e5145dc52cb2d638087df6ade5be2a5e;hpb=c881aa3386c00d7021ffabf2f66275d6c110c1c1;p=inform.git diff --git a/src/expressp.c b/src/expressp.c index c5577db..906eed1 100644 --- a/src/expressp.c +++ b/src/expressp.c @@ -1,8 +1,8 @@ /* ------------------------------------------------------------------------- */ /* "expressp" : The expression parser */ /* */ -/* Part of Inform 6.35 */ -/* copyright (c) Graham Nelson 1993 - 2021 */ +/* Part of Inform 6.42 */ +/* copyright (c) Graham Nelson 1993 - 2024 */ /* */ /* Inform is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ @@ -65,9 +65,9 @@ static int comma_allowed, arrow_allowed, superclass_allowed, array_init_ambiguity, action_ambiguity, etoken_count, inserting_token, bracket_level; -extern int *variable_usage; +int system_function_usage[NUMBER_SYSTEM_FUNCTIONS]; -int system_function_usage[32]; +static void check_system_constant_available(int); static int get_next_etoken(void) { int v, symbol = 0, mark_symbol_as_used = FALSE, @@ -85,6 +85,7 @@ static int get_next_etoken(void) current_token.value = token_value; current_token.type = token_type; current_token.marker = 0; + current_token.symindex = -1; current_token.symtype = 0; current_token.symflags = -1; } @@ -92,7 +93,7 @@ static int get_next_etoken(void) switch(current_token.type) { case LOCAL_VARIABLE_TT: current_token.type = VARIABLE_TT; - variable_usage[current_token.value] = TRUE; + variables[current_token.value].usage = TRUE; break; case DQ_TT: @@ -135,17 +136,17 @@ but not used as a value:", unicode); mark_symbol_as_used = TRUE; - v = svals[symbol]; + v = symbols[symbol].value; - current_token.symtype = stypes[symbol]; - current_token.symflags = sflags[symbol]; - switch(stypes[symbol]) + current_token.symindex = symbol; + current_token.symtype = symbols[symbol].type; + current_token.symflags = symbols[symbol].flags; + switch(symbols[symbol].type) { case ROUTINE_T: /* Replaced functions must always be backpatched because there could be another definition coming. */ - if (sflags[symbol] & REPLACE_SFLAG) + if (symbols[symbol].flags & REPLACE_SFLAG) { current_token.marker = SYMBOL_MV; - if (module_switch) import_symbol(symbol); v = symbol; break; } @@ -157,7 +158,7 @@ but not used as a value:", unicode); case OBJECT_T: case CLASS_T: /* All objects must be backpatched in Glulx. */ - if (module_switch || glulx_mode) + if (glulx_mode) current_token.marker = OBJECT_MV; break; case ARRAY_T: @@ -167,12 +168,10 @@ but not used as a value:", unicode); current_token.marker = STATIC_ARRAY_MV; break; case INDIVIDUAL_PROPERTY_T: - if (module_switch) current_token.marker = IDENT_MV; break; case CONSTANT_T: - if (sflags[symbol] & (UNKNOWN_SFLAG + CHANGE_SFLAG)) + if (symbols[symbol].flags & (UNKNOWN_SFLAG + CHANGE_SFLAG)) { current_token.marker = SYMBOL_MV; - if (module_switch) import_symbol(symbol); v = symbol; } else current_token.marker = 0; @@ -184,7 +183,7 @@ but not used as a value:", unicode); current_token.marker = 0; break; } - if (sflags[symbol] & SYSTEM_SFLAG) + if (symbols[symbol].flags & SYSTEM_SFLAG) current_token.marker = 0; current_token.value = v; @@ -204,9 +203,9 @@ but not used as a value:", unicode); else current_token.type = SMALL_NUMBER_TT; } - if (stypes[symbol] == GLOBAL_VARIABLE_T) + if (symbols[symbol].type == GLOBAL_VARIABLE_T) { current_token.type = VARIABLE_TT; - variable_usage[current_token.value] = TRUE; + variables[current_token.value].usage = TRUE; } break; @@ -327,8 +326,8 @@ but not used as a value:", unicode); current_token.text += 3; current_token.type = SYMBOL_TT; - symbol = symbol_index(current_token.text, -1); - if (stypes[symbol] != GLOBAL_VARIABLE_T) { + symbol = get_symbol_index(current_token.text); + if (symbol < 0 || symbols[symbol].type != GLOBAL_VARIABLE_T) { ebf_error( "global variable name after '#g$'", current_token.text); @@ -338,7 +337,7 @@ but not used as a value:", unicode); break; } mark_symbol_as_used = TRUE; - current_token.value = svals[symbol] - MAX_LOCAL_VARIABLES; + current_token.value = symbols[symbol].value - MAX_LOCAL_VARIABLES; current_token.marker = 0; if (!glulx_mode) { if (current_token.value >= 0x100) @@ -379,7 +378,7 @@ but not used as a value:", unicode); "'#r$Routine' can now be written just 'Routine'"); current_token.text += 3; current_token.type = SYMBOL_TT; - current_token.value = symbol_index(current_token.text, -1); + current_token.value = symbol_index(current_token.text, -1, NULL); goto ReceiveSymbol; case HASHWDOLLAR_SEP: @@ -391,13 +390,14 @@ but not used as a value:", unicode); get_next_token(); system_constants.enabled = FALSE; if (token_type != SYSTEM_CONSTANT_TT) - { ebf_error( - "'r$', 'n$', 'g$' or internal Inform constant name after '#'", - token_text); + { ebf_curtoken_error( + "'r$', 'n$', 'g$' or internal Inform constant name after '#'"); break; } else - { current_token.type = token_type; + { + check_system_constant_available(token_value); + current_token.type = token_type; current_token.value = token_value; current_token.text = token_text; current_token.marker = INCON_MV; @@ -438,7 +438,7 @@ but not used as a value:", unicode); if (token_type_allowable[current_token.type]==0) { if (expr_trace_level >= 3) { printf("Discarding as not allowable: '%s' ", current_token.text); - describe_token(current_token); + describe_token(¤t_token); printf("\n"); } current_token.type = ENDEXP_TT; @@ -453,16 +453,16 @@ but not used as a value:", unicode); || (operators[current_token.value].usage == PRE_U))) { if (expr_trace_level >= 3) { printf("Discarding as no longer part: '%s' ", current_token.text); - describe_token(current_token); + describe_token(¤t_token); printf("\n"); } current_token.type = ENDEXP_TT; } else - { if (mark_symbol_as_used) sflags[symbol] |= USED_SFLAG; + { if (mark_symbol_as_used) symbols[symbol].flags |= USED_SFLAG; if (expr_trace_level >= 3) { printf("Expr token = '%s' ", current_token.text); - describe_token(current_token); + describe_token(¤t_token); printf("\n"); } } @@ -475,36 +475,40 @@ but not used as a value:", unicode); return TRUE; } -/* --- Operator precedences ------------------------------------------------ */ +/* --- Operator precedences and error values-------------------------------- */ #define LOWER_P 101 #define EQUAL_P 102 #define GREATER_P 103 -#define e1 1 /* Missing operand error */ -#define e2 2 /* Unexpected close bracket */ -#define e3 3 /* Missing operator error */ -#define e4 4 /* Expression ends with an open bracket */ -#define e5 5 /* Associativity illegal error */ +#define BYPREC -1 /* Compare the precedence of two operators */ -const int prec_table[] = { +#define NOVAL_E 1 /* Missing operand error */ +#define CLOSEB_E 2 /* Unexpected close bracket */ +#define NOOP_E 3 /* Missing operator error */ +#define OPENB_E 4 /* Expression ends with an open bracket */ +#define ASSOC_E 5 /* Associativity illegal error */ -/* a .......... ( ) end op term */ +const int prec_table[49] = { -/* b ( */ LOWER_P, e3, LOWER_P, LOWER_P, e3, -/* . ) */ EQUAL_P, GREATER_P, e2, GREATER_P, GREATER_P, -/* . end */ e4, GREATER_P, e1, GREATER_P, GREATER_P, -/* . op */ LOWER_P, GREATER_P, LOWER_P, -1, GREATER_P, -/* . term */ LOWER_P, e3, LOWER_P, LOWER_P, e3 +/* a ....... ( ) end op:pre op:bin op:post term */ + +/* b ( */ LOWER_P, NOOP_E, LOWER_P, LOWER_P, LOWER_P, NOOP_E, NOOP_E, +/* . ) */ EQUAL_P, GREATER_P, CLOSEB_E, GREATER_P, GREATER_P, GREATER_P, GREATER_P, +/* . end */ OPENB_E, GREATER_P, NOVAL_E, GREATER_P, GREATER_P, GREATER_P, GREATER_P, +/* . op:pre */ LOWER_P, NOOP_E, LOWER_P, BYPREC, BYPREC, NOOP_E, NOOP_E, +/* . op:bin */ LOWER_P, GREATER_P, LOWER_P, BYPREC, BYPREC, BYPREC, GREATER_P, +/* . op:post */ LOWER_P, GREATER_P, LOWER_P, BYPREC, BYPREC, BYPREC, GREATER_P, +/* . term */ LOWER_P, NOOP_E, LOWER_P, LOWER_P, LOWER_P, NOOP_E, NOOP_E }; -static int find_prec(token_data a, token_data b) +static int find_prec(const token_data *a, const token_data *b) { /* We are comparing the precedence of tokens a and b (where a occurs to the left of b). If the expression is correct, the only possible values are GREATER_P, LOWER_P or EQUAL_P; - if it is malformed then one of e1 to e5 results. + if it is malformed then one of the *_E results. Note that this routine is not symmetrical and that the relation is not trichotomous. @@ -515,29 +519,54 @@ static int find_prec(token_data a, token_data b) a GREATER_P a if a left-associative */ - int i, j, l1, l2; + int ai, bi, j, l1, l2; - switch(a.type) - { case SUBOPEN_TT: i=0; break; - case SUBCLOSE_TT: i=1; break; - case ENDEXP_TT: i=2; break; - case OP_TT: i=3; break; - default: i=4; break; + /* Select a column and row in prec_table, based on the type of + a and b. If a/b is an operator, we have to distinguish three + columns/rows depending on whether the operator is prefix, + postfix, or neither. + */ + + switch(a->type) + { case SUBOPEN_TT: ai=0; break; + case SUBCLOSE_TT: ai=1; break; + case ENDEXP_TT: ai=2; break; + case OP_TT: + if (operators[a->value].usage == PRE_U) + ai=3; + else if (operators[a->value].usage == POST_U) + ai=5; + else + ai=4; + break; + default: ai=6; break; } - switch(b.type) - { case SUBOPEN_TT: i+=0; break; - case SUBCLOSE_TT: i+=5; break; - case ENDEXP_TT: i+=10; break; - case OP_TT: i+=15; break; - default: i+=20; break; + switch(b->type) + { case SUBOPEN_TT: bi=0; break; + case SUBCLOSE_TT: bi=1; break; + case ENDEXP_TT: bi=2; break; + case OP_TT: + if (operators[b->value].usage == PRE_U) + bi=3; + else if (operators[b->value].usage == POST_U) + bi=5; + else + bi=4; + break; + default: bi=6; break; } + + j = prec_table[ai+7*bi]; + if (j != BYPREC) return j; - j = prec_table[i]; if (j != -1) return j; - - l1 = operators[a.value].precedence; - l2 = operators[b.value].precedence; - if (operators[b.value].usage == PRE_U) return LOWER_P; - if (operators[a.value].usage == POST_U) return GREATER_P; + /* BYPREC is the (a=OP, b=OP) cases. We must compare the precedence of the + two operators. + (We've already eliminated invalid cases like (a++ --b).) + */ + l1 = operators[a->value].precedence; + l2 = operators[b->value].precedence; + if (operators[b->value].usage == PRE_U) return LOWER_P; + if (operators[a->value].usage == POST_U) return GREATER_P; /* Anomalous rule to resolve the function call precedence, which is different on the right from on the left, e.g., in: @@ -550,17 +579,18 @@ static int find_prec(token_data a, token_data b) if (l1 < l2) return LOWER_P; if (l1 > l2) return GREATER_P; - switch(operators[a.value].associativity) + switch(operators[a->value].associativity) { case L_A: return GREATER_P; case R_A: return LOWER_P; - case 0: return e5; + case 0: return ASSOC_E; } return GREATER_P; } /* --- Converting token to operand ----------------------------------------- */ -/* Must match the switch statement below */ +/* List used to generate gameinfo.dbg. + Must match the switch statement below. */ int z_system_constant_list[] = { adjectives_table_SC, actions_table_SC, @@ -604,10 +634,36 @@ int z_system_constant_list[] = highest_class_number_SC, class_objects_array_SC, highest_object_number_SC, + dictionary_table_SC, + grammar_table_SC, -1 }; +static void check_system_constant_available(int t) +{ + if (OMIT_SYMBOL_TABLE) { + /* Certain system constants refer to the symbol table, which + is meaningless if OMIT_SYMBOL_TABLE is set. */ + switch(t) + { + case identifiers_table_SC: + case attribute_names_array_SC: + case property_names_array_SC: + case action_names_array_SC: + case fake_action_names_array_SC: + case array_names_offset_SC: + case global_names_array_SC: + case routine_names_array_SC: + case constant_names_array_SC: + error_named("OMIT_SYMBOL_TABLE omits system constant", system_constants.keywords[t]); + default: + break; + } + } +} + static int32 value_of_system_constant_z(int t) -{ switch(t) +{ + switch(t) { case adjectives_table_SC: return adjectives_offset; case actions_table_SC: @@ -641,9 +697,13 @@ static int32 value_of_system_constant_z(int t) case ipv__end_SC: return variables_offset; case array__start_SC: - return variables_offset + (MAX_GLOBAL_VARIABLES*WORDSIZE); + return variables_offset + (MAX_ZCODE_GLOBAL_VARS*WORDSIZE); case array__end_SC: return static_memory_offset; + case dictionary_table_SC: + return dictionary_offset; + case grammar_table_SC: + return static_memory_offset; case highest_attribute_number_SC: return no_attributes-1; @@ -705,7 +765,8 @@ static int32 value_of_system_constant_z(int t) return(0); } -/* Must match the switch statement below */ +/* List used to generate gameinfo.dbg. + Must match the switch statement below. */ int glulx_system_constant_list[] = { classes_table_SC, identifiers_table_SC, @@ -764,7 +825,15 @@ extern int32 value_of_system_constant(int t) return value_of_system_constant_g(t); } -static int evaluate_term(token_data t, assembly_operand *o) +extern char *name_of_system_constant(int t) +{ + if (t < 0 || t >= NO_SYSTEM_CONSTANTS) { + return "???"; + } + return system_constants.keywords[t]; +} + +static int evaluate_term(const token_data *t, assembly_operand *o) { /* If the given token is a constant, evaluate it into the operand. For now, the identifiers are considered variables. @@ -773,13 +842,12 @@ static int evaluate_term(token_data t, assembly_operand *o) int32 v; - o->marker = t.marker; - o->symtype = t.symtype; - o->symflags = t.symflags; + o->marker = t->marker; + o->symindex = t->symindex; - switch(t.type) + switch(t->type) { case LARGE_NUMBER_TT: - v = t.value; + v = t->value; if (!glulx_mode) { if (v < 0) v = v + 0x10000; o->type = LONG_CONSTANT_OT; @@ -791,7 +859,7 @@ static int evaluate_term(token_data t, assembly_operand *o) } return(TRUE); case SMALL_NUMBER_TT: - v = t.value; + v = t->value; if (!glulx_mode) { if (v < 0) v = v + 0x10000; o->type = SHORT_CONSTANT_OT; @@ -808,7 +876,7 @@ static int evaluate_term(token_data t, assembly_operand *o) o->type = LONG_CONSTANT_OT; else o->type = CONSTANT_OT; - o->value = dictionary_add(t.text, 0x80, 0, 0); + o->value = dictionary_add(t->text, 0x80, 0, 0); return(TRUE); case DQ_TT: /* Create as a static string */ @@ -816,14 +884,14 @@ static int evaluate_term(token_data t, assembly_operand *o) o->type = LONG_CONSTANT_OT; else o->type = CONSTANT_OT; - o->value = compile_string(t.text, FALSE, FALSE); + o->value = compile_string(t->text, STRCTX_GAME); return(TRUE); case VARIABLE_TT: if (!glulx_mode) { o->type = VARIABLE_OT; } else { - if (t.value >= MAX_LOCAL_VARIABLES) { + if (t->value >= MAX_LOCAL_VARIABLES) { o->type = GLOBALVAR_OT; } else { @@ -832,21 +900,21 @@ static int evaluate_term(token_data t, assembly_operand *o) o->type = LOCALVAR_OT; } } - o->value = t.value; + o->value = t->value; return(TRUE); case SYSFUN_TT: if (!glulx_mode) { o->type = VARIABLE_OT; - o->value = t.value + 256; + o->value = t->value + 256; } else { o->type = SYSFUN_OT; - o->value = t.value; + o->value = t->value; } - system_function_usage[t.value] = 1; + system_function_usage[t->value] = 1; return(TRUE); case ACTION_TT: - *o = action_of_name(t.text); + *o = action_of_name(t->text); return(TRUE); case SYSTEM_CONSTANT_TT: /* Certain system constants depend only on the @@ -855,7 +923,7 @@ static int evaluate_term(token_data t, assembly_operand *o) them immediately. */ if (!glulx_mode) { o->type = LONG_CONSTANT_OT; - switch(t.value) + switch(t->value) { case version_number_SC: o->type = SHORT_CONSTANT_OT; @@ -872,6 +940,8 @@ static int evaluate_term(token_data t, assembly_operand *o) case dict_par3_SC: o->type = SHORT_CONSTANT_OT; o->marker = 0; + if (ZCODE_LESS_DICT_DATA) + error("#dict_par3 is unavailable when ZCODE_LESS_DICT_DATA is set"); v = (version_number==3)?6:8; break; case lowest_attribute_number_SC: case lowest_action_number_SC: @@ -892,7 +962,7 @@ static int evaluate_term(token_data t, assembly_operand *o) o->type = SHORT_CONSTANT_OT; o->marker = 0; v = oddeven_packing_switch; break; default: - v = t.value; + v = t->value; o->marker = INCON_MV; break; } @@ -900,7 +970,7 @@ static int evaluate_term(token_data t, assembly_operand *o) } else { o->type = CONSTANT_OT; - switch(t.value) + switch(t->value) { /* The three dict_par flags point at the lower byte of the flag field, because the library is written @@ -942,7 +1012,7 @@ static int evaluate_term(token_data t, assembly_operand *o) /* ###fix: need to fill more of these in! */ default: - v = t.value; + v = t->value; o->marker = INCON_MV; break; } @@ -956,35 +1026,40 @@ static int evaluate_term(token_data t, assembly_operand *o) /* --- Emitter ------------------------------------------------------------- */ -expression_tree_node *ET; +expression_tree_node *ET; /* Allocated to ET_used */ +static memory_list ET_memlist; static int ET_used; extern void clear_expression_space(void) { ET_used = 0; } -static assembly_operand *emitter_stack; -static int *emitter_markers; -static int *emitter_bracket_counts; +typedef struct emitterstackinfo_s { + assembly_operand op; + int marker; + int bracket_count; +} emitterstackinfo; #define FUNCTION_VALUE_MARKER 1 #define ARGUMENT_VALUE_MARKER 2 #define OR_VALUE_MARKER 3 +static emitterstackinfo *emitter_stack; /* Allocated to emitter_sp */ +static memory_list emitter_stack_memlist; static int emitter_sp; static int is_property_t(int symbol_type) { return ((symbol_type == PROPERTY_T) || (symbol_type == INDIVIDUAL_PROPERTY_T)); } -static void mark_top_of_emitter_stack(int marker, token_data t) +static void mark_top_of_emitter_stack(int marker, const token_data *t) { if (emitter_sp < 1) { compiler_error("SR error: Attempt to add a marker to the top of an empty emitter stack"); return; } if (expr_trace_level >= 2) { printf("Marking top of emitter stack (which is "); - print_operand(emitter_stack[emitter_sp-1]); + print_operand(&emitter_stack[emitter_sp-1].op, FALSE); printf(") as "); switch(marker) { @@ -1003,29 +1078,28 @@ static void mark_top_of_emitter_stack(int marker, token_data t) } printf("\n"); } - if (emitter_markers[emitter_sp-1]) + if (emitter_stack[emitter_sp-1].marker) { if (marker == ARGUMENT_VALUE_MARKER) { warning("Ignoring spurious leading comma"); return; } - error_named("Missing operand for", t.text); - if (emitter_sp == MAX_EXPRESSION_NODES) - memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES); - emitter_markers[emitter_sp] = 0; - emitter_bracket_counts[emitter_sp] = 0; - emitter_stack[emitter_sp] = zero_operand; + error_named("Missing operand for", t->text); + ensure_memory_list_available(&emitter_stack_memlist, emitter_sp+1); + emitter_stack[emitter_sp].marker = 0; + emitter_stack[emitter_sp].bracket_count = 0; + emitter_stack[emitter_sp].op = zero_operand; emitter_sp++; } - emitter_markers[emitter_sp-1] = marker; + emitter_stack[emitter_sp-1].marker = marker; } static void add_bracket_layer_to_emitter_stack(int depth) { /* There's no point in tracking bracket layers that don't fence off any values. */ if (emitter_sp < depth + 1) return; if (expr_trace_level >= 2) - printf("Adding bracket layer\n"); - ++emitter_bracket_counts[emitter_sp-depth-1]; + printf("Adding bracket layer (depth %d)\n", depth); + ++emitter_stack[emitter_sp-depth-1].bracket_count; } static void remove_bracket_layer_from_emitter_stack() @@ -1033,46 +1107,47 @@ static void remove_bracket_layer_from_emitter_stack() if (emitter_sp < 2) return; if (expr_trace_level >= 2) printf("Removing bracket layer\n"); - if (emitter_bracket_counts[emitter_sp-2] <= 0) + if (emitter_stack[emitter_sp-2].bracket_count <= 0) { compiler_error("SR error: Attempt to remove a nonexistent bracket layer from the emitter stack"); return; } - --emitter_bracket_counts[emitter_sp-2]; + --emitter_stack[emitter_sp-2].bracket_count; } -static void emit_token(token_data t) +static void emit_token(const token_data *t) { assembly_operand o1, o2; int arity, stack_size, i; int op_node_number, operand_node_number, previous_node_number; int32 x = 0; if (expr_trace_level >= 2) - { printf("Output: %-19s%21s ", t.text, ""); + { printf("Output: %-19s%21s ", t->text, ""); for (i=0; itype == SUBOPEN_TT) return; stack_size = 0; while ((stack_size < emitter_sp) && - !emitter_markers[emitter_sp-stack_size-1] && - !emitter_bracket_counts[emitter_sp-stack_size-1]) + !emitter_stack[emitter_sp-stack_size-1].marker && + !emitter_stack[emitter_sp-stack_size-1].bracket_count) stack_size++; - if (t.type == SUBCLOSE_TT) - { if (stack_size < emitter_sp && emitter_bracket_counts[emitter_sp-stack_size-1]) + if (t->type == SUBCLOSE_TT) + { if (stack_size < emitter_sp && emitter_stack[emitter_sp-stack_size-1].bracket_count) { if (stack_size == 0) { error("No expression between brackets '(' and ')'"); - emitter_stack[emitter_sp] = zero_operand; - emitter_markers[emitter_sp] = 0; - emitter_bracket_counts[emitter_sp] = 0; - ++emitter_sp; + ensure_memory_list_available(&emitter_stack_memlist, emitter_sp+1); + emitter_stack[emitter_sp].op = zero_operand; + emitter_stack[emitter_sp].marker = 0; + emitter_stack[emitter_sp].bracket_count = 0; + emitter_sp++; } else if (stack_size < 1) compiler_error("SR error: emitter stack empty in subexpression"); @@ -1083,14 +1158,14 @@ static void emit_token(token_data t) return; } - if (t.type != OP_TT) - { emitter_markers[emitter_sp] = 0; - emitter_bracket_counts[emitter_sp] = 0; + if (t->type != OP_TT) + { + ensure_memory_list_available(&emitter_stack_memlist, emitter_sp+1); + emitter_stack[emitter_sp].marker = 0; + emitter_stack[emitter_sp].bracket_count = 0; - if (emitter_sp == MAX_EXPRESSION_NODES) - memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES); - if (!evaluate_term(t, &(emitter_stack[emitter_sp++]))) - compiler_error_named("Emit token error:", t.text); + if (!evaluate_term(t, &(emitter_stack[emitter_sp++].op))) + compiler_error_named("Emit token error:", t->text); return; } @@ -1098,85 +1173,85 @@ static void emit_token(token_data t) call, since we ignore spurious leading commas in function argument lists) with no intervening brackets. Function calls are variadic, so we don't apply argument-separating commas. */ - if (t.value == COMMA_OP && + if (t->value == COMMA_OP && stack_size < emitter_sp && - (emitter_markers[emitter_sp-stack_size-1] == ARGUMENT_VALUE_MARKER || - emitter_markers[emitter_sp-stack_size-1] == FUNCTION_VALUE_MARKER) && - !emitter_bracket_counts[emitter_sp-stack_size-1]) + (emitter_stack[emitter_sp-stack_size-1].marker == ARGUMENT_VALUE_MARKER || + emitter_stack[emitter_sp-stack_size-1].marker == FUNCTION_VALUE_MARKER) && + !emitter_stack[emitter_sp-stack_size-1].bracket_count) { if (expr_trace_level >= 2) printf("Treating comma as argument-separating\n"); return; } - if (t.value == OR_OP) + if (t->value == OR_OP) return; arity = 1; - if (t.value == FCALL_OP) + if (t->value == FCALL_OP) { if (expr_trace_level >= 3) { printf("FCALL_OP finds marker stack: "); - for (x=0; x= 256 && - emitter_stack[emitter_sp-arity].value < 288)) - { int index = emitter_stack[emitter_sp-arity].value; + emitter_stack[emitter_sp-arity].op.type == VARIABLE_OT && + emitter_stack[emitter_sp-arity].op.value >= 256 && + emitter_stack[emitter_sp-arity].op.value < 288)) + { int index = emitter_stack[emitter_sp-arity].op.value; if(!glulx_mode) index -= 256; if(index >= 0 && index < NUMBER_SYSTEM_FUNCTIONS) error_named("System function name used as a value:", system_functions.keywords[index]); else compiler_error("Found unnamed system function used as a value"); - emitter_stack[emitter_sp-arity] = zero_operand; + emitter_stack[emitter_sp-arity].op = zero_operand; } ++arity; } } else { arity = 1; - if (operators[t.value].usage == IN_U) arity = 2; + if (operators[t->value].usage == IN_U) arity = 2; - if (operators[t.value].precedence == 3) + if (operators[t->value].precedence == 3) { arity = 2; x = emitter_sp-1; - if(!emitter_markers[x] && !emitter_bracket_counts[x]) - { for (--x; emitter_markers[x] == OR_VALUE_MARKER && !emitter_bracket_counts[x]; --x) + if(!emitter_stack[x].marker && !emitter_stack[x].bracket_count) + { for (--x; emitter_stack[x].marker == OR_VALUE_MARKER && !emitter_stack[x].bracket_count; --x) { ++arity; ++stack_size; } - for (;x >= 0 && !emitter_markers[x] && !emitter_bracket_counts[x]; --x) + for (;x >= 0 && !emitter_stack[x].marker && !emitter_stack[x].bracket_count; --x) ++stack_size; } } if (arity > stack_size) - { error_named("Missing operand for", t.text); + { error_named("Missing operand for", t->text); while (arity > stack_size) - { if (emitter_sp == MAX_EXPRESSION_NODES) - memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES); - emitter_markers[emitter_sp] = 0; - emitter_bracket_counts[emitter_sp] = 0; - emitter_stack[emitter_sp] = zero_operand; + { ensure_memory_list_available(&emitter_stack_memlist, emitter_sp+1); + emitter_stack[emitter_sp].marker = 0; + emitter_stack[emitter_sp].bracket_count = 0; + emitter_stack[emitter_sp].op = zero_operand; emitter_sp++; stack_size++; } } } - /* pseudo-typecheck in 6.30 */ + /* pseudo-typecheck in 6.30: catch an unqualified property name */ for (i = 1; i <= arity; i++) { - o1 = emitter_stack[emitter_sp - i]; - if (is_property_t(o1.symtype) ) { - switch(t.value) + o1 = emitter_stack[emitter_sp - i].op; + if ((o1.symindex >= 0) + && is_property_t(symbols[o1.symindex].type)) { + switch(t->value) { case FCALL_OP: case SETEQUALS_OP: case NOTEQUAL_OP: @@ -1188,19 +1263,28 @@ static void emit_token(token_data t) case PROPERTY_OP: if (i < arity) break; case GE_OP: case LE_OP: - if ((i < arity) && (o1.symflags & STAR_SFLAG)) break; + /* Direction properties "n_to", etc *are* compared + in some libraries. They have STAR_SFLAG to tell us + to skip the warning. */ + if ((i < arity) + && (symbols[o1.symindex].flags & STAR_SFLAG)) break; default: warning("Property name in expression is not qualified by object"); } - } /* if (is_property_t */ + } } switch(arity) { case 1: - o1 = emitter_stack[emitter_sp - 1]; + o1 = emitter_stack[emitter_sp - 1].op; if ((o1.marker == 0) && is_constant_ot(o1.type)) - { switch(t.value) - { case UNARY_MINUS_OP: x = -o1.value; goto FoldConstant; + { switch(t->value) + { case UNARY_MINUS_OP: + if ((uint32)o1.value == 0x80000000) + x = 0x80000000; + else + x = -o1.value; + goto FoldConstant; case ARTNOT_OP: if (!glulx_mode) x = (~o1.value) & 0xffff; @@ -1215,8 +1299,8 @@ static void emit_token(token_data t) break; case 2: - o1 = emitter_stack[emitter_sp - 2]; - o2 = emitter_stack[emitter_sp - 1]; + o1 = emitter_stack[emitter_sp - 2].op; + o2 = emitter_stack[emitter_sp - 1].op; if ((o1.marker == 0) && (o2.marker == 0) && is_constant_ot(o1.type) && is_constant_ot(o2.type)) @@ -1231,7 +1315,7 @@ static void emit_token(token_data t) ov2 = (o2.value >= 0x8000) ? (o2.value - 0x10000) : o2.value; } - switch(t.value) + switch(t->value) { case PLUS_OP: x = ov1 + ov2; goto FoldConstantC; case MINUS_OP: x = ov1 - ov2; goto FoldConstantC; @@ -1241,7 +1325,7 @@ static void emit_token(token_data t) if (ov2 == 0) error("Division of constant by zero"); else - if (t.value == DIVIDE_OP) { + if (t->value == DIVIDE_OP) { if (ov2 < 0) { ov1 = -ov1; ov2 = -ov2; @@ -1290,13 +1374,32 @@ static void emit_token(token_data t) } } + + /* We can also fold logical operations if they are certain + to short-circuit. The right-hand argument is skipped even + if it's non-constant or has side effects. */ + + if ((o1.marker == 0) + && is_constant_ot(o1.type)) { + + if (t->value == LOGAND_OP && o1.value == 0) + { + x = 0; + goto FoldConstant; + } + + if (t->value == LOGOR_OP && o1.value != 0) + { + x = 1; + goto FoldConstant; + } + } } + ensure_memory_list_available(&ET_memlist, ET_used+1); op_node_number = ET_used++; - if (op_node_number == MAX_EXPRESSION_NODES) - memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES); - ET[op_node_number].operator_number = t.value; + ET[op_node_number].operator_number = t->value; ET[op_node_number].up = -1; ET[op_node_number].down = -1; ET[op_node_number].right = -1; @@ -1310,14 +1413,14 @@ static void emit_token(token_data t) if (expr_trace_level >= 3) printf("i=%d, emitter_sp=%d, arity=%d, ETU=%d\n", i, emitter_sp, arity, ET_used); - if (emitter_stack[i].type == EXPRESSION_OT) - operand_node_number = emitter_stack[i].value; + if (emitter_stack[i].op.type == EXPRESSION_OT) + operand_node_number = emitter_stack[i].op.value; else - { operand_node_number = ET_used++; - if (operand_node_number == MAX_EXPRESSION_NODES) - memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES); + { + ensure_memory_list_available(&ET_memlist, ET_used+1); + operand_node_number = ET_used++; ET[operand_node_number].down = -1; - ET[operand_node_number].value = emitter_stack[i]; + ET[operand_node_number].value = emitter_stack[i].op; } ET[operand_node_number].up = op_node_number; ET[operand_node_number].right = -1; @@ -1332,11 +1435,11 @@ static void emit_token(token_data t) emitter_sp = emitter_sp - arity + 1; - emitter_stack[emitter_sp - 1].type = EXPRESSION_OT; - emitter_stack[emitter_sp - 1].value = op_node_number; + emitter_stack[emitter_sp - 1].op.type = EXPRESSION_OT; + emitter_stack[emitter_sp - 1].op.value = op_node_number; + emitter_stack[emitter_sp - 1].op.marker = 0; emitter_stack[emitter_sp - 1].marker = 0; - emitter_markers[emitter_sp - 1] = 0; - emitter_bracket_counts[emitter_sp - 1] = 0; + emitter_stack[emitter_sp - 1].bracket_count = 0; /* Remove the marker for the brackets implied by operator precedence */ remove_bracket_layer_from_emitter_stack(); @@ -1348,23 +1451,24 @@ static void emit_token(token_data t) for 32-bit arithmetic. */ if (!glulx_mode && ((x<-32768) || (x > 32767))) - { char folding_error[40]; + { int32 ov1 = (o1.value >= 0x8000) ? (o1.value - 0x10000) : o1.value; int32 ov2 = (o2.value >= 0x8000) ? (o2.value - 0x10000) : o2.value; - switch(t.value) + char op = '?'; + switch(t->value) { case PLUS_OP: - sprintf(folding_error, "%d + %d = %d", ov1, ov2, x); + op = '+'; break; case MINUS_OP: - sprintf(folding_error, "%d - %d = %d", ov1, ov2, x); + op = '-'; break; case TIMES_OP: - sprintf(folding_error, "%d * %d = %d", ov1, ov2, x); + op = '*'; break; } - error_named("Signed arithmetic on compile-time constants overflowed \ -the range -32768 to +32767:", folding_error); + error_fmt("Signed arithmetic on compile-time constants overflowed \ +the range -32768 to +32767 (%d %c %d = %d)", ov1, op, ov2, x); } FoldConstant: @@ -1381,28 +1485,28 @@ the range -32768 to +32767:", folding_error); if (!glulx_mode) { if (x<256) - emitter_stack[emitter_sp - 1].type = SHORT_CONSTANT_OT; - else emitter_stack[emitter_sp - 1].type = LONG_CONSTANT_OT; + emitter_stack[emitter_sp - 1].op.type = SHORT_CONSTANT_OT; + else emitter_stack[emitter_sp - 1].op.type = LONG_CONSTANT_OT; } else { if (x == 0) - emitter_stack[emitter_sp - 1].type = ZEROCONSTANT_OT; + emitter_stack[emitter_sp - 1].op.type = ZEROCONSTANT_OT; else if (x >= -128 && x <= 127) - emitter_stack[emitter_sp - 1].type = BYTECONSTANT_OT; + emitter_stack[emitter_sp - 1].op.type = BYTECONSTANT_OT; else if (x >= -32768 && x <= 32767) - emitter_stack[emitter_sp - 1].type = HALFCONSTANT_OT; + emitter_stack[emitter_sp - 1].op.type = HALFCONSTANT_OT; else - emitter_stack[emitter_sp - 1].type = CONSTANT_OT; + emitter_stack[emitter_sp - 1].op.type = CONSTANT_OT; } - emitter_stack[emitter_sp - 1].value = x; + emitter_stack[emitter_sp - 1].op.value = x; + emitter_stack[emitter_sp - 1].op.marker = 0; emitter_stack[emitter_sp - 1].marker = 0; - emitter_markers[emitter_sp - 1] = 0; - emitter_bracket_counts[emitter_sp - 1] = 0; + emitter_stack[emitter_sp - 1].bracket_count = 0; if (expr_trace_level >= 2) { printf("Folding constant to: "); - print_operand(emitter_stack[emitter_sp - 1]); + print_operand(&emitter_stack[emitter_sp - 1].op, FALSE); printf("\n"); } @@ -1418,9 +1522,7 @@ static void show_node(int n, int depth, int annotate) for (j=0; j<2*depth+2; j++) printf(" "); if (ET[n].down == -1) - { print_operand(ET[n].value); - if (annotate && (ET[n].value.marker != 0)) - printf(" [%s]", describe_mv(ET[n].value.marker)); + { print_operand(&ET[n].value, annotate); printf("\n"); } else @@ -1439,12 +1541,10 @@ static void show_node(int n, int depth, int annotate) if (ET[n].right != -1) show_node(ET[n].right, depth, annotate); } -extern void show_tree(assembly_operand AO, int annotate) -{ if (AO.type == EXPRESSION_OT) show_node(AO.value, 0, annotate); +extern void show_tree(const assembly_operand *AO, int annotate) +{ if (AO->type == EXPRESSION_OT) show_node(AO->value, 0, annotate); else - { printf("Constant: "); print_operand(AO); - if (annotate && (AO.marker != 0)) - printf(" [%s]", describe_mv(AO.marker)); + { printf("Constant: "); print_operand(AO, annotate); printf("\n"); } } @@ -1464,11 +1564,14 @@ static void check_property_operator(int from_node) if ((below != -1) && (ET[below].right != -1)) { int n = ET[below].right, flag = FALSE; + /* Can we handle this dot operator as a native @get_prop (etc) + opcode? Only if we recognize the property value as a declared + common property constant. */ if ((ET[n].down == -1) && ((ET[n].value.type == LONG_CONSTANT_OT) || (ET[n].value.type == SHORT_CONSTANT_OT)) && ((ET[n].value.value > 0) && (ET[n].value.value < 64)) - && ((!module_switch) || (ET[n].value.marker == 0))) + && (ET[n].value.marker == 0)) flag = TRUE; if (!flag) @@ -1619,10 +1722,25 @@ static void delete_negations(int n, int context) (etc) to delete the ~~ operator from the tree. Since this is depth first, the ~~ being deleted has no ~~s beneath it, which - is important to make "negate_condition" work. */ + is important to make "negate_condition" work. + + We also do the check for (x <= y or z) here. This must be done + before negate_condition. + */ int i; + if (ET[n].operator_number == LE_OP || ET[n].operator_number == GE_OP) { + if (ET[n].down != -1 + && ET[ET[n].down].right != -1 + && ET[ET[ET[n].down].right].right != -1) { + if (ET[n].operator_number == LE_OP) + warning("The behavior of (<= or) may be unexpected."); + else + warning("The behavior of (>= or) may be unexpected."); + } + } + if (ET[n].right != -1) delete_negations(ET[n].right, context); if (ET[n].down == -1) return; delete_negations(ET[n].down, context); @@ -1649,9 +1767,9 @@ static void insert_exp_to_cond(int n, int context) if (ET[n].down == -1) { if (context==CONDITION_CONTEXT) - { new = ET_used++; - if (new == MAX_EXPRESSION_NODES) - memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES); + { + ensure_memory_list_available(&ET_memlist, ET_used+1); + new = ET_used++; ET[new] = ET[n]; ET[n].down = new; ET[n].operator_number = NONZERO_OP; ET[new].up = n; ET[new].right = -1; @@ -1672,9 +1790,8 @@ static void insert_exp_to_cond(int n, int context) default: if (context != CONDITION_CONTEXT) break; + ensure_memory_list_available(&ET_memlist, ET_used+1); new = ET_used++; - if (new == MAX_EXPRESSION_NODES) - memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES); ET[new] = ET[n]; ET[n].down = new; ET[n].operator_number = NONZERO_OP; ET[new].up = n; ET[new].right = -1; @@ -1731,9 +1848,8 @@ static void func_args_on_stack(int n, int context) || ET[fnaddr].value.value == INDIRECT_SYSF || ET[fnaddr].value.value == GLK_SYSF))) { if (etoken_num_children(pn) > (unsigned int)(opnum == FCALL_OP ? 4:3)) { + ensure_memory_list_available(&ET_memlist, ET_used+1); new = ET_used++; - if (new == MAX_EXPRESSION_NODES) - memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES); ET[new] = ET[n]; ET[n].down = new; ET[n].operator_number = PUSH_OP; @@ -1754,9 +1870,8 @@ static assembly_operand check_conditions(assembly_operand AO, int context) if (AO.type != EXPRESSION_OT) { if (context != CONDITION_CONTEXT) return AO; + ensure_memory_list_available(&ET_memlist, ET_used+1); n = ET_used++; - if (n == MAX_EXPRESSION_NODES) - memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES); ET[n].down = -1; ET[n].up = -1; ET[n].right = -1; @@ -1777,7 +1892,8 @@ static assembly_operand check_conditions(assembly_operand AO, int context) /* --- Shift-reduce parser ------------------------------------------------- */ static int sr_sp; -static token_data *sr_stack; +static token_data *sr_stack; /* Allocated to sr_sp */ +static memory_list sr_stack_memlist; extern assembly_operand parse_expression(int context) { @@ -1828,8 +1944,11 @@ extern assembly_operand parse_expression(int context) is constant and thus known at compile time. If an error has occurred in the expression, which recovery from was - not possible, then the return is (short constant) 0. This should - minimise the chance of a cascade of further error messages. + not possible, then the return is (short constant) 0 with marker + value ERROR_MV. The caller may check for this marker value to + decide whether to (e.g.) stop reading array values. Otherwise, it + will just be treated as a zero, which should minimise the chance + of a cascade of further error messages. */ token_data a, b, pop; int i; @@ -1861,6 +1980,7 @@ extern assembly_operand parse_expression(int context) previous_token.type = ENDEXP_TT; previous_token.value = 0; + ensure_memory_list_available(&sr_stack_memlist, 1); sr_sp = 1; sr_stack[0] = previous_token; @@ -1870,7 +1990,8 @@ extern assembly_operand parse_expression(int context) directives.enabled = FALSE; if (get_next_etoken() == FALSE) - { ebf_error("expression", token_text); + { ebf_curtoken_error("expression"); + AO.marker = ERROR_MV; return AO; } @@ -1884,6 +2005,7 @@ extern assembly_operand parse_expression(int context) if (sr_sp == 0) { compiler_error("SR error: stack empty"); + AO.marker = ERROR_MV; return(AO); } @@ -1893,18 +2015,20 @@ extern assembly_operand parse_expression(int context) { if (emitter_sp == 0) { error("No expression between brackets '(' and ')'"); put_token_back(); + AO.marker = ERROR_MV; return AO; } if (emitter_sp > 1) { compiler_error("SR error: emitter stack overfull"); + AO.marker = ERROR_MV; return AO; } - AO = emitter_stack[0]; + AO = emitter_stack[0].op; if (AO.type == EXPRESSION_OT) { if (expr_trace_level >= 3) { printf("Tree before lvalue checking:\n"); - show_tree(AO, FALSE); + show_tree(&AO, FALSE); } if (!glulx_mode) check_property_operator(AO.value); @@ -1912,7 +2036,9 @@ extern assembly_operand parse_expression(int context) ET[AO.value].up = -1; } else { - if ((context != CONSTANT_CONTEXT) && is_property_t(AO.symtype) + if ((context != CONSTANT_CONTEXT) + && (AO.symindex >= 0) + && is_property_t(symbols[AO.symindex].type) && (arrow_allowed) && (!bare_prop_allowed)) warning("Bare property name found. \"self.prop\" intended?"); } @@ -1922,6 +2048,7 @@ extern assembly_operand parse_expression(int context) if (context == CONSTANT_CONTEXT) if (!is_constant_ot(AO.type)) { AO = zero_operand; + AO.marker = ERROR_MV; ebf_error("constant", ""); } put_token_back(); @@ -1929,22 +2056,21 @@ extern assembly_operand parse_expression(int context) return(AO); } - switch(find_prec(a,b)) + switch(find_prec(&a,&b)) { - case e5: /* Associativity error */ + case ASSOC_E: /* Associativity error */ error_named("Brackets mandatory to clarify order of:", a.text); case LOWER_P: case EQUAL_P: - if (sr_sp == MAX_EXPRESSION_NODES) - memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES); + ensure_memory_list_available(&sr_stack_memlist, sr_sp+1); sr_stack[sr_sp++] = b; switch(b.type) { case SUBOPEN_TT: if (sr_sp >= 2 && sr_stack[sr_sp-2].type == OP_TT && sr_stack[sr_sp-2].value == FCALL_OP) - mark_top_of_emitter_stack(FUNCTION_VALUE_MARKER, b); + mark_top_of_emitter_stack(FUNCTION_VALUE_MARKER, &b); else add_bracket_layer_to_emitter_stack(0); break; @@ -1953,7 +2079,7 @@ extern assembly_operand parse_expression(int context) case OR_OP: if (sr_stack[sr_sp-2].type == OP_TT && operators[sr_stack[sr_sp-2].value].precedence == 3) - mark_top_of_emitter_stack(OR_VALUE_MARKER, b); + mark_top_of_emitter_stack(OR_VALUE_MARKER, &b); else { error("'or' not between values to the right of a condition"); /* Convert to + for error recovery purposes */ @@ -1969,7 +2095,7 @@ extern assembly_operand parse_expression(int context) if (shallowest_open_bracket_index > 0 && sr_stack[shallowest_open_bracket_index-1].type == OP_TT && sr_stack[shallowest_open_bracket_index-1].value == FCALL_OP) - { mark_top_of_emitter_stack(ARGUMENT_VALUE_MARKER, b); + { mark_top_of_emitter_stack(ARGUMENT_VALUE_MARKER, &b); break; } /* Non-argument-separating commas get treated like any other operator; we fall through to the default case. */ @@ -1987,13 +2113,15 @@ extern assembly_operand parse_expression(int context) case GREATER_P: do { pop = sr_stack[sr_sp - 1]; - emit_token(pop); + emit_token(&pop); sr_sp--; - } while (find_prec(sr_stack[sr_sp-1], pop) != LOWER_P); + } while (find_prec(&sr_stack[sr_sp-1], &pop) != LOWER_P); break; - case e1: /* Missing operand error */ + case NOVAL_E: /* Missing operand error */ error_named("Missing operand after", a.text); + /* We insert a "0" token so that the rest of the expression + can be compiled. */ put_token_back(); current_token.type = NUMBER_TT; current_token.value = 0; @@ -2001,13 +2129,15 @@ extern assembly_operand parse_expression(int context) current_token.text = "0"; break; - case e2: /* Unexpected close bracket */ + case CLOSEB_E: /* Unexpected close bracket */ error("Found '(' without matching ')'"); get_next_etoken(); break; - case e3: /* Missing operator error */ - error("Missing operator: inserting '+'"); + case NOOP_E: /* Missing operator error */ + error_named("Missing operator after", a.text); + /* We insert a "+" token so that the rest of the expression + can be compiled. */ put_token_back(); current_token.type = OP_TT; current_token.value = PLUS_OP; @@ -2015,7 +2145,7 @@ extern assembly_operand parse_expression(int context) current_token.text = "+"; break; - case e4: /* Expression ends with an open bracket */ + case OPENB_E: /* Expression ends with an open bracket */ error("Found '(' without matching ')'"); sr_sp--; break; @@ -2043,6 +2173,80 @@ extern int test_for_incdec(assembly_operand AO) return s*(ET[ET[AO.value].down].value.value); } + +/* Determine if the operand (a parsed expression) is a constant (as + per is_constant_ot()) or a comma-separated list of such constants. + + "(1)" and "(1,2,3)" both count, and even "((1,2),3)", but + not "(1,(2,3))"; the list must be left-associated. + + Backpatched constants (function names, etc) are acceptable, as are + folded constant expressions. Variables are right out. + + The constants are stored in the ops_found array, up to a maximum of + max_ops_found. For Inform parsing reasons, the array list is backwards + from the order found. + + Returns the number of constants found. If the expression is not a list of + constants, returns zero. + + (The return value may be more than max_ops_found, in which case we weren't + able to return them all in the array.) +*/ +extern int test_constant_op_list(const assembly_operand *AO, assembly_operand *ops_found, int max_ops_found) +{ + int count = 0; + int n; + + if (AO->type != EXPRESSION_OT) { + if (!is_constant_ot(AO->type)) + return 0; + + if (ops_found && max_ops_found > 0) + ops_found[0] = *AO; + return 1; + } + + n = AO->value; + + /* For some reason the top node is always a COMMA with no .right, + just a .down. Should we rely on this? For now yes. */ + + if (operators[ET[n].operator_number].token_value != COMMA_SEP) + return 0; + if (ET[n].right != -1) + return 0; + n = ET[n].down; + + while (TRUE) { + if (ET[n].right != -1) { + if (ET[ET[n].right].down != -1) + return 0; + if (!is_constant_ot(ET[ET[n].right].value.type)) + return 0; + + if (ops_found && max_ops_found > count) + ops_found[count] = ET[ET[n].right].value; + count++; + } + + if (ET[n].down == -1) { + if (!is_constant_ot(ET[n].value.type)) + return 0; + + if (ops_found && max_ops_found > count) + ops_found[count] = ET[n].value; + count++; + return count; + } + + if (operators[ET[n].operator_number].token_value != COMMA_SEP) + return 0; + + n = ET[n].down; + } +} + /* ========================================================================= */ /* Data structure management routines */ /* ------------------------------------------------------------------------- */ @@ -2051,7 +2255,12 @@ extern void init_expressp_vars(void) { int i; /* make_operands(); */ make_lexical_interface_tables(); - for (i=0;i<32;i++) system_function_usage[i] = 0; + for (i=0; i