extern void make_fake_action(void) { int i; char action_sub[MAX_IDENTIFIER_LENGTH+4]; get_next_token(); if (token_type != SYMBOL_TT) { ebf_error("new fake action name", token_text); panic_mode_error_recovery(); return; } sprintf(action_sub, "%s__A", token_text); i = symbol_index(action_sub, -1); if (!(sflags[i] & UNKNOWN_SFLAG)) { ebf_error("new fake action name", token_text); panic_mode_error_recovery(); return; } assign_symbol(i, ((grammar_version_number==1)?256:4096)+no_fake_actions++, FAKE_ACTION_T); new_action(token_text, i); if (debugfile_switch) { write_debug_byte(FAKE_ACTION_DBR); write_debug_byte(svals[i]/256); write_debug_byte(svals[i]%256); write_debug_string(token_text); } return; }
extern void make_fake_action(void) { int i; char action_sub[MAX_IDENTIFIER_LENGTH+4]; debug_location_beginning beginning_debug_location = get_token_location_beginning(); get_next_token(); if (token_type != SYMBOL_TT) { discard_token_location(beginning_debug_location); ebf_error("new fake action name", token_text); panic_mode_error_recovery(); return; } sprintf(action_sub, "%s__A", token_text); i = symbol_index(action_sub, -1); if (!(sflags[i] & UNKNOWN_SFLAG)) { discard_token_location(beginning_debug_location); ebf_error("new fake action name", token_text); panic_mode_error_recovery(); return; } assign_symbol(i, ((grammar_version_number==1)?256:4096)+no_fake_actions++, FAKE_ACTION_T); new_action(token_text, i); if (debugfile_switch) { debug_file_printf("<fake-action>"); debug_file_printf("<identifier>##%s</identifier>", token_text); debug_file_printf("<value>%d</value>", svals[i]); get_next_token(); write_debug_locations (get_token_location_end(beginning_debug_location)); put_token_back(); debug_file_printf("</fake-action>"); } return; }
static int grammar_line(int verbnum, int line) { /* Parse a grammar line, to be written into grammar_lines[mark] onward. Syntax: * <token1> ... <token-n> -> <action> is compiled to a table in the form: <action number : word> <token 1> ... <token n> <ENDIT> where <ENDIT> is the byte 15, and each <token> is 3 bytes long. If grammar_version_number is 1, the token holds <bytecode> 00 00 and otherwise a GV2 token. Return TRUE if grammar continues after the line, FALSE if the directive comes to an end. */ int j, bytecode, mark; int32 wordcode; int grammar_token, slash_mode, last_was_slash; int reverse_action, TOKEN_SIZE; debug_location_beginning beginning_debug_location = get_token_location_beginning(); get_next_token(); if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) { discard_token_location(beginning_debug_location); return FALSE; } if (!((token_type == SEP_TT) && (token_value == TIMES_SEP))) { discard_token_location(beginning_debug_location); ebf_error("'*' divider", token_text); panic_mode_error_recovery(); return FALSE; } /* Have we run out of lines or token space? */ if (line >= MAX_LINES_PER_VERB) { discard_token_location(beginning_debug_location); error("Too many lines of grammar for verb. This maximum is built \ into Inform, so suggest rewriting grammar using general parsing routines"); return(FALSE); }
extern void parse_code_block(int break_label, int continue_label, int switch_rule) { int switch_clause_made = FALSE, default_clause_made = FALSE, switch_label = 0, unary_minus_flag; begin_syntax_line(TRUE); get_next_token(); if (token_type == SEP_TT && token_value == OPEN_BRACE_SEP) { do { begin_syntax_line(TRUE); get_next_token(); if (token_type == SEP_TT && token_value == CLOSE_BRACE_SEP) { if (switch_clause_made && (!default_clause_made)) assemble_label_no(switch_label); return; } if (token_type == EOF_TT) { ebf_error("'}'", token_text); return; } if (switch_rule != 0) { /* Within a 'switch' block */ if ((token_type==STATEMENT_TT)&&(token_value==SDEFAULT_CODE)) { if (default_clause_made) error("Multiple 'default' clauses defined in same 'switch'"); default_clause_made = TRUE; if (switch_clause_made) { if (!execution_never_reaches_here) { sequence_point_follows = FALSE; assemble_jump(break_label); } assemble_label_no(switch_label); } switch_clause_made = TRUE; get_next_token(); if ((token_type == SEP_TT) && (token_value == COLON_SEP)) continue; ebf_error("':' after 'default'", token_text); panic_mode_error_recovery(); continue; } /* Decide: is this an ordinary statement, or the start of a new case? */ if (token_type == DQ_TT) goto NotASwitchCase; unary_minus_flag = ((token_type == SEP_TT)&&(token_value == MINUS_SEP)); if (unary_minus_flag) get_next_token(); /* Now read the token _after_ any possible constant: if that's a 'to', ',' or ':' then we have a case */ misc_keywords.enabled = TRUE; get_next_token(); misc_keywords.enabled = FALSE; if (switch_sign() > 0) { assembly_operand AO; if (default_clause_made) error("'default' must be the last 'switch' case"); if (switch_clause_made) { if (!execution_never_reaches_here) { sequence_point_follows = FALSE; assemble_jump(break_label); } assemble_label_no(switch_label); } switch_label = next_label++; switch_clause_made = TRUE; put_token_back(); put_token_back(); if (unary_minus_flag) put_token_back(); AO = temp_var1; parse_switch_spec(AO, switch_label, FALSE); continue; } else { put_token_back(); put_token_back(); if (unary_minus_flag) put_token_back(); get_next_token(); } } if ((switch_rule != 0) && (!switch_clause_made)) ebf_error("switch value", token_text); NotASwitchCase: sequence_point_follows = TRUE; parse_statement(break_label, continue_label); } while(TRUE); } if (switch_rule != 0) ebf_error("braced code block after 'switch'", token_text); parse_statement(break_label, continue_label); return; }
extern int32 parse_routine(char *source, int embedded_flag, char *name, int veneer_flag, int r_symbol) { int32 packed_address; int i; int debug_flag = FALSE; int switch_clause_made = FALSE, default_clause_made = FALSE, switch_label = 0; debug_location_beginning beginning_debug_location = get_token_location_beginning(); /* (switch_label needs no initialisation here, but it prevents some compilers from issuing warnings) */ if ((source != lexical_source) || (veneer_flag)) { lexical_source = source; restart_lexer(lexical_source, name); } no_locals = 0; for (i=0; i<MAX_LOCAL_VARIABLES-1; i++) local_variables.keywords[i] = ""; do { statements.enabled = TRUE; dont_enter_into_symbol_table = TRUE; get_next_token(); dont_enter_into_symbol_table = FALSE; if ((token_type == SEP_TT) && (token_value == TIMES_SEP) && (no_locals == 0) && (!debug_flag)) { debug_flag = TRUE; continue; } if (token_type != DQ_TT) { if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break; ebf_error("local variable name or ';'", token_text); panic_mode_error_recovery(); break; } if (strlen(token_text) > MAX_IDENTIFIER_LENGTH) { error_named("Local variable identifier too long:", token_text); panic_mode_error_recovery(); break; } if (no_locals == MAX_LOCAL_VARIABLES-1) { error_numbered("Too many local variables for a routine; max is", MAX_LOCAL_VARIABLES-1); panic_mode_error_recovery(); break; } for (i=0; i<no_locals; i++) if (strcmpcis(token_text, local_variables.keywords[i])==0) error_named("Local variable defined twice:", token_text); local_variables.keywords[no_locals++] = token_text; } while(TRUE); construct_local_variable_tables(); if ((trace_fns_setting==3) || ((trace_fns_setting==2) && (veneer_mode==FALSE)) || ((trace_fns_setting==1) && (is_systemfile()==FALSE))) debug_flag = TRUE; if ((embedded_flag == FALSE) && (veneer_mode == FALSE) && debug_flag) sflags[r_symbol] |= STAR_SFLAG; packed_address = assemble_routine_header(no_locals, debug_flag, name, embedded_flag, r_symbol); do { begin_syntax_line(TRUE); get_next_token(); if (token_type == EOF_TT) { ebf_error("']'", token_text); assemble_routine_end (embedded_flag, get_token_location_end(beginning_debug_location)); put_token_back(); break; } if ((token_type == SEP_TT) && (token_value == CLOSE_SQUARE_SEP)) { if (switch_clause_made && (!default_clause_made)) assemble_label_no(switch_label); directives.enabled = TRUE; sequence_point_follows = TRUE; get_next_token(); assemble_routine_end (embedded_flag, get_token_location_end(beginning_debug_location)); put_token_back(); break; } if ((token_type == STATEMENT_TT) && (token_value == SDEFAULT_CODE)) { if (default_clause_made) error("Multiple 'default' clauses defined in same 'switch'"); default_clause_made = TRUE; if (switch_clause_made) { if (!execution_never_reaches_here) { sequence_point_follows = FALSE; if (!glulx_mode) assemblez_0((embedded_flag)?rfalse_zc:rtrue_zc); else assembleg_1(return_gc, ((embedded_flag)?zero_operand:one_operand)); } assemble_label_no(switch_label); } switch_clause_made = TRUE; get_next_token(); if ((token_type == SEP_TT) && (token_value == COLON_SEP)) continue; ebf_error("':' after 'default'", token_text); panic_mode_error_recovery(); continue; } /* Only check for the form of a case switch if the initial token isn't double-quoted text, as that would mean it was a print_ret statement: this is a mild ambiguity in the grammar. Action statements also cannot be cases. */ if ((token_type != DQ_TT) && (token_type != SEP_TT)) { get_next_token(); if (switch_sign() > 0) { assembly_operand AO; if (default_clause_made) error("'default' must be the last 'switch' case"); if (switch_clause_made) { if (!execution_never_reaches_here) { sequence_point_follows = FALSE; if (!glulx_mode) assemblez_0((embedded_flag)?rfalse_zc:rtrue_zc); else assembleg_1(return_gc, ((embedded_flag)?zero_operand:one_operand)); } assemble_label_no(switch_label); } switch_label = next_label++; switch_clause_made = TRUE; put_token_back(); put_token_back(); if (!glulx_mode) { INITAOTV(&AO, VARIABLE_OT, 249); } else { INITAOTV(&AO, GLOBALVAR_OT, MAX_LOCAL_VARIABLES+6); /* sw__var */ } parse_switch_spec(AO, switch_label, TRUE); continue; } else { put_token_back(); put_token_back(); get_next_token(); sequence_point_follows = TRUE; } } parse_statement(-1, -1); } while (TRUE); return packed_address; }
static void parse_switch_spec(assembly_operand switch_value, int label, int action_switch) { int i, j, label_after = -1, spec_sp = 0; int max_equality_args = ((!glulx_mode) ? 3 : 1); sequence_point_follows = FALSE; do { if (spec_sp == 32) { error("At most 32 values can be given in a single 'switch' case"); panic_mode_error_recovery(); return; } if (action_switch) { get_next_token(); if (token_type == SQ_TT || token_type == DQ_TT) { ebf_error("action (or fake action) name", token_text); continue; } spec_stack[spec_sp] = action_of_name(token_text); if (spec_stack[spec_sp].value == -1) { spec_stack[spec_sp].value = 0; ebf_error("action (or fake action) name", token_text); } } else spec_stack[spec_sp] = code_generate(parse_expression(CONSTANT_CONTEXT), CONSTANT_CONTEXT, -1); misc_keywords.enabled = TRUE; get_next_token(); misc_keywords.enabled = FALSE; spec_type[spec_sp++] = switch_sign(); switch(spec_type[spec_sp-1]) { case 0: if (action_switch) ebf_error("',' or ':'", token_text); else ebf_error("',', ':' or 'to'", token_text); panic_mode_error_recovery(); return; case 1: goto GenSpecCode; case 3: if (label_after == -1) label_after = next_label++; } } while(TRUE); GenSpecCode: if ((spec_sp > max_equality_args) && (label_after == -1)) label_after = next_label++; if (label_after == -1) { compile_alternatives(switch_value, spec_sp, 0, label, FALSE); return; } for (i=0; i<spec_sp;) { j=i; while ((j<spec_sp) && (spec_type[j] != 3)) j++; if (j > i) { if (j-i > max_equality_args) j=i+max_equality_args; if (j == spec_sp) compile_alternatives(switch_value, j-i, i, label, FALSE); else compile_alternatives(switch_value, j-i, i, label_after, TRUE); i=j; } else { if (!glulx_mode) { if (i == spec_sp - 2) { assemblez_2_branch(jl_zc, switch_value, spec_stack[i], label, TRUE); assemblez_2_branch(jg_zc, switch_value, spec_stack[i+1], label, TRUE); } else { assemblez_2_branch(jl_zc, switch_value, spec_stack[i], next_label, TRUE); assemblez_2_branch(jg_zc, switch_value, spec_stack[i+1], label_after, FALSE); assemble_label_no(next_label++); } } else { if (i == spec_sp - 2) { assembleg_2_branch(jlt_gc, switch_value, spec_stack[i], label); assembleg_2_branch(jgt_gc, switch_value, spec_stack[i+1], label); } else { assembleg_2_branch(jlt_gc, switch_value, spec_stack[i], next_label); assembleg_2_branch(jle_gc, switch_value, spec_stack[i+1], label_after); assemble_label_no(next_label++); } } i = i+2; } } assemble_label_no(label_after); }
extern int parse_directive(int internal_flag) { /* Internal_flag is FALSE if the directive is encountered normally, TRUE if encountered with a # prefix inside a routine or object definition. Returns: TRUE if program continues, FALSE if end of file reached. */ int routine_symbol, rep_symbol; int is_renamed; begin_syntax_line(FALSE); get_next_token(); if (token_type == EOF_TT) return(FALSE); if ((token_type == SEP_TT) && (token_value == HASH_SEP)) get_next_token(); if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP)) { if (internal_flag) { error("It is illegal to nest routines using '#['"); return(TRUE); } directives.enabled = FALSE; directive_keywords.enabled = FALSE; segment_markers.enabled = FALSE; /* The upcoming symbol is a definition; don't count it as a top-level reference *to* the function. */ df_dont_note_global_symbols = TRUE; get_next_token(); df_dont_note_global_symbols = FALSE; if ((token_type != SYMBOL_TT) || ((!(sflags[token_value] & UNKNOWN_SFLAG)) && (!(sflags[token_value] & REPLACE_SFLAG)))) { ebf_error("routine name", token_text); return(FALSE); } routine_symbol = token_value; rep_symbol = routine_symbol; is_renamed = find_symbol_replacement(&rep_symbol); if ((sflags[routine_symbol] & REPLACE_SFLAG) && !is_renamed && (is_systemfile())) { /* The function is definitely being replaced (system_file always loses priority in a replacement) but is not being renamed to something else. Skip its definition entirely. */ dont_enter_into_symbol_table = TRUE; do { get_next_token(); } while (!((token_type == EOF_TT) || ((token_type==SEP_TT) && (token_value==CLOSE_SQUARE_SEP)))); dont_enter_into_symbol_table = FALSE; if (token_type == EOF_TT) return FALSE; } else { /* Parse the function definition and assign its symbol. */ assign_symbol(routine_symbol, parse_routine(lexical_source, FALSE, (char *) symbs[routine_symbol], FALSE, routine_symbol), ROUTINE_T); slines[routine_symbol] = routine_starts_line; } if (is_renamed) { /* This function was subject to a "Replace X Y" directive. The first time we see a definition for symbol X, we copy it to Y -- that's the "original" form of the function. */ if (svals[rep_symbol] == 0) { assign_symbol(rep_symbol, svals[routine_symbol], ROUTINE_T); } } get_next_token(); if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP)) { ebf_error("';' after ']'", token_text); put_token_back(); } return TRUE; } if ((token_type == SYMBOL_TT) && (stypes[token_value] == CLASS_T)) { if (internal_flag) { error("It is illegal to nest an object in a routine using '#classname'"); return(TRUE); } sflags[token_value] |= USED_SFLAG; make_object(FALSE, NULL, -1, -1, svals[token_value]); return TRUE; } if (token_type != DIRECTIVE_TT) { /* If we're internal, we expect only a directive here. If we're top-level, the possibilities are broader. */ if (internal_flag) ebf_error("directive", token_text); else ebf_error("directive, '[' or class name", token_text); panic_mode_error_recovery(); return TRUE; } return !(parse_given_directive(internal_flag)); }