From 797cf56e68b5cace1dbabbaf9c4b9a5b58aadc2e Mon Sep 17 00:00:00 2001 From: Graham Nelson Date: Wed, 28 Jul 2021 22:44:50 +0100 Subject: [PATCH] Tentative beginnings of C transpiling --- README.md | 2 +- build.txt | 4 +- inter/Tests/Duplex/_Pairs/BinOut+B.intert | 2 +- inter/Tests/Duplex/_Pairs/BinOutRes+B.intert | 2 +- inter/Tests/Duplex/_Pairs/InOut+B.intert | 2 +- .../Tests/Duplex/_Pairs/PluggedInOut+B.intert | 1 - .../Duplex/_Pairs/TransposeInOut+B.intert | 2 +- .../Tests/Duplex/_Results_Ideal/BinOut+B.txt | 1 - .../Duplex/_Results_Ideal/BinOutRes+B.txt | 1 - inter/Tests/Duplex/_Results_Ideal/InOut+B.txt | 1 - .../Duplex/_Results_Ideal/PluggedInOut+B.txt | 1 - .../_Results_Ideal/TransposeInOut+B.txt | 1 - inter/Tests/General/C-SimpleRoutines.intert | 30 + .../_Pipelines/C-SimpleRoutines.interpipeline | 5 + inter/Tests/General/_Results_Ideal/Assim.txt | 6 + .../Tests/General/_Results_Ideal/Prepare.txt | 3 +- inter/Tests/Valid/misc.intert | 1 - inter/Tests/Valid/packages.intert | 2 - .../Chapter 4/Constants and Literals.w | 2 +- .../codegen-module/Chapter 4/Frame Control.w | 2 +- inter/codegen-module/Chapter 5/Final C.w | 580 ++++++++++++++++++ .../codegen-module/Chapter 5/Final Inform 6.w | 11 + .../codegen-module/Chapter 5/Final Targets.w | 16 + inter/codegen-module/Contents.w | 1 + 24 files changed, 660 insertions(+), 19 deletions(-) create mode 100644 inter/Tests/General/C-SimpleRoutines.intert create mode 100644 inter/Tests/General/_Pipelines/C-SimpleRoutines.interpipeline create mode 100644 inter/codegen-module/Chapter 5/Final C.w diff --git a/README.md b/README.md index ac1651fe1..9591ac06f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Inform 7 -v10.1.0-alpha.1+6S82 'Krypton' (27 July 2021) +v10.1.0-alpha.1+6S83 'Krypton' (28 July 2021) ## About Inform 7 diff --git a/build.txt b/build.txt index e02479e69..b5570e245 100644 --- a/build.txt +++ b/build.txt @@ -1,3 +1,3 @@ Prerelease: alpha.1 -Build Date: 27 July 2021 -Build Number: 6S82 +Build Date: 28 July 2021 +Build Number: 6S83 diff --git a/inter/Tests/Duplex/_Pairs/BinOut+B.intert b/inter/Tests/Duplex/_Pairs/BinOut+B.intert index e46b6b329..e5f9580eb 100644 --- a/inter/Tests/Duplex/_Pairs/BinOut+B.intert +++ b/inter/Tests/Duplex/_Pairs/BinOut+B.intert @@ -161,4 +161,4 @@ package main _plain val K_colour I_red constant R_102 K_colour____colour = R_102_B constant amount K_number = sum{ 2, C_taxes } - response R_101_A R_101 0 = C_taxes + diff --git a/inter/Tests/Duplex/_Pairs/BinOutRes+B.intert b/inter/Tests/Duplex/_Pairs/BinOutRes+B.intert index d7e79c963..76022d939 100644 --- a/inter/Tests/Duplex/_Pairs/BinOutRes+B.intert +++ b/inter/Tests/Duplex/_Pairs/BinOutRes+B.intert @@ -161,4 +161,4 @@ package main _plain val K_colour I_red constant R_102 K_colour____colour = R_102_B constant amount K_number = sum{ 2, C_taxes } - response R_101_A R_101 0 = C_taxes + diff --git a/inter/Tests/Duplex/_Pairs/InOut+B.intert b/inter/Tests/Duplex/_Pairs/InOut+B.intert index e46b6b329..e5f9580eb 100644 --- a/inter/Tests/Duplex/_Pairs/InOut+B.intert +++ b/inter/Tests/Duplex/_Pairs/InOut+B.intert @@ -161,4 +161,4 @@ package main _plain val K_colour I_red constant R_102 K_colour____colour = R_102_B constant amount K_number = sum{ 2, C_taxes } - response R_101_A R_101 0 = C_taxes + diff --git a/inter/Tests/Duplex/_Pairs/PluggedInOut+B.intert b/inter/Tests/Duplex/_Pairs/PluggedInOut+B.intert index 3d17c331f..e1fd64ef9 100644 --- a/inter/Tests/Duplex/_Pairs/PluggedInOut+B.intert +++ b/inter/Tests/Duplex/_Pairs/PluggedInOut+B.intert @@ -162,7 +162,6 @@ package main _plain val K_colour I_red constant R_102 K_colour____colour = R_102_B constant amount K_number = sum{ 2, C_taxes } - response R_101_A R_101 0 = C_taxes package connectors _linkage symbol socket misc C_majors --> /main/C_majors symbol plug misc plug_00001 --? secret diff --git a/inter/Tests/Duplex/_Pairs/TransposeInOut+B.intert b/inter/Tests/Duplex/_Pairs/TransposeInOut+B.intert index 07c3caf7e..abbb88c1d 100644 --- a/inter/Tests/Duplex/_Pairs/TransposeInOut+B.intert +++ b/inter/Tests/Duplex/_Pairs/TransposeInOut+B.intert @@ -162,4 +162,4 @@ package main _plain val K_colour I_red constant R_102 K_colour____colour = R_102_B constant amount K_number = sum{ 2, C_taxes } - response R_101_A R_101 0 = C_taxes + diff --git a/inter/Tests/Duplex/_Results_Ideal/BinOut+B.txt b/inter/Tests/Duplex/_Results_Ideal/BinOut+B.txt index e46b6b329..39d11f343 100644 --- a/inter/Tests/Duplex/_Results_Ideal/BinOut+B.txt +++ b/inter/Tests/Duplex/_Results_Ideal/BinOut+B.txt @@ -161,4 +161,3 @@ package main _plain val K_colour I_red constant R_102 K_colour____colour = R_102_B constant amount K_number = sum{ 2, C_taxes } - response R_101_A R_101 0 = C_taxes diff --git a/inter/Tests/Duplex/_Results_Ideal/BinOutRes+B.txt b/inter/Tests/Duplex/_Results_Ideal/BinOutRes+B.txt index d7e79c963..3b4d94220 100644 --- a/inter/Tests/Duplex/_Results_Ideal/BinOutRes+B.txt +++ b/inter/Tests/Duplex/_Results_Ideal/BinOutRes+B.txt @@ -161,4 +161,3 @@ package main _plain val K_colour I_red constant R_102 K_colour____colour = R_102_B constant amount K_number = sum{ 2, C_taxes } - response R_101_A R_101 0 = C_taxes diff --git a/inter/Tests/Duplex/_Results_Ideal/InOut+B.txt b/inter/Tests/Duplex/_Results_Ideal/InOut+B.txt index e46b6b329..39d11f343 100644 --- a/inter/Tests/Duplex/_Results_Ideal/InOut+B.txt +++ b/inter/Tests/Duplex/_Results_Ideal/InOut+B.txt @@ -161,4 +161,3 @@ package main _plain val K_colour I_red constant R_102 K_colour____colour = R_102_B constant amount K_number = sum{ 2, C_taxes } - response R_101_A R_101 0 = C_taxes diff --git a/inter/Tests/Duplex/_Results_Ideal/PluggedInOut+B.txt b/inter/Tests/Duplex/_Results_Ideal/PluggedInOut+B.txt index 27c8ce41c..e729cecdc 100644 --- a/inter/Tests/Duplex/_Results_Ideal/PluggedInOut+B.txt +++ b/inter/Tests/Duplex/_Results_Ideal/PluggedInOut+B.txt @@ -164,7 +164,6 @@ package main _plain val K_colour I_red constant R_102 K_colour____colour = R_102_B constant amount K_number = sum{ 2, C_taxes } - response R_101_A R_101 0 = C_taxes package connectors _linkage symbol socket misc C_majors --> /main/C_majors symbol plug misc plug_00001 --? secret diff --git a/inter/Tests/Duplex/_Results_Ideal/TransposeInOut+B.txt b/inter/Tests/Duplex/_Results_Ideal/TransposeInOut+B.txt index 00887a0b9..6fe8a1f8d 100644 --- a/inter/Tests/Duplex/_Results_Ideal/TransposeInOut+B.txt +++ b/inter/Tests/Duplex/_Results_Ideal/TransposeInOut+B.txt @@ -164,7 +164,6 @@ package main _plain val K_colour I_red constant R_102 K_colour____colour = R_102_B constant amount K_number = sum{ 2, C_taxes } - response R_101_A R_101 0 = C_taxes # Imported my_fn here package my_fn _plain symbol public misc R_101 diff --git a/inter/Tests/General/C-SimpleRoutines.intert b/inter/Tests/General/C-SimpleRoutines.intert new file mode 100644 index 000000000..97e2cb5e2 --- /dev/null +++ b/inter/Tests/General/C-SimpleRoutines.intert @@ -0,0 +1,30 @@ +packagetype _plain +packagetype _code +packagetype _linkage + +package main _plain + package resources _plain + kind K_unchecked unchecked + kind K_unchecked_function function K_unchecked -> K_unchecked + package Falsity_B _code + code + splat &"return false;" + constant Falsity K_unchecked_function = Falsity_B + package Demo_B _code + symbol private misc x + symbol private misc y + symbol external misc K_unchecked + local x K_unchecked + local y K_unchecked + code + splat &"return x+y;" + constant Demo K_unchecked_function = Demo_B + package Prop_Falsity_B _code + symbol private misc reason + symbol private misc obj + symbol external misc K_unchecked + local reason K_unchecked + local obj K_unchecked + code + splat &"return 0;" + constant Prop_Falsity K_unchecked_function = Prop_Falsity_B diff --git a/inter/Tests/General/_Pipelines/C-SimpleRoutines.interpipeline b/inter/Tests/General/_Pipelines/C-SimpleRoutines.interpipeline new file mode 100644 index 000000000..29e559459 --- /dev/null +++ b/inter/Tests/General/_Pipelines/C-SimpleRoutines.interpipeline @@ -0,0 +1,5 @@ +read <- *in +parse-linked-matter +resolve-conditional-compilation +assimilate +generate c -> *out diff --git a/inter/Tests/General/_Results_Ideal/Assim.txt b/inter/Tests/General/_Results_Ideal/Assim.txt index 2be9d7a3b..f1711407b 100644 --- a/inter/Tests/General/_Results_Ideal/Assim.txt +++ b/inter/Tests/General/_Results_Ideal/Assim.txt @@ -135,11 +135,16 @@ package main _plain package properties _submodule package marmorial_prop _plain symbol public misc marmorial `marmorial` + symbol public misc property_id* + symbol external misc K_unchecked --> /main/other/K_unchecked symbol external misc K_truth_state --> /main/other/K_truth_state + constant property_id K_unchecked = 0 property marmorial K_truth_state __assimilated=1 __attribute=1 __either_or=1 package density_prop _plain symbol public misc density + symbol public misc property_id* symbol external misc K_unchecked --> /main/other/K_unchecked + constant property_id K_unchecked = 0 property density K_unchecked __assimilated=1 package connectors _linkage symbol plug misc plug_00001 --? VERB_DIRECTIVE_REVERSE @@ -160,6 +165,7 @@ package main _plain symbol socket misc Banana --> /main/template/functions/Banana_fn/Banana symbol socket misc Peach --> /main/template/functions/Peach_fn/Peach symbol socket misc marmorial --> /main/template/properties/marmorial_prop/marmorial + symbol socket misc property_id --> /main/template/properties/marmorial_prop/property_id symbol socket misc P_marmorial --> /main/template/properties/marmorial_prop/marmorial symbol socket misc density --> /main/template/properties/density_prop/density symbol socket misc DEBUG --> /main/template/constants/DEBUG_con/DEBUG diff --git a/inter/Tests/General/_Results_Ideal/Prepare.txt b/inter/Tests/General/_Results_Ideal/Prepare.txt index 03c05c7a0..75f2a2cc2 100644 --- a/inter/Tests/General/_Results_Ideal/Prepare.txt +++ b/inter/Tests/General/_Results_Ideal/Prepare.txt @@ -10,6 +10,7 @@ packagetype _action packagetype _command packagetype _property packagetype _to_phrase +packagetype _response # Pragmas: # Primitives: primitive !font val -> void @@ -122,7 +123,7 @@ primitive !notin val val -> val primitive !read val val -> void primitive !inversion void -> void package main _plain - package veneer _module + package veneer _linkage symbol external misc K_unchecked --> /main/generic/K_unchecked symbol public misc WORDSIZE symbol public misc TARGET_ZCODE diff --git a/inter/Tests/Valid/misc.intert b/inter/Tests/Valid/misc.intert index 9674de6bc..17f2b065e 100644 --- a/inter/Tests/Valid/misc.intert +++ b/inter/Tests/Valid/misc.intert @@ -163,4 +163,3 @@ package main _plain val K_colour I_red constant R_102 K_colour____colour = R_102_B constant amount K_number = sum{ 2, C_taxes } - response R_101_A R_101 0 = C_taxes diff --git a/inter/Tests/Valid/packages.intert b/inter/Tests/Valid/packages.intert index 18baf5dc4..b43f459da 100644 --- a/inter/Tests/Valid/packages.intert +++ b/inter/Tests/Valid/packages.intert @@ -12,6 +12,4 @@ package main _plain symbol external misc K_number --> /main/K_number symbol public misc `name symbol public misc `purpose - metadata `name: "My test subpackage" - metadata `purpose: "No real purpose, honestly" constant y K_number = 17 diff --git a/inter/codegen-module/Chapter 4/Constants and Literals.w b/inter/codegen-module/Chapter 4/Constants and Literals.w index 80bccd5f9..db2253ca3 100644 --- a/inter/codegen-module/Chapter 4/Constants and Literals.w +++ b/inter/codegen-module/Chapter 4/Constants and Literals.w @@ -105,7 +105,7 @@ void CodeGen::CL::constant(code_generation *gen, inter_tree_node *P) { if (Inter::Constant::is_routine(con_name)) { inter_package *code_block = Inter::Constant::code_block(con_name); - WRITE("[ %S", CodeGen::CL::name(con_name)); + CodeGen::Targets::begin_function(gen, CodeGen::CL::name(con_name)); void_level = Inter::Defn::get_level(P) + 2; inter_tree_node *D = Inter::Packages::definition(code_block); CodeGen::FC::frame(gen, D); diff --git a/inter/codegen-module/Chapter 4/Frame Control.w b/inter/codegen-module/Chapter 4/Frame Control.w index 13fd63691..3cc8daef2 100644 --- a/inter/codegen-module/Chapter 4/Frame Control.w +++ b/inter/codegen-module/Chapter 4/Frame Control.w @@ -139,7 +139,7 @@ void CodeGen::FC::code(code_generation *gen, inter_tree_node *P) { LOOP_THROUGH_INTER_CHILDREN(F, P) CodeGen::FC::frame(gen, F); void_level = old_level; - if (function_code_block) { OUTDENT; WRITE("];\n"); } + if (function_code_block) { OUTDENT; CodeGen::Targets::end_function(gen); WRITE("\n"); } } void CodeGen::FC::evaluation(code_generation *gen, inter_tree_node *P) { diff --git a/inter/codegen-module/Chapter 5/Final C.w b/inter/codegen-module/Chapter 5/Final C.w new file mode 100644 index 000000000..afb7d2bf8 --- /dev/null +++ b/inter/codegen-module/Chapter 5/Final C.w @@ -0,0 +1,580 @@ +[CodeGen::C::] Generating C. + +To generate I6 code from intermediate code. + +@h Target. + += +code_generation_target *c_target = NULL; +void CodeGen::C::create_target(void) { + code_generation_target *cgt = CodeGen::Targets::new(I"c"); + METHOD_ADD(cgt, BEGIN_GENERATION_MTID, CodeGen::C::begin_generation); + METHOD_ADD(cgt, GENERAL_SEGMENT_MTID, CodeGen::C::general_segment); + METHOD_ADD(cgt, TL_SEGMENT_MTID, CodeGen::C::tl_segment); + METHOD_ADD(cgt, DEFAULT_SEGMENT_MTID, CodeGen::C::default_segment); + METHOD_ADD(cgt, BASIC_CONSTANT_SEGMENT_MTID, CodeGen::C::basic_constant_segment); + METHOD_ADD(cgt, CONSTANT_SEGMENT_MTID, CodeGen::C::constant_segment); + METHOD_ADD(cgt, PROPERTY_SEGMENT_MTID, CodeGen::C::property_segment); + METHOD_ADD(cgt, COMPILE_PRIMITIVE_MTID, CodeGen::C::compile_primitive); + METHOD_ADD(cgt, COMPILE_DICTIONARY_WORD_MTID, CodeGen::C::compile_dictionary_word); + METHOD_ADD(cgt, COMPILE_LITERAL_TEXT_MTID, CodeGen::C::compile_literal_text); + METHOD_ADD(cgt, DECLARE_PROPERTY_MTID, CodeGen::C::declare_property); + METHOD_ADD(cgt, PREPARE_VARIABLE_MTID, CodeGen::C::prepare_variable); + METHOD_ADD(cgt, DECLARE_VARIABLE_MTID, CodeGen::C::declare_variable); + METHOD_ADD(cgt, DECLARE_LOCAL_VARIABLE_MTID, CodeGen::C::declare_local_variable); + METHOD_ADD(cgt, BEGIN_CONSTANT_MTID, CodeGen::C::begin_constant); + METHOD_ADD(cgt, END_CONSTANT_MTID, CodeGen::C::end_constant); + METHOD_ADD(cgt, BEGIN_FUNCTION_MTID, CodeGen::C::begin_function); + METHOD_ADD(cgt, END_FUNCTION_MTID, CodeGen::C::end_function); + METHOD_ADD(cgt, OFFER_PRAGMA_MTID, CodeGen::C::offer_pragma) + c_target = cgt; +} + +code_generation_target *CodeGen::C::target(void) { + return inform6_target; +} + +@h Segmentation. + += +int CodeGen::C::begin_generation(code_generation_target *cgt, code_generation *gen) { + gen->segments[pragmatic_matter_I7CGS] = CodeGen::new_segment(); + gen->segments[compiler_versioning_matter_I7CGS] = CodeGen::new_segment(); + gen->segments[attributes_at_eof_I7CGS] = CodeGen::new_segment(); + gen->segments[very_early_matter_I7CGS] = CodeGen::new_segment(); + gen->segments[constants_1_I7CGS] = CodeGen::new_segment(); + gen->segments[constants_2_I7CGS] = CodeGen::new_segment(); + gen->segments[constants_3_I7CGS] = CodeGen::new_segment(); + gen->segments[constants_4_I7CGS] = CodeGen::new_segment(); + gen->segments[constants_5_I7CGS] = CodeGen::new_segment(); + gen->segments[constants_6_I7CGS] = CodeGen::new_segment(); + gen->segments[constants_7_I7CGS] = CodeGen::new_segment(); + gen->segments[constants_8_I7CGS] = CodeGen::new_segment(); + gen->segments[constants_9_I7CGS] = CodeGen::new_segment(); + gen->segments[constants_10_I7CGS] = CodeGen::new_segment(); + gen->segments[early_matter_I7CGS] = CodeGen::new_segment(); + gen->segments[text_literals_code_I7CGS] = CodeGen::new_segment(); + gen->segments[summations_at_eof_I7CGS] = CodeGen::new_segment(); + gen->segments[arrays_at_eof_I7CGS] = CodeGen::new_segment(); + gen->segments[globals_array_I7CGS] = CodeGen::new_segment(); + gen->segments[main_matter_I7CGS] = CodeGen::new_segment(); + gen->segments[routines_at_eof_I7CGS] = CodeGen::new_segment(); + gen->segments[code_at_eof_I7CGS] = CodeGen::new_segment(); + gen->segments[verbs_at_eof_I7CGS] = CodeGen::new_segment(); + gen->segments[stubs_at_eof_I7CGS] = CodeGen::new_segment(); + + generated_segment *saved = CodeGen::select(gen, compiler_versioning_matter_I7CGS); + text_stream *OUT = CodeGen::current(gen); + WRITE("#define Grammar__Version 2;\n"); + WRITE("int debug_flag = 0;\n"); + WRITE("int reason_code = NULL;\n"); + WRITE("int life = NULL;\n"); + CodeGen::deselect(gen, saved); + + return FALSE; +} + +int CodeGen::C::general_segment(code_generation_target *cgt, code_generation *gen, inter_tree_node *P) { + switch (P->W.data[ID_IFLD]) { + case CONSTANT_IST: { + inter_symbol *con_name = + InterSymbolsTables::symbol_from_frame_data(P, DEFN_CONST_IFLD); + int choice = early_matter_I7CGS; + if (Str::eq(con_name->symbol_name, I"DynamicMemoryAllocation")) choice = very_early_matter_I7CGS; + if (Inter::Symbols::read_annotation(con_name, LATE_IANN) == 1) choice = code_at_eof_I7CGS; + if (Inter::Symbols::read_annotation(con_name, BUFFERARRAY_IANN) == 1) choice = arrays_at_eof_I7CGS; + if (Inter::Symbols::read_annotation(con_name, BYTEARRAY_IANN) == 1) choice = arrays_at_eof_I7CGS; + if (Inter::Symbols::read_annotation(con_name, STRINGARRAY_IANN) == 1) choice = arrays_at_eof_I7CGS; + if (Inter::Symbols::read_annotation(con_name, TABLEARRAY_IANN) == 1) choice = arrays_at_eof_I7CGS; + if (P->W.data[FORMAT_CONST_IFLD] == CONSTANT_INDIRECT_LIST) choice = arrays_at_eof_I7CGS; + if (Inter::Symbols::read_annotation(con_name, VERBARRAY_IANN) == 1) choice = verbs_at_eof_I7CGS; + if (Inter::Constant::is_routine(con_name)) choice = routines_at_eof_I7CGS; + return choice; + } + } + return CodeGen::C::default_segment(cgt); +} + +int CodeGen::C::default_segment(code_generation_target *cgt) { + return main_matter_I7CGS; +} +int CodeGen::C::constant_segment(code_generation_target *cgt, code_generation *gen) { + return early_matter_I7CGS; +} +int CodeGen::C::basic_constant_segment(code_generation_target *cgt, code_generation *gen, int depth) { + if (depth >= 10) depth = 10; + return constants_1_I7CGS + depth - 1; +} +int CodeGen::C::property_segment(code_generation_target *cgt) { + return attributes_at_eof_I7CGS; +} +int CodeGen::C::tl_segment(code_generation_target *cgt) { + return text_literals_code_I7CGS; +} + +void CodeGen::C::offer_pragma(code_generation_target *cgt, code_generation *gen, + inter_tree_node *P, text_stream *tag, text_stream *content) { +} + +int CodeGen::C::compile_primitive(code_generation_target *cgt, code_generation *gen, + inter_symbol *prim_name, inter_tree_node *P) { + text_stream *OUT = CodeGen::current(gen); + int suppress_terminal_semicolon = FALSE; + inter_tree *I = gen->from; + inter_ti bip = Primitives::to_bip(I, prim_name); + switch (bip) { + case INVERSION_BIP: WRITE("inversion"); break; + + case PLUS_BIP: WRITE("("); INV_A1; WRITE(" + "); INV_A2; WRITE(")"); break; + case MINUS_BIP: WRITE("("); INV_A1; WRITE(" - "); INV_A2; WRITE(")"); break; + case UNARYMINUS_BIP: WRITE("(-("); INV_A1; WRITE("))"); break; + case TIMES_BIP: WRITE("("); INV_A1; WRITE("*"); INV_A2; WRITE(")"); break; + case DIVIDE_BIP: WRITE("("); INV_A1; WRITE("/"); INV_A2; WRITE(")"); break; + case MODULO_BIP: WRITE("("); INV_A1; WRITE("%%"); INV_A2; WRITE(")"); break; + case BITWISEAND_BIP: WRITE("(("); INV_A1; WRITE(")&("); INV_A2; WRITE("))"); break; + case BITWISEOR_BIP: WRITE("(("); INV_A1; WRITE(")|("); INV_A2; WRITE("))"); break; + case BITWISENOT_BIP: WRITE("(~("); INV_A1; WRITE("))"); break; + + case NOT_BIP: WRITE("(~~("); INV_A1; WRITE("))"); break; + case AND_BIP: WRITE("(("); INV_A1; WRITE(") && ("); INV_A2; WRITE("))"); break; + case OR_BIP: WRITE("(("); INV_A1; WRITE(") || ("); INV_A2; WRITE("))"); break; + case EQ_BIP: WRITE("("); INV_A1; WRITE(" == "); INV_A2; WRITE(")"); break; + case NE_BIP: WRITE("("); INV_A1; WRITE(" ~= "); INV_A2; WRITE(")"); break; + case GT_BIP: WRITE("("); INV_A1; WRITE(" > "); INV_A2; WRITE(")"); break; + case GE_BIP: WRITE("("); INV_A1; WRITE(" >= "); INV_A2; WRITE(")"); break; + case LT_BIP: WRITE("("); INV_A1; WRITE(" < "); INV_A2; WRITE(")"); break; + case LE_BIP: WRITE("("); INV_A1; WRITE(" <= "); INV_A2; WRITE(")"); break; + case OFCLASS_BIP: WRITE("("); INV_A1; WRITE(" ofclass "); INV_A2; WRITE(")"); break; + case HAS_BIP: WRITE("("); INV_A1; WRITE(" has "); INV_A2; WRITE(")"); break; + case HASNT_BIP: WRITE("("); INV_A1; WRITE(" hasnt "); INV_A2; WRITE(")"); break; + case IN_BIP: WRITE("("); INV_A1; WRITE(" in "); INV_A2; WRITE(")"); break; + case NOTIN_BIP: WRITE("("); INV_A1; WRITE(" notin "); INV_A2; WRITE(")"); break; + case PROVIDES_BIP: WRITE("("); INV_A1; WRITE(" provides "); INV_A2; WRITE(")"); break; + case ALTERNATIVE_BIP: INV_A1; WRITE(" or "); INV_A2; break; + + case PUSH_BIP: WRITE("@push "); INV_A1; break; + case PULL_BIP: WRITE("@pull "); INV_A1; break; + case PREINCREMENT_BIP: WRITE("++("); INV_A1; WRITE(")"); break; + case POSTINCREMENT_BIP: WRITE("("); INV_A1; WRITE(")++"); break; + case PREDECREMENT_BIP: WRITE("--("); INV_A1; WRITE(")"); break; + case POSTDECREMENT_BIP: WRITE("("); INV_A1; WRITE(")--"); break; + case STORE_BIP: WRITE("("); INV_A1; WRITE(" = "); INV_A2; WRITE(")"); break; + case SETBIT_BIP: INV_A1; WRITE(" = "); INV_A1; WRITE(" | "); INV_A2; break; + case CLEARBIT_BIP: INV_A1; WRITE(" = "); INV_A1; WRITE(" &~ ("); INV_A2; WRITE(")"); break; + case LOOKUP_BIP: WRITE("("); INV_A1; WRITE("-->("); INV_A2; WRITE("))"); break; + case LOOKUPBYTE_BIP: WRITE("("); INV_A1; WRITE("->("); INV_A2; WRITE("))"); break; + case LOOKUPREF_BIP: WRITE("("); INV_A1; WRITE("-->("); INV_A2; WRITE("))"); break; + case PROPERTYADDRESS_BIP: WRITE("("); INV_A1; WRITE(".& "); INV_A2; WRITE(")"); break; + case PROPERTYLENGTH_BIP: WRITE("("); INV_A1; WRITE(".# "); INV_A2; WRITE(")"); break; + case PROPERTYVALUE_BIP: WRITE("("); INV_A1; WRITE("."); INV_A2; WRITE(")"); break; + + case BREAK_BIP: WRITE("break"); break; + case CONTINUE_BIP: WRITE("continue"); break; + case RETURN_BIP: @; break; + case JUMP_BIP: WRITE("jump "); INV_A1; break; + case QUIT_BIP: WRITE("quit"); break; + case RESTORE_BIP: WRITE("restore "); INV_A1; break; + + case INDIRECT0_BIP: case INDIRECT0V_BIP: + WRITE("("); INV_A1; WRITE(")()"); break; + case INDIRECT1_BIP: case INDIRECT1V_BIP: + WRITE("("); INV_A1; WRITE(")("); + INV_A2; WRITE(")"); break; + case INDIRECT2_BIP: case INDIRECT2V_BIP: + WRITE("("); INV_A1; WRITE(")("); + INV_A2; WRITE(","); INV_A3; WRITE(")"); break; + case INDIRECT3_BIP: case INDIRECT3V_BIP: + WRITE("("); INV_A1; WRITE(")("); + INV_A2; WRITE(","); INV_A3; WRITE(","); INV_A4; WRITE(")"); break; + case INDIRECT4_BIP: case INDIRECT4V_BIP: + WRITE("("); INV_A1; WRITE(")("); + INV_A2; WRITE(","); INV_A3; WRITE(","); INV_A4; WRITE(","); + INV_A5; WRITE(")"); break; + case INDIRECT5_BIP: case INDIRECT5V_BIP: + WRITE("("); INV_A1; WRITE(")("); + INV_A2; WRITE(","); INV_A3; WRITE(","); INV_A4; WRITE(","); + INV_A5; WRITE(","); INV_A6; WRITE(")"); break; + case MESSAGE0_BIP: WRITE("("); INV_A1; WRITE("."); INV_A2; WRITE("())"); break; + case MESSAGE1_BIP: WRITE("("); INV_A1; WRITE("."); INV_A2; WRITE("("); + INV_A3; WRITE("))"); break; + case MESSAGE2_BIP: WRITE("("); INV_A1; WRITE("."); INV_A2; WRITE("("); + INV_A3; WRITE(","); INV_A4; WRITE("))"); break; + case MESSAGE3_BIP: WRITE("("); INV_A1; WRITE("."); INV_A2; WRITE("("); + INV_A3; WRITE(","); INV_A4; WRITE(","); INV_A5; WRITE("))"); break; + case CALLMESSAGE0_BIP: WRITE("("); INV_A1; WRITE(".call())"); break; + case CALLMESSAGE1_BIP: WRITE("("); INV_A1; WRITE(".call("); + INV_A2; WRITE("))"); break; + case CALLMESSAGE2_BIP: WRITE("("); INV_A1; WRITE(".call("); + INV_A2; WRITE(","); INV_A3; WRITE("))"); break; + case CALLMESSAGE3_BIP: WRITE("("); INV_A1; WRITE(".call("); + INV_A2; WRITE(","); INV_A3; WRITE(","); INV_A4; WRITE("))"); break; + + case SPACES_BIP: WRITE("spaces "); INV_A1; break; + case FONT_BIP: + WRITE("if ("); INV_A1; WRITE(") { font on; } else { font off; }"); + suppress_terminal_semicolon = TRUE; + break; + case STYLEROMAN_BIP: WRITE("style roman"); break; + case STYLEBOLD_BIP: WRITE("style bold"); break; + case STYLEUNDERLINE_BIP: WRITE("style underline"); break; + case STYLEREVERSE_BIP: WRITE("style reverse"); break; + + case MOVE_BIP: WRITE("move "); INV_A1; WRITE(" to "); INV_A2; break; + case REMOVE_BIP: WRITE("remove "); INV_A1; break; + case GIVE_BIP: WRITE("give "); INV_A1; WRITE(" "); INV_A2; break; + case TAKE_BIP: WRITE("give "); INV_A1; WRITE(" ~"); INV_A2; break; + + case ALTERNATIVECASE_BIP: INV_A1; WRITE(", "); INV_A2; break; + case SEQUENTIAL_BIP: WRITE("("); INV_A1; WRITE(","); INV_A2; WRITE(")"); break; + case TERNARYSEQUENTIAL_BIP: @; break; + + case PRINT_BIP: WRITE("print "); INV_A1_PRINTMODE; break; + case PRINTRET_BIP: INV_A1_PRINTMODE; break; + case PRINTCHAR_BIP: WRITE("print (char) "); INV_A1; break; + case PRINTNAME_BIP: WRITE("print (name) "); INV_A1; break; + case PRINTOBJ_BIP: WRITE("print (object) "); INV_A1; break; + case PRINTPROPERTY_BIP: WRITE("print (property) "); INV_A1; break; + case PRINTNUMBER_BIP: WRITE("print "); INV_A1; break; + case PRINTADDRESS_BIP: WRITE("print (address) "); INV_A1; break; + case PRINTSTRING_BIP: WRITE("print (string) "); INV_A1; break; + case PRINTNLNUMBER_BIP: WRITE("print (number) "); INV_A1; break; + case PRINTDEF_BIP: WRITE("print (the) "); INV_A1; break; + case PRINTCDEF_BIP: WRITE("print (The) "); INV_A1; break; + case PRINTINDEF_BIP: WRITE("print (a) "); INV_A1; break; + case PRINTCINDEF_BIP: WRITE("print (A) "); INV_A1; break; + case BOX_BIP: WRITE("box "); INV_A1_BOXMODE; break; + + case IF_BIP: @; break; + case IFDEBUG_BIP: @; break; + case IFSTRICT_BIP: @; break; + case IFELSE_BIP: @; break; + case WHILE_BIP: @; break; + case DO_BIP: @; break; + case FOR_BIP: @; break; + case OBJECTLOOP_BIP: @; break; + case OBJECTLOOPX_BIP: @; break; + case LOOP_BIP: @; break; + case SWITCH_BIP: @; break; + case CASE_BIP: @; break; + case DEFAULT_BIP: @; break; + + case RANDOM_BIP: WRITE("random("); INV_A1; WRITE(")"); break; + + case READ_BIP: WRITE("read "); INV_A1; WRITE(" "); INV_A2; break; + + default: LOG("Prim: %S\n", prim_name->symbol_name); internal_error("unimplemented prim"); + } + return suppress_terminal_semicolon; +} + +@ = + int rboolean = NOT_APPLICABLE; + inter_tree_node *V = InterTree::first_child(P); + if (V->W.data[ID_IFLD] == VAL_IST) { + inter_ti val1 = V->W.data[VAL1_VAL_IFLD]; + inter_ti val2 = V->W.data[VAL2_VAL_IFLD]; + if (val1 == LITERAL_IVAL) { + if (val2 == 0) rboolean = FALSE; + if (val2 == 1) rboolean = TRUE; + } + } + switch (rboolean) { + case FALSE: WRITE("rfalse"); break; + case TRUE: WRITE("rtrue"); break; + case NOT_APPLICABLE: WRITE("return "); CodeGen::FC::frame(gen, V); break; + } + + +@ Here we need some gymnastics. We need to produce a value which the +sometimes shaky I6 expression parser will accept, which turns out to be +quite a constraint. If we were compiling to C, we might try this: += (text as C) + (a, b, c) += +using the serial comma operator -- that is, where the expression |(a, b)| +evaluates |a| then |b| and returns the value of |b|, discarding |a|. +Now I6 does support the comma operator, and this makes a workable scheme, +right up to the point where some of the token values themselves include +invocations of functions, because I6's syntax analyser won't always +allow the serial comma to be mixed in the same expression with the +function argument comma, i.e., I6 is unable properly to handle expressions +like this one: += (text as C) + (a(b, c), d) += +where the first comma constructs a list and the second is the operator. +(Many such expressions work fine, but not all.) That being so, the scheme +I actually use is: += (text as C) + (c) + 0*((b) + (a)) += +Because I6 evaluates the leaves in an expression tree right-to-left, not +left-to-right, the parameter assignments happen first, then the conditions, +then the result. + + +@ = + WRITE("(\n"); INDENT; + WRITE("! This value evaluates third (i.e., last)\n"); INV_A3; + OUTDENT; WRITE("+\n"); INDENT; + WRITE("0*(\n"); INDENT; + WRITE("! The following condition evaluates second\n"); + WRITE("((\n"); INDENT; INV_A2; + OUTDENT; WRITE("\n))\n"); + OUTDENT; WRITE("+\n"); INDENT; + WRITE("! The following assignments evaluate first\n"); + WRITE("("); INV_A1; WRITE(")"); + OUTDENT; WRITE(")\n"); + OUTDENT; WRITE(")\n"); + +@ = + WRITE("if ("); INV_A1; WRITE(") {\n"); INDENT; INV_A2; + OUTDENT; WRITE("}\n"); + suppress_terminal_semicolon = TRUE; + +@ = + WRITE("#ifdef DEBUG;\n"); INDENT; INV_A1; OUTDENT; WRITE("#endif;\n"); + suppress_terminal_semicolon = TRUE; + +@ = + WRITE("#ifdef STRICT_MODE;\n"); INDENT; INV_A1; OUTDENT; WRITE("#endif;\n"); + suppress_terminal_semicolon = TRUE; + +@ = + WRITE("if ("); INV_A1; WRITE(") {\n"); INDENT; INV_A2; OUTDENT; + WRITE("} else {\n"); INDENT; INV_A3; OUTDENT; WRITE("}\n"); + suppress_terminal_semicolon = TRUE; + +@ = + WRITE("while ("); INV_A1; WRITE(") {\n"); INDENT; INV_A2; OUTDENT; WRITE("}\n"); + suppress_terminal_semicolon = TRUE; + +@ = + WRITE("do {"); INV_A2; WRITE("} until (\n"); INDENT; INV_A1; OUTDENT; WRITE(")\n"); + +@ = + WRITE("for ("); + inter_tree_node *INIT = InterTree::first_child(P); + if (!((INIT->W.data[ID_IFLD] == VAL_IST) && (INIT->W.data[VAL1_VAL_IFLD] == LITERAL_IVAL) && (INIT->W.data[VAL2_VAL_IFLD] == 1))) INV_A1; + WRITE(":"); INV_A2; + WRITE(":"); + inter_tree_node *U = InterTree::third_child(P); + if (U->W.data[ID_IFLD] != VAL_IST) + CodeGen::FC::frame(gen, U); + WRITE(") {\n"); INDENT; INV_A4; + OUTDENT; WRITE("}\n"); + suppress_terminal_semicolon = TRUE; + +@ = + int in_flag = FALSE; + inter_tree_node *U = InterTree::third_child(P); + if ((U->W.data[ID_IFLD] == INV_IST) && (U->W.data[METHOD_INV_IFLD] == INVOKED_PRIMITIVE)) { + inter_symbol *prim = Inter::Inv::invokee(U); + if ((prim) && (Primitives::to_bip(I, prim) == IN_BIP)) in_flag = TRUE; + } + + WRITE("objectloop "); + if (in_flag == FALSE) { + WRITE("("); INV_A1; WRITE(" ofclass "); INV_A2; + WRITE(" && "); + } INV_A3; + if (in_flag == FALSE) { + WRITE(")"); + } + WRITE(" {\n"); INDENT; INV_A4; + OUTDENT; WRITE("}\n"); + suppress_terminal_semicolon = TRUE; + +@ = + WRITE("objectloop ("); INV_A1; WRITE(" ofclass "); INV_A2; + WRITE(") {\n"); INDENT; INV_A3; OUTDENT; WRITE("}\n"); + suppress_terminal_semicolon = TRUE; + +@ = + WRITE("{\n"); INDENT; INV_A1; OUTDENT; WRITE("}\n"); + suppress_terminal_semicolon = TRUE; + +@ = + WRITE("switch ("); INV_A1; + WRITE(") {\n"); INDENT; INV_A2; OUTDENT; WRITE("}\n"); + suppress_terminal_semicolon = TRUE; + +@ = + INV_A1; WRITE(":\n"); INDENT; INV_A2; WRITE(";\n"); OUTDENT; + suppress_terminal_semicolon = TRUE; + +@ = + WRITE("default:\n"); INDENT; INV_A1; WRITE(";\n"); OUTDENT; + suppress_terminal_semicolon = TRUE; + +@ + += +void CodeGen::C::compile_dictionary_word(code_generation_target *cgt, code_generation *gen, + text_stream *S, int pluralise) { + text_stream *OUT = CodeGen::current(gen); + int n = 0; + WRITE("'"); + LOOP_THROUGH_TEXT(pos, S) { + wchar_t c = Str::get(pos); + switch(c) { + case '/': if (Str::len(S) == 1) WRITE("@{2F}"); else WRITE("/"); break; + case '\'': WRITE("^"); break; + case '^': WRITE("@{5E}"); break; + case '~': WRITE("@{7E}"); break; + case '@': WRITE("@{40}"); break; + default: PUT(c); + } + if (n++ > 32) break; + } + if (pluralise) WRITE("//p"); + else if (Str::len(S) == 1) WRITE("//"); + WRITE("'"); +} + +@ + += +void CodeGen::C::compile_literal_text(code_generation_target *cgt, code_generation *gen, + text_stream *S, int printing_mode, int box_mode) { + text_stream *OUT = CodeGen::current(gen); + WRITE("\""); + int esc_char = FALSE; + LOOP_THROUGH_TEXT(pos, S) { + wchar_t c = Str::get(pos); + if (box_mode) { + switch(c) { + case '@': WRITE("@{40}"); break; + case '"': WRITE("~"); break; + case '^': WRITE("@{5E}"); break; + case '~': WRITE("@{7E}"); break; + case '\\': WRITE("@{5C}"); break; + case '\t': WRITE(" "); break; + case '\n': WRITE("\"\n\""); break; + case NEWLINE_IN_STRING: WRITE("\"\n\""); break; + default: PUT(c); + } + } else { + switch(c) { + case '@': + if (printing_mode) { + WRITE("@@64"); esc_char = TRUE; continue; + } + WRITE("@{40}"); break; + case '"': WRITE("~"); break; + case '^': + if (printing_mode) { + WRITE("@@94"); esc_char = TRUE; continue; + } + WRITE("@{5E}"); break; + case '~': + if (printing_mode) { + WRITE("@@126"); esc_char = TRUE; continue; + } + WRITE("@{7E}"); break; + case '\\': WRITE("@{5C}"); break; + case '\t': WRITE(" "); break; + case '\n': WRITE("^"); break; + case NEWLINE_IN_STRING: WRITE("^"); break; + default: { + if (esc_char) WRITE("@{%02x}", c); + else PUT(c); + } + } + esc_char = FALSE; + } + } + WRITE("\""); +} + +@ Because in I6 source code some properties aren't declared before use, it follows +that if not used by any object then they won't ever be created. This is a +problem since it means that I6 code can't refer to them, because it would need +to mention an I6 symbol which doesn't exist. To get around this, we create the +property names which don't exist as constant symbols with the harmless value +0; we do this right at the end of the compiled I6 code. (This is a standard I6 +trick called "stubbing", these being "stub definitions".) + += +void CodeGen::C::declare_property(code_generation_target *cgt, code_generation *gen, + inter_symbol *prop_name, int used) { + text_stream *name = CodeGen::CL::name(prop_name); + if (used) { + generated_segment *saved = CodeGen::select(gen, attributes_at_eof_I7CGS); + WRITE_TO(CodeGen::current(gen), "Property %S;\n", prop_name->symbol_name); + CodeGen::deselect(gen, saved); + } else { + generated_segment *saved = CodeGen::select(gen, code_at_eof_I7CGS); + WRITE_TO(CodeGen::current(gen), "#ifndef %S; Constant %S = 0; #endif;\n", name, name); + CodeGen::deselect(gen, saved); + } +} + +@ + += +int CodeGen::C::prepare_variable(code_generation_target *cgt, code_generation *gen, + inter_tree_node *P, inter_symbol *var_name, int k) { + if (Inter::Symbols::read_annotation(var_name, EXPLICIT_VARIABLE_IANN) != 1) { + if (Inter::Symbols::read_annotation(var_name, ASSIMILATED_IANN) != 1) { + text_stream *S = Str::new(); + WRITE_TO(S, "(Global_Vars-->%d)", k); + Inter::Symbols::set_translate(var_name, S); + } + k++; + } + return k; +} + +int CodeGen::C::declare_variable(code_generation_target *cgt, code_generation *gen, + inter_tree_node *P, inter_symbol *var_name, int k, int of) { + if (Inter::Symbols::read_annotation(var_name, ASSIMILATED_IANN) == 1) { + generated_segment *saved = CodeGen::select(gen, main_matter_I7CGS); + text_stream *OUT = CodeGen::current(gen); + WRITE("int %S = ", CodeGen::CL::name(var_name)); + CodeGen::CL::literal(gen, NULL, Inter::Packages::scope_of(P), P->W.data[VAL1_VAR_IFLD], P->W.data[VAL2_VAR_IFLD], FALSE); + WRITE(";\n"); + CodeGen::deselect(gen, saved); + } + if (Inter::Symbols::read_annotation(var_name, EXPLICIT_VARIABLE_IANN) != 1) { + generated_segment *saved = CodeGen::select(gen, attributes_at_eof_I7CGS); + text_stream *OUT = CodeGen::current(gen); + if (k == 0) WRITE("Array Global_Vars -->\n"); + WRITE(" ("); + inter_symbols_table *globals = Inter::Packages::scope_of(P); + CodeGen::CL::literal(gen, NULL, globals, P->W.data[VAL1_VAR_IFLD], P->W.data[VAL2_VAR_IFLD], FALSE); + WRITE(") ! -->%d = %S (%S)\n", k, CodeGen::CL::name(var_name), var_name->symbol_name); + k++; + if (k == of) { + if (k < 2) WRITE(" NULL NULL"); + WRITE(";\n"); + } + CodeGen::deselect(gen, saved); + } + return k; +} + +void CodeGen::C::declare_local_variable(code_generation_target *cgt, code_generation *gen, + inter_tree_node *P, inter_symbol *var_name) { + text_stream *OUT = CodeGen::current(gen); + WRITE(" %S", var_name->symbol_name); +} + +void CodeGen::C::begin_constant(code_generation_target *cgt, code_generation *gen, text_stream *const_name, int continues) { + text_stream *OUT = CodeGen::current(gen); + WRITE("#define %S", const_name); + if (continues) WRITE(" "); +} +void CodeGen::C::end_constant(code_generation_target *cgt, code_generation *gen, text_stream *const_name) { + text_stream *OUT = CodeGen::current(gen); + WRITE(";\n"); +} + +void CodeGen::C::begin_function(code_generation_target *cgt, code_generation *gen, text_stream *fn_name) { + text_stream *OUT = CodeGen::current(gen); + WRITE("int %S(", fn_name); +} +void CodeGen::C::end_function(code_generation_target *cgt, code_generation *gen) { + text_stream *OUT = CodeGen::current(gen); + WRITE("}\n"); +} diff --git a/inter/codegen-module/Chapter 5/Final Inform 6.w b/inter/codegen-module/Chapter 5/Final Inform 6.w index 7fd6f7278..04226bd51 100644 --- a/inter/codegen-module/Chapter 5/Final Inform 6.w +++ b/inter/codegen-module/Chapter 5/Final Inform 6.w @@ -24,6 +24,8 @@ void CodeGen::I6::create_target(void) { METHOD_ADD(cgt, DECLARE_LOCAL_VARIABLE_MTID, CodeGen::I6::declare_local_variable); METHOD_ADD(cgt, BEGIN_CONSTANT_MTID, CodeGen::I6::begin_constant); METHOD_ADD(cgt, END_CONSTANT_MTID, CodeGen::I6::end_constant); + METHOD_ADD(cgt, BEGIN_FUNCTION_MTID, CodeGen::I6::begin_function); + METHOD_ADD(cgt, END_FUNCTION_MTID, CodeGen::I6::end_function); METHOD_ADD(cgt, OFFER_PRAGMA_MTID, CodeGen::I6::offer_pragma) inform6_target = cgt; } @@ -608,3 +610,12 @@ void CodeGen::I6::end_constant(code_generation_target *cgt, code_generation *gen text_stream *OUT = CodeGen::current(gen); WRITE(";\n"); } + +void CodeGen::I6::begin_function(code_generation_target *cgt, code_generation *gen, text_stream *fn_name) { + text_stream *OUT = CodeGen::current(gen); + WRITE("[ %S", fn_name); +} +void CodeGen::I6::end_function(code_generation_target *cgt, code_generation *gen) { + text_stream *OUT = CodeGen::current(gen); + WRITE("];"); +} diff --git a/inter/codegen-module/Chapter 5/Final Targets.w b/inter/codegen-module/Chapter 5/Final Targets.w index f32a7bb02..2700f0478 100644 --- a/inter/codegen-module/Chapter 5/Final Targets.w +++ b/inter/codegen-module/Chapter 5/Final Targets.w @@ -31,6 +31,7 @@ void CodeGen::Targets::make_targets(void) { CodeGen::Binary::create_target(); CodeGen::Inventory::create_target(); CodeGen::I6::create_target(); + CodeGen::C::create_target(); } } @@ -189,3 +190,18 @@ void CodeGen::Targets::begin_constant(code_generation *gen, text_stream *const_n void CodeGen::Targets::end_constant(code_generation *gen, text_stream *const_name) { VOID_METHOD_CALL(gen->target, END_CONSTANT_MTID, gen, const_name); } + +@ + +@e BEGIN_FUNCTION_MTID +@e END_FUNCTION_MTID + += +VOID_METHOD_TYPE(BEGIN_FUNCTION_MTID, code_generation_target *cgt, code_generation *gen, text_stream *fn_name) +VOID_METHOD_TYPE(END_FUNCTION_MTID, code_generation_target *cgt, code_generation *gen) +void CodeGen::Targets::begin_function(code_generation *gen, text_stream *fn_name) { + VOID_METHOD_CALL(gen->target, BEGIN_FUNCTION_MTID, gen, fn_name); +} +void CodeGen::Targets::end_function(code_generation *gen) { + VOID_METHOD_CALL(gen->target, END_FUNCTION_MTID, gen); +} diff --git a/inter/codegen-module/Contents.w b/inter/codegen-module/Contents.w index caa63d510..17ae2e3a0 100644 --- a/inter/codegen-module/Contents.w +++ b/inter/codegen-module/Contents.w @@ -59,3 +59,4 @@ Chapter 5: Final Code Final Binary Inter Final Inventory Final Inform 6 + Final C