directs.c 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140
  1. /* ------------------------------------------------------------------------- */
  2. /* "directs" : Directives (# commands) */
  3. /* */
  4. /* Part of Inform 6.33 */
  5. /* copyright (c) Graham Nelson 1993 - 2014 */
  6. /* */
  7. /* ------------------------------------------------------------------------- */
  8. #include "header.h"
  9. int no_routines, /* Number of routines compiled so far */
  10. no_named_routines, /* Number not embedded in objects */
  11. no_locals, /* Number of locals in current routine */
  12. no_termcs; /* Number of terminating characters */
  13. int terminating_characters[32];
  14. int32 routine_starts_line; /* Source code line on which the current
  15. routine starts. (Useful for reporting
  16. "unused variable" warnings on the start
  17. line rather than the end line.) */
  18. static int constant_made_yet; /* Have any constants been defined yet? */
  19. static int ifdef_stack[32], ifdef_sp;
  20. /* ------------------------------------------------------------------------- */
  21. static int ebf_error_recover(char *s1, char *s2)
  22. {
  23. /* Display an "expected... but found..." error, then skim forward
  24. to the next semicolon and return FALSE. This is such a common
  25. case in parse_given_directive() that it's worth a utility
  26. function. You will see many error paths that look like:
  27. return ebf_error_recover(...);
  28. */
  29. ebf_error(s1, s2);
  30. panic_mode_error_recovery();
  31. return FALSE;
  32. }
  33. /* ------------------------------------------------------------------------- */
  34. extern int parse_given_directive(int internal_flag)
  35. { /* Internal_flag is FALSE if the directive is encountered normally,
  36. TRUE if encountered with a # prefix inside a routine or object
  37. definition.
  38. Returns: FALSE if program continues, TRUE if end of file reached. */
  39. int *trace_level; int32 i, j, k, n, flag;
  40. const char *constant_name;
  41. debug_location_beginning beginning_debug_location;
  42. switch(token_value)
  43. {
  44. /* --------------------------------------------------------------------- */
  45. /* Abbreviate "string1" ["string2" ...] */
  46. /* --------------------------------------------------------------------- */
  47. case ABBREVIATE_CODE:
  48. do
  49. { get_next_token();
  50. if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
  51. return FALSE;
  52. /* Z-code has a 64-abbrev limit; Glulx doesn't. */
  53. if (!glulx_mode && no_abbreviations==64)
  54. { error("All 64 abbreviations already declared");
  55. panic_mode_error_recovery(); return FALSE;
  56. }
  57. if (no_abbreviations==MAX_ABBREVS)
  58. memoryerror("MAX_ABBREVS", MAX_ABBREVS);
  59. if (abbrevs_lookup_table_made)
  60. { error("All abbreviations must be declared together");
  61. panic_mode_error_recovery(); return FALSE;
  62. }
  63. if (token_type != DQ_TT)
  64. return ebf_error_recover("abbreviation string", token_text);
  65. if (strlen(token_text)<2)
  66. { error_named("It's not worth abbreviating", token_text);
  67. continue;
  68. }
  69. make_abbreviation(token_text);
  70. } while (TRUE);
  71. /* --------------------------------------------------------------------- */
  72. /* Array arrayname array... */
  73. /* --------------------------------------------------------------------- */
  74. case ARRAY_CODE: make_global(TRUE, FALSE); break; /* See "tables.c" */
  75. /* --------------------------------------------------------------------- */
  76. /* Attribute newname [alias oldname] */
  77. /* --------------------------------------------------------------------- */
  78. case ATTRIBUTE_CODE:
  79. make_attribute(); break; /* See "objects.c" */
  80. /* --------------------------------------------------------------------- */
  81. /* Class classname ... */
  82. /* --------------------------------------------------------------------- */
  83. case CLASS_CODE:
  84. if (internal_flag)
  85. { error("Cannot nest #Class inside a routine or object");
  86. panic_mode_error_recovery(); return FALSE;
  87. }
  88. make_class(NULL); /* See "objects.c" */
  89. return FALSE;
  90. /* --------------------------------------------------------------------- */
  91. /* Constant newname [[=] value] [, ...] */
  92. /* --------------------------------------------------------------------- */
  93. case CONSTANT_CODE:
  94. constant_made_yet=TRUE;
  95. ParseConstantSpec:
  96. get_next_token(); i = token_value;
  97. beginning_debug_location = get_token_location_beginning();
  98. if ((token_type != SYMBOL_TT)
  99. || (!(sflags[i] & (UNKNOWN_SFLAG + REDEFINABLE_SFLAG))))
  100. { discard_token_location(beginning_debug_location);
  101. return ebf_error_recover("new constant name", token_text);
  102. }
  103. assign_symbol(i, 0, CONSTANT_T);
  104. constant_name = token_text;
  105. get_next_token();
  106. if ((token_type == SEP_TT) && (token_value == COMMA_SEP))
  107. { if (debugfile_switch && !(sflags[i] & REDEFINABLE_SFLAG))
  108. { debug_file_printf("<constant>");
  109. debug_file_printf("<identifier>%s</identifier>", constant_name);
  110. write_debug_symbol_optional_backpatch(i);
  111. write_debug_locations(get_token_location_end(beginning_debug_location));
  112. debug_file_printf("</constant>");
  113. }
  114. goto ParseConstantSpec;
  115. }
  116. if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
  117. { if (debugfile_switch && !(sflags[i] & REDEFINABLE_SFLAG))
  118. { debug_file_printf("<constant>");
  119. debug_file_printf("<identifier>%s</identifier>", constant_name);
  120. write_debug_symbol_optional_backpatch(i);
  121. write_debug_locations(get_token_location_end(beginning_debug_location));
  122. debug_file_printf("</constant>");
  123. }
  124. return FALSE;
  125. }
  126. if (!((token_type == SEP_TT) && (token_value == SETEQUALS_SEP)))
  127. put_token_back();
  128. { assembly_operand AO = parse_expression(CONSTANT_CONTEXT);
  129. if (AO.marker != 0)
  130. { assign_marked_symbol(i, AO.marker, AO.value,
  131. CONSTANT_T);
  132. sflags[i] |= CHANGE_SFLAG;
  133. if (i == grammar_version_symbol)
  134. error(
  135. "Grammar__Version must be given an explicit constant value");
  136. }
  137. else
  138. { assign_symbol(i, AO.value, CONSTANT_T);
  139. if (i == grammar_version_symbol)
  140. { if ((grammar_version_number != AO.value)
  141. && (no_fake_actions > 0))
  142. error(
  143. "Once a fake action has been defined it is too late to \
  144. change the grammar version. (If you are using the library, move any \
  145. Fake_Action directives to a point after the inclusion of \"Parser\".)");
  146. grammar_version_number = AO.value;
  147. }
  148. }
  149. }
  150. if (debugfile_switch && !(sflags[i] & REDEFINABLE_SFLAG))
  151. { debug_file_printf("<constant>");
  152. debug_file_printf("<identifier>%s</identifier>", constant_name);
  153. write_debug_symbol_optional_backpatch(i);
  154. write_debug_locations
  155. (get_token_location_end(beginning_debug_location));
  156. debug_file_printf("</constant>");
  157. }
  158. get_next_token();
  159. if ((token_type == SEP_TT) && (token_value == COMMA_SEP))
  160. goto ParseConstantSpec;
  161. put_token_back();
  162. break;
  163. /* --------------------------------------------------------------------- */
  164. /* Default constantname integer */
  165. /* --------------------------------------------------------------------- */
  166. case DEFAULT_CODE:
  167. if (module_switch)
  168. { error("'Default' cannot be used in -M (Module) mode");
  169. panic_mode_error_recovery(); return FALSE;
  170. }
  171. get_next_token();
  172. if (token_type != SYMBOL_TT)
  173. return ebf_error_recover("name", token_text);
  174. i = -1;
  175. if (sflags[token_value] & UNKNOWN_SFLAG)
  176. { i = token_value;
  177. sflags[i] |= DEFCON_SFLAG;
  178. }
  179. get_next_token();
  180. if (!((token_type == SEP_TT) && (token_value == SETEQUALS_SEP)))
  181. put_token_back();
  182. { assembly_operand AO;
  183. AO = parse_expression(CONSTANT_CONTEXT);
  184. if (i != -1)
  185. { if (AO.marker != 0)
  186. { assign_marked_symbol(i, AO.marker, AO.value,
  187. CONSTANT_T);
  188. sflags[i] |= CHANGE_SFLAG;
  189. }
  190. else assign_symbol(i, AO.value, CONSTANT_T);
  191. }
  192. }
  193. break;
  194. /* --------------------------------------------------------------------- */
  195. /* Dictionary 'word' */
  196. /* Dictionary 'word' val1 */
  197. /* Dictionary 'word' val1 val3 */
  198. /* --------------------------------------------------------------------- */
  199. case DICTIONARY_CODE:
  200. /* In Inform 5, this directive had the form
  201. Dictionary SYMBOL "word";
  202. This was deprecated as of I6 (if not earlier), and is no longer
  203. supported at all. The current form just creates a dictionary word,
  204. with the given values for dict_par1 and dict_par3. If the word
  205. already exists, the values are bit-or'd in with the existing
  206. values.
  207. (We don't offer a way to set dict_par2, because that is entirely
  208. reserved for the verb number. Or'ing values into it would create
  209. garbage.)
  210. */
  211. get_next_token();
  212. if (token_type != SQ_TT && token_type != DQ_TT)
  213. return ebf_error_recover("dictionary word", token_text);
  214. {
  215. char *wd = token_text;
  216. int val1 = 0;
  217. int val3 = 0;
  218. get_next_token();
  219. if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
  220. put_token_back();
  221. }
  222. else {
  223. assembly_operand AO;
  224. put_token_back();
  225. AO = parse_expression(CONSTANT_CONTEXT);
  226. if (module_switch && (AO.marker != 0))
  227. error("A definite value must be given as a Dictionary flag");
  228. else
  229. val1 = AO.value;
  230. get_next_token();
  231. if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
  232. put_token_back();
  233. }
  234. else {
  235. assembly_operand AO;
  236. put_token_back();
  237. AO = parse_expression(CONSTANT_CONTEXT);
  238. if (module_switch && (AO.marker != 0))
  239. error("A definite value must be given as a Dictionary flag");
  240. else
  241. val3 = AO.value;
  242. }
  243. }
  244. if (!glulx_mode) {
  245. if ((val1 & ~0xFF) || (val3 & ~0xFF)) {
  246. warning("Dictionary flag values cannot exceed $FF in Z-code");
  247. }
  248. }
  249. else {
  250. if ((val1 & ~0xFFFF) || (val3 & ~0xFFFF)) {
  251. warning("Dictionary flag values cannot exceed $FFFF in Glulx");
  252. }
  253. }
  254. dictionary_add(wd, val1, 0, val3);
  255. }
  256. break;
  257. /* --------------------------------------------------------------------- */
  258. /* End */
  259. /* --------------------------------------------------------------------- */
  260. case END_CODE: return(TRUE);
  261. case ENDIF_CODE:
  262. if (ifdef_sp == 0) error("'Endif' without matching 'If...'");
  263. else ifdef_sp--;
  264. break;
  265. /* --------------------------------------------------------------------- */
  266. /* Extend ... */
  267. /* --------------------------------------------------------------------- */
  268. case EXTEND_CODE: extend_verb(); return FALSE; /* see "tables.c" */
  269. /* --------------------------------------------------------------------- */
  270. /* Fake_Action name */
  271. /* --------------------------------------------------------------------- */
  272. case FAKE_ACTION_CODE:
  273. make_fake_action(); break; /* see "verbs.c" */
  274. /* --------------------------------------------------------------------- */
  275. /* Global variable [= value / array...] */
  276. /* --------------------------------------------------------------------- */
  277. case GLOBAL_CODE: make_global(FALSE, FALSE); break; /* See "tables.c" */
  278. /* --------------------------------------------------------------------- */
  279. /* If... */
  280. /* */
  281. /* Note that each time Inform tests an If... condition, it stacks the */
  282. /* result (TRUE or FALSE) on ifdef_stack: thus, the top of this stack */
  283. /* reveals what clause of the current If... is being compiled: */
  284. /* */
  285. /* If...; ... Ifnot; ... Endif; */
  286. /* top of stack: TRUE FALSE */
  287. /* */
  288. /* This is used to detect "two Ifnots in same If" errors. */
  289. /* --------------------------------------------------------------------- */
  290. case IFDEF_CODE:
  291. flag = TRUE;
  292. goto DefCondition;
  293. case IFNDEF_CODE:
  294. flag = FALSE;
  295. DefCondition:
  296. get_next_token();
  297. if (token_type != SYMBOL_TT)
  298. return ebf_error_recover("symbol name", token_text);
  299. if ((token_text[0] == 'V')
  300. && (token_text[1] == 'N')
  301. && (token_text[2] == '_')
  302. && (strlen(token_text)==7))
  303. { i = atoi(token_text+3);
  304. if (VNUMBER < i) flag = (flag)?FALSE:TRUE;
  305. goto HashIfCondition;
  306. }
  307. if (sflags[token_value] & UNKNOWN_SFLAG) flag = (flag)?FALSE:TRUE;
  308. else sflags[token_value] |= USED_SFLAG;
  309. goto HashIfCondition;
  310. case IFNOT_CODE:
  311. if (ifdef_sp == 0)
  312. error("'Ifnot' without matching 'If...'");
  313. else
  314. if (!(ifdef_stack[ifdef_sp-1]))
  315. error("Second 'Ifnot' for the same 'If...' condition");
  316. else
  317. { dont_enter_into_symbol_table = -2; n = 1;
  318. directives.enabled = TRUE;
  319. do
  320. { get_next_token();
  321. if (token_type == EOF_TT)
  322. { error("End of file reached in code 'If...'d out");
  323. directives.enabled = FALSE;
  324. return TRUE;
  325. }
  326. if (token_type == DIRECTIVE_TT)
  327. { switch(token_value)
  328. { case ENDIF_CODE:
  329. n--; break;
  330. case IFV3_CODE:
  331. case IFV5_CODE:
  332. case IFDEF_CODE:
  333. case IFNDEF_CODE:
  334. case IFTRUE_CODE:
  335. case IFFALSE_CODE:
  336. n++; break;
  337. case IFNOT_CODE:
  338. if (n == 1)
  339. { error(
  340. "Second 'Ifnot' for the same 'If...' condition");
  341. break;
  342. }
  343. }
  344. }
  345. } while (n > 0);
  346. ifdef_sp--;
  347. dont_enter_into_symbol_table = FALSE;
  348. directives.enabled = FALSE;
  349. }
  350. break;
  351. case IFV3_CODE:
  352. flag = FALSE; if (version_number == 3) flag = TRUE;
  353. goto HashIfCondition;
  354. case IFV5_CODE:
  355. flag = TRUE; if (version_number == 3) flag = FALSE;
  356. goto HashIfCondition;
  357. case IFTRUE_CODE:
  358. { assembly_operand AO;
  359. AO = parse_expression(CONSTANT_CONTEXT);
  360. if (module_switch && (AO.marker != 0))
  361. { error("This condition can't be determined");
  362. flag = 0;
  363. }
  364. else flag = (AO.value != 0);
  365. }
  366. goto HashIfCondition;
  367. case IFFALSE_CODE:
  368. { assembly_operand AO;
  369. AO = parse_expression(CONSTANT_CONTEXT);
  370. if (module_switch && (AO.marker != 0))
  371. { error("This condition can't be determined");
  372. flag = 1;
  373. }
  374. else flag = (AO.value == 0);
  375. }
  376. goto HashIfCondition;
  377. HashIfCondition:
  378. get_next_token();
  379. if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
  380. return ebf_error_recover("semicolon after 'If...' condition", token_text);
  381. if (flag)
  382. { ifdef_stack[ifdef_sp++] = TRUE; return FALSE; }
  383. else
  384. { dont_enter_into_symbol_table = -2; n = 1;
  385. directives.enabled = TRUE;
  386. do
  387. { get_next_token();
  388. if (token_type == EOF_TT)
  389. { error("End of file reached in code 'If...'d out");
  390. directives.enabled = FALSE;
  391. return TRUE;
  392. }
  393. if (token_type == DIRECTIVE_TT)
  394. {
  395. switch(token_value)
  396. { case ENDIF_CODE:
  397. n--; break;
  398. case IFV3_CODE:
  399. case IFV5_CODE:
  400. case IFDEF_CODE:
  401. case IFNDEF_CODE:
  402. case IFTRUE_CODE:
  403. case IFFALSE_CODE:
  404. n++; break;
  405. case IFNOT_CODE:
  406. if (n == 1)
  407. { ifdef_stack[ifdef_sp++] = FALSE;
  408. n--; break;
  409. }
  410. }
  411. }
  412. } while (n > 0);
  413. directives.enabled = FALSE;
  414. dont_enter_into_symbol_table = FALSE;
  415. }
  416. break;
  417. /* --------------------------------------------------------------------- */
  418. /* Import global <varname> [, ...] */
  419. /* */
  420. /* (Further imported goods may be allowed later.) */
  421. /* --------------------------------------------------------------------- */
  422. case IMPORT_CODE:
  423. if (!module_switch)
  424. { error("'Import' can only be used in -M (Module) mode");
  425. panic_mode_error_recovery(); return FALSE;
  426. }
  427. directives.enabled = TRUE;
  428. do
  429. { get_next_token();
  430. if ((token_type == DIRECTIVE_TT) && (token_value == GLOBAL_CODE))
  431. make_global(FALSE, TRUE);
  432. else error_named("'Import' cannot import things of this type:",
  433. token_text);
  434. get_next_token();
  435. } while ((token_type == SEP_TT) && (token_value == COMMA_SEP));
  436. put_token_back();
  437. directives.enabled = FALSE;
  438. break;
  439. /* --------------------------------------------------------------------- */
  440. /* Include "[>]filename" */
  441. /* */
  442. /* The ">" character means to load the file from the same directory as */
  443. /* the current file, instead of relying on the include path. */
  444. /* --------------------------------------------------------------------- */
  445. case INCLUDE_CODE:
  446. get_next_token();
  447. if (token_type != DQ_TT)
  448. return ebf_error_recover("filename in double-quotes", token_text);
  449. { char *name = token_text;
  450. get_next_token();
  451. if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
  452. ebf_error("semicolon ';' after Include filename", token_text);
  453. if (strcmp(name, "language__") == 0)
  454. load_sourcefile(Language_Name, 0);
  455. else if (name[0] == '>')
  456. load_sourcefile(name+1, 1);
  457. else load_sourcefile(name, 0);
  458. return FALSE;
  459. }
  460. /* --------------------------------------------------------------------- */
  461. /* Link "filename" */
  462. /* --------------------------------------------------------------------- */
  463. case LINK_CODE:
  464. get_next_token();
  465. if (token_type != DQ_TT)
  466. return ebf_error_recover("filename in double-quotes", token_text);
  467. link_module(token_text); /* See "linker.c" */
  468. break;
  469. /* --------------------------------------------------------------------- */
  470. /* Lowstring constantname "text of string" */
  471. /* --------------------------------------------------------------------- */
  472. /* Unlike most constant creations, these do not require backpatching: */
  473. /* the low strings always occupy a table at a fixed offset in the */
  474. /* Z-machine (after the abbreviations table has finished, at 0x100). */
  475. /* --------------------------------------------------------------------- */
  476. case LOWSTRING_CODE:
  477. if (module_switch)
  478. { error("'LowString' cannot be used in -M (Module) mode");
  479. panic_mode_error_recovery(); return FALSE;
  480. }
  481. get_next_token(); i = token_value;
  482. if ((token_type != SYMBOL_TT) || (!(sflags[i] & UNKNOWN_SFLAG)))
  483. return ebf_error_recover("new low string name", token_text);
  484. get_next_token();
  485. if (token_type != DQ_TT)
  486. return ebf_error_recover("literal string in double-quotes", token_text);
  487. assign_symbol(i, compile_string(token_text, TRUE, TRUE), CONSTANT_T);
  488. break;
  489. /* --------------------------------------------------------------------- */
  490. /* Message | "information" */
  491. /* | error "error message" */
  492. /* | fatalerror "fatal error message" */
  493. /* | warning "warning message" */
  494. /* --------------------------------------------------------------------- */
  495. case MESSAGE_CODE:
  496. directive_keywords.enabled = TRUE;
  497. get_next_token();
  498. directive_keywords.enabled = FALSE;
  499. if (token_type == DQ_TT)
  500. { int i;
  501. if (hash_printed_since_newline) printf("\n");
  502. for (i=0; token_text[i]!=0; i++)
  503. { if (token_text[i] == '^') printf("\n");
  504. else
  505. if (token_text[i] == '~') printf("\"");
  506. else printf("%c", token_text[i]);
  507. }
  508. printf("\n");
  509. break;
  510. }
  511. if ((token_type == DIR_KEYWORD_TT) && (token_value == ERROR_DK))
  512. { get_next_token();
  513. if (token_type != DQ_TT)
  514. { return ebf_error_recover("error message in double-quotes", token_text);
  515. }
  516. error(token_text); break;
  517. }
  518. if ((token_type == DIR_KEYWORD_TT) && (token_value == FATALERROR_DK))
  519. { get_next_token();
  520. if (token_type != DQ_TT)
  521. { return ebf_error_recover("fatal error message in double-quotes", token_text);
  522. }
  523. fatalerror(token_text); break;
  524. }
  525. if ((token_type == DIR_KEYWORD_TT) && (token_value == WARNING_DK))
  526. { get_next_token();
  527. if (token_type != DQ_TT)
  528. { return ebf_error_recover("warning message in double-quotes", token_text);
  529. }
  530. warning(token_text); break;
  531. }
  532. return ebf_error_recover("a message in double-quotes, 'error', 'fatalerror' or 'warning'",
  533. token_text);
  534. break;
  535. /* --------------------------------------------------------------------- */
  536. /* Nearby objname "short name" ... */
  537. /* --------------------------------------------------------------------- */
  538. case NEARBY_CODE:
  539. if (internal_flag)
  540. { error("Cannot nest #Nearby inside a routine or object");
  541. panic_mode_error_recovery(); return FALSE;
  542. }
  543. make_object(TRUE, NULL, -1, -1, -1);
  544. return FALSE; /* See "objects.c" */
  545. /* --------------------------------------------------------------------- */
  546. /* Object objname "short name" ... */
  547. /* --------------------------------------------------------------------- */
  548. case OBJECT_CODE:
  549. if (internal_flag)
  550. { error("Cannot nest #Object inside a routine or object");
  551. panic_mode_error_recovery(); return FALSE;
  552. }
  553. make_object(FALSE, NULL, -1, -1, -1);
  554. return FALSE; /* See "objects.c" */
  555. /* --------------------------------------------------------------------- */
  556. /* Property [long] [additive] name [alias oldname] */
  557. /* --------------------------------------------------------------------- */
  558. case PROPERTY_CODE: make_property(); break; /* See "objects.c" */
  559. /* --------------------------------------------------------------------- */
  560. /* Release <number> */
  561. /* --------------------------------------------------------------------- */
  562. case RELEASE_CODE:
  563. { assembly_operand AO;
  564. AO = parse_expression(CONSTANT_CONTEXT);
  565. if (module_switch && (AO.marker != 0))
  566. error("A definite value must be given as release number");
  567. else
  568. release_number = AO.value;
  569. }
  570. break;
  571. /* --------------------------------------------------------------------- */
  572. /* Replace routine [routinename] */
  573. /* --------------------------------------------------------------------- */
  574. case REPLACE_CODE:
  575. /* You can also replace system functions normally implemented in */
  576. /* the "hardware" of the Z-machine, like "random()": */
  577. system_functions.enabled = TRUE;
  578. directives.enabled = FALSE;
  579. directive_keywords.enabled = FALSE;
  580. /* Don't count the upcoming symbol as a top-level reference
  581. *to* the function. */
  582. df_dont_note_global_symbols = TRUE;
  583. get_next_token();
  584. df_dont_note_global_symbols = FALSE;
  585. if (token_type == SYSFUN_TT)
  586. { if (system_function_usage[token_value] == 1)
  587. error("You can't 'Replace' a system function already used");
  588. else system_function_usage[token_value] = 2;
  589. get_next_token();
  590. if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
  591. {
  592. error("You can't give a 'Replace'd system function a new name");
  593. panic_mode_error_recovery(); return FALSE;
  594. }
  595. return FALSE;
  596. }
  597. if (token_type != SYMBOL_TT)
  598. return ebf_error_recover("name of routine to replace", token_text);
  599. if (!(sflags[token_value] & UNKNOWN_SFLAG))
  600. return ebf_error_recover("name of routine not yet defined", token_text);
  601. sflags[token_value] |= REPLACE_SFLAG;
  602. /* If a second symbol is provided, it will refer to the
  603. original (replaced) definition of the routine. */
  604. i = token_value;
  605. system_functions.enabled = FALSE;
  606. df_dont_note_global_symbols = TRUE;
  607. get_next_token();
  608. df_dont_note_global_symbols = FALSE;
  609. if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
  610. { return FALSE;
  611. }
  612. if (token_type != SYMBOL_TT || !(sflags[token_value] & UNKNOWN_SFLAG))
  613. return ebf_error_recover("semicolon ';' or new routine name", token_text);
  614. /* Define the original-form symbol as a zero constant. Its
  615. value will be overwritten later, when we define the
  616. replacement. */
  617. assign_symbol(token_value, 0, CONSTANT_T);
  618. add_symbol_replacement_mapping(i, token_value);
  619. break;
  620. /* --------------------------------------------------------------------- */
  621. /* Serial "yymmdd" */
  622. /* --------------------------------------------------------------------- */
  623. case SERIAL_CODE:
  624. get_next_token();
  625. if ((token_type != DQ_TT) || (strlen(token_text)!=6))
  626. { error("The serial number must be a 6-digit date in double-quotes");
  627. panic_mode_error_recovery(); return FALSE;
  628. }
  629. for (i=0; i<6; i++) if (isdigit(token_text[i])==0)
  630. { error("The serial number must be a 6-digit date in double-quotes");
  631. panic_mode_error_recovery(); return FALSE;
  632. }
  633. strcpy(serial_code_buffer, token_text);
  634. serial_code_given_in_program = TRUE;
  635. break;
  636. /* --------------------------------------------------------------------- */
  637. /* Statusline score/time */
  638. /* --------------------------------------------------------------------- */
  639. case STATUSLINE_CODE:
  640. if (module_switch)
  641. warning("This does not set the final game's statusline");
  642. directive_keywords.enabled = TRUE;
  643. get_next_token();
  644. directive_keywords.enabled = FALSE;
  645. if ((token_type != DIR_KEYWORD_TT)
  646. || ((token_value != SCORE_DK) && (token_value != TIME_DK)))
  647. return ebf_error_recover("'score' or 'time' after 'statusline'", token_text);
  648. if (token_value == SCORE_DK) statusline_flag = SCORE_STYLE;
  649. else statusline_flag = TIME_STYLE;
  650. break;
  651. /* --------------------------------------------------------------------- */
  652. /* Stub routinename number-of-locals */
  653. /* --------------------------------------------------------------------- */
  654. case STUB_CODE:
  655. if (internal_flag)
  656. { error("Cannot nest #Stub inside a routine or object");
  657. panic_mode_error_recovery(); return FALSE;
  658. }
  659. /* The upcoming symbol is a definition; don't count it as a
  660. top-level reference *to* the stub function. */
  661. df_dont_note_global_symbols = TRUE;
  662. get_next_token();
  663. df_dont_note_global_symbols = FALSE;
  664. if (token_type != SYMBOL_TT)
  665. return ebf_error_recover("routine name to stub", token_text);
  666. i = token_value; flag = FALSE;
  667. if (sflags[i] & UNKNOWN_SFLAG)
  668. { sflags[i] |= STUB_SFLAG;
  669. flag = TRUE;
  670. }
  671. get_next_token(); k = token_value;
  672. if (token_type != NUMBER_TT)
  673. return ebf_error_recover("number of local variables", token_text);
  674. if ((k>4) || (k<0))
  675. { error("Must specify 0 to 4 local variables for 'Stub' routine");
  676. k = 0;
  677. }
  678. if (flag)
  679. {
  680. /* Give these parameter-receiving local variables names
  681. for the benefit of the debugging information file,
  682. and for assembly tracing to look sensible. */
  683. local_variable_texts[0] = "dummy1";
  684. local_variable_texts[1] = "dummy2";
  685. local_variable_texts[2] = "dummy3";
  686. local_variable_texts[3] = "dummy4";
  687. assign_symbol(i,
  688. assemble_routine_header(k, FALSE, (char *) symbs[i], FALSE, i),
  689. ROUTINE_T);
  690. /* Ensure the return value of a stubbed routine is false,
  691. since this is necessary to make the library work properly */
  692. if (!glulx_mode)
  693. assemblez_0(rfalse_zc);
  694. else
  695. assembleg_1(return_gc, zero_operand);
  696. /* Inhibit "local variable unused" warnings */
  697. for (i=1; i<=k; i++) variable_usage[i] = 1;
  698. sequence_point_follows = FALSE;
  699. assemble_routine_end(FALSE, get_token_locations());
  700. }
  701. break;
  702. /* --------------------------------------------------------------------- */
  703. /* Switches switchblock */
  704. /* (this directive is ignored if the -i switch was set at command line) */
  705. /* --------------------------------------------------------------------- */
  706. case SWITCHES_CODE:
  707. dont_enter_into_symbol_table = TRUE;
  708. get_next_token();
  709. dont_enter_into_symbol_table = FALSE;
  710. if (token_type != DQ_TT)
  711. return ebf_error_recover("string of switches", token_text);
  712. if (!ignore_switches_switch)
  713. { if (constant_made_yet)
  714. error("A 'Switches' directive must must come before \
  715. the first constant definition");
  716. switches(token_text, 0); /* see "inform.c" */
  717. }
  718. break;
  719. /* --------------------------------------------------------------------- */
  720. /* System_file */
  721. /* */
  722. /* Some files are declared as "system files": this information is used */
  723. /* by Inform only to skip the definition of a routine X if the designer */
  724. /* has indicated his intention to Replace X. */
  725. /* --------------------------------------------------------------------- */
  726. case SYSTEM_CODE:
  727. declare_systemfile(); break; /* see "files.c" */
  728. /* --------------------------------------------------------------------- */
  729. /* Trace dictionary */
  730. /* objects */
  731. /* symbols */
  732. /* verbs */
  733. /* [on/off] */
  734. /* assembly [on/off] */
  735. /* expressions [on/off] */
  736. /* lines [on/off] */
  737. /* --------------------------------------------------------------------- */
  738. case TRACE_CODE:
  739. directives.enabled = FALSE;
  740. trace_keywords.enabled = TRUE;
  741. get_next_token();
  742. trace_keywords.enabled = FALSE;
  743. directives.enabled = TRUE;
  744. if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
  745. { asm_trace_level = 1; return FALSE; }
  746. if (token_type != TRACE_KEYWORD_TT)
  747. return ebf_error_recover("debugging keyword", token_text);
  748. trace_keywords.enabled = TRUE;
  749. i = token_value; j = 0;
  750. switch(i)
  751. { case DICTIONARY_TK: break;
  752. case OBJECTS_TK: break;
  753. case VERBS_TK: break;
  754. default:
  755. switch(token_value)
  756. { case ASSEMBLY_TK:
  757. trace_level = &asm_trace_level; break;
  758. case EXPRESSIONS_TK:
  759. trace_level = &expr_trace_level; break;
  760. case LINES_TK:
  761. trace_level = &line_trace_level; break;
  762. case TOKENS_TK:
  763. trace_level = &tokens_trace_level; break;
  764. case LINKER_TK:
  765. trace_level = &linker_trace_level; break;
  766. case SYMBOLS_TK:
  767. trace_level = NULL; break;
  768. default:
  769. put_token_back();
  770. trace_level = &asm_trace_level; break;
  771. }
  772. j = 1;
  773. get_next_token();
  774. if ((token_type == SEP_TT) &&
  775. (token_value == SEMICOLON_SEP))
  776. { put_token_back(); break;
  777. }
  778. if (token_type == NUMBER_TT)
  779. { j = token_value; break; }
  780. if ((token_type == TRACE_KEYWORD_TT) && (token_value == ON_TK))
  781. { j = 1; break; }
  782. if ((token_type == TRACE_KEYWORD_TT) && (token_value == OFF_TK))
  783. { j = 0; break; }
  784. put_token_back(); break;
  785. }
  786. switch(i)
  787. { case DICTIONARY_TK: show_dictionary(); break;
  788. case OBJECTS_TK: list_object_tree(); break;
  789. case SYMBOLS_TK: list_symbols(j); break;
  790. case VERBS_TK: list_verb_table(); break;
  791. default:
  792. *trace_level = j;
  793. break;
  794. }
  795. trace_keywords.enabled = FALSE;
  796. break;
  797. /* --------------------------------------------------------------------- */
  798. /* Undef symbol */
  799. /* --------------------------------------------------------------------- */
  800. case UNDEF_CODE:
  801. get_next_token();
  802. if (token_type != SYMBOL_TT)
  803. return ebf_error_recover("symbol name", token_text);
  804. if (sflags[token_value] & UNKNOWN_SFLAG)
  805. { break; /* undef'ing an undefined constant is okay */
  806. }
  807. if (stypes[token_value] != CONSTANT_T)
  808. { error_named("Cannot Undef a symbol which is not a defined constant:", (char *)symbs[token_value]);
  809. break;
  810. }
  811. if (debugfile_switch)
  812. { write_debug_undef(token_value);
  813. }
  814. end_symbol_scope(token_value);
  815. sflags[token_value] |= USED_SFLAG;
  816. break;
  817. /* --------------------------------------------------------------------- */
  818. /* Verb ... */
  819. /* --------------------------------------------------------------------- */
  820. case VERB_CODE: make_verb(); return FALSE; /* see "tables.c" */
  821. /* --------------------------------------------------------------------- */
  822. /* Version <number> */
  823. /* --------------------------------------------------------------------- */
  824. case VERSION_CODE:
  825. { assembly_operand AO;
  826. AO = parse_expression(CONSTANT_CONTEXT);
  827. /* If a version has already been set on the command line,
  828. that overrides this. */
  829. if (version_set_switch)
  830. {
  831. warning("The Version directive was overridden by a command-line argument.");
  832. break;
  833. }
  834. if (module_switch && (AO.marker != 0))
  835. error("A definite value must be given as version number");
  836. else
  837. if (glulx_mode)
  838. {
  839. warning("The Version directive does not work in Glulx. Use \
  840. -vX.Y.Z instead, as either a command-line argument or a header comment.");
  841. break;
  842. }
  843. else
  844. { i = AO.value;
  845. if ((i<3) || (i>8))
  846. { error("The version number must be in the range 3 to 8");
  847. break;
  848. }
  849. select_version(i);
  850. }
  851. }
  852. break; /* see "inform.c" */
  853. /* --------------------------------------------------------------------- */
  854. /* Zcharacter table <num> ... */
  855. /* Zcharacter table + <num> ... */
  856. /* Zcharacter <string> <string> <string> */
  857. /* Zcharacter <char> */
  858. /* --------------------------------------------------------------------- */
  859. case ZCHARACTER_CODE:
  860. if (glulx_mode) {
  861. error("The Zcharacter directive has no meaning in Glulx.");
  862. panic_mode_error_recovery(); return FALSE;
  863. }
  864. directive_keywords.enabled = TRUE;
  865. get_next_token();
  866. directive_keywords.enabled = FALSE;
  867. switch(token_type)
  868. { case DQ_TT:
  869. new_alphabet(token_text, 0);
  870. get_next_token();
  871. if (token_type != DQ_TT)
  872. return ebf_error_recover("double-quoted alphabet string", token_text);
  873. new_alphabet(token_text, 1);
  874. get_next_token();
  875. if (token_type != DQ_TT)
  876. return ebf_error_recover("double-quoted alphabet string", token_text);
  877. new_alphabet(token_text, 2);
  878. break;
  879. case SQ_TT:
  880. map_new_zchar(text_to_unicode(token_text));
  881. if (token_text[textual_form_length] != 0)
  882. return ebf_error_recover("single character value", token_text);
  883. break;
  884. case DIR_KEYWORD_TT:
  885. switch(token_value)
  886. { case TABLE_DK:
  887. { int plus_flag = FALSE;
  888. get_next_token();
  889. if ((token_type == SEP_TT) && (token_value == PLUS_SEP))
  890. { plus_flag = TRUE;
  891. get_next_token();
  892. }
  893. while ((token_type!=SEP_TT) || (token_value!=SEMICOLON_SEP))
  894. { switch(token_type)
  895. { case NUMBER_TT:
  896. new_zscii_character(token_value, plus_flag);
  897. plus_flag = TRUE; break;
  898. case SQ_TT:
  899. new_zscii_character(text_to_unicode(token_text),
  900. plus_flag);
  901. if (token_text[textual_form_length] != 0)
  902. return ebf_error_recover("single character value",
  903. token_text);
  904. plus_flag = TRUE;
  905. break;
  906. default:
  907. return ebf_error_recover("character or Unicode number",
  908. token_text);
  909. }
  910. get_next_token();
  911. }
  912. if (plus_flag) new_zscii_finished();
  913. put_token_back();
  914. }
  915. break;
  916. case TERMINATING_DK:
  917. get_next_token();
  918. while ((token_type!=SEP_TT) || (token_value!=SEMICOLON_SEP))
  919. { switch(token_type)
  920. { case NUMBER_TT:
  921. terminating_characters[no_termcs++]
  922. = token_value;
  923. break;
  924. default:
  925. return ebf_error_recover("ZSCII number",
  926. token_text);
  927. }
  928. get_next_token();
  929. }
  930. put_token_back();
  931. break;
  932. default:
  933. return ebf_error_recover("'table', 'terminating', \
  934. a string or a constant",
  935. token_text);
  936. }
  937. break;
  938. default:
  939. return ebf_error_recover("three alphabet strings, \
  940. a 'table' or 'terminating' command or a single character", token_text);
  941. }
  942. break;
  943. /* ===================================================================== */
  944. }
  945. /* We are now at the end of a syntactically valid directive. It
  946. should be terminated by a semicolon. */
  947. get_next_token();
  948. if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
  949. { ebf_error("';'", token_text);
  950. /* Put the non-semicolon back. We will continue parsing from
  951. that point, in hope that it's the start of a new directive.
  952. (This recovers cleanly from a missing semicolon at the end
  953. of a directive. It's not so clean if the directive *does*
  954. end with a semicolon, but there's extra garbage before it.) */
  955. put_token_back();
  956. }
  957. return FALSE;
  958. }
  959. /* ========================================================================= */
  960. /* Data structure management routines */
  961. /* ------------------------------------------------------------------------- */
  962. extern void init_directs_vars(void)
  963. {
  964. }
  965. extern void directs_begin_pass(void)
  966. { no_routines = 0;
  967. no_named_routines = 0;
  968. no_locals = 0;
  969. no_termcs = 0;
  970. constant_made_yet = FALSE;
  971. ifdef_sp = 0;
  972. }
  973. extern void directs_allocate_arrays(void)
  974. {
  975. }
  976. extern void directs_free_arrays(void)
  977. {
  978. }
  979. /* ========================================================================= */