states.c 113 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704
  1. /* ------------------------------------------------------------------------- */
  2. /* "states" : Statement translator */
  3. /* */
  4. /* Part of Inform 6.33 */
  5. /* copyright (c) Graham Nelson 1993 - 2014 */
  6. /* */
  7. /* ------------------------------------------------------------------------- */
  8. #include "header.h"
  9. static int match_colon(void)
  10. { get_next_token();
  11. if (token_type == SEP_TT)
  12. { if (token_value == SEMICOLON_SEP)
  13. warning("Unlike C, Inform uses ':' to divide parts \
  14. of a 'for' loop specification: replacing ';' with ':'");
  15. else
  16. if (token_value != COLON_SEP)
  17. { ebf_error("':'", token_text);
  18. panic_mode_error_recovery();
  19. return(FALSE);
  20. }
  21. }
  22. else
  23. { ebf_error("':'", token_text);
  24. panic_mode_error_recovery();
  25. return(FALSE);
  26. }
  27. return(TRUE);
  28. }
  29. static void match_open_bracket(void)
  30. { get_next_token();
  31. if ((token_type == SEP_TT) && (token_value == OPENB_SEP)) return;
  32. put_token_back();
  33. ebf_error("'('", token_text);
  34. }
  35. extern void match_close_bracket(void)
  36. { get_next_token();
  37. if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP)) return;
  38. put_token_back();
  39. ebf_error("')'", token_text);
  40. }
  41. static void parse_action(void)
  42. { int level = 1, args = 0, codegen_action;
  43. assembly_operand AO, AO2, AO3, AO4, AO5;
  44. /* An action statement has the form <ACTION NOUN SECOND, ACTOR>
  45. or <<ACTION NOUN SECOND, ACTOR>>. It simply compiles into a call
  46. to R_Process() with those four arguments. (The latter form,
  47. with double brackets, means "return true afterwards".)
  48. The R_Process() function should be supplied by the library,
  49. although a stub is defined in the veneer.
  50. The NOUN, SECOND, and ACTOR arguments are optional. If not
  51. supplied, R_Process() will be called with fewer arguments.
  52. (But if you supply ACTOR, it must be preceded by a comma.
  53. <ACTION, ACTOR> is equivalent to <ACTION 0 0, ACTOR>.)
  54. To complicate life, the ACTION argument may be a bare action
  55. name or a parenthesized expression. (So <Take> is equivalent
  56. to <(##Take)>.) We have to peek at the first token, checking
  57. whether it's an open-paren, to distinguish these cases.
  58. You may ask why the ACTOR argument is last; the "natural"
  59. Inform ordering would be "<floyd, take ball>". True! Sadly,
  60. Inform's lexer isn't smart enough to parse this consistently,
  61. so we can't do it.
  62. */
  63. dont_enter_into_symbol_table = TRUE;
  64. get_next_token();
  65. if ((token_type == SEP_TT) && (token_value == LESS_SEP))
  66. { level = 2; get_next_token();
  67. }
  68. dont_enter_into_symbol_table = FALSE;
  69. /* Peek at the next token; see if it's an open-paren. */
  70. if ((token_type==SEP_TT) && (token_value==OPENB_SEP))
  71. { put_token_back();
  72. AO2 = parse_expression(ACTION_Q_CONTEXT);
  73. codegen_action = TRUE;
  74. }
  75. else
  76. { codegen_action = FALSE;
  77. AO2 = action_of_name(token_text);
  78. }
  79. get_next_token();
  80. AO3 = zero_operand;
  81. AO4 = zero_operand;
  82. AO5 = zero_operand;
  83. if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
  84. { put_token_back();
  85. args = 1;
  86. AO3 = parse_expression(ACTION_Q_CONTEXT);
  87. get_next_token();
  88. }
  89. if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
  90. { put_token_back();
  91. args = 2;
  92. AO4 = parse_expression(QUANTITY_CONTEXT);
  93. get_next_token();
  94. }
  95. if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
  96. {
  97. ebf_error("',' or '>'", token_text);
  98. }
  99. if ((token_type == SEP_TT) && (token_value == COMMA_SEP))
  100. {
  101. if (!glulx_mode && (version_number < 4))
  102. {
  103. error("<x, y> syntax is not available in Z-code V3 or earlier");
  104. }
  105. args = 3;
  106. AO5 = parse_expression(QUANTITY_CONTEXT);
  107. get_next_token();
  108. if (!((token_type == SEP_TT) && (token_value == GREATER_SEP)))
  109. {
  110. ebf_error("'>'", token_text);
  111. }
  112. }
  113. if (level == 2)
  114. { get_next_token();
  115. if (!((token_type == SEP_TT) && (token_value == GREATER_SEP)))
  116. { put_token_back();
  117. ebf_error("'>>'", token_text);
  118. }
  119. }
  120. if (!glulx_mode) {
  121. AO = veneer_routine(R_Process_VR);
  122. switch(args)
  123. { case 0:
  124. if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
  125. if (version_number>=5)
  126. assemblez_2(call_2n_zc, AO, AO2);
  127. else
  128. if (version_number==4)
  129. assemblez_2_to(call_vs_zc, AO, AO2, temp_var1);
  130. else
  131. assemblez_2_to(call_zc, AO, AO2, temp_var1);
  132. break;
  133. case 1:
  134. AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
  135. if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
  136. if (version_number>=5)
  137. assemblez_3(call_vn_zc, AO, AO2, AO3);
  138. else
  139. if (version_number==4)
  140. assemblez_3_to(call_vs_zc, AO, AO2, AO3, temp_var1);
  141. else
  142. assemblez_3_to(call_zc, AO, AO2, AO3, temp_var1);
  143. break;
  144. case 2:
  145. AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
  146. AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
  147. if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
  148. if (version_number>=5)
  149. assemblez_4(call_vn_zc, AO, AO2, AO3, AO4);
  150. else
  151. if (version_number==4)
  152. assemblez_4_to(call_vs_zc, AO, AO2, AO3, AO4, temp_var1);
  153. else
  154. assemblez_4(call_zc, AO, AO2, AO3, AO4);
  155. break;
  156. case 3:
  157. AO5 = code_generate(AO5, QUANTITY_CONTEXT, -1);
  158. AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
  159. AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
  160. if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
  161. if (version_number>=5)
  162. assemblez_5(call_vn2_zc, AO, AO2, AO3, AO4, AO5);
  163. else
  164. if (version_number==4)
  165. assemblez_5_to(call_vs2_zc, AO, AO2, AO3, AO4, AO5, temp_var1);
  166. /* if V3 or earlier, we've already displayed an error */
  167. break;
  168. break;
  169. }
  170. if (level == 2) assemblez_0(rtrue_zc);
  171. }
  172. else {
  173. AO = veneer_routine(R_Process_VR);
  174. switch (args) {
  175. case 0:
  176. if (codegen_action)
  177. AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
  178. assembleg_call_1(AO, AO2, zero_operand);
  179. break;
  180. case 1:
  181. AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
  182. if (codegen_action)
  183. AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
  184. assembleg_call_2(AO, AO2, AO3, zero_operand);
  185. break;
  186. case 2:
  187. AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
  188. AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
  189. if (codegen_action)
  190. AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
  191. assembleg_call_3(AO, AO2, AO3, AO4, zero_operand);
  192. break;
  193. case 3:
  194. AO5 = code_generate(AO5, QUANTITY_CONTEXT, -1);
  195. if (!((AO5.type == LOCALVAR_OT) && (AO5.value == 0)))
  196. assembleg_store(stack_pointer, AO5);
  197. AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
  198. if (!((AO4.type == LOCALVAR_OT) && (AO4.value == 0)))
  199. assembleg_store(stack_pointer, AO4);
  200. AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
  201. if (!((AO3.type == LOCALVAR_OT) && (AO3.value == 0)))
  202. assembleg_store(stack_pointer, AO3);
  203. if (codegen_action)
  204. AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
  205. if (!((AO2.type == LOCALVAR_OT) && (AO2.value == 0)))
  206. assembleg_store(stack_pointer, AO2);
  207. assembleg_3(call_gc, AO, four_operand, zero_operand);
  208. break;
  209. }
  210. if (level == 2)
  211. assembleg_1(return_gc, one_operand);
  212. }
  213. }
  214. extern int parse_label(void)
  215. {
  216. get_next_token();
  217. if ((token_type == SYMBOL_TT) &&
  218. (stypes[token_value] == LABEL_T))
  219. { sflags[token_value] |= USED_SFLAG;
  220. return(svals[token_value]);
  221. }
  222. if ((token_type == SYMBOL_TT) && (sflags[token_value] & UNKNOWN_SFLAG))
  223. { assign_symbol(token_value, next_label, LABEL_T);
  224. define_symbol_label(token_value);
  225. next_label++;
  226. sflags[token_value] |= CHANGE_SFLAG + USED_SFLAG;
  227. return(svals[token_value]);
  228. }
  229. ebf_error("label name", token_text);
  230. return 0;
  231. }
  232. static void parse_print_z(int finally_return)
  233. { int count = 0; assembly_operand AO;
  234. /* print <printlist> -------------------------------------------------- */
  235. /* print_ret <printlist> ---------------------------------------------- */
  236. /* <literal-string> --------------------------------------------------- */
  237. /* */
  238. /* <printlist> is a comma-separated list of items: */
  239. /* */
  240. /* <literal-string> */
  241. /* <other-expression> */
  242. /* (char) <expression> */
  243. /* (address) <expression> */
  244. /* (string) <expression> */
  245. /* (a) <expression> */
  246. /* (the) <expression> */
  247. /* (The) <expression> */
  248. /* (name) <expression> */
  249. /* (number) <expression> */
  250. /* (property) <expression> */
  251. /* (<routine>) <expression> */
  252. /* (object) <expression> (for use in low-level code only) */
  253. /* --------------------------------------------------------------------- */
  254. do
  255. { AI.text = token_text;
  256. if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
  257. switch(token_type)
  258. { case DQ_TT:
  259. if (strlen(token_text) > 32)
  260. { AO.marker = STRING_MV;
  261. AO.type = LONG_CONSTANT_OT;
  262. AO.value = compile_string(token_text, FALSE, FALSE);
  263. assemblez_1(print_paddr_zc, AO);
  264. if (finally_return)
  265. { get_next_token();
  266. if ((token_type == SEP_TT)
  267. && (token_value == SEMICOLON_SEP))
  268. { assemblez_0(new_line_zc);
  269. assemblez_0(rtrue_zc);
  270. return;
  271. }
  272. put_token_back();
  273. }
  274. break;
  275. }
  276. if (finally_return)
  277. { get_next_token();
  278. if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
  279. { assemblez_0(print_ret_zc); return;
  280. }
  281. put_token_back();
  282. }
  283. assemblez_0(print_zc);
  284. break;
  285. case SEP_TT:
  286. if (token_value == OPENB_SEP)
  287. { misc_keywords.enabled = TRUE;
  288. get_next_token();
  289. get_next_token();
  290. if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
  291. { assembly_operand AO1;
  292. put_token_back(); put_token_back();
  293. local_variables.enabled = FALSE;
  294. get_next_token();
  295. misc_keywords.enabled = FALSE;
  296. local_variables.enabled = TRUE;
  297. if ((token_type == STATEMENT_TT)
  298. &&(token_value == STRING_CODE))
  299. { token_type = MISC_KEYWORD_TT;
  300. token_value = STRING_MK;
  301. }
  302. switch(token_type)
  303. {
  304. case MISC_KEYWORD_TT:
  305. switch(token_value)
  306. { case CHAR_MK:
  307. if (runtime_error_checking_switch)
  308. { AO = veneer_routine(RT__ChPrintC_VR);
  309. goto PrintByRoutine;
  310. }
  311. get_next_token();
  312. AO1 = code_generate(
  313. parse_expression(QUANTITY_CONTEXT),
  314. QUANTITY_CONTEXT, -1);
  315. assemblez_1(print_char_zc, AO1);
  316. goto PrintTermDone;
  317. case ADDRESS_MK:
  318. if (runtime_error_checking_switch)
  319. { AO = veneer_routine(RT__ChPrintA_VR);
  320. goto PrintByRoutine;
  321. }
  322. get_next_token();
  323. AO1 = code_generate(
  324. parse_expression(QUANTITY_CONTEXT),
  325. QUANTITY_CONTEXT, -1);
  326. assemblez_1(print_addr_zc, AO1);
  327. goto PrintTermDone;
  328. case STRING_MK:
  329. if (runtime_error_checking_switch)
  330. { AO = veneer_routine(RT__ChPrintS_VR);
  331. goto PrintByRoutine;
  332. }
  333. get_next_token();
  334. AO1 = code_generate(
  335. parse_expression(QUANTITY_CONTEXT),
  336. QUANTITY_CONTEXT, -1);
  337. assemblez_1(print_paddr_zc, AO1);
  338. goto PrintTermDone;
  339. case OBJECT_MK:
  340. if (runtime_error_checking_switch)
  341. { AO = veneer_routine(RT__ChPrintO_VR);
  342. goto PrintByRoutine;
  343. }
  344. get_next_token();
  345. AO1 = code_generate(
  346. parse_expression(QUANTITY_CONTEXT),
  347. QUANTITY_CONTEXT, -1);
  348. assemblez_1(print_obj_zc, AO1);
  349. goto PrintTermDone;
  350. case THE_MK:
  351. AO = veneer_routine(DefArt_VR);
  352. goto PrintByRoutine;
  353. case AN_MK:
  354. case A_MK:
  355. AO = veneer_routine(InDefArt_VR);
  356. goto PrintByRoutine;
  357. case CAP_THE_MK:
  358. AO = veneer_routine(CDefArt_VR);
  359. goto PrintByRoutine;
  360. case CAP_A_MK:
  361. AO = veneer_routine(CInDefArt_VR);
  362. goto PrintByRoutine;
  363. case NAME_MK:
  364. AO = veneer_routine(PrintShortName_VR);
  365. goto PrintByRoutine;
  366. case NUMBER_MK:
  367. AO = veneer_routine(EnglishNumber_VR);
  368. goto PrintByRoutine;
  369. case PROPERTY_MK:
  370. AO = veneer_routine(Print__Pname_VR);
  371. goto PrintByRoutine;
  372. default:
  373. error_named("A reserved word was used as a print specification:",
  374. token_text);
  375. }
  376. break;
  377. case SYMBOL_TT:
  378. if (sflags[token_value] & UNKNOWN_SFLAG)
  379. { AO.type = LONG_CONSTANT_OT;
  380. AO.value = token_value;
  381. AO.marker = SYMBOL_MV;
  382. }
  383. else
  384. { AO.type = LONG_CONSTANT_OT;
  385. AO.value = svals[token_value];
  386. AO.marker = IROUTINE_MV;
  387. if (stypes[token_value] != ROUTINE_T)
  388. ebf_error("printing routine name", token_text);
  389. }
  390. sflags[token_value] |= USED_SFLAG;
  391. PrintByRoutine:
  392. get_next_token();
  393. if (version_number >= 5)
  394. assemblez_2(call_2n_zc, AO,
  395. code_generate(parse_expression(QUANTITY_CONTEXT),
  396. QUANTITY_CONTEXT, -1));
  397. else if (version_number == 4)
  398. assemblez_2_to(call_vs_zc, AO,
  399. code_generate(parse_expression(QUANTITY_CONTEXT),
  400. QUANTITY_CONTEXT, -1), temp_var1);
  401. else
  402. assemblez_2_to(call_zc, AO,
  403. code_generate(parse_expression(QUANTITY_CONTEXT),
  404. QUANTITY_CONTEXT, -1), temp_var1);
  405. goto PrintTermDone;
  406. default: ebf_error("print specification", token_text);
  407. get_next_token();
  408. assemblez_1(print_num_zc,
  409. code_generate(parse_expression(QUANTITY_CONTEXT),
  410. QUANTITY_CONTEXT, -1));
  411. goto PrintTermDone;
  412. }
  413. }
  414. put_token_back(); put_token_back(); put_token_back();
  415. misc_keywords.enabled = FALSE;
  416. assemblez_1(print_num_zc,
  417. code_generate(parse_expression(QUANTITY_CONTEXT),
  418. QUANTITY_CONTEXT, -1));
  419. break;
  420. }
  421. default:
  422. put_token_back(); misc_keywords.enabled = FALSE;
  423. assemblez_1(print_num_zc,
  424. code_generate(parse_expression(QUANTITY_CONTEXT),
  425. QUANTITY_CONTEXT, -1));
  426. break;
  427. }
  428. PrintTermDone: misc_keywords.enabled = FALSE;
  429. count++;
  430. get_next_token();
  431. if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
  432. if ((token_type != SEP_TT) || (token_value != COMMA_SEP))
  433. { ebf_error("comma", token_text);
  434. panic_mode_error_recovery(); return;
  435. }
  436. else get_next_token();
  437. } while(TRUE);
  438. if (count == 0) ebf_error("something to print", token_text);
  439. if (finally_return)
  440. { assemblez_0(new_line_zc);
  441. assemblez_0(rtrue_zc);
  442. }
  443. }
  444. static void parse_print_g(int finally_return)
  445. { int count = 0; assembly_operand AO, AO2;
  446. /* print <printlist> -------------------------------------------------- */
  447. /* print_ret <printlist> ---------------------------------------------- */
  448. /* <literal-string> --------------------------------------------------- */
  449. /* */
  450. /* <printlist> is a comma-separated list of items: */
  451. /* */
  452. /* <literal-string> */
  453. /* <other-expression> */
  454. /* (char) <expression> */
  455. /* (address) <expression> */
  456. /* (string) <expression> */
  457. /* (a) <expression> */
  458. /* (A) <expression> */
  459. /* (the) <expression> */
  460. /* (The) <expression> */
  461. /* (name) <expression> */
  462. /* (number) <expression> */
  463. /* (property) <expression> */
  464. /* (<routine>) <expression> */
  465. /* (object) <expression> (for use in low-level code only) */
  466. /* --------------------------------------------------------------------- */
  467. do
  468. {
  469. if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
  470. switch(token_type)
  471. { case DQ_TT:
  472. /* We can't compile a string into the instruction,
  473. so this always goes into the string area. */
  474. { AO.marker = STRING_MV;
  475. AO.type = CONSTANT_OT;
  476. AO.value = compile_string(token_text, FALSE, FALSE);
  477. assembleg_1(streamstr_gc, AO);
  478. if (finally_return)
  479. { get_next_token();
  480. if ((token_type == SEP_TT)
  481. && (token_value == SEMICOLON_SEP))
  482. { AO.type = BYTECONSTANT_OT;
  483. AO.value = 0x0A; AO.marker = 0;
  484. assembleg_1(streamchar_gc, AO);
  485. AO.type = BYTECONSTANT_OT;
  486. AO.value = 1; AO.marker = 0;
  487. assembleg_1(return_gc, AO);
  488. return;
  489. }
  490. put_token_back();
  491. }
  492. break;
  493. }
  494. break;
  495. case SEP_TT:
  496. if (token_value == OPENB_SEP)
  497. { misc_keywords.enabled = TRUE;
  498. get_next_token();
  499. get_next_token();
  500. if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
  501. { assembly_operand AO1;
  502. int ln, ln2;
  503. put_token_back(); put_token_back();
  504. local_variables.enabled = FALSE;
  505. get_next_token();
  506. misc_keywords.enabled = FALSE;
  507. local_variables.enabled = TRUE;
  508. if ((token_type == STATEMENT_TT)
  509. &&(token_value == STRING_CODE))
  510. { token_type = MISC_KEYWORD_TT;
  511. token_value = STRING_MK;
  512. }
  513. switch(token_type)
  514. {
  515. case MISC_KEYWORD_TT:
  516. switch(token_value)
  517. { case CHAR_MK:
  518. if (runtime_error_checking_switch)
  519. { AO = veneer_routine(RT__ChPrintC_VR);
  520. goto PrintByRoutine;
  521. }
  522. get_next_token();
  523. AO1 = code_generate(
  524. parse_expression(QUANTITY_CONTEXT),
  525. QUANTITY_CONTEXT, -1);
  526. if ((AO1.type == LOCALVAR_OT) && (AO1.value == 0))
  527. { assembleg_2(stkpeek_gc, zero_operand,
  528. stack_pointer);
  529. }
  530. AO2.type = HALFCONSTANT_OT; AO2.value = 0x100; AO2.marker = 0;
  531. assembleg_2_branch(jgeu_gc, AO1, AO2,
  532. ln = next_label++);
  533. ln2 = next_label++;
  534. assembleg_1(streamchar_gc, AO1);
  535. assembleg_jump(ln2);
  536. assemble_label_no(ln);
  537. assembleg_1(streamunichar_gc, AO1);
  538. assemble_label_no(ln2);
  539. goto PrintTermDone;
  540. case ADDRESS_MK:
  541. if (runtime_error_checking_switch)
  542. AO = veneer_routine(RT__ChPrintA_VR);
  543. else
  544. AO = veneer_routine(Print__Addr_VR);
  545. goto PrintByRoutine;
  546. case STRING_MK:
  547. if (runtime_error_checking_switch)
  548. { AO = veneer_routine(RT__ChPrintS_VR);
  549. goto PrintByRoutine;
  550. }
  551. get_next_token();
  552. AO1 = code_generate(
  553. parse_expression(QUANTITY_CONTEXT),
  554. QUANTITY_CONTEXT, -1);
  555. assembleg_1(streamstr_gc, AO1);
  556. goto PrintTermDone;
  557. case OBJECT_MK:
  558. if (runtime_error_checking_switch)
  559. { AO = veneer_routine(RT__ChPrintO_VR);
  560. goto PrintByRoutine;
  561. }
  562. get_next_token();
  563. AO1 = code_generate(
  564. parse_expression(QUANTITY_CONTEXT),
  565. QUANTITY_CONTEXT, -1);
  566. AO2.type = BYTECONSTANT_OT;
  567. AO2.value = GOBJFIELD_NAME();
  568. AO2.marker = 0;
  569. assembleg_3(aload_gc, AO1, AO2,
  570. stack_pointer);
  571. assembleg_1(streamstr_gc, stack_pointer);
  572. goto PrintTermDone;
  573. case THE_MK:
  574. AO = veneer_routine(DefArt_VR);
  575. goto PrintByRoutine;
  576. case AN_MK:
  577. case A_MK:
  578. AO = veneer_routine(InDefArt_VR);
  579. goto PrintByRoutine;
  580. case CAP_THE_MK:
  581. AO = veneer_routine(CDefArt_VR);
  582. goto PrintByRoutine;
  583. case CAP_A_MK:
  584. AO = veneer_routine(CInDefArt_VR);
  585. goto PrintByRoutine;
  586. case NAME_MK:
  587. AO = veneer_routine(PrintShortName_VR);
  588. goto PrintByRoutine;
  589. case NUMBER_MK:
  590. AO = veneer_routine(EnglishNumber_VR);
  591. goto PrintByRoutine;
  592. case PROPERTY_MK:
  593. AO = veneer_routine(Print__Pname_VR);
  594. goto PrintByRoutine;
  595. default:
  596. error_named("A reserved word was used as a print specification:",
  597. token_text);
  598. }
  599. break;
  600. case SYMBOL_TT:
  601. if (sflags[token_value] & UNKNOWN_SFLAG)
  602. { AO.type = CONSTANT_OT;
  603. AO.value = token_value;
  604. AO.marker = SYMBOL_MV;
  605. }
  606. else
  607. { AO.type = CONSTANT_OT;
  608. AO.value = svals[token_value];
  609. AO.marker = IROUTINE_MV;
  610. if (stypes[token_value] != ROUTINE_T)
  611. ebf_error("printing routine name", token_text);
  612. }
  613. sflags[token_value] |= USED_SFLAG;
  614. PrintByRoutine:
  615. get_next_token();
  616. AO2.type = ZEROCONSTANT_OT;
  617. AO2.value = 0; AO2.marker = 0;
  618. assembleg_call_1(AO,
  619. code_generate(parse_expression(QUANTITY_CONTEXT),
  620. QUANTITY_CONTEXT, -1),
  621. AO2);
  622. goto PrintTermDone;
  623. default: ebf_error("print specification", token_text);
  624. get_next_token();
  625. assembleg_1(streamnum_gc,
  626. code_generate(parse_expression(QUANTITY_CONTEXT),
  627. QUANTITY_CONTEXT, -1));
  628. goto PrintTermDone;
  629. }
  630. }
  631. put_token_back(); put_token_back(); put_token_back();
  632. misc_keywords.enabled = FALSE;
  633. assembleg_1(streamnum_gc,
  634. code_generate(parse_expression(QUANTITY_CONTEXT),
  635. QUANTITY_CONTEXT, -1));
  636. break;
  637. }
  638. default:
  639. put_token_back(); misc_keywords.enabled = FALSE;
  640. assembleg_1(streamnum_gc,
  641. code_generate(parse_expression(QUANTITY_CONTEXT),
  642. QUANTITY_CONTEXT, -1));
  643. break;
  644. }
  645. PrintTermDone: misc_keywords.enabled = FALSE;
  646. count++;
  647. get_next_token();
  648. if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
  649. if ((token_type != SEP_TT) || (token_value != COMMA_SEP))
  650. { ebf_error("comma", token_text);
  651. panic_mode_error_recovery(); return;
  652. }
  653. else get_next_token();
  654. } while(TRUE);
  655. if (count == 0) ebf_error("something to print", token_text);
  656. if (finally_return)
  657. {
  658. AO.type = BYTECONSTANT_OT; AO.value = 0x0A; AO.marker = 0;
  659. assembleg_1(streamchar_gc, AO);
  660. AO.type = BYTECONSTANT_OT; AO.value = 1; AO.marker = 0;
  661. assembleg_1(return_gc, AO);
  662. }
  663. }
  664. static void parse_statement_z(int break_label, int continue_label)
  665. { int ln, ln2, ln3, ln4, flag;
  666. assembly_operand AO, AO2, AO3, AO4;
  667. debug_location spare_debug_location1, spare_debug_location2;
  668. ASSERT_ZCODE();
  669. if ((token_type == SEP_TT) && (token_value == PROPERTY_SEP))
  670. { /* That is, a full stop, signifying a label */
  671. get_next_token();
  672. if (token_type == SYMBOL_TT)
  673. {
  674. if (sflags[token_value] & UNKNOWN_SFLAG)
  675. { assign_symbol(token_value, next_label, LABEL_T);
  676. sflags[token_value] |= USED_SFLAG;
  677. assemble_label_no(next_label);
  678. define_symbol_label(token_value);
  679. next_label++;
  680. }
  681. else
  682. { if (stypes[token_value] != LABEL_T) goto LabelError;
  683. if (sflags[token_value] & CHANGE_SFLAG)
  684. { sflags[token_value] &= (~(CHANGE_SFLAG));
  685. assemble_label_no(svals[token_value]);
  686. define_symbol_label(token_value);
  687. }
  688. else error_named("Duplicate definition of label:", token_text);
  689. }
  690. get_next_token();
  691. if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
  692. { ebf_error("';'", token_text);
  693. put_token_back(); return;
  694. }
  695. /* Interesting point of Inform grammar: a statement can only
  696. consist solely of a label when it is immediately followed
  697. by a "}". */
  698. get_next_token();
  699. if ((token_type == SEP_TT) && (token_value == CLOSE_BRACE_SEP))
  700. { put_token_back(); return;
  701. }
  702. statement_debug_location = get_token_location();
  703. parse_statement(break_label, continue_label);
  704. return;
  705. }
  706. LabelError: ebf_error("label name", token_text);
  707. }
  708. if ((token_type == SEP_TT) && (token_value == HASH_SEP))
  709. { parse_directive(TRUE);
  710. parse_statement(break_label, continue_label); return;
  711. }
  712. if ((token_type == SEP_TT) && (token_value == AT_SEP))
  713. { parse_assembly(); return;
  714. }
  715. if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) return;
  716. if (token_type == DQ_TT)
  717. { parse_print_z(TRUE); return;
  718. }
  719. if ((token_type == SEP_TT) && (token_value == LESS_SEP))
  720. { parse_action(); goto StatementTerminator; }
  721. if (token_type == EOF_TT)
  722. { ebf_error("statement", token_text); return; }
  723. if (token_type != STATEMENT_TT)
  724. { put_token_back();
  725. AO = parse_expression(VOID_CONTEXT);
  726. code_generate(AO, VOID_CONTEXT, -1);
  727. if (vivc_flag) { panic_mode_error_recovery(); return; }
  728. goto StatementTerminator;
  729. }
  730. statements.enabled = FALSE;
  731. switch(token_value)
  732. {
  733. /* -------------------------------------------------------------------- */
  734. /* box <string-1> ... <string-n> -------------------------------------- */
  735. /* -------------------------------------------------------------------- */
  736. case BOX_CODE:
  737. if (version_number == 3)
  738. warning("The 'box' statement has no effect in a version 3 game");
  739. AO3.type = LONG_CONSTANT_OT;
  740. AO3.value = begin_table_array();
  741. AO3.marker = ARRAY_MV;
  742. ln = 0; ln2 = 0;
  743. do
  744. { get_next_token();
  745. if ((token_type==SEP_TT)&&(token_value==SEMICOLON_SEP))
  746. break;
  747. if (token_type != DQ_TT)
  748. ebf_error("text of box line in double-quotes",
  749. token_text);
  750. { int i, j;
  751. for (i=0, j=0; token_text[i] != 0; j++)
  752. if (token_text[i] == '@')
  753. { if (token_text[i+1] == '@')
  754. { i = i + 2;
  755. while (isdigit(token_text[i])) i++;
  756. }
  757. else
  758. { i++;
  759. if (token_text[i] != 0) i++;
  760. if (token_text[i] != 0) i++;
  761. }
  762. }
  763. else i++;
  764. if (j > ln2) ln2 = j;
  765. }
  766. put_token_back();
  767. array_entry(ln++,parse_expression(CONSTANT_CONTEXT));
  768. } while (TRUE);
  769. finish_array(ln);
  770. if (ln == 0)
  771. error("No lines of text given for 'box' display");
  772. if (version_number == 3) return;
  773. AO2.type = SHORT_CONSTANT_OT; AO2.value = ln2; AO2.marker = 0;
  774. AO4.type = VARIABLE_OT; AO4.value = 255; AO4.marker = 0;
  775. assemblez_3_to(call_vs_zc, veneer_routine(Box__Routine_VR),
  776. AO2, AO3, AO4);
  777. return;
  778. /* -------------------------------------------------------------------- */
  779. /* break -------------------------------------------------------------- */
  780. /* -------------------------------------------------------------------- */
  781. case BREAK_CODE:
  782. if (break_label == -1)
  783. error("'break' can only be used in a loop or 'switch' block");
  784. else
  785. assemblez_jump(break_label);
  786. break;
  787. /* -------------------------------------------------------------------- */
  788. /* continue ----------------------------------------------------------- */
  789. /* -------------------------------------------------------------------- */
  790. case CONTINUE_CODE:
  791. if (continue_label == -1)
  792. error("'continue' can only be used in a loop block");
  793. else
  794. assemblez_jump(continue_label);
  795. break;
  796. /* -------------------------------------------------------------------- */
  797. /* do <codeblock> until (<condition>) --------------------------------- */
  798. /* -------------------------------------------------------------------- */
  799. case DO_CODE:
  800. assemble_label_no(ln = next_label++);
  801. ln2 = next_label++; ln3 = next_label++;
  802. parse_code_block(ln3, ln2, 0);
  803. statements.enabled = TRUE;
  804. get_next_token();
  805. if ((token_type == STATEMENT_TT)
  806. && (token_value == UNTIL_CODE))
  807. { assemble_label_no(ln2);
  808. match_open_bracket();
  809. AO = parse_expression(CONDITION_CONTEXT);
  810. match_close_bracket();
  811. code_generate(AO, CONDITION_CONTEXT, ln);
  812. }
  813. else error("'do' without matching 'until'");
  814. assemble_label_no(ln3);
  815. break;
  816. /* -------------------------------------------------------------------- */
  817. /* font on/off -------------------------------------------------------- */
  818. /* -------------------------------------------------------------------- */
  819. case FONT_CODE:
  820. misc_keywords.enabled = TRUE;
  821. get_next_token();
  822. misc_keywords.enabled = FALSE;
  823. if ((token_type != MISC_KEYWORD_TT)
  824. || ((token_value != ON_MK)
  825. && (token_value != OFF_MK)))
  826. { ebf_error("'on' or 'off'", token_text);
  827. panic_mode_error_recovery();
  828. break;
  829. }
  830. if (version_number >= 5)
  831. { /* Use the V5 @set_font opcode, setting font 4
  832. (for font off) or 1 (for font on). */
  833. AO.type = SHORT_CONSTANT_OT; AO.marker = 0;
  834. if (token_value == ON_MK)
  835. AO.value = 1;
  836. else
  837. AO.value = 4;
  838. assemblez_1_to(set_font_zc, AO, temp_var1);
  839. break;
  840. }
  841. /* Set the fixed-pitch header bit. */
  842. AO.type = SHORT_CONSTANT_OT;
  843. AO.value = 0;
  844. AO.marker = 0;
  845. AO2.type = SHORT_CONSTANT_OT;
  846. AO2.value = 8;
  847. AO2.marker = 0;
  848. AO3.type = VARIABLE_OT;
  849. AO3.value = 255;
  850. AO3.marker = 0;
  851. assemblez_2_to(loadw_zc, AO, AO2, AO3);
  852. if (token_value == ON_MK)
  853. { AO4.type = LONG_CONSTANT_OT;
  854. AO4.value = 0xfffd;
  855. AO4.marker = 0;
  856. assemblez_2_to(and_zc, AO4, AO3, AO3);
  857. }
  858. else
  859. { AO4.type = SHORT_CONSTANT_OT;
  860. AO4.value = 2;
  861. AO4.marker = 0;
  862. assemblez_2_to(or_zc, AO4, AO3, AO3);
  863. }
  864. assemblez_3(storew_zc, AO, AO2, AO3);
  865. break;
  866. /* -------------------------------------------------------------------- */
  867. /* for (<initialisation> : <continue-condition> : <updating>) --------- */
  868. /* -------------------------------------------------------------------- */
  869. /* Note that it's legal for any or all of the three sections of a
  870. 'for' specification to be empty. This 'for' implementation
  871. often wastes 3 bytes with a redundant branch rather than keep
  872. expression parse trees for long periods (as previous versions
  873. of Inform did, somewhat crudely by simply storing the textual
  874. form of a 'for' loop). It is adequate for now. */
  875. case FOR_CODE:
  876. match_open_bracket();
  877. get_next_token();
  878. /* Initialisation code */
  879. if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
  880. { put_token_back();
  881. if (!((token_type==SEP_TT)&&(token_value==SUPERCLASS_SEP)))
  882. { sequence_point_follows = TRUE;
  883. statement_debug_location = get_token_location();
  884. code_generate(parse_expression(FORINIT_CONTEXT),
  885. VOID_CONTEXT, -1);
  886. }
  887. get_next_token();
  888. if ((token_type==SEP_TT)&&(token_value == SUPERCLASS_SEP))
  889. { get_next_token();
  890. if ((token_type==SEP_TT)&&(token_value == CLOSEB_SEP))
  891. { assemble_label_no(ln = next_label++);
  892. ln2 = next_label++;
  893. parse_code_block(ln2, ln, 0);
  894. sequence_point_follows = FALSE;
  895. if (!execution_never_reaches_here)
  896. assemblez_jump(ln);
  897. assemble_label_no(ln2);
  898. return;
  899. }
  900. AO.type = OMITTED_OT;
  901. goto ParseUpdate;
  902. }
  903. put_token_back();
  904. if (!match_colon()) break;
  905. }
  906. get_next_token();
  907. AO.type = OMITTED_OT;
  908. if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
  909. { put_token_back();
  910. spare_debug_location1 = get_token_location();
  911. AO = parse_expression(CONDITION_CONTEXT);
  912. if (!match_colon()) break;
  913. }
  914. get_next_token();
  915. ParseUpdate:
  916. AO2.type = OMITTED_OT; flag = 0;
  917. if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP)))
  918. { put_token_back();
  919. spare_debug_location2 = get_token_location();
  920. AO2 = parse_expression(VOID_CONTEXT);
  921. match_close_bracket();
  922. flag = test_for_incdec(AO2);
  923. }
  924. ln = next_label++;
  925. ln2 = next_label++;
  926. ln3 = next_label++;
  927. if ((AO2.type == OMITTED_OT) || (flag != 0))
  928. {
  929. assemble_label_no(ln);
  930. if (flag==0) assemble_label_no(ln2);
  931. /* The "finished yet?" condition */
  932. if (AO.type != OMITTED_OT)
  933. { sequence_point_follows = TRUE;
  934. statement_debug_location = spare_debug_location1;
  935. code_generate(AO, CONDITION_CONTEXT, ln3);
  936. }
  937. }
  938. else
  939. {
  940. /* This is the jump which could be avoided with the aid
  941. of long-term expression storage */
  942. sequence_point_follows = FALSE;
  943. assemblez_jump(ln2);
  944. /* The "update" part */
  945. assemble_label_no(ln);
  946. sequence_point_follows = TRUE;
  947. statement_debug_location = spare_debug_location2;
  948. code_generate(AO2, VOID_CONTEXT, -1);
  949. assemble_label_no(ln2);
  950. /* The "finished yet?" condition */
  951. if (AO.type != OMITTED_OT)
  952. { sequence_point_follows = TRUE;
  953. statement_debug_location = spare_debug_location1;
  954. code_generate(AO, CONDITION_CONTEXT, ln3);
  955. }
  956. }
  957. if (flag != 0)
  958. {
  959. /* In this optimised case, update code is at the end
  960. of the loop block, so "continue" goes there */
  961. parse_code_block(ln3, ln2, 0);
  962. assemble_label_no(ln2);
  963. sequence_point_follows = TRUE;
  964. statement_debug_location = spare_debug_location2;
  965. if (flag > 0)
  966. { AO3.type = SHORT_CONSTANT_OT;
  967. AO3.value = flag;
  968. if (module_switch
  969. && (flag>=MAX_LOCAL_VARIABLES) && (flag<LOWEST_SYSTEM_VAR_NUMBER))
  970. AO3.marker = VARIABLE_MV;
  971. else AO3.marker = 0;
  972. assemblez_1(inc_zc, AO3);
  973. }
  974. else
  975. { AO3.type = SHORT_CONSTANT_OT;
  976. AO3.value = -flag;
  977. if ((module_switch) && (flag>=MAX_LOCAL_VARIABLES)
  978. && (flag<LOWEST_SYSTEM_VAR_NUMBER))
  979. AO3.marker = VARIABLE_MV;
  980. else AO3.marker = 0;
  981. assemblez_1(dec_zc, AO3);
  982. }
  983. assemblez_jump(ln);
  984. }
  985. else
  986. {
  987. /* In the unoptimised case, update code is at the
  988. start of the loop block, so "continue" goes there */
  989. parse_code_block(ln3, ln, 0);
  990. if (!execution_never_reaches_here)
  991. { sequence_point_follows = FALSE;
  992. assemblez_jump(ln);
  993. }
  994. }
  995. assemble_label_no(ln3);
  996. return;
  997. /* -------------------------------------------------------------------- */
  998. /* give <expression> [~]attr [, [~]attr [, ...]] ---------------------- */
  999. /* -------------------------------------------------------------------- */
  1000. case GIVE_CODE:
  1001. AO = code_generate(parse_expression(QUANTITY_CONTEXT),
  1002. QUANTITY_CONTEXT, -1);
  1003. if ((AO.type == VARIABLE_OT) && (AO.value == 0))
  1004. { AO.value = 252;
  1005. AO.marker = 0;
  1006. AO.type = SHORT_CONSTANT_OT;
  1007. if (version_number != 6) assemblez_1(pull_zc, AO);
  1008. else assemblez_0_to(pull_zc, AO);
  1009. AO.type = VARIABLE_OT;
  1010. }
  1011. do
  1012. { get_next_token();
  1013. if ((token_type == SEP_TT)&&(token_value == SEMICOLON_SEP))
  1014. return;
  1015. if ((token_type == SEP_TT)&&(token_value == ARTNOT_SEP))
  1016. ln = clear_attr_zc;
  1017. else
  1018. { if ((token_type == SYMBOL_TT)
  1019. && (stypes[token_value] != ATTRIBUTE_T))
  1020. warning_named("This is not a declared Attribute:",
  1021. token_text);
  1022. ln = set_attr_zc;
  1023. put_token_back();
  1024. }
  1025. AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
  1026. QUANTITY_CONTEXT, -1);
  1027. if (runtime_error_checking_switch)
  1028. { ln2 = (ln==set_attr_zc)?RT__ChG_VR:RT__ChGt_VR;
  1029. if (version_number >= 5)
  1030. assemblez_3(call_vn_zc, veneer_routine(ln2),
  1031. AO, AO2);
  1032. else
  1033. {
  1034. assemblez_3_to(call_zc, veneer_routine(ln2),
  1035. AO, AO2, temp_var1);
  1036. }
  1037. }
  1038. else
  1039. assemblez_2(ln, AO, AO2);
  1040. } while(TRUE);
  1041. /* -------------------------------------------------------------------- */
  1042. /* if (<condition>) <codeblock> [else <codeblock>] -------------------- */
  1043. /* -------------------------------------------------------------------- */
  1044. case IF_CODE:
  1045. flag = FALSE;
  1046. match_open_bracket();
  1047. AO = parse_expression(CONDITION_CONTEXT);
  1048. match_close_bracket();
  1049. statements.enabled = TRUE;
  1050. get_next_token();
  1051. if ((token_type == STATEMENT_TT)&&(token_value == RTRUE_CODE))
  1052. ln = -4;
  1053. else
  1054. if ((token_type == STATEMENT_TT)&&(token_value == RFALSE_CODE))
  1055. ln = -3;
  1056. else
  1057. { put_token_back();
  1058. ln = next_label++;
  1059. }
  1060. code_generate(AO, CONDITION_CONTEXT, ln);
  1061. if (ln >= 0) parse_code_block(break_label, continue_label, 0);
  1062. else
  1063. { get_next_token();
  1064. if ((token_type != SEP_TT)
  1065. || (token_value != SEMICOLON_SEP))
  1066. { ebf_error("';'", token_text);
  1067. put_token_back();
  1068. }
  1069. }
  1070. statements.enabled = TRUE;
  1071. get_next_token();
  1072. if ((token_type == STATEMENT_TT) && (token_value == ELSE_CODE))
  1073. { flag = TRUE;
  1074. if (ln >= 0)
  1075. { ln2 = next_label++;
  1076. if (!execution_never_reaches_here)
  1077. { sequence_point_follows = FALSE;
  1078. assemblez_jump(ln2);
  1079. }
  1080. }
  1081. }
  1082. else put_token_back();
  1083. if (ln >= 0) assemble_label_no(ln);
  1084. if (flag)
  1085. { parse_code_block(break_label, continue_label, 0);
  1086. if (ln >= 0) assemble_label_no(ln2);
  1087. }
  1088. return;
  1089. /* -------------------------------------------------------------------- */
  1090. /* inversion ---------------------------------------------------------- */
  1091. /* -------------------------------------------------------------------- */
  1092. case INVERSION_CODE:
  1093. AO.marker = 0;
  1094. AO.type = SHORT_CONSTANT_OT;
  1095. AO.value = 0;
  1096. AO2.marker = 0;
  1097. AO2.type = SHORT_CONSTANT_OT;
  1098. AO2.value = 60;
  1099. assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
  1100. assemblez_1(print_char_zc, temp_var1);
  1101. AO2.value = 61;
  1102. assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
  1103. assemblez_1(print_char_zc, temp_var1);
  1104. AO2.value = 62;
  1105. assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
  1106. assemblez_1(print_char_zc, temp_var1);
  1107. AO2.value = 63;
  1108. assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
  1109. assemblez_1(print_char_zc, temp_var1);
  1110. break;
  1111. /* -------------------------------------------------------------------- */
  1112. /* jump <label> ------------------------------------------------------- */
  1113. /* -------------------------------------------------------------------- */
  1114. case JUMP_CODE:
  1115. assemblez_jump(parse_label());
  1116. break;
  1117. /* -------------------------------------------------------------------- */
  1118. /* move <expression> to <expression> ---------------------------------- */
  1119. /* -------------------------------------------------------------------- */
  1120. case MOVE_CODE:
  1121. misc_keywords.enabled = TRUE;
  1122. AO = parse_expression(QUANTITY_CONTEXT);
  1123. get_next_token();
  1124. misc_keywords.enabled = FALSE;
  1125. if ((token_type != MISC_KEYWORD_TT)
  1126. || (token_value != TO_MK))
  1127. { ebf_error("'to'", token_text);
  1128. panic_mode_error_recovery();
  1129. return;
  1130. }
  1131. AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
  1132. QUANTITY_CONTEXT, -1);
  1133. AO = code_generate(AO, QUANTITY_CONTEXT, -1);
  1134. if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
  1135. { if (version_number >= 5)
  1136. assemblez_3(call_vn_zc, veneer_routine(RT__ChT_VR),
  1137. AO, AO2);
  1138. else
  1139. { assemblez_3_to(call_zc, veneer_routine(RT__ChT_VR),
  1140. AO, AO2, temp_var1);
  1141. }
  1142. }
  1143. else
  1144. assemblez_2(insert_obj_zc, AO, AO2);
  1145. break;
  1146. /* -------------------------------------------------------------------- */
  1147. /* new_line ----------------------------------------------------------- */
  1148. /* -------------------------------------------------------------------- */
  1149. case NEW_LINE_CODE: assemblez_0(new_line_zc); break;
  1150. /* -------------------------------------------------------------------- */
  1151. /* objectloop (<initialisation>) <codeblock> -------------------------- */
  1152. /* -------------------------------------------------------------------- */
  1153. case OBJECTLOOP_CODE:
  1154. match_open_bracket();
  1155. get_next_token();
  1156. if (token_type == LOCAL_VARIABLE_TT)
  1157. AO.value = token_value;
  1158. else
  1159. if ((token_type == SYMBOL_TT) &&
  1160. (stypes[token_value] == GLOBAL_VARIABLE_T))
  1161. AO.value = svals[token_value];
  1162. else
  1163. { ebf_error("'objectloop' variable", token_text);
  1164. panic_mode_error_recovery(); break;
  1165. }
  1166. AO.type = VARIABLE_OT;
  1167. if ((module_switch) && (AO.value >= MAX_LOCAL_VARIABLES)
  1168. && (AO.value < LOWEST_SYSTEM_VAR_NUMBER))
  1169. AO.marker = VARIABLE_MV;
  1170. else AO.marker = 0;
  1171. misc_keywords.enabled = TRUE;
  1172. get_next_token(); flag = TRUE;
  1173. misc_keywords.enabled = FALSE;
  1174. if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
  1175. flag = FALSE;
  1176. ln = 0;
  1177. if ((token_type == MISC_KEYWORD_TT)
  1178. && (token_value == NEAR_MK)) ln = 1;
  1179. if ((token_type == MISC_KEYWORD_TT)
  1180. && (token_value == FROM_MK)) ln = 2;
  1181. if ((token_type == CND_TT) && (token_value == IN_COND))
  1182. { get_next_token();
  1183. get_next_token();
  1184. if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
  1185. ln = 3;
  1186. put_token_back();
  1187. put_token_back();
  1188. }
  1189. if (ln > 0)
  1190. { /* Old style (Inform 5) objectloops: note that we
  1191. implement objectloop (a in b) in the old way since
  1192. this runs through objects in a different order from
  1193. the new way, and there may be existing Inform code
  1194. relying on this. */
  1195. assembly_operand AO4;
  1196. sequence_point_follows = TRUE;
  1197. AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
  1198. QUANTITY_CONTEXT, -1);
  1199. match_close_bracket();
  1200. if (ln == 1)
  1201. { AO3.type = VARIABLE_OT; AO3.value = 0; AO3.marker = 0;
  1202. if (runtime_error_checking_switch)
  1203. AO2 = check_nonzero_at_runtime(AO2, -1,
  1204. OBJECTLOOP_RTE);
  1205. assemblez_1_to(get_parent_zc, AO2, AO3);
  1206. assemblez_objcode(get_child_zc, AO3, AO3, -2, TRUE);
  1207. AO2 = AO3;
  1208. }
  1209. if (ln == 3)
  1210. { AO3.type = VARIABLE_OT; AO3.value = 0; AO3.marker = 0;
  1211. if (runtime_error_checking_switch)
  1212. { AO4 = AO2;
  1213. AO2 = check_nonzero_at_runtime(AO2, -1,
  1214. CHILD_RTE);
  1215. }
  1216. assemblez_objcode(get_child_zc, AO2, AO3, -2, TRUE);
  1217. AO2 = AO3;
  1218. }
  1219. assemblez_store(AO, AO2);
  1220. assemblez_1_branch(jz_zc, AO, ln2 = next_label++, TRUE);
  1221. assemble_label_no(ln4 = next_label++);
  1222. parse_code_block(ln2, ln3 = next_label++, 0);
  1223. sequence_point_follows = FALSE;
  1224. assemble_label_no(ln3);
  1225. if (runtime_error_checking_switch)
  1226. { AO2 = check_nonzero_at_runtime(AO, ln2,
  1227. OBJECTLOOP2_RTE);
  1228. if ((ln == 3)
  1229. && ((AO4.type != VARIABLE_OT)||(AO4.value != 0))
  1230. && ((AO4.type != VARIABLE_OT)
  1231. ||(AO4.value != AO.value)))
  1232. { assembly_operand en_ao;
  1233. en_ao.value = OBJECTLOOP_BROKEN_RTE;
  1234. en_ao.marker = 0;
  1235. en_ao.type = SHORT_CONSTANT_OT;
  1236. assemblez_2_branch(jin_zc, AO, AO4,
  1237. next_label, TRUE);
  1238. assemblez_3(call_vn_zc, veneer_routine(RT__Err_VR),
  1239. en_ao, AO);
  1240. assemblez_jump(ln2);
  1241. assemble_label_no(next_label++);
  1242. }
  1243. }
  1244. else AO2 = AO;
  1245. assemblez_objcode(get_sibling_zc, AO2, AO, ln4, TRUE);
  1246. assemble_label_no(ln2);
  1247. return;
  1248. }
  1249. sequence_point_follows = TRUE;
  1250. AO2.type = SHORT_CONSTANT_OT; AO2.value = 1; AO2.marker = 0;
  1251. assemblez_store(AO, AO2);
  1252. assemble_label_no(ln = next_label++);
  1253. ln2 = next_label++;
  1254. ln3 = next_label++;
  1255. if (flag)
  1256. { put_token_back();
  1257. put_token_back();
  1258. sequence_point_follows = TRUE;
  1259. code_generate(parse_expression(CONDITION_CONTEXT),
  1260. CONDITION_CONTEXT, ln3);
  1261. match_close_bracket();
  1262. }
  1263. parse_code_block(ln2, ln3, 0);
  1264. sequence_point_follows = FALSE;
  1265. assemble_label_no(ln3);
  1266. assemblez_inc(AO);
  1267. AO2.type = LONG_CONSTANT_OT; AO2.value = no_objects;
  1268. AO2.marker = NO_OBJS_MV;
  1269. assemblez_2_branch(jg_zc, AO, AO2, ln2, TRUE);
  1270. assemblez_jump(ln);
  1271. assemble_label_no(ln2);
  1272. return;
  1273. /* -------------------------------------------------------------------- */
  1274. /* (see routine above) ------------------------------------------------ */
  1275. /* -------------------------------------------------------------------- */
  1276. case PRINT_CODE:
  1277. get_next_token();
  1278. parse_print_z(FALSE); return;
  1279. case PRINT_RET_CODE:
  1280. get_next_token();
  1281. parse_print_z(TRUE); return;
  1282. /* -------------------------------------------------------------------- */
  1283. /* quit --------------------------------------------------------------- */
  1284. /* -------------------------------------------------------------------- */
  1285. case QUIT_CODE: assemblez_0(quit_zc); break;
  1286. /* -------------------------------------------------------------------- */
  1287. /* read <expression> <expression> [<Routine>] ------------------------- */
  1288. /* -------------------------------------------------------------------- */
  1289. case READ_CODE:
  1290. AO.type = VARIABLE_OT; AO.value = 252; AO.marker = 0;
  1291. assemblez_store(AO,
  1292. code_generate(parse_expression(QUANTITY_CONTEXT),
  1293. QUANTITY_CONTEXT, -1));
  1294. if (version_number > 3)
  1295. { AO3.type = SHORT_CONSTANT_OT; AO3.value = 1;AO3.marker = 0;
  1296. AO4.type = SHORT_CONSTANT_OT; AO4.value = 0;AO4.marker = 0;
  1297. assemblez_3(storeb_zc, AO, AO3, AO4);
  1298. }
  1299. AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
  1300. QUANTITY_CONTEXT, -1);
  1301. get_next_token();
  1302. if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
  1303. put_token_back();
  1304. else
  1305. { if (version_number == 3)
  1306. error(
  1307. "In Version 3 no status-line drawing routine can be given");
  1308. else
  1309. { assembly_operand AO5;
  1310. /* Move the temp4 (buffer) value to the stack,
  1311. since the routine might alter temp4. */
  1312. assemblez_store(stack_pointer, AO);
  1313. AO = stack_pointer;
  1314. put_token_back();
  1315. AO5 = parse_expression(CONSTANT_CONTEXT);
  1316. if (version_number >= 5)
  1317. assemblez_1(call_1n_zc, AO5);
  1318. else
  1319. assemblez_1_to(call_zc, AO5, temp_var1);
  1320. }
  1321. }
  1322. if (version_number > 4)
  1323. { assemblez_2_to(aread_zc, AO, AO2, temp_var1);
  1324. }
  1325. else assemblez_2(sread_zc, AO, AO2);
  1326. break;
  1327. /* -------------------------------------------------------------------- */
  1328. /* remove <expression> ------------------------------------------------ */
  1329. /* -------------------------------------------------------------------- */
  1330. case REMOVE_CODE:
  1331. AO = code_generate(parse_expression(QUANTITY_CONTEXT),
  1332. QUANTITY_CONTEXT, -1);
  1333. if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
  1334. { if (version_number >= 5)
  1335. assemblez_2(call_2n_zc, veneer_routine(RT__ChR_VR),
  1336. AO);
  1337. else
  1338. { assemblez_2_to(call_zc, veneer_routine(RT__ChR_VR),
  1339. AO, temp_var1);
  1340. }
  1341. }
  1342. else
  1343. assemblez_1(remove_obj_zc, AO);
  1344. break;
  1345. /* -------------------------------------------------------------------- */
  1346. /* restore <label> ---------------------------------------------------- */
  1347. /* -------------------------------------------------------------------- */
  1348. case RESTORE_CODE:
  1349. if (version_number < 5)
  1350. assemblez_0_branch(restore_zc, parse_label(), TRUE);
  1351. else
  1352. { AO2.type = SHORT_CONSTANT_OT; AO2.value = 2;
  1353. AO2.marker = 0;
  1354. assemblez_0_to(restore_zc, temp_var1);
  1355. assemblez_2_branch(je_zc, temp_var1, AO2, parse_label(), TRUE);
  1356. }
  1357. break;
  1358. /* -------------------------------------------------------------------- */
  1359. /* return [<expression>] ---------------------------------------------- */
  1360. /* -------------------------------------------------------------------- */
  1361. case RETURN_CODE:
  1362. get_next_token();
  1363. if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
  1364. { assemblez_0(rtrue_zc); return; }
  1365. put_token_back();
  1366. AO = code_generate(parse_expression(RETURN_Q_CONTEXT),
  1367. QUANTITY_CONTEXT, -1);
  1368. if ((AO.type == SHORT_CONSTANT_OT) && (AO.value == 0)
  1369. && (AO.marker == 0))
  1370. { assemblez_0(rfalse_zc); break; }
  1371. if ((AO.type == SHORT_CONSTANT_OT) && (AO.value == 1)
  1372. && (AO.marker == 0))
  1373. { assemblez_0(rtrue_zc); break; }
  1374. if ((AO.type == VARIABLE_OT) && (AO.value == 0))
  1375. { assemblez_0(ret_popped_zc); break; }
  1376. assemblez_1(ret_zc, AO);
  1377. break;
  1378. /* -------------------------------------------------------------------- */
  1379. /* rfalse ------------------------------------------------------------- */
  1380. /* -------------------------------------------------------------------- */
  1381. case RFALSE_CODE: assemblez_0(rfalse_zc); break;
  1382. /* -------------------------------------------------------------------- */
  1383. /* rtrue -------------------------------------------------------------- */
  1384. /* -------------------------------------------------------------------- */
  1385. case RTRUE_CODE: assemblez_0(rtrue_zc); break;
  1386. /* -------------------------------------------------------------------- */
  1387. /* save <label> ------------------------------------------------------- */
  1388. /* -------------------------------------------------------------------- */
  1389. case SAVE_CODE:
  1390. if (version_number < 5)
  1391. assemblez_0_branch(save_zc, parse_label(), TRUE);
  1392. else
  1393. { AO.type = VARIABLE_OT; AO.value = 255; AO.marker = 0;
  1394. assemblez_0_to(save_zc, AO);
  1395. assemblez_1_branch(jz_zc, AO, parse_label(), FALSE);
  1396. }
  1397. break;
  1398. /* -------------------------------------------------------------------- */
  1399. /* spaces <expression> ------------------------------------------------ */
  1400. /* -------------------------------------------------------------------- */
  1401. case SPACES_CODE:
  1402. AO = code_generate(parse_expression(QUANTITY_CONTEXT),
  1403. QUANTITY_CONTEXT, -1);
  1404. AO2.type = VARIABLE_OT; AO2.value = 255; AO2.marker = 0;
  1405. assemblez_store(AO2, AO);
  1406. AO.type = SHORT_CONSTANT_OT; AO.value = 32; AO.marker = 0;
  1407. AO3.type = SHORT_CONSTANT_OT; AO3.value = 1; AO3.marker = 0;
  1408. assemblez_2_branch(jl_zc, AO2, AO3, ln = next_label++, TRUE);
  1409. assemble_label_no(ln2 = next_label++);
  1410. assemblez_1(print_char_zc, AO);
  1411. assemblez_dec(AO2);
  1412. assemblez_1_branch(jz_zc, AO2, ln2, FALSE);
  1413. assemble_label_no(ln);
  1414. break;
  1415. /* -------------------------------------------------------------------- */
  1416. /* string <expression> <literal-string> ------------------------------- */
  1417. /* -------------------------------------------------------------------- */
  1418. case STRING_CODE:
  1419. AO.type = SHORT_CONSTANT_OT; AO.value = 0; AO.marker = 0;
  1420. AO2.type = SHORT_CONSTANT_OT; AO2.value = 12; AO2.marker = 0;
  1421. AO3.type = VARIABLE_OT; AO3.value = 252; AO3.marker = 0;
  1422. assemblez_2_to(loadw_zc, AO, AO2, AO3);
  1423. AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
  1424. QUANTITY_CONTEXT, -1);
  1425. get_next_token();
  1426. if (token_type == DQ_TT)
  1427. { AO4.value = compile_string(token_text, TRUE, TRUE);
  1428. AO4.marker = 0;
  1429. AO4.type = LONG_CONSTANT_OT;
  1430. }
  1431. else
  1432. { put_token_back();
  1433. AO4 = parse_expression(CONSTANT_CONTEXT);
  1434. }
  1435. assemblez_3(storew_zc, AO3, AO2, AO4);
  1436. break;
  1437. /* -------------------------------------------------------------------- */
  1438. /* style roman/reverse/bold/underline/fixed --------------------------- */
  1439. /* -------------------------------------------------------------------- */
  1440. case STYLE_CODE:
  1441. if (version_number==3)
  1442. { error(
  1443. "The 'style' statement cannot be used for Version 3 games");
  1444. panic_mode_error_recovery();
  1445. break;
  1446. }
  1447. misc_keywords.enabled = TRUE;
  1448. get_next_token();
  1449. misc_keywords.enabled = FALSE;
  1450. if ((token_type != MISC_KEYWORD_TT)
  1451. || ((token_value != ROMAN_MK)
  1452. && (token_value != REVERSE_MK)
  1453. && (token_value != BOLD_MK)
  1454. && (token_value != UNDERLINE_MK)
  1455. && (token_value != FIXED_MK)))
  1456. { ebf_error(
  1457. "'roman', 'bold', 'underline', 'reverse' or 'fixed'",
  1458. token_text);
  1459. panic_mode_error_recovery();
  1460. break;
  1461. }
  1462. AO.type = SHORT_CONSTANT_OT; AO.marker = 0;
  1463. switch(token_value)
  1464. { case ROMAN_MK: AO.value = 0; break;
  1465. case REVERSE_MK: AO.value = 1; break;
  1466. case BOLD_MK: AO.value = 2; break;
  1467. case UNDERLINE_MK: AO.value = 4; break;
  1468. case FIXED_MK: AO.value = 8; break;
  1469. }
  1470. assemblez_1(set_text_style_zc, AO); break;
  1471. /* -------------------------------------------------------------------- */
  1472. /* switch (<expression>) <codeblock> ---------------------------------- */
  1473. /* -------------------------------------------------------------------- */
  1474. case SWITCH_CODE:
  1475. match_open_bracket();
  1476. AO = code_generate(parse_expression(QUANTITY_CONTEXT),
  1477. QUANTITY_CONTEXT, -1);
  1478. match_close_bracket();
  1479. AO2.type = VARIABLE_OT; AO2.value = 255; AO2.marker = 0;
  1480. assemblez_store(AO2, AO);
  1481. parse_code_block(ln = next_label++, continue_label, 1);
  1482. assemble_label_no(ln);
  1483. return;
  1484. /* -------------------------------------------------------------------- */
  1485. /* while (<condition>) <codeblock> ------------------------------------ */
  1486. /* -------------------------------------------------------------------- */
  1487. case WHILE_CODE:
  1488. assemble_label_no(ln = next_label++);
  1489. match_open_bracket();
  1490. code_generate(parse_expression(CONDITION_CONTEXT),
  1491. CONDITION_CONTEXT, ln2 = next_label++);
  1492. match_close_bracket();
  1493. parse_code_block(ln2, ln, 0);
  1494. sequence_point_follows = FALSE;
  1495. assemblez_jump(ln);
  1496. assemble_label_no(ln2);
  1497. return;
  1498. /* -------------------------------------------------------------------- */
  1499. case SDEFAULT_CODE:
  1500. error("'default' without matching 'switch'"); break;
  1501. case ELSE_CODE:
  1502. error("'else' without matching 'if'"); break;
  1503. case UNTIL_CODE:
  1504. error("'until' without matching 'do'");
  1505. panic_mode_error_recovery(); return;
  1506. }
  1507. StatementTerminator:
  1508. get_next_token();
  1509. if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
  1510. { ebf_error("';'", token_text);
  1511. put_token_back();
  1512. }
  1513. }
  1514. static void parse_statement_g(int break_label, int continue_label)
  1515. { int ln, ln2, ln3, ln4, flag, onstack;
  1516. assembly_operand AO, AO2, AO3, AO4;
  1517. debug_location spare_debug_location1, spare_debug_location2;
  1518. ASSERT_GLULX();
  1519. if ((token_type == SEP_TT) && (token_value == PROPERTY_SEP))
  1520. { /* That is, a full stop, signifying a label */
  1521. get_next_token();
  1522. if (token_type == SYMBOL_TT)
  1523. {
  1524. if (sflags[token_value] & UNKNOWN_SFLAG)
  1525. { assign_symbol(token_value, next_label, LABEL_T);
  1526. sflags[token_value] |= USED_SFLAG;
  1527. assemble_label_no(next_label);
  1528. define_symbol_label(token_value);
  1529. next_label++;
  1530. }
  1531. else
  1532. { if (stypes[token_value] != LABEL_T) goto LabelError;
  1533. if (sflags[token_value] & CHANGE_SFLAG)
  1534. { sflags[token_value] &= (~(CHANGE_SFLAG));
  1535. assemble_label_no(svals[token_value]);
  1536. define_symbol_label(token_value);
  1537. }
  1538. else error_named("Duplicate definition of label:", token_text);
  1539. }
  1540. get_next_token();
  1541. if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
  1542. { ebf_error("';'", token_text);
  1543. put_token_back(); return;
  1544. }
  1545. /* Interesting point of Inform grammar: a statement can only
  1546. consist solely of a label when it is immediately followed
  1547. by a "}". */
  1548. get_next_token();
  1549. if ((token_type == SEP_TT) && (token_value == CLOSE_BRACE_SEP))
  1550. { put_token_back(); return;
  1551. }
  1552. /* The following line prevents labels from influencing the positions
  1553. of sequence points. */
  1554. statement_debug_location = get_token_location();
  1555. parse_statement(break_label, continue_label);
  1556. return;
  1557. }
  1558. LabelError: ebf_error("label name", token_text);
  1559. }
  1560. if ((token_type == SEP_TT) && (token_value == HASH_SEP))
  1561. { parse_directive(TRUE);
  1562. parse_statement(break_label, continue_label); return;
  1563. }
  1564. if ((token_type == SEP_TT) && (token_value == AT_SEP))
  1565. { parse_assembly(); return;
  1566. }
  1567. if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) return;
  1568. if (token_type == DQ_TT)
  1569. { parse_print_g(TRUE); return;
  1570. }
  1571. if ((token_type == SEP_TT) && (token_value == LESS_SEP))
  1572. { parse_action(); goto StatementTerminator; }
  1573. if (token_type == EOF_TT)
  1574. { ebf_error("statement", token_text); return; }
  1575. if (token_type != STATEMENT_TT)
  1576. { put_token_back();
  1577. AO = parse_expression(VOID_CONTEXT);
  1578. code_generate(AO, VOID_CONTEXT, -1);
  1579. if (vivc_flag) { panic_mode_error_recovery(); return; }
  1580. goto StatementTerminator;
  1581. }
  1582. statements.enabled = FALSE;
  1583. switch(token_value)
  1584. {
  1585. /* -------------------------------------------------------------------- */
  1586. /* box <string-1> ... <string-n> -------------------------------------- */
  1587. /* -------------------------------------------------------------------- */
  1588. case BOX_CODE:
  1589. AO3.type = CONSTANT_OT;
  1590. AO3.value = begin_table_array();
  1591. AO3.marker = ARRAY_MV;
  1592. ln = 0; ln2 = 0;
  1593. do
  1594. { get_next_token();
  1595. if ((token_type==SEP_TT)&&(token_value==SEMICOLON_SEP))
  1596. break;
  1597. if (token_type != DQ_TT)
  1598. ebf_error("text of box line in double-quotes",
  1599. token_text);
  1600. { int i, j;
  1601. for (i=0, j=0; token_text[i] != 0; j++)
  1602. if (token_text[i] == '@')
  1603. { if (token_text[i+1] == '@')
  1604. { i = i + 2;
  1605. while (isdigit(token_text[i])) i++;
  1606. }
  1607. else
  1608. { i++;
  1609. if (token_text[i] != 0) i++;
  1610. if (token_text[i] != 0) i++;
  1611. }
  1612. }
  1613. else i++;
  1614. if (j > ln2) ln2 = j;
  1615. }
  1616. put_token_back();
  1617. array_entry(ln++,parse_expression(CONSTANT_CONTEXT));
  1618. } while (TRUE);
  1619. finish_array(ln);
  1620. if (ln == 0)
  1621. error("No lines of text given for 'box' display");
  1622. AO2.value = ln2; AO2.marker = 0; set_constant_ot(&AO2);
  1623. assembleg_call_2(veneer_routine(Box__Routine_VR),
  1624. AO2, AO3, zero_operand);
  1625. return;
  1626. /* -------------------------------------------------------------------- */
  1627. /* break -------------------------------------------------------------- */
  1628. /* -------------------------------------------------------------------- */
  1629. case BREAK_CODE:
  1630. if (break_label == -1)
  1631. error("'break' can only be used in a loop or 'switch' block");
  1632. else
  1633. assembleg_jump(break_label);
  1634. break;
  1635. /* -------------------------------------------------------------------- */
  1636. /* continue ----------------------------------------------------------- */
  1637. /* -------------------------------------------------------------------- */
  1638. case CONTINUE_CODE:
  1639. if (continue_label == -1)
  1640. error("'continue' can only be used in a loop block");
  1641. else
  1642. assembleg_jump(continue_label);
  1643. break;
  1644. /* -------------------------------------------------------------------- */
  1645. /* do <codeblock> until (<condition>) --------------------------------- */
  1646. /* -------------------------------------------------------------------- */
  1647. case DO_CODE:
  1648. assemble_label_no(ln = next_label++);
  1649. ln2 = next_label++; ln3 = next_label++;
  1650. parse_code_block(ln3, ln2, 0);
  1651. statements.enabled = TRUE;
  1652. get_next_token();
  1653. if ((token_type == STATEMENT_TT)
  1654. && (token_value == UNTIL_CODE))
  1655. { assemble_label_no(ln2);
  1656. match_open_bracket();
  1657. AO = parse_expression(CONDITION_CONTEXT);
  1658. match_close_bracket();
  1659. code_generate(AO, CONDITION_CONTEXT, ln);
  1660. }
  1661. else error("'do' without matching 'until'");
  1662. assemble_label_no(ln3);
  1663. break;
  1664. /* -------------------------------------------------------------------- */
  1665. /* font on/off -------------------------------------------------------- */
  1666. /* -------------------------------------------------------------------- */
  1667. case FONT_CODE:
  1668. misc_keywords.enabled = TRUE;
  1669. get_next_token();
  1670. misc_keywords.enabled = FALSE;
  1671. if ((token_type != MISC_KEYWORD_TT)
  1672. || ((token_value != ON_MK)
  1673. && (token_value != OFF_MK)))
  1674. { ebf_error("'on' or 'off'", token_text);
  1675. panic_mode_error_recovery();
  1676. break;
  1677. }
  1678. /* Call glk_set_style(normal or preformatted) */
  1679. AO.value = 0x0086;
  1680. AO.marker = 0;
  1681. set_constant_ot(&AO);
  1682. if (token_value == ON_MK)
  1683. AO2 = zero_operand;
  1684. else
  1685. AO2 = two_operand;
  1686. assembleg_call_2(veneer_routine(Glk__Wrap_VR),
  1687. AO, AO2, zero_operand);
  1688. break;
  1689. /* -------------------------------------------------------------------- */
  1690. /* for (<initialisation> : <continue-condition> : <updating>) --------- */
  1691. /* -------------------------------------------------------------------- */
  1692. /* Note that it's legal for any or all of the three sections of a
  1693. 'for' specification to be empty. This 'for' implementation
  1694. often wastes 3 bytes with a redundant branch rather than keep
  1695. expression parse trees for long periods (as previous versions
  1696. of Inform did, somewhat crudely by simply storing the textual
  1697. form of a 'for' loop). It is adequate for now. */
  1698. case FOR_CODE:
  1699. match_open_bracket();
  1700. get_next_token();
  1701. /* Initialisation code */
  1702. if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
  1703. { put_token_back();
  1704. if (!((token_type==SEP_TT)&&(token_value==SUPERCLASS_SEP)))
  1705. { sequence_point_follows = TRUE;
  1706. statement_debug_location = get_token_location();
  1707. code_generate(parse_expression(FORINIT_CONTEXT),
  1708. VOID_CONTEXT, -1);
  1709. }
  1710. get_next_token();
  1711. if ((token_type==SEP_TT)&&(token_value == SUPERCLASS_SEP))
  1712. { get_next_token();
  1713. if ((token_type==SEP_TT)&&(token_value == CLOSEB_SEP))
  1714. { assemble_label_no(ln = next_label++);
  1715. ln2 = next_label++;
  1716. parse_code_block(ln2, ln, 0);
  1717. sequence_point_follows = FALSE;
  1718. if (!execution_never_reaches_here)
  1719. assembleg_jump(ln);
  1720. assemble_label_no(ln2);
  1721. return;
  1722. }
  1723. AO.type = OMITTED_OT;
  1724. goto ParseUpdate;
  1725. }
  1726. put_token_back();
  1727. if (!match_colon()) break;
  1728. }
  1729. get_next_token();
  1730. AO.type = OMITTED_OT;
  1731. if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
  1732. { put_token_back();
  1733. spare_debug_location1 = get_token_location();
  1734. AO = parse_expression(CONDITION_CONTEXT);
  1735. if (!match_colon()) break;
  1736. }
  1737. get_next_token();
  1738. ParseUpdate:
  1739. AO2.type = OMITTED_OT; flag = 0;
  1740. if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP)))
  1741. { put_token_back();
  1742. spare_debug_location2 = get_token_location();
  1743. AO2 = parse_expression(VOID_CONTEXT);
  1744. match_close_bracket();
  1745. flag = test_for_incdec(AO2);
  1746. }
  1747. ln = next_label++;
  1748. ln2 = next_label++;
  1749. ln3 = next_label++;
  1750. if ((AO2.type == OMITTED_OT) || (flag != 0))
  1751. {
  1752. assemble_label_no(ln);
  1753. if (flag==0) assemble_label_no(ln2);
  1754. /* The "finished yet?" condition */
  1755. if (AO.type != OMITTED_OT)
  1756. { sequence_point_follows = TRUE;
  1757. statement_debug_location = spare_debug_location1;
  1758. code_generate(AO, CONDITION_CONTEXT, ln3);
  1759. }
  1760. }
  1761. else
  1762. {
  1763. /* This is the jump which could be avoided with the aid
  1764. of long-term expression storage */
  1765. sequence_point_follows = FALSE;
  1766. assembleg_jump(ln2);
  1767. /* The "update" part */
  1768. assemble_label_no(ln);
  1769. sequence_point_follows = TRUE;
  1770. statement_debug_location = spare_debug_location2;
  1771. code_generate(AO2, VOID_CONTEXT, -1);
  1772. assemble_label_no(ln2);
  1773. /* The "finished yet?" condition */
  1774. if (AO.type != OMITTED_OT)
  1775. { sequence_point_follows = TRUE;
  1776. statement_debug_location = spare_debug_location1;
  1777. code_generate(AO, CONDITION_CONTEXT, ln3);
  1778. }
  1779. }
  1780. if (flag != 0)
  1781. {
  1782. /* In this optimised case, update code is at the end
  1783. of the loop block, so "continue" goes there */
  1784. parse_code_block(ln3, ln2, 0);
  1785. assemble_label_no(ln2);
  1786. sequence_point_follows = TRUE;
  1787. statement_debug_location = spare_debug_location2;
  1788. if (flag > 0)
  1789. { AO3.value = flag;
  1790. if (AO3.value >= MAX_LOCAL_VARIABLES)
  1791. AO3.type = GLOBALVAR_OT;
  1792. else
  1793. AO3.type = LOCALVAR_OT;
  1794. AO3.marker = 0;
  1795. assembleg_3(add_gc, AO3, one_operand, AO3);
  1796. }
  1797. else
  1798. { AO3.value = -flag;
  1799. if (AO3.value >= MAX_LOCAL_VARIABLES)
  1800. AO3.type = GLOBALVAR_OT;
  1801. else
  1802. AO3.type = LOCALVAR_OT;
  1803. AO3.marker = 0;
  1804. assembleg_3(sub_gc, AO3, one_operand, AO3);
  1805. }
  1806. assembleg_jump(ln);
  1807. }
  1808. else
  1809. {
  1810. /* In the unoptimised case, update code is at the
  1811. start of the loop block, so "continue" goes there */
  1812. parse_code_block(ln3, ln, 0);
  1813. if (!execution_never_reaches_here)
  1814. { sequence_point_follows = FALSE;
  1815. assembleg_jump(ln);
  1816. }
  1817. }
  1818. assemble_label_no(ln3);
  1819. return;
  1820. /* -------------------------------------------------------------------- */
  1821. /* give <expression> [~]attr [, [~]attr [, ...]] ---------------------- */
  1822. /* -------------------------------------------------------------------- */
  1823. case GIVE_CODE:
  1824. AO = code_generate(parse_expression(QUANTITY_CONTEXT),
  1825. QUANTITY_CONTEXT, -1);
  1826. if ((AO.type == LOCALVAR_OT) && (AO.value == 0))
  1827. onstack = TRUE;
  1828. else
  1829. onstack = FALSE;
  1830. do
  1831. { get_next_token();
  1832. if ((token_type == SEP_TT)
  1833. && (token_value == SEMICOLON_SEP)) {
  1834. if (onstack) {
  1835. assembleg_2(copy_gc, stack_pointer, zero_operand);
  1836. }
  1837. return;
  1838. }
  1839. if ((token_type == SEP_TT)&&(token_value == ARTNOT_SEP))
  1840. ln = 0;
  1841. else
  1842. { if ((token_type == SYMBOL_TT)
  1843. && (stypes[token_value] != ATTRIBUTE_T))
  1844. warning_named("This is not a declared Attribute:",
  1845. token_text);
  1846. ln = 1;
  1847. put_token_back();
  1848. }
  1849. AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
  1850. QUANTITY_CONTEXT, -1);
  1851. if (runtime_error_checking_switch && (!veneer_mode))
  1852. { ln2 = (ln ? RT__ChG_VR : RT__ChGt_VR);
  1853. if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0)) {
  1854. /* already on stack */
  1855. }
  1856. else {
  1857. assembleg_store(stack_pointer, AO2);
  1858. }
  1859. if (onstack)
  1860. assembleg_2(stkpeek_gc, one_operand, stack_pointer);
  1861. else
  1862. assembleg_store(stack_pointer, AO);
  1863. assembleg_3(call_gc, veneer_routine(ln2), two_operand,
  1864. zero_operand);
  1865. }
  1866. else {
  1867. if (is_constant_ot(AO2.type) && AO2.marker == 0) {
  1868. AO2.value += 8;
  1869. set_constant_ot(&AO2);
  1870. }
  1871. else {
  1872. AO3.value = 8;
  1873. AO3.marker = 0;
  1874. AO3.type = BYTECONSTANT_OT;
  1875. assembleg_3(add_gc, AO2, AO3, stack_pointer);
  1876. AO2 = stack_pointer;
  1877. }
  1878. if (onstack) {
  1879. if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0))
  1880. assembleg_2(stkpeek_gc, one_operand,
  1881. stack_pointer);
  1882. else
  1883. assembleg_2(stkpeek_gc, zero_operand,
  1884. stack_pointer);
  1885. }
  1886. if (ln)
  1887. AO3 = one_operand;
  1888. else
  1889. AO3 = zero_operand;
  1890. assembleg_3(astorebit_gc, AO, AO2, AO3);
  1891. }
  1892. } while(TRUE);
  1893. /* -------------------------------------------------------------------- */
  1894. /* if (<condition>) <codeblock> [else <codeblock>] -------------------- */
  1895. /* -------------------------------------------------------------------- */
  1896. case IF_CODE:
  1897. flag = FALSE;
  1898. match_open_bracket();
  1899. AO = parse_expression(CONDITION_CONTEXT);
  1900. match_close_bracket();
  1901. statements.enabled = TRUE;
  1902. get_next_token();
  1903. if ((token_type == STATEMENT_TT)&&(token_value == RTRUE_CODE))
  1904. ln = -4;
  1905. else
  1906. if ((token_type == STATEMENT_TT)&&(token_value == RFALSE_CODE))
  1907. ln = -3;
  1908. else
  1909. { put_token_back();
  1910. ln = next_label++;
  1911. }
  1912. code_generate(AO, CONDITION_CONTEXT, ln);
  1913. if (ln >= 0) parse_code_block(break_label, continue_label, 0);
  1914. else
  1915. { get_next_token();
  1916. if ((token_type != SEP_TT)
  1917. || (token_value != SEMICOLON_SEP))
  1918. { ebf_error("';'", token_text);
  1919. put_token_back();
  1920. }
  1921. }
  1922. statements.enabled = TRUE;
  1923. get_next_token();
  1924. if ((token_type == STATEMENT_TT) && (token_value == ELSE_CODE))
  1925. { flag = TRUE;
  1926. if (ln >= 0)
  1927. { ln2 = next_label++;
  1928. if (!execution_never_reaches_here)
  1929. { sequence_point_follows = FALSE;
  1930. assembleg_jump(ln2);
  1931. }
  1932. }
  1933. }
  1934. else put_token_back();
  1935. if (ln >= 0) assemble_label_no(ln);
  1936. if (flag)
  1937. { parse_code_block(break_label, continue_label, 0);
  1938. if (ln >= 0) assemble_label_no(ln2);
  1939. }
  1940. return;
  1941. /* -------------------------------------------------------------------- */
  1942. /* inversion ---------------------------------------------------------- */
  1943. /* -------------------------------------------------------------------- */
  1944. case INVERSION_CODE:
  1945. AO2.marker = 0;
  1946. AO2.type = DEREFERENCE_OT;
  1947. AO2.value = GLULX_HEADER_SIZE+8;
  1948. assembleg_2(copyb_gc, AO2, stack_pointer);
  1949. assembleg_1(streamchar_gc, stack_pointer);
  1950. AO2.value = GLULX_HEADER_SIZE+9;
  1951. assembleg_2(copyb_gc, AO2, stack_pointer);
  1952. assembleg_1(streamchar_gc, stack_pointer);
  1953. AO2.value = GLULX_HEADER_SIZE+10;
  1954. assembleg_2(copyb_gc, AO2, stack_pointer);
  1955. assembleg_1(streamchar_gc, stack_pointer);
  1956. AO2.value = GLULX_HEADER_SIZE+11;
  1957. assembleg_2(copyb_gc, AO2, stack_pointer);
  1958. assembleg_1(streamchar_gc, stack_pointer);
  1959. if (0) {
  1960. AO.marker = 0;
  1961. AO.value = '(';
  1962. set_constant_ot(&AO);
  1963. assembleg_1(streamchar_gc, AO);
  1964. AO.value = 'G';
  1965. set_constant_ot(&AO);
  1966. assembleg_1(streamchar_gc, AO);
  1967. AO2.value = GLULX_HEADER_SIZE+12;
  1968. assembleg_2(copyb_gc, AO2, stack_pointer);
  1969. assembleg_1(streamchar_gc, stack_pointer);
  1970. AO2.value = GLULX_HEADER_SIZE+13;
  1971. assembleg_2(copyb_gc, AO2, stack_pointer);
  1972. assembleg_1(streamchar_gc, stack_pointer);
  1973. AO2.value = GLULX_HEADER_SIZE+14;
  1974. assembleg_2(copyb_gc, AO2, stack_pointer);
  1975. assembleg_1(streamchar_gc, stack_pointer);
  1976. AO2.value = GLULX_HEADER_SIZE+15;
  1977. assembleg_2(copyb_gc, AO2, stack_pointer);
  1978. assembleg_1(streamchar_gc, stack_pointer);
  1979. AO.marker = 0;
  1980. AO.value = ')';
  1981. set_constant_ot(&AO);
  1982. assembleg_1(streamchar_gc, AO);
  1983. }
  1984. break;
  1985. /* -------------------------------------------------------------------- */
  1986. /* jump <label> ------------------------------------------------------- */
  1987. /* -------------------------------------------------------------------- */
  1988. case JUMP_CODE:
  1989. assembleg_jump(parse_label());
  1990. break;
  1991. /* -------------------------------------------------------------------- */
  1992. /* move <expression> to <expression> ---------------------------------- */
  1993. /* -------------------------------------------------------------------- */
  1994. case MOVE_CODE:
  1995. misc_keywords.enabled = TRUE;
  1996. AO = parse_expression(QUANTITY_CONTEXT);
  1997. get_next_token();
  1998. misc_keywords.enabled = FALSE;
  1999. if ((token_type != MISC_KEYWORD_TT)
  2000. || (token_value != TO_MK))
  2001. { ebf_error("'to'", token_text);
  2002. panic_mode_error_recovery();
  2003. return;
  2004. }
  2005. AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
  2006. QUANTITY_CONTEXT, -1);
  2007. AO = code_generate(AO, QUANTITY_CONTEXT, -1);
  2008. if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
  2009. assembleg_call_2(veneer_routine(RT__ChT_VR), AO, AO2,
  2010. zero_operand);
  2011. else
  2012. assembleg_call_2(veneer_routine(OB__Move_VR), AO, AO2,
  2013. zero_operand);
  2014. break;
  2015. /* -------------------------------------------------------------------- */
  2016. /* new_line ----------------------------------------------------------- */
  2017. /* -------------------------------------------------------------------- */
  2018. case NEW_LINE_CODE:
  2019. AO.type = BYTECONSTANT_OT; AO.value = 0x0A; AO.marker = 0;
  2020. assembleg_1(streamchar_gc, AO);
  2021. break;
  2022. /* -------------------------------------------------------------------- */
  2023. /* objectloop (<initialisation>) <codeblock> -------------------------- */
  2024. /* -------------------------------------------------------------------- */
  2025. case OBJECTLOOP_CODE:
  2026. match_open_bracket();
  2027. get_next_token();
  2028. if (token_type == LOCAL_VARIABLE_TT) {
  2029. AO.value = token_value;
  2030. AO.type = LOCALVAR_OT;
  2031. AO.marker = 0;
  2032. }
  2033. else if ((token_type == SYMBOL_TT) &&
  2034. (stypes[token_value] == GLOBAL_VARIABLE_T)) {
  2035. AO.value = svals[token_value];
  2036. AO.type = GLOBALVAR_OT;
  2037. AO.marker = 0;
  2038. }
  2039. else {
  2040. ebf_error("'objectloop' variable", token_text);
  2041. panic_mode_error_recovery();
  2042. break;
  2043. }
  2044. misc_keywords.enabled = TRUE;
  2045. get_next_token(); flag = TRUE;
  2046. misc_keywords.enabled = FALSE;
  2047. if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
  2048. flag = FALSE;
  2049. ln = 0;
  2050. if ((token_type == MISC_KEYWORD_TT)
  2051. && (token_value == NEAR_MK)) ln = 1;
  2052. if ((token_type == MISC_KEYWORD_TT)
  2053. && (token_value == FROM_MK)) ln = 2;
  2054. if ((token_type == CND_TT) && (token_value == IN_COND))
  2055. { get_next_token();
  2056. get_next_token();
  2057. if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
  2058. ln = 3;
  2059. put_token_back();
  2060. put_token_back();
  2061. }
  2062. if (ln != 0) {
  2063. /* Old style (Inform 5) objectloops: note that we
  2064. implement objectloop (a in b) in the old way since
  2065. this runs through objects in a different order from
  2066. the new way, and there may be existing Inform code
  2067. relying on this. */
  2068. assembly_operand AO4, AO5;
  2069. sequence_point_follows = TRUE;
  2070. AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
  2071. QUANTITY_CONTEXT, -1);
  2072. match_close_bracket();
  2073. if (ln == 1) {
  2074. if (runtime_error_checking_switch)
  2075. AO2 = check_nonzero_at_runtime(AO2, -1,
  2076. OBJECTLOOP_RTE);
  2077. AO4.type = BYTECONSTANT_OT;
  2078. AO4.value = GOBJFIELD_PARENT();
  2079. AO4.marker = 0;
  2080. assembleg_3(aload_gc, AO2, AO4, stack_pointer);
  2081. AO4.type = BYTECONSTANT_OT;
  2082. AO4.value = GOBJFIELD_CHILD();
  2083. AO4.marker = 0;
  2084. assembleg_3(aload_gc, stack_pointer, AO4, stack_pointer);
  2085. AO2 = stack_pointer;
  2086. }
  2087. else if (ln == 3) {
  2088. if (runtime_error_checking_switch) {
  2089. AO5 = AO2;
  2090. AO2 = check_nonzero_at_runtime(AO2, -1,
  2091. CHILD_RTE);
  2092. }
  2093. AO4.type = BYTECONSTANT_OT;
  2094. AO4.value = GOBJFIELD_CHILD();
  2095. AO4.marker = 0;
  2096. assembleg_3(aload_gc, AO2, AO4, stack_pointer);
  2097. AO2 = stack_pointer;
  2098. }
  2099. else {
  2100. /* do nothing */
  2101. }
  2102. assembleg_store(AO, AO2);
  2103. assembleg_1_branch(jz_gc, AO, ln2 = next_label++);
  2104. assemble_label_no(ln4 = next_label++);
  2105. parse_code_block(ln2, ln3 = next_label++, 0);
  2106. sequence_point_follows = FALSE;
  2107. assemble_label_no(ln3);
  2108. if (runtime_error_checking_switch) {
  2109. AO2 = check_nonzero_at_runtime(AO, ln2,
  2110. OBJECTLOOP2_RTE);
  2111. if ((ln == 3)
  2112. && ((AO5.type != LOCALVAR_OT)||(AO5.value != 0))
  2113. && ((AO5.type != LOCALVAR_OT)||(AO5.value != AO.value)))
  2114. { assembly_operand en_ao;
  2115. en_ao.value = OBJECTLOOP_BROKEN_RTE;
  2116. en_ao.marker = 0;
  2117. set_constant_ot(&en_ao);
  2118. AO4.type = BYTECONSTANT_OT;
  2119. AO4.value = GOBJFIELD_PARENT();
  2120. AO4.marker = 0;
  2121. assembleg_3(aload_gc, AO, AO4, stack_pointer);
  2122. assembleg_2_branch(jeq_gc, stack_pointer, AO5,
  2123. next_label);
  2124. assembleg_call_2(veneer_routine(RT__Err_VR),
  2125. en_ao, AO, zero_operand);
  2126. assembleg_jump(ln2);
  2127. assemble_label_no(next_label++);
  2128. }
  2129. }
  2130. else {
  2131. AO2 = AO;
  2132. }
  2133. AO4.type = BYTECONSTANT_OT;
  2134. AO4.value = GOBJFIELD_SIBLING();
  2135. AO4.marker = 0;
  2136. assembleg_3(aload_gc, AO2, AO4, AO);
  2137. assembleg_1_branch(jnz_gc, AO, ln4);
  2138. assemble_label_no(ln2);
  2139. return;
  2140. }
  2141. sequence_point_follows = TRUE;
  2142. ln = symbol_index("Class", -1);
  2143. AO2.value = svals[ln];
  2144. AO2.marker = OBJECT_MV;
  2145. AO2.type = CONSTANT_OT;
  2146. assembleg_store(AO, AO2);
  2147. assemble_label_no(ln = next_label++);
  2148. ln2 = next_label++;
  2149. ln3 = next_label++;
  2150. if (flag)
  2151. { put_token_back();
  2152. put_token_back();
  2153. sequence_point_follows = TRUE;
  2154. code_generate(parse_expression(CONDITION_CONTEXT),
  2155. CONDITION_CONTEXT, ln3);
  2156. match_close_bracket();
  2157. }
  2158. parse_code_block(ln2, ln3, 0);
  2159. sequence_point_follows = FALSE;
  2160. assemble_label_no(ln3);
  2161. AO4.type = BYTECONSTANT_OT;
  2162. AO4.value = GOBJFIELD_CHAIN();
  2163. AO4.marker = 0;
  2164. assembleg_3(aload_gc, AO, AO4, AO);
  2165. assembleg_1_branch(jnz_gc, AO, ln);
  2166. assemble_label_no(ln2);
  2167. return;
  2168. /* -------------------------------------------------------------------- */
  2169. /* (see routine above) ------------------------------------------------ */
  2170. /* -------------------------------------------------------------------- */
  2171. case PRINT_CODE:
  2172. get_next_token();
  2173. parse_print_g(FALSE); return;
  2174. case PRINT_RET_CODE:
  2175. get_next_token();
  2176. parse_print_g(TRUE); return;
  2177. /* -------------------------------------------------------------------- */
  2178. /* quit --------------------------------------------------------------- */
  2179. /* -------------------------------------------------------------------- */
  2180. case QUIT_CODE:
  2181. assembleg_0(quit_gc); break;
  2182. /* -------------------------------------------------------------------- */
  2183. /* remove <expression> ------------------------------------------------ */
  2184. /* -------------------------------------------------------------------- */
  2185. case REMOVE_CODE:
  2186. AO = code_generate(parse_expression(QUANTITY_CONTEXT),
  2187. QUANTITY_CONTEXT, -1);
  2188. if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
  2189. assembleg_call_1(veneer_routine(RT__ChR_VR), AO,
  2190. zero_operand);
  2191. else
  2192. assembleg_call_1(veneer_routine(OB__Remove_VR), AO,
  2193. zero_operand);
  2194. break;
  2195. /* -------------------------------------------------------------------- */
  2196. /* return [<expression>] ---------------------------------------------- */
  2197. /* -------------------------------------------------------------------- */
  2198. case RETURN_CODE:
  2199. get_next_token();
  2200. if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
  2201. AO.type = BYTECONSTANT_OT; AO.value = 1; AO.marker = 0;
  2202. assembleg_1(return_gc, AO);
  2203. return;
  2204. }
  2205. put_token_back();
  2206. AO = code_generate(parse_expression(RETURN_Q_CONTEXT),
  2207. QUANTITY_CONTEXT, -1);
  2208. assembleg_1(return_gc, AO);
  2209. break;
  2210. /* -------------------------------------------------------------------- */
  2211. /* rfalse ------------------------------------------------------------- */
  2212. /* -------------------------------------------------------------------- */
  2213. case RFALSE_CODE:
  2214. assembleg_1(return_gc, zero_operand);
  2215. break;
  2216. /* -------------------------------------------------------------------- */
  2217. /* rtrue -------------------------------------------------------------- */
  2218. /* -------------------------------------------------------------------- */
  2219. case RTRUE_CODE:
  2220. assembleg_1(return_gc, one_operand);
  2221. break;
  2222. /* -------------------------------------------------------------------- */
  2223. /* spaces <expression> ------------------------------------------------ */
  2224. /* -------------------------------------------------------------------- */
  2225. case SPACES_CODE:
  2226. AO = code_generate(parse_expression(QUANTITY_CONTEXT),
  2227. QUANTITY_CONTEXT, -1);
  2228. assembleg_store(temp_var1, AO);
  2229. AO.value = 32; AO.marker = 0; set_constant_ot(&AO);
  2230. assembleg_2_branch(jlt_gc, temp_var1, one_operand,
  2231. ln = next_label++);
  2232. assemble_label_no(ln2 = next_label++);
  2233. assembleg_1(streamchar_gc, AO);
  2234. assembleg_dec(temp_var1);
  2235. assembleg_1_branch(jnz_gc, temp_var1, ln2);
  2236. assemble_label_no(ln);
  2237. break;
  2238. /* -------------------------------------------------------------------- */
  2239. /* string <expression> <literal-string> ------------------------------- */
  2240. /* -------------------------------------------------------------------- */
  2241. case STRING_CODE:
  2242. AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
  2243. QUANTITY_CONTEXT, -1);
  2244. get_next_token();
  2245. if (token_type == DQ_TT)
  2246. { AO4.value = compile_string(token_text, TRUE, TRUE);
  2247. AO4.marker = STRING_MV;
  2248. AO4.type = CONSTANT_OT;
  2249. }
  2250. else
  2251. { put_token_back();
  2252. AO4 = parse_expression(CONSTANT_CONTEXT);
  2253. }
  2254. assembleg_call_2(veneer_routine(Dynam__String_VR),
  2255. AO2, AO4, zero_operand);
  2256. break;
  2257. /* -------------------------------------------------------------------- */
  2258. /* style roman/reverse/bold/underline/fixed --------------------------- */
  2259. /* -------------------------------------------------------------------- */
  2260. case STYLE_CODE:
  2261. misc_keywords.enabled = TRUE;
  2262. get_next_token();
  2263. misc_keywords.enabled = FALSE;
  2264. if ((token_type != MISC_KEYWORD_TT)
  2265. || ((token_value != ROMAN_MK)
  2266. && (token_value != REVERSE_MK)
  2267. && (token_value != BOLD_MK)
  2268. && (token_value != UNDERLINE_MK)
  2269. && (token_value != FIXED_MK)))
  2270. { ebf_error(
  2271. "'roman', 'bold', 'underline', 'reverse' or 'fixed'",
  2272. token_text);
  2273. panic_mode_error_recovery();
  2274. break;
  2275. }
  2276. /* Call glk_set_style() */
  2277. AO.value = 0x0086;
  2278. AO.marker = 0;
  2279. set_constant_ot(&AO);
  2280. switch(token_value)
  2281. { case ROMAN_MK:
  2282. AO2 = zero_operand; /* normal */
  2283. break;
  2284. case REVERSE_MK:
  2285. AO2.value = 5; /* alert */
  2286. AO2.marker = 0;
  2287. set_constant_ot(&AO2);
  2288. break;
  2289. case BOLD_MK:
  2290. AO2.value = 4; /* subheader */
  2291. AO2.marker = 0;
  2292. set_constant_ot(&AO2);
  2293. break;
  2294. case UNDERLINE_MK:
  2295. AO2 = one_operand; /* emphasized */
  2296. break;
  2297. case FIXED_MK:
  2298. AO2 = two_operand; /* preformatted */
  2299. break;
  2300. }
  2301. assembleg_call_2(veneer_routine(Glk__Wrap_VR),
  2302. AO, AO2, zero_operand);
  2303. break;
  2304. /* -------------------------------------------------------------------- */
  2305. /* switch (<expression>) <codeblock> ---------------------------------- */
  2306. /* -------------------------------------------------------------------- */
  2307. case SWITCH_CODE:
  2308. match_open_bracket();
  2309. AO = code_generate(parse_expression(QUANTITY_CONTEXT),
  2310. QUANTITY_CONTEXT, -1);
  2311. match_close_bracket();
  2312. assembleg_store(temp_var1, AO);
  2313. parse_code_block(ln = next_label++, continue_label, 1);
  2314. assemble_label_no(ln);
  2315. return;
  2316. /* -------------------------------------------------------------------- */
  2317. /* while (<condition>) <codeblock> ------------------------------------ */
  2318. /* -------------------------------------------------------------------- */
  2319. case WHILE_CODE:
  2320. assemble_label_no(ln = next_label++);
  2321. match_open_bracket();
  2322. code_generate(parse_expression(CONDITION_CONTEXT),
  2323. CONDITION_CONTEXT, ln2 = next_label++);
  2324. match_close_bracket();
  2325. parse_code_block(ln2, ln, 0);
  2326. sequence_point_follows = FALSE;
  2327. assembleg_jump(ln);
  2328. assemble_label_no(ln2);
  2329. return;
  2330. /* -------------------------------------------------------------------- */
  2331. case SDEFAULT_CODE:
  2332. error("'default' without matching 'switch'"); break;
  2333. case ELSE_CODE:
  2334. error("'else' without matching 'if'"); break;
  2335. case UNTIL_CODE:
  2336. error("'until' without matching 'do'");
  2337. panic_mode_error_recovery(); return;
  2338. /* -------------------------------------------------------------------- */
  2339. /* And a useful default, which will never be triggered in a complete
  2340. Inform compiler, but which is important in development. */
  2341. default:
  2342. error("*** Statement code gen: Can't generate yet ***\n");
  2343. panic_mode_error_recovery(); return;
  2344. }
  2345. StatementTerminator:
  2346. get_next_token();
  2347. if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
  2348. { ebf_error("';'", token_text);
  2349. put_token_back();
  2350. }
  2351. }
  2352. extern void parse_statement(int break_label, int continue_label)
  2353. {
  2354. if (!glulx_mode)
  2355. parse_statement_z(break_label, continue_label);
  2356. else
  2357. parse_statement_g(break_label, continue_label);
  2358. }
  2359. /* ========================================================================= */
  2360. /* Data structure management routines */
  2361. /* ------------------------------------------------------------------------- */
  2362. extern void init_states_vars(void)
  2363. {
  2364. }
  2365. extern void states_begin_pass(void)
  2366. {
  2367. }
  2368. extern void states_allocate_arrays(void)
  2369. {
  2370. }
  2371. extern void states_free_arrays(void)
  2372. {
  2373. }
  2374. /* ========================================================================= */