/* ------------------------------------------------------------------------- */
/* "directs" : Directives (# commands) */
/* */
-/* Copyright (c) Graham Nelson 1993 - 2020 */
-/* */
-/* This file is part of Inform. */
+/* Part of Inform 6.35 */
+/* copyright (c) Graham Nelson 1993 - 2021 */
/* */
/* Inform is free software: you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
static int constant_made_yet; /* Have any constants been defined yet? */
-static int ifdef_stack[32], ifdef_sp;
+#define MAX_IFDEF_STACK (32)
+static int ifdef_stack[MAX_IFDEF_STACK], ifdef_sp;
/* ------------------------------------------------------------------------- */
return FALSE;
}
+static int ebf_symbol_error_recover(char *s1, char *name, char *type, brief_location report_line)
+{
+ /* Same for ebf_symbol_error(). */
+ ebf_symbol_error(s1, name, type, report_line);
+ panic_mode_error_recovery();
+ return FALSE;
+}
+
/* ------------------------------------------------------------------------- */
extern int parse_given_directive(int internal_flag)
const char *constant_name;
debug_location_beginning beginning_debug_location;
+ if (internal_flag)
+ {
+ /* Only certain directives, such as #ifdef, are permitted within
+ a routine or object definition. In older versions of Inform,
+ nearly any directive was accepted, but this was -- to quote
+ an old code comment -- "about as well-supported as Wile E.
+ Coyote one beat before the plummet-lines kick in." */
+
+ if (token_value != IFV3_CODE && token_value != IFV5_CODE
+ && token_value != IFDEF_CODE && token_value != IFNDEF_CODE
+ && token_value != IFTRUE_CODE && token_value != IFFALSE_CODE
+ && token_value != IFNOT_CODE && token_value != ENDIF_CODE
+ && token_value != MESSAGE_CODE && token_value != ORIGSOURCE_CODE
+ && token_value != TRACE_CODE) {
+ char *dirname = directives.keywords[token_value];
+ error_named("Cannot nest this directive inside a routine or object:", dirname);
+ panic_mode_error_recovery(); return FALSE;
+ }
+ }
+
switch(token_value)
{
if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
return FALSE;
- /* Z-code has a 64-abbrev limit; Glulx doesn't. */
- if (!glulx_mode && no_abbreviations==64)
- { error("All 64 abbreviations already declared");
+ if (!glulx_mode && no_abbreviations==96)
+ { error("All 96 Z-machine abbreviations already declared");
panic_mode_error_recovery(); return FALSE;
}
if (no_abbreviations==MAX_ABBREVS)
/* --------------------------------------------------------------------- */
case CLASS_CODE:
- if (internal_flag)
- { error("Cannot nest #Class inside a routine or object");
- panic_mode_error_recovery(); return FALSE;
- }
make_class(NULL); /* See "objects.c" */
return FALSE;
get_next_token(); i = token_value;
beginning_debug_location = get_token_location_beginning();
- if ((token_type != SYMBOL_TT)
- || (!(sflags[i] & (UNKNOWN_SFLAG + REDEFINABLE_SFLAG))))
+ if (token_type != SYMBOL_TT)
{ discard_token_location(beginning_debug_location);
return ebf_error_recover("new constant name", token_text);
}
+ if (!(sflags[i] & (UNKNOWN_SFLAG + REDEFINABLE_SFLAG)))
+ { discard_token_location(beginning_debug_location);
+ return ebf_symbol_error_recover("new constant name", token_text, typename(stypes[i]), slines[i]);
+ }
+
assign_symbol(i, 0, CONSTANT_T);
constant_name = token_text;
assembly_operand AO;
put_token_back();
AO = parse_expression(CONSTANT_CONTEXT);
- if (module_switch && (AO.marker != 0))
+ if (AO.marker != 0)
error("A definite value must be given as a Dictionary flag");
else
val1 = AO.value;
assembly_operand AO;
put_token_back();
AO = parse_expression(CONSTANT_CONTEXT);
- if (module_switch && (AO.marker != 0))
+ if (AO.marker != 0)
error("A definite value must be given as a Dictionary flag");
else
val3 = AO.value;
case IFTRUE_CODE:
{ assembly_operand AO;
AO = parse_expression(CONSTANT_CONTEXT);
- if (module_switch && (AO.marker != 0))
+ if (AO.marker != 0)
{ error("This condition can't be determined");
flag = 0;
}
case IFFALSE_CODE:
{ assembly_operand AO;
AO = parse_expression(CONSTANT_CONTEXT);
- if (module_switch && (AO.marker != 0))
+ if (AO.marker != 0)
{ error("This condition can't be determined");
flag = 1;
}
if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
return ebf_error_recover("semicolon after 'If...' condition", token_text);
+ if (ifdef_sp >= MAX_IFDEF_STACK) {
+ error("'If' directives nested too deeply");
+ panic_mode_error_recovery(); return FALSE;
+ }
+
if (flag)
{ ifdef_stack[ifdef_sp++] = TRUE; return FALSE; }
else
{ error("'LowString' cannot be used in -M (Module) mode");
panic_mode_error_recovery(); return FALSE;
}
+ if (glulx_mode) {
+ error("The LowString directive has no meaning in Glulx.");
+ panic_mode_error_recovery(); return FALSE;
+ }
get_next_token(); i = token_value;
- if ((token_type != SYMBOL_TT) || (!(sflags[i] & UNKNOWN_SFLAG)))
+ if (token_type != SYMBOL_TT)
return ebf_error_recover("new low string name", token_text);
+ if (!(sflags[i] & UNKNOWN_SFLAG))
+ return ebf_symbol_error_recover("new low string name", token_text, typename(stypes[i]), slines[i]);
get_next_token();
if (token_type != DQ_TT)
return ebf_error_recover("literal string in double-quotes", token_text);
- assign_symbol(i, compile_string(token_text, TRUE, TRUE), CONSTANT_T);
+ assign_symbol(i, compile_string(token_text, STRCTX_LOWSTRING), CONSTANT_T);
break;
/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
case NEARBY_CODE:
- if (internal_flag)
- { error("Cannot nest #Nearby inside a routine or object");
- panic_mode_error_recovery(); return FALSE;
- }
make_object(TRUE, NULL, -1, -1, -1);
return FALSE; /* See "objects.c" */
/* --------------------------------------------------------------------- */
case OBJECT_CODE:
- if (internal_flag)
- { error("Cannot nest #Object inside a routine or object");
- panic_mode_error_recovery(); return FALSE;
- }
make_object(FALSE, NULL, -1, -1, -1);
return FALSE; /* See "objects.c" */
case RELEASE_CODE:
{ assembly_operand AO;
AO = parse_expression(CONSTANT_CONTEXT);
- if (module_switch && (AO.marker != 0))
+ if (AO.marker != 0)
error("A definite value must be given as release number");
else
release_number = AO.value;
/* --------------------------------------------------------------------- */
case STUB_CODE:
- if (internal_flag)
- { error("Cannot nest #Stub inside a routine or object");
- panic_mode_error_recovery(); return FALSE;
- }
-
/* The upcoming symbol is a definition; don't count it as a
top-level reference *to* the stub function. */
df_dont_note_global_symbols = TRUE;
break;
}
- if (module_switch && (AO.marker != 0))
+ if (AO.marker != 0)
error("A definite value must be given as version number");
else
if (glulx_mode)