1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704 |
- /* ------------------------------------------------------------------------- */
- /* "states" : Statement translator */
- /* */
- /* Part of Inform 6.33 */
- /* copyright (c) Graham Nelson 1993 - 2014 */
- /* */
- /* ------------------------------------------------------------------------- */
- #include "header.h"
- static int match_colon(void)
- { get_next_token();
- if (token_type == SEP_TT)
- { if (token_value == SEMICOLON_SEP)
- warning("Unlike C, Inform uses ':' to divide parts \
- of a 'for' loop specification: replacing ';' with ':'");
- else
- if (token_value != COLON_SEP)
- { ebf_error("':'", token_text);
- panic_mode_error_recovery();
- return(FALSE);
- }
- }
- else
- { ebf_error("':'", token_text);
- panic_mode_error_recovery();
- return(FALSE);
- }
- return(TRUE);
- }
- static void match_open_bracket(void)
- { get_next_token();
- if ((token_type == SEP_TT) && (token_value == OPENB_SEP)) return;
- put_token_back();
- ebf_error("'('", token_text);
- }
- extern void match_close_bracket(void)
- { get_next_token();
- if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP)) return;
- put_token_back();
- ebf_error("')'", token_text);
- }
- static void parse_action(void)
- { int level = 1, args = 0, codegen_action;
- assembly_operand AO, AO2, AO3, AO4, AO5;
- /* An action statement has the form <ACTION NOUN SECOND, ACTOR>
- or <<ACTION NOUN SECOND, ACTOR>>. It simply compiles into a call
- to R_Process() with those four arguments. (The latter form,
- with double brackets, means "return true afterwards".)
- The R_Process() function should be supplied by the library,
- although a stub is defined in the veneer.
- The NOUN, SECOND, and ACTOR arguments are optional. If not
- supplied, R_Process() will be called with fewer arguments.
- (But if you supply ACTOR, it must be preceded by a comma.
- <ACTION, ACTOR> is equivalent to <ACTION 0 0, ACTOR>.)
- To complicate life, the ACTION argument may be a bare action
- name or a parenthesized expression. (So <Take> is equivalent
- to <(##Take)>.) We have to peek at the first token, checking
- whether it's an open-paren, to distinguish these cases.
- You may ask why the ACTOR argument is last; the "natural"
- Inform ordering would be "<floyd, take ball>". True! Sadly,
- Inform's lexer isn't smart enough to parse this consistently,
- so we can't do it.
- */
- dont_enter_into_symbol_table = TRUE;
- get_next_token();
- if ((token_type == SEP_TT) && (token_value == LESS_SEP))
- { level = 2; get_next_token();
- }
- dont_enter_into_symbol_table = FALSE;
- /* Peek at the next token; see if it's an open-paren. */
- if ((token_type==SEP_TT) && (token_value==OPENB_SEP))
- { put_token_back();
- AO2 = parse_expression(ACTION_Q_CONTEXT);
- codegen_action = TRUE;
- }
- else
- { codegen_action = FALSE;
- AO2 = action_of_name(token_text);
- }
- get_next_token();
- AO3 = zero_operand;
- AO4 = zero_operand;
- AO5 = zero_operand;
- if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
- { put_token_back();
- args = 1;
- AO3 = parse_expression(ACTION_Q_CONTEXT);
- get_next_token();
- }
- if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
- { put_token_back();
- args = 2;
- AO4 = parse_expression(QUANTITY_CONTEXT);
- get_next_token();
- }
- if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
- {
- ebf_error("',' or '>'", token_text);
- }
- if ((token_type == SEP_TT) && (token_value == COMMA_SEP))
- {
- if (!glulx_mode && (version_number < 4))
- {
- error("<x, y> syntax is not available in Z-code V3 or earlier");
- }
- args = 3;
- AO5 = parse_expression(QUANTITY_CONTEXT);
- get_next_token();
- if (!((token_type == SEP_TT) && (token_value == GREATER_SEP)))
- {
- ebf_error("'>'", token_text);
- }
- }
- if (level == 2)
- { get_next_token();
- if (!((token_type == SEP_TT) && (token_value == GREATER_SEP)))
- { put_token_back();
- ebf_error("'>>'", token_text);
- }
- }
- if (!glulx_mode) {
- AO = veneer_routine(R_Process_VR);
- switch(args)
- { case 0:
- if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
- if (version_number>=5)
- assemblez_2(call_2n_zc, AO, AO2);
- else
- if (version_number==4)
- assemblez_2_to(call_vs_zc, AO, AO2, temp_var1);
- else
- assemblez_2_to(call_zc, AO, AO2, temp_var1);
- break;
- case 1:
- AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
- if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
- if (version_number>=5)
- assemblez_3(call_vn_zc, AO, AO2, AO3);
- else
- if (version_number==4)
- assemblez_3_to(call_vs_zc, AO, AO2, AO3, temp_var1);
- else
- assemblez_3_to(call_zc, AO, AO2, AO3, temp_var1);
- break;
- case 2:
- AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
- AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
- if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
- if (version_number>=5)
- assemblez_4(call_vn_zc, AO, AO2, AO3, AO4);
- else
- if (version_number==4)
- assemblez_4_to(call_vs_zc, AO, AO2, AO3, AO4, temp_var1);
- else
- assemblez_4(call_zc, AO, AO2, AO3, AO4);
- break;
- case 3:
- AO5 = code_generate(AO5, QUANTITY_CONTEXT, -1);
- AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
- AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
- if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
- if (version_number>=5)
- assemblez_5(call_vn2_zc, AO, AO2, AO3, AO4, AO5);
- else
- if (version_number==4)
- assemblez_5_to(call_vs2_zc, AO, AO2, AO3, AO4, AO5, temp_var1);
- /* if V3 or earlier, we've already displayed an error */
- break;
- break;
- }
- if (level == 2) assemblez_0(rtrue_zc);
- }
- else {
- AO = veneer_routine(R_Process_VR);
- switch (args) {
- case 0:
- if (codegen_action)
- AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
- assembleg_call_1(AO, AO2, zero_operand);
- break;
- case 1:
- AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
- if (codegen_action)
- AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
- assembleg_call_2(AO, AO2, AO3, zero_operand);
- break;
- case 2:
- AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
- AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
- if (codegen_action)
- AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
- assembleg_call_3(AO, AO2, AO3, AO4, zero_operand);
- break;
- case 3:
- AO5 = code_generate(AO5, QUANTITY_CONTEXT, -1);
- if (!((AO5.type == LOCALVAR_OT) && (AO5.value == 0)))
- assembleg_store(stack_pointer, AO5);
- AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
- if (!((AO4.type == LOCALVAR_OT) && (AO4.value == 0)))
- assembleg_store(stack_pointer, AO4);
- AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
- if (!((AO3.type == LOCALVAR_OT) && (AO3.value == 0)))
- assembleg_store(stack_pointer, AO3);
- if (codegen_action)
- AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
- if (!((AO2.type == LOCALVAR_OT) && (AO2.value == 0)))
- assembleg_store(stack_pointer, AO2);
- assembleg_3(call_gc, AO, four_operand, zero_operand);
- break;
- }
- if (level == 2)
- assembleg_1(return_gc, one_operand);
- }
- }
- extern int parse_label(void)
- {
- get_next_token();
- if ((token_type == SYMBOL_TT) &&
- (stypes[token_value] == LABEL_T))
- { sflags[token_value] |= USED_SFLAG;
- return(svals[token_value]);
- }
- if ((token_type == SYMBOL_TT) && (sflags[token_value] & UNKNOWN_SFLAG))
- { assign_symbol(token_value, next_label, LABEL_T);
- define_symbol_label(token_value);
- next_label++;
- sflags[token_value] |= CHANGE_SFLAG + USED_SFLAG;
- return(svals[token_value]);
- }
- ebf_error("label name", token_text);
- return 0;
- }
- static void parse_print_z(int finally_return)
- { int count = 0; assembly_operand AO;
- /* print <printlist> -------------------------------------------------- */
- /* print_ret <printlist> ---------------------------------------------- */
- /* <literal-string> --------------------------------------------------- */
- /* */
- /* <printlist> is a comma-separated list of items: */
- /* */
- /* <literal-string> */
- /* <other-expression> */
- /* (char) <expression> */
- /* (address) <expression> */
- /* (string) <expression> */
- /* (a) <expression> */
- /* (the) <expression> */
- /* (The) <expression> */
- /* (name) <expression> */
- /* (number) <expression> */
- /* (property) <expression> */
- /* (<routine>) <expression> */
- /* (object) <expression> (for use in low-level code only) */
- /* --------------------------------------------------------------------- */
- do
- { AI.text = token_text;
- if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
- switch(token_type)
- { case DQ_TT:
- if (strlen(token_text) > 32)
- { AO.marker = STRING_MV;
- AO.type = LONG_CONSTANT_OT;
- AO.value = compile_string(token_text, FALSE, FALSE);
- assemblez_1(print_paddr_zc, AO);
- if (finally_return)
- { get_next_token();
- if ((token_type == SEP_TT)
- && (token_value == SEMICOLON_SEP))
- { assemblez_0(new_line_zc);
- assemblez_0(rtrue_zc);
- return;
- }
- put_token_back();
- }
- break;
- }
- if (finally_return)
- { get_next_token();
- if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
- { assemblez_0(print_ret_zc); return;
- }
- put_token_back();
- }
- assemblez_0(print_zc);
- break;
- case SEP_TT:
- if (token_value == OPENB_SEP)
- { misc_keywords.enabled = TRUE;
- get_next_token();
- get_next_token();
- if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
- { assembly_operand AO1;
- put_token_back(); put_token_back();
- local_variables.enabled = FALSE;
- get_next_token();
- misc_keywords.enabled = FALSE;
- local_variables.enabled = TRUE;
- if ((token_type == STATEMENT_TT)
- &&(token_value == STRING_CODE))
- { token_type = MISC_KEYWORD_TT;
- token_value = STRING_MK;
- }
- switch(token_type)
- {
- case MISC_KEYWORD_TT:
- switch(token_value)
- { case CHAR_MK:
- if (runtime_error_checking_switch)
- { AO = veneer_routine(RT__ChPrintC_VR);
- goto PrintByRoutine;
- }
- get_next_token();
- AO1 = code_generate(
- parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- assemblez_1(print_char_zc, AO1);
- goto PrintTermDone;
- case ADDRESS_MK:
- if (runtime_error_checking_switch)
- { AO = veneer_routine(RT__ChPrintA_VR);
- goto PrintByRoutine;
- }
- get_next_token();
- AO1 = code_generate(
- parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- assemblez_1(print_addr_zc, AO1);
- goto PrintTermDone;
- case STRING_MK:
- if (runtime_error_checking_switch)
- { AO = veneer_routine(RT__ChPrintS_VR);
- goto PrintByRoutine;
- }
- get_next_token();
- AO1 = code_generate(
- parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- assemblez_1(print_paddr_zc, AO1);
- goto PrintTermDone;
- case OBJECT_MK:
- if (runtime_error_checking_switch)
- { AO = veneer_routine(RT__ChPrintO_VR);
- goto PrintByRoutine;
- }
- get_next_token();
- AO1 = code_generate(
- parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- assemblez_1(print_obj_zc, AO1);
- goto PrintTermDone;
- case THE_MK:
- AO = veneer_routine(DefArt_VR);
- goto PrintByRoutine;
- case AN_MK:
- case A_MK:
- AO = veneer_routine(InDefArt_VR);
- goto PrintByRoutine;
- case CAP_THE_MK:
- AO = veneer_routine(CDefArt_VR);
- goto PrintByRoutine;
- case CAP_A_MK:
- AO = veneer_routine(CInDefArt_VR);
- goto PrintByRoutine;
- case NAME_MK:
- AO = veneer_routine(PrintShortName_VR);
- goto PrintByRoutine;
- case NUMBER_MK:
- AO = veneer_routine(EnglishNumber_VR);
- goto PrintByRoutine;
- case PROPERTY_MK:
- AO = veneer_routine(Print__Pname_VR);
- goto PrintByRoutine;
- default:
- error_named("A reserved word was used as a print specification:",
- token_text);
- }
- break;
- case SYMBOL_TT:
- if (sflags[token_value] & UNKNOWN_SFLAG)
- { AO.type = LONG_CONSTANT_OT;
- AO.value = token_value;
- AO.marker = SYMBOL_MV;
- }
- else
- { AO.type = LONG_CONSTANT_OT;
- AO.value = svals[token_value];
- AO.marker = IROUTINE_MV;
- if (stypes[token_value] != ROUTINE_T)
- ebf_error("printing routine name", token_text);
- }
- sflags[token_value] |= USED_SFLAG;
- PrintByRoutine:
- get_next_token();
- if (version_number >= 5)
- assemblez_2(call_2n_zc, AO,
- code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1));
- else if (version_number == 4)
- assemblez_2_to(call_vs_zc, AO,
- code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1), temp_var1);
- else
- assemblez_2_to(call_zc, AO,
- code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1), temp_var1);
- goto PrintTermDone;
- default: ebf_error("print specification", token_text);
- get_next_token();
- assemblez_1(print_num_zc,
- code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1));
- goto PrintTermDone;
- }
- }
- put_token_back(); put_token_back(); put_token_back();
- misc_keywords.enabled = FALSE;
- assemblez_1(print_num_zc,
- code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1));
- break;
- }
- default:
- put_token_back(); misc_keywords.enabled = FALSE;
- assemblez_1(print_num_zc,
- code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1));
- break;
- }
- PrintTermDone: misc_keywords.enabled = FALSE;
- count++;
- get_next_token();
- if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
- if ((token_type != SEP_TT) || (token_value != COMMA_SEP))
- { ebf_error("comma", token_text);
- panic_mode_error_recovery(); return;
- }
- else get_next_token();
- } while(TRUE);
- if (count == 0) ebf_error("something to print", token_text);
- if (finally_return)
- { assemblez_0(new_line_zc);
- assemblez_0(rtrue_zc);
- }
- }
- static void parse_print_g(int finally_return)
- { int count = 0; assembly_operand AO, AO2;
- /* print <printlist> -------------------------------------------------- */
- /* print_ret <printlist> ---------------------------------------------- */
- /* <literal-string> --------------------------------------------------- */
- /* */
- /* <printlist> is a comma-separated list of items: */
- /* */
- /* <literal-string> */
- /* <other-expression> */
- /* (char) <expression> */
- /* (address) <expression> */
- /* (string) <expression> */
- /* (a) <expression> */
- /* (A) <expression> */
- /* (the) <expression> */
- /* (The) <expression> */
- /* (name) <expression> */
- /* (number) <expression> */
- /* (property) <expression> */
- /* (<routine>) <expression> */
- /* (object) <expression> (for use in low-level code only) */
- /* --------------------------------------------------------------------- */
- do
- {
- if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
- switch(token_type)
- { case DQ_TT:
- /* We can't compile a string into the instruction,
- so this always goes into the string area. */
- { AO.marker = STRING_MV;
- AO.type = CONSTANT_OT;
- AO.value = compile_string(token_text, FALSE, FALSE);
- assembleg_1(streamstr_gc, AO);
- if (finally_return)
- { get_next_token();
- if ((token_type == SEP_TT)
- && (token_value == SEMICOLON_SEP))
- { AO.type = BYTECONSTANT_OT;
- AO.value = 0x0A; AO.marker = 0;
- assembleg_1(streamchar_gc, AO);
- AO.type = BYTECONSTANT_OT;
- AO.value = 1; AO.marker = 0;
- assembleg_1(return_gc, AO);
- return;
- }
- put_token_back();
- }
- break;
- }
- break;
- case SEP_TT:
- if (token_value == OPENB_SEP)
- { misc_keywords.enabled = TRUE;
- get_next_token();
- get_next_token();
- if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
- { assembly_operand AO1;
- int ln, ln2;
- put_token_back(); put_token_back();
- local_variables.enabled = FALSE;
- get_next_token();
- misc_keywords.enabled = FALSE;
- local_variables.enabled = TRUE;
- if ((token_type == STATEMENT_TT)
- &&(token_value == STRING_CODE))
- { token_type = MISC_KEYWORD_TT;
- token_value = STRING_MK;
- }
- switch(token_type)
- {
- case MISC_KEYWORD_TT:
- switch(token_value)
- { case CHAR_MK:
- if (runtime_error_checking_switch)
- { AO = veneer_routine(RT__ChPrintC_VR);
- goto PrintByRoutine;
- }
- get_next_token();
- AO1 = code_generate(
- parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- if ((AO1.type == LOCALVAR_OT) && (AO1.value == 0))
- { assembleg_2(stkpeek_gc, zero_operand,
- stack_pointer);
- }
- AO2.type = HALFCONSTANT_OT; AO2.value = 0x100; AO2.marker = 0;
- assembleg_2_branch(jgeu_gc, AO1, AO2,
- ln = next_label++);
- ln2 = next_label++;
- assembleg_1(streamchar_gc, AO1);
- assembleg_jump(ln2);
- assemble_label_no(ln);
- assembleg_1(streamunichar_gc, AO1);
- assemble_label_no(ln2);
- goto PrintTermDone;
- case ADDRESS_MK:
- if (runtime_error_checking_switch)
- AO = veneer_routine(RT__ChPrintA_VR);
- else
- AO = veneer_routine(Print__Addr_VR);
- goto PrintByRoutine;
- case STRING_MK:
- if (runtime_error_checking_switch)
- { AO = veneer_routine(RT__ChPrintS_VR);
- goto PrintByRoutine;
- }
- get_next_token();
- AO1 = code_generate(
- parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- assembleg_1(streamstr_gc, AO1);
- goto PrintTermDone;
- case OBJECT_MK:
- if (runtime_error_checking_switch)
- { AO = veneer_routine(RT__ChPrintO_VR);
- goto PrintByRoutine;
- }
- get_next_token();
- AO1 = code_generate(
- parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- AO2.type = BYTECONSTANT_OT;
- AO2.value = GOBJFIELD_NAME();
- AO2.marker = 0;
- assembleg_3(aload_gc, AO1, AO2,
- stack_pointer);
- assembleg_1(streamstr_gc, stack_pointer);
- goto PrintTermDone;
- case THE_MK:
- AO = veneer_routine(DefArt_VR);
- goto PrintByRoutine;
- case AN_MK:
- case A_MK:
- AO = veneer_routine(InDefArt_VR);
- goto PrintByRoutine;
- case CAP_THE_MK:
- AO = veneer_routine(CDefArt_VR);
- goto PrintByRoutine;
- case CAP_A_MK:
- AO = veneer_routine(CInDefArt_VR);
- goto PrintByRoutine;
- case NAME_MK:
- AO = veneer_routine(PrintShortName_VR);
- goto PrintByRoutine;
- case NUMBER_MK:
- AO = veneer_routine(EnglishNumber_VR);
- goto PrintByRoutine;
- case PROPERTY_MK:
- AO = veneer_routine(Print__Pname_VR);
- goto PrintByRoutine;
- default:
- error_named("A reserved word was used as a print specification:",
- token_text);
- }
- break;
- case SYMBOL_TT:
- if (sflags[token_value] & UNKNOWN_SFLAG)
- { AO.type = CONSTANT_OT;
- AO.value = token_value;
- AO.marker = SYMBOL_MV;
- }
- else
- { AO.type = CONSTANT_OT;
- AO.value = svals[token_value];
- AO.marker = IROUTINE_MV;
- if (stypes[token_value] != ROUTINE_T)
- ebf_error("printing routine name", token_text);
- }
- sflags[token_value] |= USED_SFLAG;
- PrintByRoutine:
- get_next_token();
- AO2.type = ZEROCONSTANT_OT;
- AO2.value = 0; AO2.marker = 0;
- assembleg_call_1(AO,
- code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1),
- AO2);
- goto PrintTermDone;
- default: ebf_error("print specification", token_text);
- get_next_token();
- assembleg_1(streamnum_gc,
- code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1));
- goto PrintTermDone;
- }
- }
- put_token_back(); put_token_back(); put_token_back();
- misc_keywords.enabled = FALSE;
- assembleg_1(streamnum_gc,
- code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1));
- break;
- }
- default:
- put_token_back(); misc_keywords.enabled = FALSE;
- assembleg_1(streamnum_gc,
- code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1));
- break;
- }
- PrintTermDone: misc_keywords.enabled = FALSE;
- count++;
- get_next_token();
- if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
- if ((token_type != SEP_TT) || (token_value != COMMA_SEP))
- { ebf_error("comma", token_text);
- panic_mode_error_recovery(); return;
- }
- else get_next_token();
- } while(TRUE);
- if (count == 0) ebf_error("something to print", token_text);
- if (finally_return)
- {
- AO.type = BYTECONSTANT_OT; AO.value = 0x0A; AO.marker = 0;
- assembleg_1(streamchar_gc, AO);
- AO.type = BYTECONSTANT_OT; AO.value = 1; AO.marker = 0;
- assembleg_1(return_gc, AO);
- }
- }
- static void parse_statement_z(int break_label, int continue_label)
- { int ln, ln2, ln3, ln4, flag;
- assembly_operand AO, AO2, AO3, AO4;
- debug_location spare_debug_location1, spare_debug_location2;
- ASSERT_ZCODE();
- if ((token_type == SEP_TT) && (token_value == PROPERTY_SEP))
- { /* That is, a full stop, signifying a label */
- get_next_token();
- if (token_type == SYMBOL_TT)
- {
- if (sflags[token_value] & UNKNOWN_SFLAG)
- { assign_symbol(token_value, next_label, LABEL_T);
- sflags[token_value] |= USED_SFLAG;
- assemble_label_no(next_label);
- define_symbol_label(token_value);
- next_label++;
- }
- else
- { if (stypes[token_value] != LABEL_T) goto LabelError;
- if (sflags[token_value] & CHANGE_SFLAG)
- { sflags[token_value] &= (~(CHANGE_SFLAG));
- assemble_label_no(svals[token_value]);
- define_symbol_label(token_value);
- }
- else error_named("Duplicate definition of label:", token_text);
- }
- get_next_token();
- if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
- { ebf_error("';'", token_text);
- put_token_back(); return;
- }
- /* Interesting point of Inform grammar: a statement can only
- consist solely of a label when it is immediately followed
- by a "}". */
- get_next_token();
- if ((token_type == SEP_TT) && (token_value == CLOSE_BRACE_SEP))
- { put_token_back(); return;
- }
- statement_debug_location = get_token_location();
- parse_statement(break_label, continue_label);
- return;
- }
- LabelError: ebf_error("label name", token_text);
- }
- if ((token_type == SEP_TT) && (token_value == HASH_SEP))
- { parse_directive(TRUE);
- parse_statement(break_label, continue_label); return;
- }
- if ((token_type == SEP_TT) && (token_value == AT_SEP))
- { parse_assembly(); return;
- }
- if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) return;
- if (token_type == DQ_TT)
- { parse_print_z(TRUE); return;
- }
- if ((token_type == SEP_TT) && (token_value == LESS_SEP))
- { parse_action(); goto StatementTerminator; }
- if (token_type == EOF_TT)
- { ebf_error("statement", token_text); return; }
- if (token_type != STATEMENT_TT)
- { put_token_back();
- AO = parse_expression(VOID_CONTEXT);
- code_generate(AO, VOID_CONTEXT, -1);
- if (vivc_flag) { panic_mode_error_recovery(); return; }
- goto StatementTerminator;
- }
- statements.enabled = FALSE;
- switch(token_value)
- {
- /* -------------------------------------------------------------------- */
- /* box <string-1> ... <string-n> -------------------------------------- */
- /* -------------------------------------------------------------------- */
- case BOX_CODE:
- if (version_number == 3)
- warning("The 'box' statement has no effect in a version 3 game");
- AO3.type = LONG_CONSTANT_OT;
- AO3.value = begin_table_array();
- AO3.marker = ARRAY_MV;
- ln = 0; ln2 = 0;
- do
- { get_next_token();
- if ((token_type==SEP_TT)&&(token_value==SEMICOLON_SEP))
- break;
- if (token_type != DQ_TT)
- ebf_error("text of box line in double-quotes",
- token_text);
- { int i, j;
- for (i=0, j=0; token_text[i] != 0; j++)
- if (token_text[i] == '@')
- { if (token_text[i+1] == '@')
- { i = i + 2;
- while (isdigit(token_text[i])) i++;
- }
- else
- { i++;
- if (token_text[i] != 0) i++;
- if (token_text[i] != 0) i++;
- }
- }
- else i++;
- if (j > ln2) ln2 = j;
- }
- put_token_back();
- array_entry(ln++,parse_expression(CONSTANT_CONTEXT));
- } while (TRUE);
- finish_array(ln);
- if (ln == 0)
- error("No lines of text given for 'box' display");
- if (version_number == 3) return;
- AO2.type = SHORT_CONSTANT_OT; AO2.value = ln2; AO2.marker = 0;
- AO4.type = VARIABLE_OT; AO4.value = 255; AO4.marker = 0;
- assemblez_3_to(call_vs_zc, veneer_routine(Box__Routine_VR),
- AO2, AO3, AO4);
- return;
- /* -------------------------------------------------------------------- */
- /* break -------------------------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case BREAK_CODE:
- if (break_label == -1)
- error("'break' can only be used in a loop or 'switch' block");
- else
- assemblez_jump(break_label);
- break;
- /* -------------------------------------------------------------------- */
- /* continue ----------------------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case CONTINUE_CODE:
- if (continue_label == -1)
- error("'continue' can only be used in a loop block");
- else
- assemblez_jump(continue_label);
- break;
- /* -------------------------------------------------------------------- */
- /* do <codeblock> until (<condition>) --------------------------------- */
- /* -------------------------------------------------------------------- */
- case DO_CODE:
- assemble_label_no(ln = next_label++);
- ln2 = next_label++; ln3 = next_label++;
- parse_code_block(ln3, ln2, 0);
- statements.enabled = TRUE;
- get_next_token();
- if ((token_type == STATEMENT_TT)
- && (token_value == UNTIL_CODE))
- { assemble_label_no(ln2);
- match_open_bracket();
- AO = parse_expression(CONDITION_CONTEXT);
- match_close_bracket();
- code_generate(AO, CONDITION_CONTEXT, ln);
- }
- else error("'do' without matching 'until'");
- assemble_label_no(ln3);
- break;
- /* -------------------------------------------------------------------- */
- /* font on/off -------------------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case FONT_CODE:
- misc_keywords.enabled = TRUE;
- get_next_token();
- misc_keywords.enabled = FALSE;
- if ((token_type != MISC_KEYWORD_TT)
- || ((token_value != ON_MK)
- && (token_value != OFF_MK)))
- { ebf_error("'on' or 'off'", token_text);
- panic_mode_error_recovery();
- break;
- }
- if (version_number >= 5)
- { /* Use the V5 @set_font opcode, setting font 4
- (for font off) or 1 (for font on). */
- AO.type = SHORT_CONSTANT_OT; AO.marker = 0;
- if (token_value == ON_MK)
- AO.value = 1;
- else
- AO.value = 4;
- assemblez_1_to(set_font_zc, AO, temp_var1);
- break;
- }
- /* Set the fixed-pitch header bit. */
- AO.type = SHORT_CONSTANT_OT;
- AO.value = 0;
- AO.marker = 0;
- AO2.type = SHORT_CONSTANT_OT;
- AO2.value = 8;
- AO2.marker = 0;
- AO3.type = VARIABLE_OT;
- AO3.value = 255;
- AO3.marker = 0;
- assemblez_2_to(loadw_zc, AO, AO2, AO3);
- if (token_value == ON_MK)
- { AO4.type = LONG_CONSTANT_OT;
- AO4.value = 0xfffd;
- AO4.marker = 0;
- assemblez_2_to(and_zc, AO4, AO3, AO3);
- }
- else
- { AO4.type = SHORT_CONSTANT_OT;
- AO4.value = 2;
- AO4.marker = 0;
- assemblez_2_to(or_zc, AO4, AO3, AO3);
- }
- assemblez_3(storew_zc, AO, AO2, AO3);
- break;
- /* -------------------------------------------------------------------- */
- /* for (<initialisation> : <continue-condition> : <updating>) --------- */
- /* -------------------------------------------------------------------- */
- /* Note that it's legal for any or all of the three sections of a
- 'for' specification to be empty. This 'for' implementation
- often wastes 3 bytes with a redundant branch rather than keep
- expression parse trees for long periods (as previous versions
- of Inform did, somewhat crudely by simply storing the textual
- form of a 'for' loop). It is adequate for now. */
- case FOR_CODE:
- match_open_bracket();
- get_next_token();
- /* Initialisation code */
- if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
- { put_token_back();
- if (!((token_type==SEP_TT)&&(token_value==SUPERCLASS_SEP)))
- { sequence_point_follows = TRUE;
- statement_debug_location = get_token_location();
- code_generate(parse_expression(FORINIT_CONTEXT),
- VOID_CONTEXT, -1);
- }
- get_next_token();
- if ((token_type==SEP_TT)&&(token_value == SUPERCLASS_SEP))
- { get_next_token();
- if ((token_type==SEP_TT)&&(token_value == CLOSEB_SEP))
- { assemble_label_no(ln = next_label++);
- ln2 = next_label++;
- parse_code_block(ln2, ln, 0);
- sequence_point_follows = FALSE;
- if (!execution_never_reaches_here)
- assemblez_jump(ln);
- assemble_label_no(ln2);
- return;
- }
- AO.type = OMITTED_OT;
- goto ParseUpdate;
- }
- put_token_back();
- if (!match_colon()) break;
- }
- get_next_token();
- AO.type = OMITTED_OT;
- if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
- { put_token_back();
- spare_debug_location1 = get_token_location();
- AO = parse_expression(CONDITION_CONTEXT);
- if (!match_colon()) break;
- }
- get_next_token();
- ParseUpdate:
- AO2.type = OMITTED_OT; flag = 0;
- if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP)))
- { put_token_back();
- spare_debug_location2 = get_token_location();
- AO2 = parse_expression(VOID_CONTEXT);
- match_close_bracket();
- flag = test_for_incdec(AO2);
- }
- ln = next_label++;
- ln2 = next_label++;
- ln3 = next_label++;
- if ((AO2.type == OMITTED_OT) || (flag != 0))
- {
- assemble_label_no(ln);
- if (flag==0) assemble_label_no(ln2);
- /* The "finished yet?" condition */
- if (AO.type != OMITTED_OT)
- { sequence_point_follows = TRUE;
- statement_debug_location = spare_debug_location1;
- code_generate(AO, CONDITION_CONTEXT, ln3);
- }
- }
- else
- {
- /* This is the jump which could be avoided with the aid
- of long-term expression storage */
- sequence_point_follows = FALSE;
- assemblez_jump(ln2);
- /* The "update" part */
- assemble_label_no(ln);
- sequence_point_follows = TRUE;
- statement_debug_location = spare_debug_location2;
- code_generate(AO2, VOID_CONTEXT, -1);
- assemble_label_no(ln2);
- /* The "finished yet?" condition */
- if (AO.type != OMITTED_OT)
- { sequence_point_follows = TRUE;
- statement_debug_location = spare_debug_location1;
- code_generate(AO, CONDITION_CONTEXT, ln3);
- }
- }
- if (flag != 0)
- {
- /* In this optimised case, update code is at the end
- of the loop block, so "continue" goes there */
- parse_code_block(ln3, ln2, 0);
- assemble_label_no(ln2);
- sequence_point_follows = TRUE;
- statement_debug_location = spare_debug_location2;
- if (flag > 0)
- { AO3.type = SHORT_CONSTANT_OT;
- AO3.value = flag;
- if (module_switch
- && (flag>=MAX_LOCAL_VARIABLES) && (flag<LOWEST_SYSTEM_VAR_NUMBER))
- AO3.marker = VARIABLE_MV;
- else AO3.marker = 0;
- assemblez_1(inc_zc, AO3);
- }
- else
- { AO3.type = SHORT_CONSTANT_OT;
- AO3.value = -flag;
- if ((module_switch) && (flag>=MAX_LOCAL_VARIABLES)
- && (flag<LOWEST_SYSTEM_VAR_NUMBER))
- AO3.marker = VARIABLE_MV;
- else AO3.marker = 0;
- assemblez_1(dec_zc, AO3);
- }
- assemblez_jump(ln);
- }
- else
- {
- /* In the unoptimised case, update code is at the
- start of the loop block, so "continue" goes there */
- parse_code_block(ln3, ln, 0);
- if (!execution_never_reaches_here)
- { sequence_point_follows = FALSE;
- assemblez_jump(ln);
- }
- }
- assemble_label_no(ln3);
- return;
- /* -------------------------------------------------------------------- */
- /* give <expression> [~]attr [, [~]attr [, ...]] ---------------------- */
- /* -------------------------------------------------------------------- */
- case GIVE_CODE:
- AO = code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- if ((AO.type == VARIABLE_OT) && (AO.value == 0))
- { AO.value = 252;
- AO.marker = 0;
- AO.type = SHORT_CONSTANT_OT;
- if (version_number != 6) assemblez_1(pull_zc, AO);
- else assemblez_0_to(pull_zc, AO);
- AO.type = VARIABLE_OT;
- }
- do
- { get_next_token();
- if ((token_type == SEP_TT)&&(token_value == SEMICOLON_SEP))
- return;
- if ((token_type == SEP_TT)&&(token_value == ARTNOT_SEP))
- ln = clear_attr_zc;
- else
- { if ((token_type == SYMBOL_TT)
- && (stypes[token_value] != ATTRIBUTE_T))
- warning_named("This is not a declared Attribute:",
- token_text);
- ln = set_attr_zc;
- put_token_back();
- }
- AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- if (runtime_error_checking_switch)
- { ln2 = (ln==set_attr_zc)?RT__ChG_VR:RT__ChGt_VR;
- if (version_number >= 5)
- assemblez_3(call_vn_zc, veneer_routine(ln2),
- AO, AO2);
- else
- {
- assemblez_3_to(call_zc, veneer_routine(ln2),
- AO, AO2, temp_var1);
- }
- }
- else
- assemblez_2(ln, AO, AO2);
- } while(TRUE);
- /* -------------------------------------------------------------------- */
- /* if (<condition>) <codeblock> [else <codeblock>] -------------------- */
- /* -------------------------------------------------------------------- */
- case IF_CODE:
- flag = FALSE;
- match_open_bracket();
- AO = parse_expression(CONDITION_CONTEXT);
- match_close_bracket();
- statements.enabled = TRUE;
- get_next_token();
- if ((token_type == STATEMENT_TT)&&(token_value == RTRUE_CODE))
- ln = -4;
- else
- if ((token_type == STATEMENT_TT)&&(token_value == RFALSE_CODE))
- ln = -3;
- else
- { put_token_back();
- ln = next_label++;
- }
- code_generate(AO, CONDITION_CONTEXT, ln);
- if (ln >= 0) parse_code_block(break_label, continue_label, 0);
- else
- { get_next_token();
- if ((token_type != SEP_TT)
- || (token_value != SEMICOLON_SEP))
- { ebf_error("';'", token_text);
- put_token_back();
- }
- }
- statements.enabled = TRUE;
- get_next_token();
- if ((token_type == STATEMENT_TT) && (token_value == ELSE_CODE))
- { flag = TRUE;
- if (ln >= 0)
- { ln2 = next_label++;
- if (!execution_never_reaches_here)
- { sequence_point_follows = FALSE;
- assemblez_jump(ln2);
- }
- }
- }
- else put_token_back();
- if (ln >= 0) assemble_label_no(ln);
- if (flag)
- { parse_code_block(break_label, continue_label, 0);
- if (ln >= 0) assemble_label_no(ln2);
- }
- return;
- /* -------------------------------------------------------------------- */
- /* inversion ---------------------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case INVERSION_CODE:
- AO.marker = 0;
- AO.type = SHORT_CONSTANT_OT;
- AO.value = 0;
- AO2.marker = 0;
- AO2.type = SHORT_CONSTANT_OT;
- AO2.value = 60;
- assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
- assemblez_1(print_char_zc, temp_var1);
- AO2.value = 61;
- assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
- assemblez_1(print_char_zc, temp_var1);
- AO2.value = 62;
- assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
- assemblez_1(print_char_zc, temp_var1);
- AO2.value = 63;
- assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
- assemblez_1(print_char_zc, temp_var1);
- break;
- /* -------------------------------------------------------------------- */
- /* jump <label> ------------------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case JUMP_CODE:
- assemblez_jump(parse_label());
- break;
- /* -------------------------------------------------------------------- */
- /* move <expression> to <expression> ---------------------------------- */
- /* -------------------------------------------------------------------- */
- case MOVE_CODE:
- misc_keywords.enabled = TRUE;
- AO = parse_expression(QUANTITY_CONTEXT);
- get_next_token();
- misc_keywords.enabled = FALSE;
- if ((token_type != MISC_KEYWORD_TT)
- || (token_value != TO_MK))
- { ebf_error("'to'", token_text);
- panic_mode_error_recovery();
- return;
- }
- AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- AO = code_generate(AO, QUANTITY_CONTEXT, -1);
- if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
- { if (version_number >= 5)
- assemblez_3(call_vn_zc, veneer_routine(RT__ChT_VR),
- AO, AO2);
- else
- { assemblez_3_to(call_zc, veneer_routine(RT__ChT_VR),
- AO, AO2, temp_var1);
- }
- }
- else
- assemblez_2(insert_obj_zc, AO, AO2);
- break;
- /* -------------------------------------------------------------------- */
- /* new_line ----------------------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case NEW_LINE_CODE: assemblez_0(new_line_zc); break;
- /* -------------------------------------------------------------------- */
- /* objectloop (<initialisation>) <codeblock> -------------------------- */
- /* -------------------------------------------------------------------- */
- case OBJECTLOOP_CODE:
- match_open_bracket();
- get_next_token();
- if (token_type == LOCAL_VARIABLE_TT)
- AO.value = token_value;
- else
- if ((token_type == SYMBOL_TT) &&
- (stypes[token_value] == GLOBAL_VARIABLE_T))
- AO.value = svals[token_value];
- else
- { ebf_error("'objectloop' variable", token_text);
- panic_mode_error_recovery(); break;
- }
- AO.type = VARIABLE_OT;
- if ((module_switch) && (AO.value >= MAX_LOCAL_VARIABLES)
- && (AO.value < LOWEST_SYSTEM_VAR_NUMBER))
- AO.marker = VARIABLE_MV;
- else AO.marker = 0;
- misc_keywords.enabled = TRUE;
- get_next_token(); flag = TRUE;
- misc_keywords.enabled = FALSE;
- if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
- flag = FALSE;
- ln = 0;
- if ((token_type == MISC_KEYWORD_TT)
- && (token_value == NEAR_MK)) ln = 1;
- if ((token_type == MISC_KEYWORD_TT)
- && (token_value == FROM_MK)) ln = 2;
- if ((token_type == CND_TT) && (token_value == IN_COND))
- { get_next_token();
- get_next_token();
- if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
- ln = 3;
- put_token_back();
- put_token_back();
- }
- if (ln > 0)
- { /* Old style (Inform 5) objectloops: note that we
- implement objectloop (a in b) in the old way since
- this runs through objects in a different order from
- the new way, and there may be existing Inform code
- relying on this. */
- assembly_operand AO4;
- sequence_point_follows = TRUE;
- AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- match_close_bracket();
- if (ln == 1)
- { AO3.type = VARIABLE_OT; AO3.value = 0; AO3.marker = 0;
- if (runtime_error_checking_switch)
- AO2 = check_nonzero_at_runtime(AO2, -1,
- OBJECTLOOP_RTE);
- assemblez_1_to(get_parent_zc, AO2, AO3);
- assemblez_objcode(get_child_zc, AO3, AO3, -2, TRUE);
- AO2 = AO3;
- }
- if (ln == 3)
- { AO3.type = VARIABLE_OT; AO3.value = 0; AO3.marker = 0;
- if (runtime_error_checking_switch)
- { AO4 = AO2;
- AO2 = check_nonzero_at_runtime(AO2, -1,
- CHILD_RTE);
- }
- assemblez_objcode(get_child_zc, AO2, AO3, -2, TRUE);
- AO2 = AO3;
- }
- assemblez_store(AO, AO2);
- assemblez_1_branch(jz_zc, AO, ln2 = next_label++, TRUE);
- assemble_label_no(ln4 = next_label++);
- parse_code_block(ln2, ln3 = next_label++, 0);
- sequence_point_follows = FALSE;
- assemble_label_no(ln3);
- if (runtime_error_checking_switch)
- { AO2 = check_nonzero_at_runtime(AO, ln2,
- OBJECTLOOP2_RTE);
- if ((ln == 3)
- && ((AO4.type != VARIABLE_OT)||(AO4.value != 0))
- && ((AO4.type != VARIABLE_OT)
- ||(AO4.value != AO.value)))
- { assembly_operand en_ao;
- en_ao.value = OBJECTLOOP_BROKEN_RTE;
- en_ao.marker = 0;
- en_ao.type = SHORT_CONSTANT_OT;
- assemblez_2_branch(jin_zc, AO, AO4,
- next_label, TRUE);
- assemblez_3(call_vn_zc, veneer_routine(RT__Err_VR),
- en_ao, AO);
- assemblez_jump(ln2);
- assemble_label_no(next_label++);
- }
- }
- else AO2 = AO;
- assemblez_objcode(get_sibling_zc, AO2, AO, ln4, TRUE);
- assemble_label_no(ln2);
- return;
- }
- sequence_point_follows = TRUE;
- AO2.type = SHORT_CONSTANT_OT; AO2.value = 1; AO2.marker = 0;
- assemblez_store(AO, AO2);
- assemble_label_no(ln = next_label++);
- ln2 = next_label++;
- ln3 = next_label++;
- if (flag)
- { put_token_back();
- put_token_back();
- sequence_point_follows = TRUE;
- code_generate(parse_expression(CONDITION_CONTEXT),
- CONDITION_CONTEXT, ln3);
- match_close_bracket();
- }
- parse_code_block(ln2, ln3, 0);
- sequence_point_follows = FALSE;
- assemble_label_no(ln3);
- assemblez_inc(AO);
- AO2.type = LONG_CONSTANT_OT; AO2.value = no_objects;
- AO2.marker = NO_OBJS_MV;
- assemblez_2_branch(jg_zc, AO, AO2, ln2, TRUE);
- assemblez_jump(ln);
- assemble_label_no(ln2);
- return;
- /* -------------------------------------------------------------------- */
- /* (see routine above) ------------------------------------------------ */
- /* -------------------------------------------------------------------- */
- case PRINT_CODE:
- get_next_token();
- parse_print_z(FALSE); return;
- case PRINT_RET_CODE:
- get_next_token();
- parse_print_z(TRUE); return;
- /* -------------------------------------------------------------------- */
- /* quit --------------------------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case QUIT_CODE: assemblez_0(quit_zc); break;
- /* -------------------------------------------------------------------- */
- /* read <expression> <expression> [<Routine>] ------------------------- */
- /* -------------------------------------------------------------------- */
- case READ_CODE:
- AO.type = VARIABLE_OT; AO.value = 252; AO.marker = 0;
- assemblez_store(AO,
- code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1));
- if (version_number > 3)
- { AO3.type = SHORT_CONSTANT_OT; AO3.value = 1;AO3.marker = 0;
- AO4.type = SHORT_CONSTANT_OT; AO4.value = 0;AO4.marker = 0;
- assemblez_3(storeb_zc, AO, AO3, AO4);
- }
- AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- get_next_token();
- if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
- put_token_back();
- else
- { if (version_number == 3)
- error(
- "In Version 3 no status-line drawing routine can be given");
- else
- { assembly_operand AO5;
- /* Move the temp4 (buffer) value to the stack,
- since the routine might alter temp4. */
- assemblez_store(stack_pointer, AO);
- AO = stack_pointer;
- put_token_back();
- AO5 = parse_expression(CONSTANT_CONTEXT);
- if (version_number >= 5)
- assemblez_1(call_1n_zc, AO5);
- else
- assemblez_1_to(call_zc, AO5, temp_var1);
- }
- }
- if (version_number > 4)
- { assemblez_2_to(aread_zc, AO, AO2, temp_var1);
- }
- else assemblez_2(sread_zc, AO, AO2);
- break;
- /* -------------------------------------------------------------------- */
- /* remove <expression> ------------------------------------------------ */
- /* -------------------------------------------------------------------- */
- case REMOVE_CODE:
- AO = code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
- { if (version_number >= 5)
- assemblez_2(call_2n_zc, veneer_routine(RT__ChR_VR),
- AO);
- else
- { assemblez_2_to(call_zc, veneer_routine(RT__ChR_VR),
- AO, temp_var1);
- }
- }
- else
- assemblez_1(remove_obj_zc, AO);
- break;
- /* -------------------------------------------------------------------- */
- /* restore <label> ---------------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case RESTORE_CODE:
- if (version_number < 5)
- assemblez_0_branch(restore_zc, parse_label(), TRUE);
- else
- { AO2.type = SHORT_CONSTANT_OT; AO2.value = 2;
- AO2.marker = 0;
- assemblez_0_to(restore_zc, temp_var1);
- assemblez_2_branch(je_zc, temp_var1, AO2, parse_label(), TRUE);
- }
- break;
- /* -------------------------------------------------------------------- */
- /* return [<expression>] ---------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case RETURN_CODE:
- get_next_token();
- if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
- { assemblez_0(rtrue_zc); return; }
- put_token_back();
- AO = code_generate(parse_expression(RETURN_Q_CONTEXT),
- QUANTITY_CONTEXT, -1);
- if ((AO.type == SHORT_CONSTANT_OT) && (AO.value == 0)
- && (AO.marker == 0))
- { assemblez_0(rfalse_zc); break; }
- if ((AO.type == SHORT_CONSTANT_OT) && (AO.value == 1)
- && (AO.marker == 0))
- { assemblez_0(rtrue_zc); break; }
- if ((AO.type == VARIABLE_OT) && (AO.value == 0))
- { assemblez_0(ret_popped_zc); break; }
- assemblez_1(ret_zc, AO);
- break;
- /* -------------------------------------------------------------------- */
- /* rfalse ------------------------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case RFALSE_CODE: assemblez_0(rfalse_zc); break;
- /* -------------------------------------------------------------------- */
- /* rtrue -------------------------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case RTRUE_CODE: assemblez_0(rtrue_zc); break;
- /* -------------------------------------------------------------------- */
- /* save <label> ------------------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case SAVE_CODE:
- if (version_number < 5)
- assemblez_0_branch(save_zc, parse_label(), TRUE);
- else
- { AO.type = VARIABLE_OT; AO.value = 255; AO.marker = 0;
- assemblez_0_to(save_zc, AO);
- assemblez_1_branch(jz_zc, AO, parse_label(), FALSE);
- }
- break;
- /* -------------------------------------------------------------------- */
- /* spaces <expression> ------------------------------------------------ */
- /* -------------------------------------------------------------------- */
- case SPACES_CODE:
- AO = code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- AO2.type = VARIABLE_OT; AO2.value = 255; AO2.marker = 0;
- assemblez_store(AO2, AO);
- AO.type = SHORT_CONSTANT_OT; AO.value = 32; AO.marker = 0;
- AO3.type = SHORT_CONSTANT_OT; AO3.value = 1; AO3.marker = 0;
- assemblez_2_branch(jl_zc, AO2, AO3, ln = next_label++, TRUE);
- assemble_label_no(ln2 = next_label++);
- assemblez_1(print_char_zc, AO);
- assemblez_dec(AO2);
- assemblez_1_branch(jz_zc, AO2, ln2, FALSE);
- assemble_label_no(ln);
- break;
- /* -------------------------------------------------------------------- */
- /* string <expression> <literal-string> ------------------------------- */
- /* -------------------------------------------------------------------- */
- case STRING_CODE:
- AO.type = SHORT_CONSTANT_OT; AO.value = 0; AO.marker = 0;
- AO2.type = SHORT_CONSTANT_OT; AO2.value = 12; AO2.marker = 0;
- AO3.type = VARIABLE_OT; AO3.value = 252; AO3.marker = 0;
- assemblez_2_to(loadw_zc, AO, AO2, AO3);
- AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- get_next_token();
- if (token_type == DQ_TT)
- { AO4.value = compile_string(token_text, TRUE, TRUE);
- AO4.marker = 0;
- AO4.type = LONG_CONSTANT_OT;
- }
- else
- { put_token_back();
- AO4 = parse_expression(CONSTANT_CONTEXT);
- }
- assemblez_3(storew_zc, AO3, AO2, AO4);
- break;
- /* -------------------------------------------------------------------- */
- /* style roman/reverse/bold/underline/fixed --------------------------- */
- /* -------------------------------------------------------------------- */
- case STYLE_CODE:
- if (version_number==3)
- { error(
- "The 'style' statement cannot be used for Version 3 games");
- panic_mode_error_recovery();
- break;
- }
- misc_keywords.enabled = TRUE;
- get_next_token();
- misc_keywords.enabled = FALSE;
- if ((token_type != MISC_KEYWORD_TT)
- || ((token_value != ROMAN_MK)
- && (token_value != REVERSE_MK)
- && (token_value != BOLD_MK)
- && (token_value != UNDERLINE_MK)
- && (token_value != FIXED_MK)))
- { ebf_error(
- "'roman', 'bold', 'underline', 'reverse' or 'fixed'",
- token_text);
- panic_mode_error_recovery();
- break;
- }
- AO.type = SHORT_CONSTANT_OT; AO.marker = 0;
- switch(token_value)
- { case ROMAN_MK: AO.value = 0; break;
- case REVERSE_MK: AO.value = 1; break;
- case BOLD_MK: AO.value = 2; break;
- case UNDERLINE_MK: AO.value = 4; break;
- case FIXED_MK: AO.value = 8; break;
- }
- assemblez_1(set_text_style_zc, AO); break;
- /* -------------------------------------------------------------------- */
- /* switch (<expression>) <codeblock> ---------------------------------- */
- /* -------------------------------------------------------------------- */
- case SWITCH_CODE:
- match_open_bracket();
- AO = code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- match_close_bracket();
- AO2.type = VARIABLE_OT; AO2.value = 255; AO2.marker = 0;
- assemblez_store(AO2, AO);
- parse_code_block(ln = next_label++, continue_label, 1);
- assemble_label_no(ln);
- return;
- /* -------------------------------------------------------------------- */
- /* while (<condition>) <codeblock> ------------------------------------ */
- /* -------------------------------------------------------------------- */
- case WHILE_CODE:
- assemble_label_no(ln = next_label++);
- match_open_bracket();
- code_generate(parse_expression(CONDITION_CONTEXT),
- CONDITION_CONTEXT, ln2 = next_label++);
- match_close_bracket();
- parse_code_block(ln2, ln, 0);
- sequence_point_follows = FALSE;
- assemblez_jump(ln);
- assemble_label_no(ln2);
- return;
- /* -------------------------------------------------------------------- */
- case SDEFAULT_CODE:
- error("'default' without matching 'switch'"); break;
- case ELSE_CODE:
- error("'else' without matching 'if'"); break;
- case UNTIL_CODE:
- error("'until' without matching 'do'");
- panic_mode_error_recovery(); return;
- }
- StatementTerminator:
- get_next_token();
- if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
- { ebf_error("';'", token_text);
- put_token_back();
- }
- }
- static void parse_statement_g(int break_label, int continue_label)
- { int ln, ln2, ln3, ln4, flag, onstack;
- assembly_operand AO, AO2, AO3, AO4;
- debug_location spare_debug_location1, spare_debug_location2;
- ASSERT_GLULX();
- if ((token_type == SEP_TT) && (token_value == PROPERTY_SEP))
- { /* That is, a full stop, signifying a label */
- get_next_token();
- if (token_type == SYMBOL_TT)
- {
- if (sflags[token_value] & UNKNOWN_SFLAG)
- { assign_symbol(token_value, next_label, LABEL_T);
- sflags[token_value] |= USED_SFLAG;
- assemble_label_no(next_label);
- define_symbol_label(token_value);
- next_label++;
- }
- else
- { if (stypes[token_value] != LABEL_T) goto LabelError;
- if (sflags[token_value] & CHANGE_SFLAG)
- { sflags[token_value] &= (~(CHANGE_SFLAG));
- assemble_label_no(svals[token_value]);
- define_symbol_label(token_value);
- }
- else error_named("Duplicate definition of label:", token_text);
- }
- get_next_token();
- if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
- { ebf_error("';'", token_text);
- put_token_back(); return;
- }
- /* Interesting point of Inform grammar: a statement can only
- consist solely of a label when it is immediately followed
- by a "}". */
- get_next_token();
- if ((token_type == SEP_TT) && (token_value == CLOSE_BRACE_SEP))
- { put_token_back(); return;
- }
- /* The following line prevents labels from influencing the positions
- of sequence points. */
- statement_debug_location = get_token_location();
- parse_statement(break_label, continue_label);
- return;
- }
- LabelError: ebf_error("label name", token_text);
- }
- if ((token_type == SEP_TT) && (token_value == HASH_SEP))
- { parse_directive(TRUE);
- parse_statement(break_label, continue_label); return;
- }
- if ((token_type == SEP_TT) && (token_value == AT_SEP))
- { parse_assembly(); return;
- }
- if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) return;
- if (token_type == DQ_TT)
- { parse_print_g(TRUE); return;
- }
- if ((token_type == SEP_TT) && (token_value == LESS_SEP))
- { parse_action(); goto StatementTerminator; }
- if (token_type == EOF_TT)
- { ebf_error("statement", token_text); return; }
- if (token_type != STATEMENT_TT)
- { put_token_back();
- AO = parse_expression(VOID_CONTEXT);
- code_generate(AO, VOID_CONTEXT, -1);
- if (vivc_flag) { panic_mode_error_recovery(); return; }
- goto StatementTerminator;
- }
- statements.enabled = FALSE;
- switch(token_value)
- {
- /* -------------------------------------------------------------------- */
- /* box <string-1> ... <string-n> -------------------------------------- */
- /* -------------------------------------------------------------------- */
- case BOX_CODE:
- AO3.type = CONSTANT_OT;
- AO3.value = begin_table_array();
- AO3.marker = ARRAY_MV;
- ln = 0; ln2 = 0;
- do
- { get_next_token();
- if ((token_type==SEP_TT)&&(token_value==SEMICOLON_SEP))
- break;
- if (token_type != DQ_TT)
- ebf_error("text of box line in double-quotes",
- token_text);
- { int i, j;
- for (i=0, j=0; token_text[i] != 0; j++)
- if (token_text[i] == '@')
- { if (token_text[i+1] == '@')
- { i = i + 2;
- while (isdigit(token_text[i])) i++;
- }
- else
- { i++;
- if (token_text[i] != 0) i++;
- if (token_text[i] != 0) i++;
- }
- }
- else i++;
- if (j > ln2) ln2 = j;
- }
- put_token_back();
- array_entry(ln++,parse_expression(CONSTANT_CONTEXT));
- } while (TRUE);
- finish_array(ln);
- if (ln == 0)
- error("No lines of text given for 'box' display");
- AO2.value = ln2; AO2.marker = 0; set_constant_ot(&AO2);
- assembleg_call_2(veneer_routine(Box__Routine_VR),
- AO2, AO3, zero_operand);
- return;
- /* -------------------------------------------------------------------- */
- /* break -------------------------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case BREAK_CODE:
- if (break_label == -1)
- error("'break' can only be used in a loop or 'switch' block");
- else
- assembleg_jump(break_label);
- break;
- /* -------------------------------------------------------------------- */
- /* continue ----------------------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case CONTINUE_CODE:
- if (continue_label == -1)
- error("'continue' can only be used in a loop block");
- else
- assembleg_jump(continue_label);
- break;
- /* -------------------------------------------------------------------- */
- /* do <codeblock> until (<condition>) --------------------------------- */
- /* -------------------------------------------------------------------- */
- case DO_CODE:
- assemble_label_no(ln = next_label++);
- ln2 = next_label++; ln3 = next_label++;
- parse_code_block(ln3, ln2, 0);
- statements.enabled = TRUE;
- get_next_token();
- if ((token_type == STATEMENT_TT)
- && (token_value == UNTIL_CODE))
- { assemble_label_no(ln2);
- match_open_bracket();
- AO = parse_expression(CONDITION_CONTEXT);
- match_close_bracket();
- code_generate(AO, CONDITION_CONTEXT, ln);
- }
- else error("'do' without matching 'until'");
- assemble_label_no(ln3);
- break;
- /* -------------------------------------------------------------------- */
- /* font on/off -------------------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case FONT_CODE:
- misc_keywords.enabled = TRUE;
- get_next_token();
- misc_keywords.enabled = FALSE;
- if ((token_type != MISC_KEYWORD_TT)
- || ((token_value != ON_MK)
- && (token_value != OFF_MK)))
- { ebf_error("'on' or 'off'", token_text);
- panic_mode_error_recovery();
- break;
- }
- /* Call glk_set_style(normal or preformatted) */
- AO.value = 0x0086;
- AO.marker = 0;
- set_constant_ot(&AO);
- if (token_value == ON_MK)
- AO2 = zero_operand;
- else
- AO2 = two_operand;
- assembleg_call_2(veneer_routine(Glk__Wrap_VR),
- AO, AO2, zero_operand);
- break;
- /* -------------------------------------------------------------------- */
- /* for (<initialisation> : <continue-condition> : <updating>) --------- */
- /* -------------------------------------------------------------------- */
- /* Note that it's legal for any or all of the three sections of a
- 'for' specification to be empty. This 'for' implementation
- often wastes 3 bytes with a redundant branch rather than keep
- expression parse trees for long periods (as previous versions
- of Inform did, somewhat crudely by simply storing the textual
- form of a 'for' loop). It is adequate for now. */
- case FOR_CODE:
- match_open_bracket();
- get_next_token();
- /* Initialisation code */
- if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
- { put_token_back();
- if (!((token_type==SEP_TT)&&(token_value==SUPERCLASS_SEP)))
- { sequence_point_follows = TRUE;
- statement_debug_location = get_token_location();
- code_generate(parse_expression(FORINIT_CONTEXT),
- VOID_CONTEXT, -1);
- }
- get_next_token();
- if ((token_type==SEP_TT)&&(token_value == SUPERCLASS_SEP))
- { get_next_token();
- if ((token_type==SEP_TT)&&(token_value == CLOSEB_SEP))
- { assemble_label_no(ln = next_label++);
- ln2 = next_label++;
- parse_code_block(ln2, ln, 0);
- sequence_point_follows = FALSE;
- if (!execution_never_reaches_here)
- assembleg_jump(ln);
- assemble_label_no(ln2);
- return;
- }
- AO.type = OMITTED_OT;
- goto ParseUpdate;
- }
- put_token_back();
- if (!match_colon()) break;
- }
- get_next_token();
- AO.type = OMITTED_OT;
- if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
- { put_token_back();
- spare_debug_location1 = get_token_location();
- AO = parse_expression(CONDITION_CONTEXT);
- if (!match_colon()) break;
- }
- get_next_token();
- ParseUpdate:
- AO2.type = OMITTED_OT; flag = 0;
- if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP)))
- { put_token_back();
- spare_debug_location2 = get_token_location();
- AO2 = parse_expression(VOID_CONTEXT);
- match_close_bracket();
- flag = test_for_incdec(AO2);
- }
- ln = next_label++;
- ln2 = next_label++;
- ln3 = next_label++;
- if ((AO2.type == OMITTED_OT) || (flag != 0))
- {
- assemble_label_no(ln);
- if (flag==0) assemble_label_no(ln2);
- /* The "finished yet?" condition */
- if (AO.type != OMITTED_OT)
- { sequence_point_follows = TRUE;
- statement_debug_location = spare_debug_location1;
- code_generate(AO, CONDITION_CONTEXT, ln3);
- }
- }
- else
- {
- /* This is the jump which could be avoided with the aid
- of long-term expression storage */
- sequence_point_follows = FALSE;
- assembleg_jump(ln2);
- /* The "update" part */
- assemble_label_no(ln);
- sequence_point_follows = TRUE;
- statement_debug_location = spare_debug_location2;
- code_generate(AO2, VOID_CONTEXT, -1);
- assemble_label_no(ln2);
- /* The "finished yet?" condition */
- if (AO.type != OMITTED_OT)
- { sequence_point_follows = TRUE;
- statement_debug_location = spare_debug_location1;
- code_generate(AO, CONDITION_CONTEXT, ln3);
- }
- }
- if (flag != 0)
- {
- /* In this optimised case, update code is at the end
- of the loop block, so "continue" goes there */
- parse_code_block(ln3, ln2, 0);
- assemble_label_no(ln2);
- sequence_point_follows = TRUE;
- statement_debug_location = spare_debug_location2;
- if (flag > 0)
- { AO3.value = flag;
- if (AO3.value >= MAX_LOCAL_VARIABLES)
- AO3.type = GLOBALVAR_OT;
- else
- AO3.type = LOCALVAR_OT;
- AO3.marker = 0;
- assembleg_3(add_gc, AO3, one_operand, AO3);
- }
- else
- { AO3.value = -flag;
- if (AO3.value >= MAX_LOCAL_VARIABLES)
- AO3.type = GLOBALVAR_OT;
- else
- AO3.type = LOCALVAR_OT;
- AO3.marker = 0;
- assembleg_3(sub_gc, AO3, one_operand, AO3);
- }
- assembleg_jump(ln);
- }
- else
- {
- /* In the unoptimised case, update code is at the
- start of the loop block, so "continue" goes there */
- parse_code_block(ln3, ln, 0);
- if (!execution_never_reaches_here)
- { sequence_point_follows = FALSE;
- assembleg_jump(ln);
- }
- }
- assemble_label_no(ln3);
- return;
- /* -------------------------------------------------------------------- */
- /* give <expression> [~]attr [, [~]attr [, ...]] ---------------------- */
- /* -------------------------------------------------------------------- */
- case GIVE_CODE:
- AO = code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- if ((AO.type == LOCALVAR_OT) && (AO.value == 0))
- onstack = TRUE;
- else
- onstack = FALSE;
- do
- { get_next_token();
- if ((token_type == SEP_TT)
- && (token_value == SEMICOLON_SEP)) {
- if (onstack) {
- assembleg_2(copy_gc, stack_pointer, zero_operand);
- }
- return;
- }
- if ((token_type == SEP_TT)&&(token_value == ARTNOT_SEP))
- ln = 0;
- else
- { if ((token_type == SYMBOL_TT)
- && (stypes[token_value] != ATTRIBUTE_T))
- warning_named("This is not a declared Attribute:",
- token_text);
- ln = 1;
- put_token_back();
- }
- AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- if (runtime_error_checking_switch && (!veneer_mode))
- { ln2 = (ln ? RT__ChG_VR : RT__ChGt_VR);
- if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0)) {
- /* already on stack */
- }
- else {
- assembleg_store(stack_pointer, AO2);
- }
- if (onstack)
- assembleg_2(stkpeek_gc, one_operand, stack_pointer);
- else
- assembleg_store(stack_pointer, AO);
- assembleg_3(call_gc, veneer_routine(ln2), two_operand,
- zero_operand);
- }
- else {
- if (is_constant_ot(AO2.type) && AO2.marker == 0) {
- AO2.value += 8;
- set_constant_ot(&AO2);
- }
- else {
- AO3.value = 8;
- AO3.marker = 0;
- AO3.type = BYTECONSTANT_OT;
- assembleg_3(add_gc, AO2, AO3, stack_pointer);
- AO2 = stack_pointer;
- }
- if (onstack) {
- if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0))
- assembleg_2(stkpeek_gc, one_operand,
- stack_pointer);
- else
- assembleg_2(stkpeek_gc, zero_operand,
- stack_pointer);
- }
- if (ln)
- AO3 = one_operand;
- else
- AO3 = zero_operand;
- assembleg_3(astorebit_gc, AO, AO2, AO3);
- }
- } while(TRUE);
- /* -------------------------------------------------------------------- */
- /* if (<condition>) <codeblock> [else <codeblock>] -------------------- */
- /* -------------------------------------------------------------------- */
- case IF_CODE:
- flag = FALSE;
- match_open_bracket();
- AO = parse_expression(CONDITION_CONTEXT);
- match_close_bracket();
- statements.enabled = TRUE;
- get_next_token();
- if ((token_type == STATEMENT_TT)&&(token_value == RTRUE_CODE))
- ln = -4;
- else
- if ((token_type == STATEMENT_TT)&&(token_value == RFALSE_CODE))
- ln = -3;
- else
- { put_token_back();
- ln = next_label++;
- }
- code_generate(AO, CONDITION_CONTEXT, ln);
- if (ln >= 0) parse_code_block(break_label, continue_label, 0);
- else
- { get_next_token();
- if ((token_type != SEP_TT)
- || (token_value != SEMICOLON_SEP))
- { ebf_error("';'", token_text);
- put_token_back();
- }
- }
- statements.enabled = TRUE;
- get_next_token();
- if ((token_type == STATEMENT_TT) && (token_value == ELSE_CODE))
- { flag = TRUE;
- if (ln >= 0)
- { ln2 = next_label++;
- if (!execution_never_reaches_here)
- { sequence_point_follows = FALSE;
- assembleg_jump(ln2);
- }
- }
- }
- else put_token_back();
- if (ln >= 0) assemble_label_no(ln);
- if (flag)
- { parse_code_block(break_label, continue_label, 0);
- if (ln >= 0) assemble_label_no(ln2);
- }
- return;
- /* -------------------------------------------------------------------- */
- /* inversion ---------------------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case INVERSION_CODE:
- AO2.marker = 0;
- AO2.type = DEREFERENCE_OT;
- AO2.value = GLULX_HEADER_SIZE+8;
- assembleg_2(copyb_gc, AO2, stack_pointer);
- assembleg_1(streamchar_gc, stack_pointer);
- AO2.value = GLULX_HEADER_SIZE+9;
- assembleg_2(copyb_gc, AO2, stack_pointer);
- assembleg_1(streamchar_gc, stack_pointer);
- AO2.value = GLULX_HEADER_SIZE+10;
- assembleg_2(copyb_gc, AO2, stack_pointer);
- assembleg_1(streamchar_gc, stack_pointer);
- AO2.value = GLULX_HEADER_SIZE+11;
- assembleg_2(copyb_gc, AO2, stack_pointer);
- assembleg_1(streamchar_gc, stack_pointer);
- if (0) {
- AO.marker = 0;
- AO.value = '(';
- set_constant_ot(&AO);
- assembleg_1(streamchar_gc, AO);
- AO.value = 'G';
- set_constant_ot(&AO);
- assembleg_1(streamchar_gc, AO);
- AO2.value = GLULX_HEADER_SIZE+12;
- assembleg_2(copyb_gc, AO2, stack_pointer);
- assembleg_1(streamchar_gc, stack_pointer);
- AO2.value = GLULX_HEADER_SIZE+13;
- assembleg_2(copyb_gc, AO2, stack_pointer);
- assembleg_1(streamchar_gc, stack_pointer);
- AO2.value = GLULX_HEADER_SIZE+14;
- assembleg_2(copyb_gc, AO2, stack_pointer);
- assembleg_1(streamchar_gc, stack_pointer);
- AO2.value = GLULX_HEADER_SIZE+15;
- assembleg_2(copyb_gc, AO2, stack_pointer);
- assembleg_1(streamchar_gc, stack_pointer);
- AO.marker = 0;
- AO.value = ')';
- set_constant_ot(&AO);
- assembleg_1(streamchar_gc, AO);
- }
- break;
- /* -------------------------------------------------------------------- */
- /* jump <label> ------------------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case JUMP_CODE:
- assembleg_jump(parse_label());
- break;
- /* -------------------------------------------------------------------- */
- /* move <expression> to <expression> ---------------------------------- */
- /* -------------------------------------------------------------------- */
- case MOVE_CODE:
- misc_keywords.enabled = TRUE;
- AO = parse_expression(QUANTITY_CONTEXT);
- get_next_token();
- misc_keywords.enabled = FALSE;
- if ((token_type != MISC_KEYWORD_TT)
- || (token_value != TO_MK))
- { ebf_error("'to'", token_text);
- panic_mode_error_recovery();
- return;
- }
- AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- AO = code_generate(AO, QUANTITY_CONTEXT, -1);
- if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
- assembleg_call_2(veneer_routine(RT__ChT_VR), AO, AO2,
- zero_operand);
- else
- assembleg_call_2(veneer_routine(OB__Move_VR), AO, AO2,
- zero_operand);
- break;
- /* -------------------------------------------------------------------- */
- /* new_line ----------------------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case NEW_LINE_CODE:
- AO.type = BYTECONSTANT_OT; AO.value = 0x0A; AO.marker = 0;
- assembleg_1(streamchar_gc, AO);
- break;
- /* -------------------------------------------------------------------- */
- /* objectloop (<initialisation>) <codeblock> -------------------------- */
- /* -------------------------------------------------------------------- */
- case OBJECTLOOP_CODE:
- match_open_bracket();
- get_next_token();
- if (token_type == LOCAL_VARIABLE_TT) {
- AO.value = token_value;
- AO.type = LOCALVAR_OT;
- AO.marker = 0;
- }
- else if ((token_type == SYMBOL_TT) &&
- (stypes[token_value] == GLOBAL_VARIABLE_T)) {
- AO.value = svals[token_value];
- AO.type = GLOBALVAR_OT;
- AO.marker = 0;
- }
- else {
- ebf_error("'objectloop' variable", token_text);
- panic_mode_error_recovery();
- break;
- }
- misc_keywords.enabled = TRUE;
- get_next_token(); flag = TRUE;
- misc_keywords.enabled = FALSE;
- if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
- flag = FALSE;
- ln = 0;
- if ((token_type == MISC_KEYWORD_TT)
- && (token_value == NEAR_MK)) ln = 1;
- if ((token_type == MISC_KEYWORD_TT)
- && (token_value == FROM_MK)) ln = 2;
- if ((token_type == CND_TT) && (token_value == IN_COND))
- { get_next_token();
- get_next_token();
- if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
- ln = 3;
- put_token_back();
- put_token_back();
- }
- if (ln != 0) {
- /* Old style (Inform 5) objectloops: note that we
- implement objectloop (a in b) in the old way since
- this runs through objects in a different order from
- the new way, and there may be existing Inform code
- relying on this. */
- assembly_operand AO4, AO5;
- sequence_point_follows = TRUE;
- AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- match_close_bracket();
- if (ln == 1) {
- if (runtime_error_checking_switch)
- AO2 = check_nonzero_at_runtime(AO2, -1,
- OBJECTLOOP_RTE);
- AO4.type = BYTECONSTANT_OT;
- AO4.value = GOBJFIELD_PARENT();
- AO4.marker = 0;
- assembleg_3(aload_gc, AO2, AO4, stack_pointer);
- AO4.type = BYTECONSTANT_OT;
- AO4.value = GOBJFIELD_CHILD();
- AO4.marker = 0;
- assembleg_3(aload_gc, stack_pointer, AO4, stack_pointer);
- AO2 = stack_pointer;
- }
- else if (ln == 3) {
- if (runtime_error_checking_switch) {
- AO5 = AO2;
- AO2 = check_nonzero_at_runtime(AO2, -1,
- CHILD_RTE);
- }
- AO4.type = BYTECONSTANT_OT;
- AO4.value = GOBJFIELD_CHILD();
- AO4.marker = 0;
- assembleg_3(aload_gc, AO2, AO4, stack_pointer);
- AO2 = stack_pointer;
- }
- else {
- /* do nothing */
- }
- assembleg_store(AO, AO2);
- assembleg_1_branch(jz_gc, AO, ln2 = next_label++);
- assemble_label_no(ln4 = next_label++);
- parse_code_block(ln2, ln3 = next_label++, 0);
- sequence_point_follows = FALSE;
- assemble_label_no(ln3);
- if (runtime_error_checking_switch) {
- AO2 = check_nonzero_at_runtime(AO, ln2,
- OBJECTLOOP2_RTE);
- if ((ln == 3)
- && ((AO5.type != LOCALVAR_OT)||(AO5.value != 0))
- && ((AO5.type != LOCALVAR_OT)||(AO5.value != AO.value)))
- { assembly_operand en_ao;
- en_ao.value = OBJECTLOOP_BROKEN_RTE;
- en_ao.marker = 0;
- set_constant_ot(&en_ao);
- AO4.type = BYTECONSTANT_OT;
- AO4.value = GOBJFIELD_PARENT();
- AO4.marker = 0;
- assembleg_3(aload_gc, AO, AO4, stack_pointer);
- assembleg_2_branch(jeq_gc, stack_pointer, AO5,
- next_label);
- assembleg_call_2(veneer_routine(RT__Err_VR),
- en_ao, AO, zero_operand);
- assembleg_jump(ln2);
- assemble_label_no(next_label++);
- }
- }
- else {
- AO2 = AO;
- }
- AO4.type = BYTECONSTANT_OT;
- AO4.value = GOBJFIELD_SIBLING();
- AO4.marker = 0;
- assembleg_3(aload_gc, AO2, AO4, AO);
- assembleg_1_branch(jnz_gc, AO, ln4);
- assemble_label_no(ln2);
- return;
- }
- sequence_point_follows = TRUE;
- ln = symbol_index("Class", -1);
- AO2.value = svals[ln];
- AO2.marker = OBJECT_MV;
- AO2.type = CONSTANT_OT;
- assembleg_store(AO, AO2);
- assemble_label_no(ln = next_label++);
- ln2 = next_label++;
- ln3 = next_label++;
- if (flag)
- { put_token_back();
- put_token_back();
- sequence_point_follows = TRUE;
- code_generate(parse_expression(CONDITION_CONTEXT),
- CONDITION_CONTEXT, ln3);
- match_close_bracket();
- }
- parse_code_block(ln2, ln3, 0);
- sequence_point_follows = FALSE;
- assemble_label_no(ln3);
- AO4.type = BYTECONSTANT_OT;
- AO4.value = GOBJFIELD_CHAIN();
- AO4.marker = 0;
- assembleg_3(aload_gc, AO, AO4, AO);
- assembleg_1_branch(jnz_gc, AO, ln);
- assemble_label_no(ln2);
- return;
- /* -------------------------------------------------------------------- */
- /* (see routine above) ------------------------------------------------ */
- /* -------------------------------------------------------------------- */
- case PRINT_CODE:
- get_next_token();
- parse_print_g(FALSE); return;
- case PRINT_RET_CODE:
- get_next_token();
- parse_print_g(TRUE); return;
- /* -------------------------------------------------------------------- */
- /* quit --------------------------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case QUIT_CODE:
- assembleg_0(quit_gc); break;
- /* -------------------------------------------------------------------- */
- /* remove <expression> ------------------------------------------------ */
- /* -------------------------------------------------------------------- */
- case REMOVE_CODE:
- AO = code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
- assembleg_call_1(veneer_routine(RT__ChR_VR), AO,
- zero_operand);
- else
- assembleg_call_1(veneer_routine(OB__Remove_VR), AO,
- zero_operand);
- break;
- /* -------------------------------------------------------------------- */
- /* return [<expression>] ---------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case RETURN_CODE:
- get_next_token();
- if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
- AO.type = BYTECONSTANT_OT; AO.value = 1; AO.marker = 0;
- assembleg_1(return_gc, AO);
- return;
- }
- put_token_back();
- AO = code_generate(parse_expression(RETURN_Q_CONTEXT),
- QUANTITY_CONTEXT, -1);
- assembleg_1(return_gc, AO);
- break;
- /* -------------------------------------------------------------------- */
- /* rfalse ------------------------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case RFALSE_CODE:
- assembleg_1(return_gc, zero_operand);
- break;
- /* -------------------------------------------------------------------- */
- /* rtrue -------------------------------------------------------------- */
- /* -------------------------------------------------------------------- */
- case RTRUE_CODE:
- assembleg_1(return_gc, one_operand);
- break;
- /* -------------------------------------------------------------------- */
- /* spaces <expression> ------------------------------------------------ */
- /* -------------------------------------------------------------------- */
- case SPACES_CODE:
- AO = code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- assembleg_store(temp_var1, AO);
- AO.value = 32; AO.marker = 0; set_constant_ot(&AO);
- assembleg_2_branch(jlt_gc, temp_var1, one_operand,
- ln = next_label++);
- assemble_label_no(ln2 = next_label++);
- assembleg_1(streamchar_gc, AO);
- assembleg_dec(temp_var1);
- assembleg_1_branch(jnz_gc, temp_var1, ln2);
- assemble_label_no(ln);
- break;
- /* -------------------------------------------------------------------- */
- /* string <expression> <literal-string> ------------------------------- */
- /* -------------------------------------------------------------------- */
- case STRING_CODE:
- AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- get_next_token();
- if (token_type == DQ_TT)
- { AO4.value = compile_string(token_text, TRUE, TRUE);
- AO4.marker = STRING_MV;
- AO4.type = CONSTANT_OT;
- }
- else
- { put_token_back();
- AO4 = parse_expression(CONSTANT_CONTEXT);
- }
- assembleg_call_2(veneer_routine(Dynam__String_VR),
- AO2, AO4, zero_operand);
- break;
- /* -------------------------------------------------------------------- */
- /* style roman/reverse/bold/underline/fixed --------------------------- */
- /* -------------------------------------------------------------------- */
- case STYLE_CODE:
- misc_keywords.enabled = TRUE;
- get_next_token();
- misc_keywords.enabled = FALSE;
- if ((token_type != MISC_KEYWORD_TT)
- || ((token_value != ROMAN_MK)
- && (token_value != REVERSE_MK)
- && (token_value != BOLD_MK)
- && (token_value != UNDERLINE_MK)
- && (token_value != FIXED_MK)))
- { ebf_error(
- "'roman', 'bold', 'underline', 'reverse' or 'fixed'",
- token_text);
- panic_mode_error_recovery();
- break;
- }
- /* Call glk_set_style() */
- AO.value = 0x0086;
- AO.marker = 0;
- set_constant_ot(&AO);
- switch(token_value)
- { case ROMAN_MK:
- AO2 = zero_operand; /* normal */
- break;
- case REVERSE_MK:
- AO2.value = 5; /* alert */
- AO2.marker = 0;
- set_constant_ot(&AO2);
- break;
- case BOLD_MK:
- AO2.value = 4; /* subheader */
- AO2.marker = 0;
- set_constant_ot(&AO2);
- break;
- case UNDERLINE_MK:
- AO2 = one_operand; /* emphasized */
- break;
- case FIXED_MK:
- AO2 = two_operand; /* preformatted */
- break;
- }
- assembleg_call_2(veneer_routine(Glk__Wrap_VR),
- AO, AO2, zero_operand);
- break;
- /* -------------------------------------------------------------------- */
- /* switch (<expression>) <codeblock> ---------------------------------- */
- /* -------------------------------------------------------------------- */
- case SWITCH_CODE:
- match_open_bracket();
- AO = code_generate(parse_expression(QUANTITY_CONTEXT),
- QUANTITY_CONTEXT, -1);
- match_close_bracket();
- assembleg_store(temp_var1, AO);
- parse_code_block(ln = next_label++, continue_label, 1);
- assemble_label_no(ln);
- return;
- /* -------------------------------------------------------------------- */
- /* while (<condition>) <codeblock> ------------------------------------ */
- /* -------------------------------------------------------------------- */
- case WHILE_CODE:
- assemble_label_no(ln = next_label++);
- match_open_bracket();
- code_generate(parse_expression(CONDITION_CONTEXT),
- CONDITION_CONTEXT, ln2 = next_label++);
- match_close_bracket();
- parse_code_block(ln2, ln, 0);
- sequence_point_follows = FALSE;
- assembleg_jump(ln);
- assemble_label_no(ln2);
- return;
- /* -------------------------------------------------------------------- */
- case SDEFAULT_CODE:
- error("'default' without matching 'switch'"); break;
- case ELSE_CODE:
- error("'else' without matching 'if'"); break;
- case UNTIL_CODE:
- error("'until' without matching 'do'");
- panic_mode_error_recovery(); return;
- /* -------------------------------------------------------------------- */
- /* And a useful default, which will never be triggered in a complete
- Inform compiler, but which is important in development. */
- default:
- error("*** Statement code gen: Can't generate yet ***\n");
- panic_mode_error_recovery(); return;
- }
- StatementTerminator:
- get_next_token();
- if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
- { ebf_error("';'", token_text);
- put_token_back();
- }
- }
- extern void parse_statement(int break_label, int continue_label)
- {
- if (!glulx_mode)
- parse_statement_z(break_label, continue_label);
- else
- parse_statement_g(break_label, continue_label);
- }
- /* ========================================================================= */
- /* Data structure management routines */
- /* ------------------------------------------------------------------------- */
- extern void init_states_vars(void)
- {
- }
- extern void states_begin_pass(void)
- {
- }
- extern void states_allocate_arrays(void)
- {
- }
- extern void states_free_arrays(void)
- {
- }
- /* ========================================================================= */
|