1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-03 07:24:58 +03:00
inform7/inter/codegen-module/Chapter 2/Resolving Conditional Compilation.w
2021-04-15 22:42:28 +01:00

180 lines
5.9 KiB
OpenEdge ABL

[CodeGen::RCC::] Resolving Conditional Compilation.
To generate the initial state of storage for variables.
@h Pipeline stage.
=
void CodeGen::RCC::create_pipeline_stage(void) {
CodeGen::Stage::new(I"resolve-conditional-compilation", CodeGen::RCC::run_pipeline_stage, NO_STAGE_ARG, FALSE);
}
int CodeGen::RCC::run_pipeline_stage(pipeline_step *step) {
CodeGen::RCC::resolve(step->repository);
return TRUE;
}
@h Resolution.
@d MAX_CC_STACK_SIZE 32
=
typedef struct rcc_state {
struct dictionary *I6_level_symbols;
int cc_stack[MAX_CC_STACK_SIZE];
int cc_sp;
} rcc_state;
void CodeGen::RCC::resolve(inter_tree *I) {
rcc_state state;
state.I6_level_symbols = Dictionaries::new(1024, TRUE);
state.cc_sp = 0;
InterTree::traverse(I, CodeGen::RCC::visitor, &state, NULL, 0);
if (state.cc_sp != 0)
TemplateReader::error("conditional compilation is wrongly structured in the template: not enough #endif", NULL);
}
void CodeGen::RCC::visitor(inter_tree *I, inter_tree_node *P, void *v_state) {
rcc_state *state = (rcc_state *) v_state;
int allow = TRUE;
for (int i=0; i<state->cc_sp; i++) if (state->cc_stack[i] == FALSE) allow = FALSE;
inter_package *outer = Inter::Packages::container(P);
if ((outer == NULL) || (Inter::Packages::is_codelike(outer) == FALSE)) {
if (P->W.data[ID_IFLD] == SPLAT_IST) {
text_stream *S = Inode::ID_to_text(P, P->W.data[MATTER_SPLAT_IFLD]);
switch (P->W.data[PLM_SPLAT_IFLD]) {
case CONSTANT_PLM:
case GLOBAL_PLM:
case ARRAY_PLM:
case ROUTINE_PLM:
case DEFAULT_PLM:
case STUB_PLM:
if (allow) @<Symbol definition@>;
break;
case IFDEF_PLM: @<Deal with an IFDEF@>; break;
case IFNDEF_PLM: @<Deal with an IFNDEF@>; break;
case IFTRUE_PLM: @<Deal with an IFTRUE@>; break;
case IFNOT_PLM: @<Deal with an IFNOT@>; break;
case ENDIF_PLM: @<Deal with an ENDIF@>; break;
}
}
}
if (allow == FALSE) InterTree::remove_node(P);
}
@<Extract second token into ident@> =
int tcount = 0;
LOOP_THROUGH_TEXT(pos, S) {
wchar_t c = Str::get(pos);
if ((c == ' ') || (c == '\t') || (c == '\n')) {
if (tcount == 1) tcount = 2;
else if (tcount == 2) break;
} else {
if (tcount == 0) tcount = 1;
if ((c == ';') || (c == '-')) break;
if (tcount == 2) PUT_TO(ident, c);
}
}
@<Extract rest of text into ident@> =
int tcount = 0;
LOOP_THROUGH_TEXT(pos, S) {
wchar_t c = Str::get(pos);
if ((c == ' ') || (c == '\t') || (c == '\n')) {
if (tcount == 1) tcount = 2;
} else {
if (tcount == 0) tcount = 1;
if ((c == ';') || (c == '-')) break;
if (tcount == 2) PUT_TO(ident, c);
}
}
@<Symbol definition@> =
TEMPORARY_TEXT(ident)
@<Extract second token into ident@>;
LOGIF(RESOLVING_CONDITIONAL_COMPILATION, "I6 defines %S here\n", ident);
Dictionaries::create(state->I6_level_symbols, ident);
DISCARD_TEXT(ident)
@<Deal with an IFDEF@> =
TEMPORARY_TEXT(ident)
@<Extract rest of text into ident@>;
int result = FALSE;
text_stream *symbol_name = ident;
@<Decide whether symbol defined@>;
@<Stack up the result@>;
allow = FALSE;
DISCARD_TEXT(ident)
@<Deal with an IFNDEF@> =
TEMPORARY_TEXT(ident)
@<Extract rest of text into ident@>;
int result = FALSE;
text_stream *symbol_name = ident;
@<Decide whether symbol defined@>;
result = (result)?FALSE:TRUE;
@<Stack up the result@>;
allow = FALSE;
DISCARD_TEXT(ident)
@<Decide whether symbol defined@> =
inter_symbol *symbol = InterSymbolsTables::symbol_from_name_in_main_or_basics(I, symbol_name);
if (symbol) {
result = TRUE;
if (Inter::Symbols::is_extern(symbol)) result = FALSE;
} else if (Dictionaries::find(state->I6_level_symbols, symbol_name)) result = TRUE;
LOGIF(RESOLVING_CONDITIONAL_COMPILATION, "Must decide if %S defined: %s\n", symbol_name, (result)?"yes":"no");
if (Log::aspect_switched_on(RESOLVING_CONDITIONAL_COMPILATION_DA)) LOG_INDENT;
@<Deal with an IFTRUE@> =
TEMPORARY_TEXT(ident)
@<Extract rest of text into ident@>;
int result = NOT_APPLICABLE;
text_stream *cond = ident;
match_results mr2 = Regexp::create_mr();
if (Regexp::match(&mr2, cond, L" *(%C+?) *== *(%d+) *")) {
text_stream *identifier = mr2.exp[0];
inter_symbol *symbol = InterSymbolsTables::symbol_from_name_in_main_or_basics(I, identifier);
if (symbol) {
inter_tree_node *P = Inter::Symbols::definition(symbol);
if ((P) &&
(P->W.data[ID_IFLD] == CONSTANT_IST) &&
(P->W.data[FORMAT_CONST_IFLD] == CONSTANT_DIRECT) &&
(P->W.data[DATA_CONST_IFLD] == LITERAL_IVAL)) {
int V = (int) P->W.data[DATA_CONST_IFLD + 1];
int W = Str::atoi(mr2.exp[1], 0);
if (V == W) result = TRUE; else result = FALSE;
}
}
}
if (result == NOT_APPLICABLE) {
TemplateReader::error("conditional compilation is too difficult in the template: #iftrue on %S", cond);
result = FALSE;
}
LOGIF(RESOLVING_CONDITIONAL_COMPILATION, "Must decide if %S: ", cond);
LOGIF(RESOLVING_CONDITIONAL_COMPILATION, "%s\n", (result)?"true":"false");
if (Log::aspect_switched_on(RESOLVING_CONDITIONAL_COMPILATION_DA)) LOG_INDENT;
@<Stack up the result@>;
allow = FALSE;
DISCARD_TEXT(ident)
@<Stack up the result@> =
if (state->cc_sp >= MAX_CC_STACK_SIZE) {
state->cc_sp = MAX_CC_STACK_SIZE; TemplateReader::error("conditional compilation is wrongly structured in the template: too many nested #ifdef or #iftrue", NULL);
} else {
state->cc_stack[state->cc_sp++] = result;
}
@<Deal with an IFNOT@> =
LOGIF(RESOLVING_CONDITIONAL_COMPILATION, "ifnot\n");
if (state->cc_sp == 0) TemplateReader::error("conditional compilation is wrongly structured in the template: #ifnot at top level", NULL);
else state->cc_stack[state->cc_sp-1] = (state->cc_stack[state->cc_sp-1])?FALSE:TRUE;
allow = FALSE;
@<Deal with an ENDIF@> =
if (Log::aspect_switched_on(RESOLVING_CONDITIONAL_COMPILATION_DA)) LOG_OUTDENT;
LOGIF(RESOLVING_CONDITIONAL_COMPILATION, "endif\n");
state->cc_sp--;
if (state->cc_sp < 0) { state->cc_sp = 0; TemplateReader::error("conditional compilation is wrongly structured in the template: too many #endif", NULL); }
allow = FALSE;