├── module_bundle ├── chap1 │ ├── main.c │ ├── prog1.h │ ├── util.h │ ├── makefile │ ├── prog1.c │ ├── util.c │ ├── slp.h │ └── slp.c ├── testcases │ ├── test8.tig │ ├── compilation_error │ │ ├── test26.tig │ │ ├── test10.tig │ │ ├── test15.tig │ │ ├── test13.tig │ │ ├── test20.tig │ │ ├── test9.tig │ │ ├── test33.tig │ │ ├── test24.tig │ │ ├── test25.tig │ │ ├── test31.tig │ │ ├── test40.tig │ │ ├── test11.tig │ │ ├── test43.tig │ │ ├── test35.tig │ │ ├── test36.tig │ │ ├── test34.tig │ │ ├── test32.tig │ │ ├── test45.tig │ │ ├── test22.tig │ │ ├── test16.tig │ │ ├── test23.tig │ │ ├── test29.tig │ │ ├── test17.tig │ │ ├── test28.tig │ │ ├── test21.tig │ │ ├── test14.tig │ │ ├── test18.tig │ │ └── test19.tig │ ├── test12.tig │ ├── test27.tig │ ├── test41.tig │ ├── test46.tig │ ├── test1.tig │ ├── test30.tig │ ├── parse_error │ │ └── test49.tig │ ├── test44.tig │ ├── test2.tig │ ├── test3.tig │ ├── test37.tig │ ├── test4.tig │ ├── test38.tig │ ├── test6.tig │ ├── test39.tig │ ├── test7.tig │ ├── test47.tig │ ├── test5.tig │ ├── test48.tig │ ├── test42.tig │ ├── queens.tig │ └── merge.tig ├── chap4 │ ├── parse.h │ ├── prabsyn.h │ ├── parse.c │ ├── makefile │ ├── tiger.grm │ ├── table.h │ ├── symbol.h │ └── symbol.c ├── chap7 │ └── printtree.h ├── chap11 │ ├── regalloc.h │ └── color.h ├── chap2 │ ├── errormsg.h │ ├── util.h │ ├── makefile │ ├── tiger.lex │ ├── util.c │ ├── tokens.h │ ├── driver.c │ └── errormsg.c ├── chap3 │ ├── errormsg.h │ ├── util.h │ ├── parsetest.c │ ├── util.c │ ├── tiger.grm │ ├── makefile │ ├── y.output │ └── errormsg.c ├── chap10 │ └── flowgraph.h ├── chap6 │ └── temp.h ├── chap5 │ └── types.h └── chap9 │ └── assem.h ├── Chapter02 ├── Program.h ├── CMakeLists.txt └── Test.cpp ├── Chapter09 ├── MachineRegistration.h.in ├── test │ ├── nil.cpp │ ├── checkedCompile.cpp │ ├── integer.cpp │ ├── string.cpp │ ├── compileFiles.cpp │ ├── assignment.cpp │ ├── array.cpp │ ├── sequence.cpp │ ├── TestMain.cpp │ ├── arithmetic.cpp │ ├── CMakeLists.txt │ ├── functionCall.cpp │ ├── for.cpp │ └── record.cpp ├── Program.h ├── Fragment.h ├── x64 │ ├── CMakeLists.txt │ ├── x64CodeGenerator.h │ ├── x64Machine.h │ ├── x64CallingConvention.h │ ├── x64Registers.h │ ├── x64Frame.h │ ├── x64Frame.cpp │ └── x64CallingConvention.cpp ├── m68k │ ├── CMakeLists.txt │ ├── m68kRegisters.h │ ├── m68kCodeGenerator.h │ ├── m68kMachine.h │ ├── m68kCallingConvention.h │ ├── m68kFrame.h │ ├── m68kFrame.cpp │ ├── m68kMachine.cpp │ └── m68kCallingConvention.cpp ├── Skipper.h ├── Machine.h ├── Types.h ├── ErrorHandler.h ├── Frame.h ├── TempMap.h ├── MachineRegistrar.h ├── CallingConvention.h ├── CMakeLists.txt └── CallingConvention.cpp ├── Chapter10 ├── MachineRegistration.h.in ├── test │ ├── integer.cpp │ ├── nil.cpp │ ├── string.cpp │ ├── assignment.cpp │ ├── compileFiles.cpp │ ├── array.cpp │ ├── sequence.cpp │ ├── arithmetic.cpp │ ├── TestMain.cpp │ ├── CMakeLists.txt │ ├── record.cpp │ ├── functionCall.cpp │ └── for.cpp ├── Fragment.h ├── x64 │ ├── CMakeLists.txt │ ├── x64CodeGenerator.h │ ├── x64Machine.h │ ├── x64Frame.h │ ├── x64CallingConvention.h │ └── x64Registers.h ├── m68k │ ├── CMakeLists.txt │ ├── m68kRegisters.h │ ├── m68kCodeGenerator.h │ ├── m68kMachine.h │ ├── m68kFrame.h │ ├── m68kCallingConvention.h │ ├── m68kMachine.cpp │ └── m68kFrame.cpp ├── Skipper.h ├── Frame.cpp ├── Machine.h ├── Program.h ├── TempRegister.h ├── TempLabel.h ├── Types.h ├── FlowGraph.h ├── ErrorHandler.h ├── TempMap.h ├── Frame.h ├── MachineRegistrar.h ├── CallingConvention.h └── TempMap.cpp ├── book └── Modern Compiler Implementation in C.pdf ├── .gitignore ├── Chapter03 ├── Program.h ├── CMakeLists.txt ├── Skipper.h ├── ErrorHandler.h └── IdentifierParser.h ├── Chapter05 ├── Program.h ├── Skipper.h ├── CMakeLists.txt ├── Types.h └── ErrorHandler.h ├── Chapter06 ├── Program.h ├── CallingConvention.h ├── x64FastCall │ ├── CallingConvention.cpp │ ├── CallingConvention.h │ ├── Frame.cpp │ └── Frame.h ├── Translator.h ├── Skipper.h ├── EscapeAnalyser.h ├── Frame.h ├── Types.h ├── CMakeLists.txt ├── ErrorHandler.h ├── TempMap.h ├── Translator.cpp └── TempMap.cpp ├── Chapter04 ├── Program.h ├── Skipper.h ├── CMakeLists.txt └── ErrorHandler.h ├── Chapter01 └── CMakeLists.txt ├── include ├── CMakeLists.txt ├── irange.h ├── type_traits.h ├── printRange.h ├── testsHelper.h.in ├── variantMatch.h ├── fusionAccumulate.h ├── overload_set.h ├── strong_typedef.h └── vectorApply.h ├── Chapter07 ├── Fragment.h ├── Program.h ├── Skipper.h ├── Types.h ├── CMakeLists.txt ├── Frame.h ├── CallingConvention.h ├── x64FastCall │ ├── CallingConvention.h │ ├── Frame.h │ ├── Registers.h │ └── Frame.cpp ├── ErrorHandler.h ├── TempMap.h └── TempMap.cpp ├── Chapter08 ├── Fragment.h ├── Program.h ├── Skipper.h ├── Types.h ├── Frame.h ├── CallingConvention.h ├── x64FastCall │ ├── CallingConvention.h │ ├── Frame.h │ ├── Registers.h │ └── Frame.cpp ├── ErrorHandler.h ├── CMakeLists.txt ├── TempMap.h └── TempMap.cpp ├── .clang-format ├── README.md └── cmake └── CompilerWarnings.cmake /module_bundle/chap1/main.c: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /module_bundle/chap1/prog1.h: -------------------------------------------------------------------------------- 1 | A_stm prog(void); 2 | -------------------------------------------------------------------------------- /module_bundle/testcases/test8.tig: -------------------------------------------------------------------------------- 1 | /* correct if */ 2 | if (10 > 20) then 30 else 40 3 | -------------------------------------------------------------------------------- /Chapter02/Program.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | bool lexFile(const std::string &filename); -------------------------------------------------------------------------------- /module_bundle/chap4/parse.h: -------------------------------------------------------------------------------- 1 | /* function prototype from parse.c */ 2 | A_exp parse(string fname); 3 | 4 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test26.tig: -------------------------------------------------------------------------------- 1 | /* error : integer required */ 2 | 3 | 3 + "var" 4 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test10.tig: -------------------------------------------------------------------------------- 1 | /* error : body of while not unit */ 2 | while(10 > 5) do 5+6 3 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test15.tig: -------------------------------------------------------------------------------- 1 | /* error : if-then returns non unit */ 2 | 3 | if 20 then 3 4 | -------------------------------------------------------------------------------- /module_bundle/chap4/prabsyn.h: -------------------------------------------------------------------------------- 1 | /* function prototype from prabsyn.c */ 2 | void pr_exp(FILE *out, A_exp v, int d); 3 | 4 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test13.tig: -------------------------------------------------------------------------------- 1 | /* error: comparison of incompatible types */ 2 | 3 | 3 > "df" 4 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test20.tig: -------------------------------------------------------------------------------- 1 | /* error: undeclared variable i */ 2 | 3 | while 10 > 5 do (i+1;()) 4 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test9.tig: -------------------------------------------------------------------------------- 1 | /* error : types of then - else differ */ 2 | 3 | if (5>4) then 13 else " " 4 | -------------------------------------------------------------------------------- /Chapter09/MachineRegistration.h.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "MachineRegistrar.h" 3 | @MACHINE_INCLUDES@ 4 | 5 | @MACHINE_REGISTRATIONS@ -------------------------------------------------------------------------------- /Chapter10/MachineRegistration.h.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "MachineRegistrar.h" 3 | @MACHINE_INCLUDES@ 4 | 5 | @MACHINE_REGISTRATIONS@ -------------------------------------------------------------------------------- /module_bundle/chap7/printtree.h: -------------------------------------------------------------------------------- 1 | /* function prototype from printtree.c */ 2 | void printStmList (FILE *out, T_stmList stmList) ; 3 | 4 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test33.tig: -------------------------------------------------------------------------------- 1 | /* error : unknown type */ 2 | let 3 | var a:= rectype {} 4 | in 5 | 0 6 | end 7 | -------------------------------------------------------------------------------- /book/Modern Compiler Implementation in C.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvirtz/GreenTiger/HEAD/book/Modern Compiler Implementation in C.pdf -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test24.tig: -------------------------------------------------------------------------------- 1 | /* error : variable not array */ 2 | let 3 | var d:=0 4 | in 5 | d[3] 6 | end 7 | 8 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test25.tig: -------------------------------------------------------------------------------- 1 | /* error : variable not record */ 2 | let 3 | var d:=0 4 | in 5 | d.f 6 | end 7 | 8 | -------------------------------------------------------------------------------- /module_bundle/testcases/test12.tig: -------------------------------------------------------------------------------- 1 | /* valid for and let */ 2 | 3 | let 4 | var a:= 0 5 | in 6 | for i:=0 to 100 do (a:=a+1;()) 7 | end 8 | -------------------------------------------------------------------------------- /module_bundle/testcases/test27.tig: -------------------------------------------------------------------------------- 1 | /* locals hide globals */ 2 | let 3 | var a:=0 4 | 5 | function g(a:int):int = a 6 | in 7 | g(2) 8 | end 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Visual Studio 2015 cache/options directory 2 | .vs/ 3 | 4 | # VS Code 5 | .vscode/ 6 | 7 | # build folders 8 | _*/ 9 | build 10 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test31.tig: -------------------------------------------------------------------------------- 1 | /* error : type constraint and init value differ */ 2 | let 3 | var a:int := " " 4 | in 5 | a 6 | end 7 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test40.tig: -------------------------------------------------------------------------------- 1 | /* error : procedure returns value */ 2 | let 3 | function g(a:int) = a 4 | in 5 | g(2) 6 | end 7 | 8 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test11.tig: -------------------------------------------------------------------------------- 1 | /* error hi expr is not int, and index variable erroneously assigned to. */ 2 | for i:=10 to " " do 3 | i := i - 1 4 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test43.tig: -------------------------------------------------------------------------------- 1 | /* initialize with unit and causing type mismatch in addition */ 2 | 3 | let 4 | var a := () 5 | in 6 | a + 3 7 | end 8 | -------------------------------------------------------------------------------- /module_bundle/testcases/test41.tig: -------------------------------------------------------------------------------- 1 | /* local types hide global */ 2 | let 3 | type a = int 4 | in 5 | let 6 | type a = string 7 | in 8 | 0 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test35.tig: -------------------------------------------------------------------------------- 1 | /* error : formals are more then actuals */ 2 | let 3 | function g (a:int , b:string):int = a 4 | in 5 | g("one") 6 | end 7 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test36.tig: -------------------------------------------------------------------------------- 1 | /* error : formals are fewer then actuals */ 2 | let 3 | function g (a:int , b:string):int = a 4 | in 5 | g(3,"one",5) 6 | end 7 | -------------------------------------------------------------------------------- /module_bundle/testcases/test46.tig: -------------------------------------------------------------------------------- 1 | /* valid rec comparisons */ 2 | let 3 | type rectype = {name:string, id:int} 4 | var b:rectype := nil 5 | in 6 | b = nil; 7 | b <> nil 8 | end 9 | -------------------------------------------------------------------------------- /module_bundle/testcases/test1.tig: -------------------------------------------------------------------------------- 1 | /* an array type and an array variable */ 2 | let 3 | type arrtype = array of int 4 | var arr1:arrtype := arrtype [10] of 0 5 | in 6 | arr1 7 | end 8 | -------------------------------------------------------------------------------- /module_bundle/chap11/regalloc.h: -------------------------------------------------------------------------------- 1 | /* function prototype from regalloc.c */ 2 | struct RA_result {Temp_map coloring; AS_instrList il;}; 3 | struct RA_result RA_regAlloc(F_frame f, AS_instrList il); 4 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test34.tig: -------------------------------------------------------------------------------- 1 | /* error : formals and actuals have different types */ 2 | let 3 | function g (a:int , b:string):int = a 4 | in 5 | g("one", "two") 6 | end 7 | -------------------------------------------------------------------------------- /module_bundle/testcases/test30.tig: -------------------------------------------------------------------------------- 1 | /* synonyms are fine */ 2 | 3 | let 4 | type a = array of int 5 | type b = a 6 | 7 | var arr1:a := b [10] of 0 8 | in 9 | arr1[2] 10 | end 11 | -------------------------------------------------------------------------------- /Chapter03/Program.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace tiger { 5 | 6 | bool parseFile(const std::string &filename); 7 | 8 | bool parse(const std::string &string); 9 | 10 | } // namespace tiger -------------------------------------------------------------------------------- /module_bundle/testcases/parse_error/test49.tig: -------------------------------------------------------------------------------- 1 | /* error: syntax error, nil should not be preceded by type-id. */ 2 | let 3 | type rectype = {name:string, id:int} 4 | 5 | var a:= rectype nil 6 | in 7 | a 8 | end 9 | -------------------------------------------------------------------------------- /module_bundle/testcases/test44.tig: -------------------------------------------------------------------------------- 1 | /* valid nil initialization and assignment */ 2 | let 3 | 4 | type rectype = {name:string, id:int} 5 | var b:rectype := nil 6 | 7 | in 8 | 9 | b := nil 10 | 11 | end 12 | -------------------------------------------------------------------------------- /Chapter05/Program.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace tiger { 5 | 6 | bool compileFile(const std::string &filename); 7 | 8 | bool compile(const std::string &string); 9 | 10 | } // namespace tiger -------------------------------------------------------------------------------- /Chapter06/Program.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace tiger { 5 | 6 | bool compileFile(const std::string &filename); 7 | 8 | bool compile(const std::string &string); 9 | 10 | } // namespace tiger -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test32.tig: -------------------------------------------------------------------------------- 1 | /* error : initializing exp and array type differ */ 2 | 3 | let 4 | type arrayty = array of int 5 | 6 | var a := arrayty [10] of " " 7 | in 8 | 0 9 | end 10 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test45.tig: -------------------------------------------------------------------------------- 1 | /* error: initializing nil expressions not constrained by record type */ 2 | let 3 | type rectype = {name:string, id:int} 4 | 5 | var a:= nil 6 | in 7 | a 8 | end 9 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test22.tig: -------------------------------------------------------------------------------- 1 | /* error : field not in record type */ 2 | 3 | let 4 | type rectype = {name:string , id:int} 5 | var rec1 := rectype {name="Name", id=0} 6 | in 7 | rec1.nam := "asd" 8 | end 9 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test16.tig: -------------------------------------------------------------------------------- 1 | /* error: mutually recursive types thet do not pass through record or array */ 2 | let 3 | 4 | type a=c 5 | type b=a 6 | type c=d 7 | type d=a 8 | 9 | in 10 | "" 11 | end 12 | -------------------------------------------------------------------------------- /module_bundle/testcases/test2.tig: -------------------------------------------------------------------------------- 1 | /* arr1 is valid since expression 0 is int = myint */ 2 | let 3 | type myint = int 4 | type arrtype = array of myint 5 | 6 | var arr1:arrtype := arrtype [10] of 0 7 | in 8 | arr1 9 | end 10 | -------------------------------------------------------------------------------- /module_bundle/chap2/errormsg.h: -------------------------------------------------------------------------------- 1 | extern bool EM_anyErrors; 2 | 3 | void EM_newline(void); 4 | 5 | extern int EM_tokPos; 6 | 7 | void EM_error(int, string,...); 8 | void EM_impossible(string,...); 9 | void EM_reset(string filename); 10 | -------------------------------------------------------------------------------- /module_bundle/chap3/errormsg.h: -------------------------------------------------------------------------------- 1 | extern bool EM_anyErrors; 2 | 3 | void EM_newline(void); 4 | 5 | extern int EM_tokPos; 6 | 7 | void EM_error(int, string,...); 8 | void EM_impossible(string,...); 9 | void EM_reset(string filename); 10 | -------------------------------------------------------------------------------- /module_bundle/testcases/test3.tig: -------------------------------------------------------------------------------- 1 | /* a record type and a record variable */ 2 | let 3 | type rectype = {name:string, age:int} 4 | var rec1:rectype := rectype {name="Nobody", age=1000} 5 | in 6 | rec1.name := "Somebody"; 7 | rec1 8 | end 9 | -------------------------------------------------------------------------------- /module_bundle/testcases/test37.tig: -------------------------------------------------------------------------------- 1 | /* redeclaration of variable; this is legal, there are two different 2 | variables with the same name. The second one hides the first. */ 3 | let 4 | var a := 0 5 | var a := " " 6 | in 7 | 0 8 | end 9 | -------------------------------------------------------------------------------- /Chapter09/test/nil.cpp: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | TEST_CASE("nil") { 4 | OptLabel end; 5 | auto program = checkedCompile("nil"); 6 | checkProgram(program, checkMain(), checkMove(returnReg(), checkImm(0)), 7 | branchToEnd(end)); 8 | } -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test23.tig: -------------------------------------------------------------------------------- 1 | /* error : type mismatch */ 2 | 3 | let 4 | type rectype = {name:string , id:int} 5 | var rec1 := rectype {name="aname", id=0} 6 | in 7 | rec1.name := 3; 8 | rec1.id := "" 9 | end 10 | -------------------------------------------------------------------------------- /Chapter09/test/checkedCompile.cpp: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | #include "Program.h" 3 | #include 4 | 5 | std::string checkedCompile(const std::string &string) { 6 | auto res = tiger::compile(arch, string); 7 | REQUIRE(res); 8 | return *res; 9 | } -------------------------------------------------------------------------------- /Chapter09/test/integer.cpp: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | TEST_CASE("integer") { 4 | OptLabel end; 5 | auto program = checkedCompile("42"); 6 | checkProgram(program, checkMain(), checkMove(returnReg(), checkImm(42)), 7 | branchToEnd(end)); 8 | } -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test29.tig: -------------------------------------------------------------------------------- 1 | /* error : different array types */ 2 | 3 | let 4 | type arrtype1 = array of int 5 | type arrtype2 = array of int 6 | 7 | var arr1: arrtype1 := arrtype2 [10] of 0 8 | in 9 | arr1 10 | end 11 | -------------------------------------------------------------------------------- /module_bundle/testcases/test4.tig: -------------------------------------------------------------------------------- 1 | /* define a recursive function */ 2 | let 3 | 4 | /* calculate n! */ 5 | function nfactor(n: int): int = 6 | if n = 0 7 | then 1 8 | else n * nfactor(n-1) 9 | 10 | in 11 | nfactor(10) 12 | end 13 | 14 | -------------------------------------------------------------------------------- /module_bundle/chap10/flowgraph.h: -------------------------------------------------------------------------------- 1 | /* 2 | * flowgraph.h - Function prototypes to represent control flow graphs. 3 | */ 4 | 5 | Temp_tempList FG_def(G_node n); 6 | Temp_tempList FG_use(G_node n); 7 | bool FG_isMove(G_node n); 8 | G_graph FG_AssemFlowGraph(AS_instrList il); 9 | -------------------------------------------------------------------------------- /module_bundle/testcases/test38.tig: -------------------------------------------------------------------------------- 1 | /* This is illegal, since there are two types with the same name 2 | in the same (consecutive) batch of mutually recursive types. 3 | See also test47 */ 4 | let 5 | type a = int 6 | type a = string 7 | in 8 | 0 9 | end 10 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test17.tig: -------------------------------------------------------------------------------- 1 | /* error: definition of recursive types is interrupted */ 2 | let 3 | /* define a tree */ 4 | type tree ={key: int, children: treelist} 5 | var d:int :=0 6 | type treelist = {hd: tree, tl: treelist} 7 | 8 | in 9 | d 10 | end 11 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test28.tig: -------------------------------------------------------------------------------- 1 | /* error : different record types */ 2 | 3 | let 4 | type rectype1 = {name:string , id:int} 5 | type rectype2 = {name:string , id:int} 6 | 7 | var rec1: rectype1 := rectype2 {name="Name", id=0} 8 | in 9 | rec1 10 | end 11 | -------------------------------------------------------------------------------- /Chapter04/Program.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "AbstractSyntaxTree.h" 3 | #include 4 | 5 | namespace tiger { 6 | 7 | bool parseFile(const std::string &filename, ast::Expression &ast); 8 | 9 | bool parse(const std::string &string, ast::Expression &ast); 10 | 11 | } // namespace tiger -------------------------------------------------------------------------------- /module_bundle/testcases/test6.tig: -------------------------------------------------------------------------------- 1 | /* define valid mutually recursive procedures */ 2 | let 3 | 4 | function do_nothing1(a: int, b: string)= 5 | do_nothing2(a+1) 6 | 7 | function do_nothing2(d: int) = 8 | do_nothing1(d, "str") 9 | 10 | in 11 | do_nothing1(0, "str2") 12 | end 13 | 14 | -------------------------------------------------------------------------------- /module_bundle/testcases/test39.tig: -------------------------------------------------------------------------------- 1 | /* This is illegal, since there are two functions with the same name 2 | in the same (consecutive) batch of mutually recursive functions. 3 | See also test48 */ 4 | let 5 | function g(a:int):int = a 6 | function g(a:int):int = a 7 | in 8 | 0 9 | end 10 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test21.tig: -------------------------------------------------------------------------------- 1 | /* error : procedure returns value and procedure is used in arexpr */ 2 | let 3 | 4 | /* calculate n! */ 5 | function nfactor(n: int) = 6 | if n = 0 7 | then 1 8 | else n * nfactor(n-1) 9 | 10 | in 11 | nfactor(10) 12 | end 13 | 14 | -------------------------------------------------------------------------------- /module_bundle/testcases/test7.tig: -------------------------------------------------------------------------------- 1 | /* define valid mutually recursive functions */ 2 | let 3 | 4 | function do_nothing1(a: int, b: string):int= 5 | (do_nothing2(a+1);0) 6 | 7 | function do_nothing2(d: int):string = 8 | (do_nothing1(d, "str");" ") 9 | 10 | in 11 | do_nothing1(0, "str2") 12 | end 13 | 14 | -------------------------------------------------------------------------------- /Chapter10/test/integer.cpp: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | TEST_CASE_METHOD(TestFixture, "integer") { 4 | OptLabel end; 5 | OptIndex endIndex; 6 | auto results = checkedCompile("42"); 7 | checkProgram(results, checkMain(), checkMove(returnReg(), 42), 8 | branchToEnd(end, endIndex), checkFunctionExit()); 9 | } -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test14.tig: -------------------------------------------------------------------------------- 1 | /* error : compare rec with array */ 2 | 3 | let 4 | 5 | type arrtype = array of int 6 | type rectype = {name:string, id: int} 7 | 8 | var rec := rectype {name="aname", id=0} 9 | var arr := arrtype [3] of 0 10 | 11 | in 12 | if rec <> arr then 3 else 4 13 | end 14 | -------------------------------------------------------------------------------- /module_bundle/chap11/color.h: -------------------------------------------------------------------------------- 1 | /* 2 | * color.h - Data structures and function prototypes for coloring algorithm 3 | * to determine register allocation. 4 | */ 5 | 6 | struct COL_result {Temp_map coloring; Temp_tempList spills;}; 7 | struct COL_result COL_color(G_graph ig, Temp_map initial, Temp_tempList regs); 8 | 9 | 10 | -------------------------------------------------------------------------------- /module_bundle/testcases/test47.tig: -------------------------------------------------------------------------------- 1 | /* This is legal. The second type "a" simply hides the first one. 2 | Because of the intervening variable declaration, the two "a" types 3 | are not in the same batch of mutually recursive types. 4 | See also test38 */ 5 | let 6 | type a = int 7 | var b := 4 8 | type a = string 9 | in 10 | 0 11 | end 12 | -------------------------------------------------------------------------------- /module_bundle/testcases/test5.tig: -------------------------------------------------------------------------------- 1 | /* define valid recursive types */ 2 | let 3 | /* define a list */ 4 | type intlist = {hd: int, tl: intlist} 5 | 6 | /* define a tree */ 7 | type tree ={key: int, children: treelist} 8 | type treelist = {hd: tree, tl: treelist} 9 | 10 | var lis:intlist := intlist { hd=0, tl= nil } 11 | 12 | in 13 | lis 14 | end 15 | -------------------------------------------------------------------------------- /Chapter06/CallingConvention.h: -------------------------------------------------------------------------------- 1 | #include "Frame.h" 2 | 3 | namespace tiger { 4 | class CallingConvention { 5 | public: 6 | virtual std::unique_ptr createFrame(TempMap &tempMap, 7 | const Label &name, 8 | const BoolList &formals) = 0; 9 | }; 10 | } // namespace tiger 11 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test18.tig: -------------------------------------------------------------------------------- 1 | /* error : definition of recursive functions is interrupted */ 2 | let 3 | 4 | function do_nothing1(a: int, b: string):int= 5 | (do_nothing2(a+1);0) 6 | 7 | var d:=0 8 | 9 | function do_nothing2(d: int):string = 10 | (do_nothing1(d, "str");" ") 11 | 12 | in 13 | do_nothing1(0, "str2") 14 | end 15 | 16 | -------------------------------------------------------------------------------- /module_bundle/testcases/compilation_error/test19.tig: -------------------------------------------------------------------------------- 1 | /* error : second function uses variables local to the first one, undeclared variable */ 2 | let 3 | 4 | function do_nothing1(a: int, b: string):int= 5 | (do_nothing2(a+1);0) 6 | 7 | function do_nothing2(d: int):string = 8 | (do_nothing1(a, "str");" ") 9 | 10 | in 11 | do_nothing1(0, "str2") 12 | end 13 | 14 | -------------------------------------------------------------------------------- /Chapter01/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES Program.cpp Exercises.inl Test.cpp) 2 | set(HEADERS Program.h Exercises.h) 3 | 4 | add_executable(Chapter01 ${HEADERS} ${SOURCES}) 5 | 6 | target_compile_definitions(Chapter01 PRIVATE CATCH_CPP14_OR_GREATER) 7 | 8 | target_link_libraries(Chapter01 PRIVATE Boost::boost Catch2::Catch includeHeaders) 9 | 10 | parse_unit_tests(Chapter01) -------------------------------------------------------------------------------- /module_bundle/chap1/util.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef char *string; 4 | typedef char bool; 5 | 6 | #define TRUE 1 7 | #define FALSE 0 8 | 9 | void *checked_malloc(int); 10 | string String(char *); 11 | 12 | typedef struct U_boolList_ *U_boolList; 13 | struct U_boolList_ {bool head; U_boolList tail;}; 14 | U_boolList U_BoolList(bool head, U_boolList tail); 15 | 16 | -------------------------------------------------------------------------------- /module_bundle/chap2/util.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef char *string; 4 | typedef char bool; 5 | 6 | #define TRUE 1 7 | #define FALSE 0 8 | 9 | void *checked_malloc(int); 10 | string String(char *); 11 | 12 | typedef struct U_boolList_ *U_boolList; 13 | struct U_boolList_ {bool head; U_boolList tail;}; 14 | U_boolList U_BoolList(bool head, U_boolList tail); 15 | 16 | -------------------------------------------------------------------------------- /module_bundle/chap3/util.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef char *string; 4 | typedef char bool; 5 | 6 | #define TRUE 1 7 | #define FALSE 0 8 | 9 | void *checked_malloc(int); 10 | string String(char *); 11 | 12 | typedef struct U_boolList_ *U_boolList; 13 | struct U_boolList_ {bool head; U_boolList tail;}; 14 | U_boolList U_BoolList(bool head, U_boolList tail); 15 | 16 | -------------------------------------------------------------------------------- /Chapter09/test/string.cpp: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | TEST_CASE("string") { 4 | auto str = R"("\tHello \"World\"!\n")"; 5 | auto program = checkedCompile(str); 6 | OptLabel stringLabel, end; 7 | checkProgram(program, checkStringInit(stringLabel, str), checkMain(), 8 | checkMove(returnReg(), checkString(stringLabel)), 9 | branchToEnd(end)); 10 | } -------------------------------------------------------------------------------- /Chapter10/test/nil.cpp: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | TEST_CASE_METHOD(TestFixture, "nil") { 4 | OptReg rv = returnReg(); 5 | OptLabel end; 6 | OptIndex endIndex; 7 | auto results = checkedCompile("nil"); 8 | checkProgram(results, checkMain(), checkMove(rv, 0), branchToEnd(end, endIndex), 9 | checkFunctionExit()); 10 | checkInterference(results.m_interferenceGraphs); 11 | } -------------------------------------------------------------------------------- /module_bundle/testcases/test48.tig: -------------------------------------------------------------------------------- 1 | /* This is legal. The second function "g" simply hides the first one. 2 | Because of the intervening variable declaration, the two "g" functions 3 | are not in the same batch of mutually recursive functions. 4 | See also test39 */ 5 | let 6 | function g(a:int):int = a 7 | type t = int 8 | function g(a:int):int = a 9 | in 10 | 0 11 | end 12 | -------------------------------------------------------------------------------- /module_bundle/chap1/makefile: -------------------------------------------------------------------------------- 1 | a.out: main.o prog1.o slp.o util.o 2 | cc -g main.o prog1.o slp.o util.o 3 | 4 | main.o: main.c slp.h util.h 5 | cc -g -c main.c 6 | 7 | prog1.o: prog1.c slp.h util.h 8 | cc -g -c prog1.c 9 | 10 | slp.o: slp.c slp.h util.h 11 | cc -g -c slp.c 12 | 13 | util.o: util.c util.h 14 | cc -g -c util.c 15 | 16 | clean: 17 | rm -f a.out util.o prog1.o slp.o main.o 18 | -------------------------------------------------------------------------------- /Chapter06/x64FastCall/CallingConvention.cpp: -------------------------------------------------------------------------------- 1 | #include "CallingConvention.h" 2 | #include "Frame.h" 3 | 4 | namespace tiger { 5 | 6 | std::unique_ptr 7 | x64FastCallCallingConvention::createFrame(TempMap &tempMap, const Label &name, 8 | const BoolList &formals) { 9 | return std::make_unique(tempMap, name, formals); 10 | } 11 | 12 | } // namespace tiger 13 | -------------------------------------------------------------------------------- /Chapter02/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES Program.cpp Test.cpp) 2 | set(HEADERS Program.h) 3 | 4 | add_executable(Chapter02 ${HEADERS} ${SOURCES}) 5 | 6 | target_compile_definitions(Chapter02 PRIVATE CATCH_CPP14_OR_GREATER) 7 | 8 | target_link_libraries(Chapter02 9 | PRIVATE 10 | Boost::boost 11 | Boost::filesystem 12 | Boost::system 13 | Catch2::Catch 14 | includeHeaders) 15 | 16 | parse_unit_tests(Chapter02) -------------------------------------------------------------------------------- /Chapter09/Program.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Assembly.h" 3 | #include "Fragment.h" 4 | #include 5 | #include 6 | 7 | namespace tiger { 8 | 9 | using CompileResult = boost::optional; 10 | 11 | CompileResult compileFile(const std::string &arch, const std::string &filename); 12 | 13 | CompileResult compile(const std::string &arch, const std::string &string); 14 | 15 | } // namespace tiger 16 | -------------------------------------------------------------------------------- /Chapter02/Test.cpp: -------------------------------------------------------------------------------- 1 | #include "Program.h" 2 | #include "testsHelper.h" 3 | #define CATCH_CONFIG_MAIN 4 | #include 5 | 6 | TEST_CASE("lex test files") { 7 | namespace fs = boost::filesystem; 8 | tiger::forEachTigerTest([](const fs::path &filepath, bool /*parseError*/, 9 | bool /*compilationError*/) { 10 | auto filename = filepath.filename(); 11 | CAPTURE(filename); 12 | REQUIRE(lexFile(filepath.string())); 13 | }); 14 | } -------------------------------------------------------------------------------- /Chapter06/x64FastCall/CallingConvention.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../CallingConvention.h" 4 | 5 | namespace tiger { 6 | class x64FastCallCallingConvention : public CallingConvention { 7 | public: 8 | // Inherited via CallingConvention 9 | virtual std::unique_ptr createFrame(TempMap &tempMap, 10 | const Label &name, 11 | const BoolList &formals) override; 12 | }; 13 | } // namespace tiger 14 | -------------------------------------------------------------------------------- /module_bundle/chap3/parsetest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "util.h" 3 | #include "errormsg.h" 4 | 5 | extern int yyparse(void); 6 | 7 | void parse(string fname) 8 | {EM_reset(fname); 9 | if (yyparse() == 0) /* parsing worked */ 10 | fprintf(stderr,"Parsing successful!\n"); 11 | else fprintf(stderr,"Parsing failed\n"); 12 | } 13 | 14 | 15 | int main(int argc, char **argv) { 16 | if (argc!=2) {fprintf(stderr,"usage: a.out filename\n"); exit(1);} 17 | parse(argv[1]); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /Chapter10/test/string.cpp: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | TEST_CASE_METHOD(TestFixture, "string") { 4 | auto str = R"("\tHello \"World\"!\n")"; 5 | auto results = checkedCompile(str); 6 | OptLabel stringLabel, end; 7 | OptIndex stringLabelIndex, endIndex; 8 | checkProgram(results, checkStringInit(stringLabel, str, stringLabelIndex), checkMain(), 9 | checkMove(checkReg(returnReg()), checkString(stringLabel), {}, {returnReg()}), 10 | branchToEnd(end, endIndex), checkFunctionExit()); 11 | } -------------------------------------------------------------------------------- /include/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(HEADERS testsHelper.h.in overload_set.h variantMatch.h fusionAccumulate.h strong_typedef.h vectorApply.h type_traits.h warning_suppress.h) 2 | 3 | add_custom_target(include SOURCES ${HEADERS}) 4 | 5 | add_library(includeHeaders INTERFACE) 6 | 7 | set(TESTS_LOCATION ${CMAKE_SOURCE_DIR}/module_bundle/testcases) 8 | configure_file(testsHelper.h.in ${CMAKE_CURRENT_BINARY_DIR}/testsHelper.h) 9 | 10 | target_include_directories(includeHeaders INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) -------------------------------------------------------------------------------- /Chapter07/Fragment.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Tree.h" 3 | #include 4 | 5 | namespace tiger { 6 | 7 | namespace frame { 8 | class Frame; 9 | } 10 | 11 | struct StringFragment { 12 | temp::Label m_label; 13 | std::string m_string; 14 | }; 15 | 16 | struct FunctionFragment { 17 | ir::Statement m_body; 18 | std::shared_ptr m_frame; 19 | }; 20 | 21 | using Fragment = boost::variant; 22 | using FragmentList = std::vector; 23 | } // namespace tiger 24 | -------------------------------------------------------------------------------- /Chapter08/Fragment.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Tree.h" 3 | #include 4 | 5 | namespace tiger { 6 | 7 | namespace frame { 8 | class Frame; 9 | } 10 | 11 | struct StringFragment { 12 | temp::Label m_label; 13 | std::string m_string; 14 | }; 15 | 16 | struct FunctionFragment { 17 | ir::Statement m_body; 18 | std::shared_ptr m_frame; 19 | }; 20 | 21 | using Fragment = boost::variant; 22 | using FragmentList = std::vector; 23 | } // namespace tiger 24 | -------------------------------------------------------------------------------- /Chapter09/Fragment.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Tree.h" 3 | #include 4 | 5 | namespace tiger { 6 | 7 | namespace frame { 8 | class Frame; 9 | } 10 | 11 | struct StringFragment { 12 | temp::Label m_label; 13 | std::string m_string; 14 | }; 15 | 16 | struct FunctionFragment { 17 | ir::Statement m_body; 18 | std::shared_ptr m_frame; 19 | }; 20 | 21 | using Fragment = boost::variant; 22 | using FragmentList = std::vector; 23 | } // namespace tiger 24 | -------------------------------------------------------------------------------- /Chapter10/Fragment.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Tree.h" 3 | #include 4 | 5 | namespace tiger { 6 | 7 | namespace frame { 8 | class Frame; 9 | } 10 | 11 | struct StringFragment { 12 | temp::Label m_label; 13 | std::string m_string; 14 | }; 15 | 16 | struct FunctionFragment { 17 | ir::Statement m_body; 18 | std::shared_ptr m_frame; 19 | }; 20 | 21 | using Fragment = boost::variant; 22 | using FragmentList = std::vector; 23 | } // namespace tiger 24 | -------------------------------------------------------------------------------- /module_bundle/chap4/parse.c: -------------------------------------------------------------------------------- 1 | /* 2 | * parse.c - Parse source file. 3 | */ 4 | 5 | #include 6 | #include "util.h" 7 | #include "symbol.h" 8 | #include "absyn.h" 9 | #include "errormsg.h" 10 | #include "parse.h" 11 | 12 | extern int yyparse(void); 13 | extern A_exp absyn_root; 14 | 15 | /* parse source file fname; 16 | return abstract syntax data structure */ 17 | A_exp parse(string fname) 18 | {EM_reset(fname); 19 | if (yyparse() == 0) /* parsing worked */ 20 | return absyn_root; 21 | else return NULL; 22 | } 23 | -------------------------------------------------------------------------------- /Chapter08/Program.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Fragment.h" 3 | #include "Tree.h" 4 | #include 5 | #include 6 | 7 | namespace tiger { 8 | 9 | using CompileResult = boost::optional; 10 | 11 | CompileResult compileFile(const std::string &filename); 12 | 13 | CompileResult compile(const std::string &string); 14 | 15 | std::ostream & 16 | operator<<(std::ostream &ost, 17 | std::pair const &compileResult); 18 | 19 | } // namespace tiger 20 | -------------------------------------------------------------------------------- /Chapter09/x64/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES x64Frame.cpp x64CallingConvention.cpp x64CodeGenerator.cpp x64Machine.cpp) 2 | set(HEADERS x64Frame.h x64CallingConvention.h x64CodeGenerator.h x64Registers.h x64Machine.h) 3 | 4 | add_library(${CHAPTER}_x64 ${HEADERS} ${SOURCES}) 5 | 6 | set_target_properties(${CHAPTER}_x64 PROPERTIES OUTPUT_NAME x64) 7 | 8 | target_include_directories(${CHAPTER}_x64 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..) 9 | 10 | target_link_libraries(${CHAPTER}_x64 11 | PRIVATE 12 | includeHeaders 13 | Boost::boost 14 | ) -------------------------------------------------------------------------------- /Chapter10/x64/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES x64Frame.cpp x64CallingConvention.cpp x64CodeGenerator.cpp x64Machine.cpp) 2 | set(HEADERS x64Frame.h x64CallingConvention.h x64CodeGenerator.h x64Registers.h x64Machine.h) 3 | 4 | add_library(${CHAPTER}_x64 ${HEADERS} ${SOURCES}) 5 | 6 | set_target_properties(${CHAPTER}_x64 PROPERTIES OUTPUT_NAME x64) 7 | 8 | target_include_directories(${CHAPTER}_x64 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..) 9 | 10 | target_link_libraries(${CHAPTER}_x64 11 | PRIVATE 12 | includeHeaders 13 | Boost::boost 14 | ) -------------------------------------------------------------------------------- /module_bundle/chap2/makefile: -------------------------------------------------------------------------------- 1 | lextest: driver.o lex.yy.o errormsg.o util.o 2 | cc -g -o lextest driver.o lex.yy.o errormsg.o util.o 3 | 4 | driver.o: driver.c tokens.h errormsg.h util.h 5 | cc -g -c driver.c 6 | 7 | errormsg.o: errormsg.c errormsg.h util.h 8 | cc -g -c errormsg.c 9 | 10 | lex.yy.o: lex.yy.c tokens.h errormsg.h util.h 11 | cc -g -c lex.yy.c 12 | 13 | lex.yy.c: tiger.lex 14 | lex tiger.lex 15 | 16 | util.o: util.c util.h 17 | cc -g -c util.c 18 | 19 | clean: 20 | rm -f a.out util.o driver.o lex.yy.o lex.yy.c errormsg.o 21 | -------------------------------------------------------------------------------- /Chapter09/m68k/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES m68kFrame.cpp m68kCallingConvention.cpp m68kCodeGenerator.cpp m68kMachine.cpp) 2 | set(HEADERS m68kFrame.h m68kCallingConvention.h m68kCodeGenerator.h m68kRegisters.h m68kMachine.h) 3 | 4 | add_library(${CHAPTER}_m68k ${HEADERS} ${SOURCES}) 5 | 6 | set_target_properties(${CHAPTER}_m68k PROPERTIES OUTPUT_NAME m68k) 7 | 8 | target_include_directories(${CHAPTER}_m68k PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..) 9 | 10 | target_link_libraries(${CHAPTER}_m68k 11 | PRIVATE 12 | includeHeaders 13 | Boost::boost 14 | ) -------------------------------------------------------------------------------- /Chapter10/m68k/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES m68kFrame.cpp m68kCallingConvention.cpp m68kCodeGenerator.cpp m68kMachine.cpp) 2 | set(HEADERS m68kFrame.h m68kCallingConvention.h m68kCodeGenerator.h m68kRegisters.h m68kMachine.h) 3 | 4 | add_library(${CHAPTER}_m68k ${HEADERS} ${SOURCES}) 5 | 6 | set_target_properties(${CHAPTER}_m68k PROPERTIES OUTPUT_NAME m68k) 7 | 8 | target_include_directories(${CHAPTER}_m68k PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..) 9 | 10 | target_link_libraries(${CHAPTER}_m68k 11 | PRIVATE 12 | includeHeaders 13 | Boost::boost 14 | ) -------------------------------------------------------------------------------- /module_bundle/chap1/prog1.c: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | #include "slp.h" 3 | 4 | A_stm prog(void) { 5 | 6 | return 7 | A_CompoundStm(A_AssignStm("a", 8 | A_OpExp(A_NumExp(5), A_plus, A_NumExp(3))), 9 | A_CompoundStm(A_AssignStm("b", 10 | A_EseqExp(A_PrintStm(A_PairExpList(A_IdExp("a"), 11 | A_LastExpList(A_OpExp(A_IdExp("a"), A_minus, 12 | A_NumExp(1))))), 13 | A_OpExp(A_NumExp(10), A_times, A_IdExp("a")))), 14 | A_PrintStm(A_LastExpList(A_IdExp("b"))))); 15 | } 16 | -------------------------------------------------------------------------------- /Chapter07/Program.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Fragment.h" 3 | #include "Tree.h" 4 | #include 5 | #include 6 | 7 | namespace tiger { 8 | 9 | using CompileResult = boost::optional>; 10 | 11 | CompileResult compileFile(const std::string &filename); 12 | 13 | CompileResult compile(const std::string &string); 14 | 15 | std::ostream & 16 | operator<<(std::ostream &ost, 17 | std::pair const &compileResult); 18 | 19 | } // namespace tiger 20 | -------------------------------------------------------------------------------- /Chapter03/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES Program.cpp Test.cpp) 2 | set(HEADERS Program.h ErrorHandler.h ExpressionParser.h Skipper.h IdentifierParser.h DeclerationParser.h) 3 | 4 | add_executable(Chapter03 ${HEADERS} ${SOURCES}) 5 | 6 | target_compile_definitions(Chapter03 PRIVATE CATCH_CPP14_OR_GREATER $<$:BOOST_SPIRIT_DEBUG>) 7 | 8 | target_link_libraries(Chapter03 9 | PRIVATE 10 | Boost::boost 11 | Boost::filesystem 12 | Boost::system 13 | Catch2::Catch 14 | includeHeaders) 15 | 16 | parse_unit_tests(Chapter03) -------------------------------------------------------------------------------- /module_bundle/chap2/tiger.lex: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include "util.h" 4 | #include "tokens.h" 5 | #include "errormsg.h" 6 | 7 | int charPos=1; 8 | 9 | int yywrap(void) 10 | { 11 | charPos=1; 12 | return 1; 13 | } 14 | 15 | 16 | void adjust(void) 17 | { 18 | EM_tokPos=charPos; 19 | charPos+=yyleng; 20 | } 21 | 22 | %} 23 | 24 | %% 25 | " " {adjust(); continue;} 26 | \n {adjust(); EM_newline(); continue;} 27 | "," {adjust(); return COMMA;} 28 | for {adjust(); return FOR;} 29 | [0-9]+ {adjust(); yylval.ival=atoi(yytext); return INT;} 30 | . {adjust(); EM_error(EM_tokPos,"illegal token");} 31 | 32 | 33 | -------------------------------------------------------------------------------- /Chapter10/test/assignment.cpp: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | TEST_CASE_METHOD(TestFixture, "assignment") { 4 | auto results = checkedCompile(R"( 5 | let 6 | var a := 3 7 | var b := 0 8 | in 9 | b := a 10 | end 11 | )"); 12 | OptReg a, b; 13 | OptLabel end; 14 | OptIndex endIndex; 15 | checkProgram(results, checkMain(), checkMove(a, 3), // move 3 to a 16 | checkMove(b, 0, {a}), // move 0 to b 17 | checkMove(b, a), // move a to b 18 | checkMove(returnReg(), 0), // return 0 19 | branchToEnd(end, endIndex), checkFunctionExit()); 20 | } -------------------------------------------------------------------------------- /include/irange.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #ifdef _MSC_VER 4 | #include 5 | #else 6 | #include 7 | #endif 8 | 9 | namespace tiger { 10 | 11 | template constexpr auto irange(I begin, S end) { 12 | #ifdef _MSC_VER 13 | return boost::make_iterator_range(begin, end); 14 | #else 15 | return ranges::make_iterator_range(begin, end); 16 | #endif 17 | } 18 | 19 | template constexpr auto irange(std::pair iterator_pair) { 20 | return tiger::irange(iterator_pair.first, iterator_pair.second); 21 | } 22 | 23 | } // namespace tiger -------------------------------------------------------------------------------- /module_bundle/chap1/util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * util.c - commonly used utility functions. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include "util.h" 9 | void *checked_malloc(int len) 10 | {void *p = malloc(len); 11 | if (!p) { 12 | fprintf(stderr,"\nRan out of memory!\n"); 13 | exit(1); 14 | } 15 | return p; 16 | } 17 | 18 | string String(char *s) 19 | {string p = checked_malloc(strlen(s)+1); 20 | strcpy(p,s); 21 | return p; 22 | } 23 | 24 | U_boolList U_BoolList(bool head, U_boolList tail) 25 | { U_boolList list = checked_malloc(sizeof(*list)); 26 | list->head = head; 27 | list->tail = tail; 28 | return list; 29 | } 30 | -------------------------------------------------------------------------------- /module_bundle/chap2/util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * util.c - commonly used utility functions. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include "util.h" 9 | void *checked_malloc(int len) 10 | {void *p = malloc(len); 11 | if (!p) { 12 | fprintf(stderr,"\nRan out of memory!\n"); 13 | exit(1); 14 | } 15 | return p; 16 | } 17 | 18 | string String(char *s) 19 | {string p = checked_malloc(strlen(s)+1); 20 | strcpy(p,s); 21 | return p; 22 | } 23 | 24 | U_boolList U_BoolList(bool head, U_boolList tail) 25 | { U_boolList list = checked_malloc(sizeof(*list)); 26 | list->head = head; 27 | list->tail = tail; 28 | return list; 29 | } 30 | -------------------------------------------------------------------------------- /module_bundle/chap3/util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * util.c - commonly used utility functions. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include "util.h" 9 | void *checked_malloc(int len) 10 | {void *p = malloc(len); 11 | if (!p) { 12 | fprintf(stderr,"\nRan out of memory!\n"); 13 | exit(1); 14 | } 15 | return p; 16 | } 17 | 18 | string String(char *s) 19 | {string p = checked_malloc(strlen(s)+1); 20 | strcpy(p,s); 21 | return p; 22 | } 23 | 24 | U_boolList U_BoolList(bool head, U_boolList tail) 25 | { U_boolList list = checked_malloc(sizeof(*list)); 26 | list->head = head; 27 | list->tail = tail; 28 | return list; 29 | } 30 | -------------------------------------------------------------------------------- /Chapter06/Translator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Frame.h" 3 | 4 | namespace tiger { 5 | 6 | class CallingConvention; 7 | 8 | class Translator { 9 | public: 10 | using Level = size_t; 11 | 12 | Translator(TempMap &tempMap, CallingConvention &callingConvention); 13 | 14 | Level outermost() const; 15 | Level newLevel(Level parent, Label label, const BoolList &formals); 16 | AccessList formals(Level level); 17 | std::pair allocateLocal(Level level, bool escapes); 18 | 19 | private: 20 | TempMap &m_tempMap; 21 | CallingConvention &m_callingConvention; 22 | std::vector> m_frames; 23 | }; 24 | } // namespace tiger 25 | -------------------------------------------------------------------------------- /Chapter09/test/compileFiles.cpp: -------------------------------------------------------------------------------- 1 | #include "Program.h" 2 | #include "testsHelper.h" 3 | #include 4 | #include 5 | 6 | extern std::string arch; 7 | 8 | TEST_CASE("compile test files") { 9 | namespace fs = boost::filesystem; 10 | tiger::forEachTigerTest( 11 | [](const fs::path &filepath, bool parseError, bool compilationError) { 12 | SECTION(filepath.filename().string()) { 13 | if (parseError || compilationError) { 14 | REQUIRE_FALSE(tiger::compileFile(arch, filepath.string())); 15 | } else { 16 | REQUIRE(tiger::compileFile(arch, filepath.string())); 17 | } 18 | } 19 | }); 20 | } -------------------------------------------------------------------------------- /Chapter10/test/compileFiles.cpp: -------------------------------------------------------------------------------- 1 | #include "Program.h" 2 | #include "testsHelper.h" 3 | #include 4 | #include 5 | 6 | extern std::string arch; 7 | 8 | TEST_CASE("compile test files") { 9 | namespace fs = boost::filesystem; 10 | tiger::forEachTigerTest( 11 | [](const fs::path &filepath, bool parseError, bool compilationError) { 12 | SECTION(filepath.filename().string()) { 13 | if (parseError || compilationError) { 14 | REQUIRE_FALSE(tiger::compileFile(arch, filepath.string())); 15 | } else { 16 | REQUIRE(tiger::compileFile(arch, filepath.string())); 17 | } 18 | } 19 | }); 20 | } -------------------------------------------------------------------------------- /Chapter09/test/assignment.cpp: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | TEST_CASE("assignment") { 4 | auto program = checkedCompile(R"( 5 | let 6 | var a := 3 7 | var b := 0 8 | in 9 | b := a 10 | end 11 | )"); 12 | OptReg a, b; 13 | OptLabel end; 14 | checkProgram(program, checkMain(), 15 | checkMove( // move 3 to a 16 | checkReg(a), checkImm(3)), 17 | checkMove( // move 0 to b 18 | checkReg(b), checkImm(0)), 19 | checkMove( // move a to b 20 | checkReg(b), checkReg(a)), 21 | checkMove( // return 0 22 | returnReg(), checkImm(0)), 23 | branchToEnd(end)); 24 | } -------------------------------------------------------------------------------- /Chapter09/m68k/m68kRegisters.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "TempMap.h" 3 | 4 | namespace tiger { 5 | namespace frame { 6 | namespace m68k { 7 | 8 | enum class Registers { 9 | D0, 10 | D1, 11 | D2, 12 | D3, 13 | D4, 14 | D5, 15 | D6, 16 | D7, 17 | A0, 18 | A1, 19 | A2, 20 | A3, 21 | A4, 22 | A5, 23 | A6, 24 | A7, 25 | Size 26 | }; 27 | 28 | constexpr temp::Register reg(Registers reg) { 29 | return temp::Register{static_cast(reg)}; 30 | } 31 | 32 | static_assert(static_cast(Registers::Size) <= temp::MIN_TEMP, 33 | "MIN_TEMP should be greater than the greatest register"); 34 | } // namespace m68k 35 | } // namespace frame 36 | } // namespace tiger -------------------------------------------------------------------------------- /Chapter10/m68k/m68kRegisters.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "TempMap.h" 3 | 4 | namespace tiger { 5 | namespace frame { 6 | namespace m68k { 7 | 8 | enum class Registers { 9 | D0, 10 | D1, 11 | D2, 12 | D3, 13 | D4, 14 | D5, 15 | D6, 16 | D7, 17 | A0, 18 | A1, 19 | A2, 20 | A3, 21 | A4, 22 | A5, 23 | A6, 24 | A7, 25 | Size 26 | }; 27 | 28 | constexpr temp::Register reg(Registers reg) { 29 | return temp::Register{static_cast(reg)}; 30 | } 31 | 32 | static_assert(static_cast(Registers::Size) <= temp::MIN_TEMP, 33 | "MIN_TEMP should be greater than the greatest register"); 34 | } // namespace m68k 35 | } // namespace frame 36 | } // namespace tiger -------------------------------------------------------------------------------- /include/type_traits.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace helpers { 6 | 7 | template using void_t = void; 8 | 9 | // check if type is a sequence 10 | template 11 | struct is_sequence : std::false_type {}; 12 | 13 | template 14 | struct is_sequence> : std::true_type {}; 15 | 16 | // check if type is an iterator 17 | template 18 | struct is_iterator : std::false_type {}; 19 | 20 | template 21 | struct is_iterator::value_type>> : std::true_type {}; 22 | 23 | } // namespace helpers 24 | -------------------------------------------------------------------------------- /Chapter04/Skipper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "warning_suppress.h" 3 | MSC_DIAG_OFF(4996 4459) 4 | #include 5 | MSC_DIAG_ON() 6 | 7 | namespace tiger { 8 | template 9 | class Skipper : public boost::spirit::qi::grammar { 10 | public: 11 | Skipper() : Skipper::base_type(skip) { 12 | namespace ascii = boost::spirit::ascii; 13 | 14 | using ascii::char_; 15 | ascii::space_type space; 16 | 17 | skip = space // tab/space/cr/lf 18 | | "/*" >> *(char_ - "*/") >> "*/" // comments 19 | ; 20 | } 21 | 22 | private: 23 | boost::spirit::qi::rule skip; 24 | }; 25 | } // namespace tiger -------------------------------------------------------------------------------- /Chapter05/Skipper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "warning_suppress.h" 3 | MSC_DIAG_OFF(4996 4459) 4 | #include 5 | MSC_DIAG_ON() 6 | 7 | namespace tiger { 8 | template 9 | class Skipper : public boost::spirit::qi::grammar { 10 | public: 11 | Skipper() : Skipper::base_type(skip) { 12 | namespace ascii = boost::spirit::ascii; 13 | 14 | using ascii::char_; 15 | ascii::space_type space; 16 | 17 | skip = space // tab/space/cr/lf 18 | | "/*" >> *(char_ - "*/") >> "*/" // comments 19 | ; 20 | } 21 | 22 | private: 23 | boost::spirit::qi::rule skip; 24 | }; 25 | } // namespace tiger -------------------------------------------------------------------------------- /Chapter06/Skipper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "warning_suppress.h" 3 | MSC_DIAG_OFF(4996 4459) 4 | #include 5 | MSC_DIAG_ON() 6 | 7 | namespace tiger { 8 | template 9 | class Skipper : public boost::spirit::qi::grammar { 10 | public: 11 | Skipper() : Skipper::base_type(skip) { 12 | namespace ascii = boost::spirit::ascii; 13 | 14 | using ascii::char_; 15 | ascii::space_type space; 16 | 17 | skip = space // tab/space/cr/lf 18 | | "/*" >> *(char_ - "*/") >> "*/" // comments 19 | ; 20 | } 21 | 22 | private: 23 | boost::spirit::qi::rule skip; 24 | }; 25 | } // namespace tiger -------------------------------------------------------------------------------- /Chapter07/Skipper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "warning_suppress.h" 3 | MSC_DIAG_OFF(4996 4459) 4 | #include 5 | MSC_DIAG_ON() 6 | 7 | namespace tiger { 8 | template 9 | class Skipper : public boost::spirit::qi::grammar { 10 | public: 11 | Skipper() : Skipper::base_type(skip) { 12 | namespace ascii = boost::spirit::ascii; 13 | 14 | using ascii::char_; 15 | ascii::space_type space; 16 | 17 | skip = space // tab/space/cr/lf 18 | | "/*" >> *(char_ - "*/") >> "*/" // comments 19 | ; 20 | } 21 | 22 | private: 23 | boost::spirit::qi::rule skip; 24 | }; 25 | } // namespace tiger -------------------------------------------------------------------------------- /Chapter08/Skipper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "warning_suppress.h" 3 | MSC_DIAG_OFF(4996 4459) 4 | #include 5 | MSC_DIAG_ON() 6 | 7 | namespace tiger { 8 | template 9 | class Skipper : public boost::spirit::qi::grammar { 10 | public: 11 | Skipper() : Skipper::base_type(skip) { 12 | namespace ascii = boost::spirit::ascii; 13 | 14 | using ascii::char_; 15 | ascii::space_type space; 16 | 17 | skip = space // tab/space/cr/lf 18 | | "/*" >> *(char_ - "*/") >> "*/" // comments 19 | ; 20 | } 21 | 22 | private: 23 | boost::spirit::qi::rule skip; 24 | }; 25 | } // namespace tiger -------------------------------------------------------------------------------- /Chapter09/Skipper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "warning_suppress.h" 3 | MSC_DIAG_OFF(4996 4459) 4 | #include 5 | MSC_DIAG_ON() 6 | 7 | namespace tiger { 8 | template 9 | class Skipper : public boost::spirit::qi::grammar { 10 | public: 11 | Skipper() : Skipper::base_type(skip) { 12 | namespace ascii = boost::spirit::ascii; 13 | 14 | using ascii::char_; 15 | ascii::space_type space; 16 | 17 | skip = space // tab/space/cr/lf 18 | | "/*" >> *(char_ - "*/") >> "*/" // comments 19 | ; 20 | } 21 | 22 | private: 23 | boost::spirit::qi::rule skip; 24 | }; 25 | } // namespace tiger -------------------------------------------------------------------------------- /Chapter10/Skipper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "warning_suppress.h" 3 | MSC_DIAG_OFF(4996 4459) 4 | #include 5 | MSC_DIAG_ON() 6 | 7 | namespace tiger { 8 | template 9 | class Skipper : public boost::spirit::qi::grammar { 10 | public: 11 | Skipper() : Skipper::base_type(skip) { 12 | namespace ascii = boost::spirit::ascii; 13 | 14 | using ascii::char_; 15 | ascii::space_type space; 16 | 17 | skip = space // tab/space/cr/lf 18 | | "/*" >> *(char_ - "*/") >> "*/" // comments 19 | ; 20 | } 21 | 22 | private: 23 | boost::spirit::qi::rule skip; 24 | }; 25 | } // namespace tiger -------------------------------------------------------------------------------- /Chapter06/EscapeAnalyser.h: -------------------------------------------------------------------------------- 1 | #include "AbstractSyntaxTree.h" 2 | #include 3 | #include 4 | 5 | namespace tiger { 6 | class EscapeAnalyser { 7 | public: 8 | using result_type = bool; 9 | 10 | result_type analyse(ast::Expression &exp); 11 | 12 | private: 13 | result_type analyseVar(ast::VarExpression &exp); 14 | result_type analyseLet(ast::LetExpression &exp); 15 | result_type analyseFuncDec(ast::FunctionDeclarations &decs); 16 | result_type analyseVarDec(ast::VarDeclaration &dec); 17 | 18 | using Environment = 19 | std::unordered_map>; 20 | 21 | std::vector m_environments; 22 | }; 23 | } // namespace tiger 24 | -------------------------------------------------------------------------------- /Chapter09/x64/x64CodeGenerator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CodeGenerator.h" 3 | 4 | namespace tiger { 5 | namespace assembly { 6 | namespace x64 { 7 | class CodeGenerator : public assembly::CodeGenerator { 8 | public: 9 | CodeGenerator(frame::CallingConvention &callingConvention); 10 | 11 | Instructions translateString(const temp::Label &label, 12 | const std::string &string, 13 | temp::Map &tempMap) override; 14 | 15 | Instructions translateArgs(const std::vector &args, 16 | const temp::Map &tempMap) const override; 17 | }; 18 | } // namespace x64 19 | } // namespace assembly 20 | } // namespace tiger 21 | -------------------------------------------------------------------------------- /Chapter10/x64/x64CodeGenerator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CodeGenerator.h" 3 | 4 | namespace tiger { 5 | namespace assembly { 6 | namespace x64 { 7 | class CodeGenerator : public assembly::CodeGenerator { 8 | public: 9 | CodeGenerator(frame::CallingConvention &callingConvention); 10 | 11 | Instructions translateString(const temp::Label &label, 12 | const std::string &string, 13 | temp::Map &tempMap) override; 14 | 15 | Instructions translateArgs(const std::vector &args, 16 | const temp::Map &tempMap) const override; 17 | }; 18 | } // namespace x64 19 | } // namespace assembly 20 | } // namespace tiger 21 | -------------------------------------------------------------------------------- /Chapter10/Frame.cpp: -------------------------------------------------------------------------------- 1 | #include "Frame.h" 2 | #include "Assembly.h" 3 | #include 4 | #include 5 | 6 | namespace tiger { 7 | namespace frame { 8 | 9 | Frame::Frame(temp::Map &tempMap, const CallingConvention &callingConvention) : 10 | m_tempMap{tempMap}, m_callingConvention{callingConvention} {} 11 | 12 | ir::Statement Frame::procEntryExit1(const ir::Statement &body) const { 13 | return ir::Sequence{ 14 | ranges::view::concat(m_parameterMoves, ranges::view::single(body))}; 15 | } 16 | 17 | assembly::Instructions 18 | Frame::procEntryExit3(const assembly::Instructions &body) const { 19 | return body; 20 | } 21 | 22 | } // namespace frame 23 | } // namespace tiger 24 | -------------------------------------------------------------------------------- /Chapter05/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES Program.cpp Test.cpp Compiler.cpp) 2 | set(HEADERS Program.h ErrorHandler.h ExpressionParser.h Skipper.h IdentifierParser.h DeclerationParser.h AbstractSyntaxTree.h Annotation.h 3 | StringParser.h Compiler.h Types.h) 4 | 5 | add_executable(Chapter05 ${HEADERS} ${SOURCES}) 6 | 7 | target_compile_definitions(Chapter05 PRIVATE CATCH_CPP14_OR_GREATER) 8 | 9 | if(MSVC) 10 | set_source_files_properties(Program.cpp PROPERTIES COMPILE_FLAGS /bigobj) 11 | endif() 12 | 13 | target_link_libraries(Chapter05 14 | PRIVATE 15 | Boost::boost 16 | Boost::filesystem 17 | Boost::system 18 | Catch2::Catch 19 | includeHeaders) 20 | 21 | parse_unit_tests(Chapter05) -------------------------------------------------------------------------------- /Chapter09/Machine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "TempMap.h" 3 | #include 4 | 5 | namespace tiger { 6 | namespace frame { 7 | class CallingConvention; 8 | } 9 | 10 | namespace assembly { 11 | class CodeGenerator; 12 | } // namespace assembly 13 | 14 | class Machine { 15 | public: 16 | virtual ~Machine() = default; 17 | 18 | virtual temp::PredefinedRegisters predefinedRegisters() = 0; 19 | 20 | virtual frame::CallingConvention &callingConvention() = 0; 21 | virtual const frame::CallingConvention &callingConvention() const = 0; 22 | 23 | virtual assembly::CodeGenerator &codeGenerator() = 0; 24 | virtual const assembly::CodeGenerator &codeGenerator() const = 0; 25 | }; 26 | } // namespace tiger -------------------------------------------------------------------------------- /Chapter09/m68k/m68kCodeGenerator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CodeGenerator.h" 3 | 4 | namespace tiger { 5 | namespace assembly { 6 | namespace m68k { 7 | class CodeGenerator : public assembly::CodeGenerator { 8 | public: 9 | CodeGenerator(frame::CallingConvention &callingConvention); 10 | 11 | Instructions translateString(const temp::Label &label, 12 | const std::string &string, 13 | temp::Map &tempMap) override; 14 | 15 | private: 16 | Instructions translateArgs(const std::vector &args, 17 | const temp::Map &tempMap) const override; 18 | }; 19 | } // namespace m68k 20 | } // namespace assembly 21 | } // namespace tiger 22 | -------------------------------------------------------------------------------- /Chapter10/m68k/m68kCodeGenerator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CodeGenerator.h" 3 | 4 | namespace tiger { 5 | namespace assembly { 6 | namespace m68k { 7 | class CodeGenerator : public assembly::CodeGenerator { 8 | public: 9 | CodeGenerator(frame::CallingConvention &callingConvention); 10 | 11 | Instructions translateString(const temp::Label &label, 12 | const std::string &string, 13 | temp::Map &tempMap) override; 14 | 15 | private: 16 | Instructions translateArgs(const std::vector &args, 17 | const temp::Map &tempMap) const override; 18 | }; 19 | } // namespace m68k 20 | } // namespace assembly 21 | } // namespace tiger 22 | -------------------------------------------------------------------------------- /Chapter04/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES Program.cpp Test.cpp) 2 | set(HEADERS Program.h ErrorHandler.h ExpressionParser.h Skipper.h IdentifierParser.h DeclerationParser.h AbstractSyntaxTree.h Annotation.h 3 | StringParser.h) 4 | 5 | add_executable(Chapter04 ${HEADERS} ${SOURCES}) 6 | 7 | target_compile_definitions(Chapter04 PRIVATE CATCH_CPP14_OR_GREATER $<$:BOOST_SPIRIT_DEBUG>) 8 | 9 | if(MSVC) 10 | set_source_files_properties(Program.cpp PROPERTIES COMPILE_FLAGS /bigobj) 11 | endif() 12 | 13 | target_link_libraries(Chapter04 14 | PRIVATE 15 | Boost::boost 16 | Boost::filesystem 17 | Boost::system 18 | Catch2::Catch 19 | includeHeaders) 20 | 21 | parse_unit_tests(Chapter04) -------------------------------------------------------------------------------- /Chapter10/Machine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "TempMap.h" 3 | #include 4 | 5 | namespace tiger { 6 | namespace frame { 7 | class CallingConvention; 8 | } 9 | 10 | namespace assembly { 11 | class CodeGenerator; 12 | } // namespace assembly 13 | 14 | class Machine { 15 | public: 16 | virtual ~Machine() = default; 17 | 18 | virtual temp::PredefinedRegisters predefinedRegisters() const = 0; 19 | 20 | virtual frame::CallingConvention &callingConvention() = 0; 21 | virtual const frame::CallingConvention &callingConvention() const = 0; 22 | 23 | virtual assembly::CodeGenerator &codeGenerator() = 0; 24 | virtual const assembly::CodeGenerator &codeGenerator() const = 0; 25 | }; 26 | } // namespace tiger -------------------------------------------------------------------------------- /Chapter03/Skipper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "warning_suppress.h" 3 | MSC_DIAG_OFF(4996 4459) 4 | #include 5 | MSC_DIAG_ON() 6 | 7 | namespace tiger { 8 | template 9 | class Skipper : public boost::spirit::qi::grammar { 10 | public: 11 | Skipper() : Skipper::base_type(start) { 12 | namespace ascii = boost::spirit::ascii; 13 | 14 | using ascii::char_; 15 | ascii::space_type space; 16 | 17 | start = space // tab/space/cr/lf 18 | | "/*" >> *(char_ - "*/") >> "*/" // comments 19 | ; 20 | 21 | BOOST_SPIRIT_DEBUG_NODES((start)) 22 | } 23 | 24 | private: 25 | boost::spirit::qi::rule start; 26 | }; 27 | } // namespace tiger -------------------------------------------------------------------------------- /module_bundle/chap3/tiger.grm: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include "util.h" 4 | #include "errormsg.h" 5 | 6 | int yylex(void); /* function prototype */ 7 | 8 | void yyerror(char *s) 9 | { 10 | EM_error(EM_tokPos, "%s", s); 11 | } 12 | %} 13 | 14 | 15 | %union { 16 | int pos; 17 | int ival; 18 | string sval; 19 | } 20 | 21 | %token ID STRING 22 | %token INT 23 | 24 | %token 25 | COMMA COLON SEMICOLON LPAREN RPAREN LBRACK RBRACK 26 | LBRACE RBRACE DOT 27 | PLUS MINUS TIMES DIVIDE EQ NEQ LT LE GT GE 28 | AND OR ASSIGN 29 | ARRAY IF THEN ELSE WHILE FOR TO DO LET IN END OF 30 | BREAK NIL 31 | FUNCTION VAR TYPE 32 | 33 | %start program 34 | 35 | %% 36 | 37 | program: exp 38 | 39 | exp: ID 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /include/printRange.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "warning_suppress.h" 3 | #include 4 | MSC_DIAG_OFF(4913) 5 | #include 6 | MSC_DIAG_ON() 7 | MSC_DIAG_OFF(4100) 8 | #include 9 | MSC_DIAG_ON() 10 | #include 11 | 12 | namespace helpers { 13 | template 14 | void printRange(std::ostream &ost, const R &rng, 15 | ElementToString &&elementToString) { 16 | using namespace ranges; 17 | ost << "{"; 18 | copy(rng | view::transform(std::forward(elementToString)) 19 | | view::intersperse(", "), 20 | ostream_iterator(ost)); 21 | ost << "}"; 22 | } 23 | 24 | } // namespace helpers -------------------------------------------------------------------------------- /module_bundle/chap3/makefile: -------------------------------------------------------------------------------- 1 | a.out: parsetest.o y.tab.o lex.yy.o errormsg.o util.o 2 | cc -g parsetest.o y.tab.o lex.yy.o errormsg.o util.o 3 | 4 | parsetest.o: parsetest.c errormsg.h util.h 5 | cc -g -c parsetest.c 6 | 7 | y.tab.o: y.tab.c 8 | cc -g -c y.tab.c 9 | 10 | y.tab.c: tiger.grm 11 | yacc -dv tiger.grm 12 | 13 | y.tab.h: y.tab.c 14 | echo "y.tab.h was created at the same time as y.tab.c" 15 | 16 | errormsg.o: errormsg.c errormsg.h util.h 17 | cc -g -c errormsg.c 18 | 19 | lex.yy.o: lex.yy.c y.tab.h errormsg.h util.h 20 | cc -g -c lex.yy.c 21 | 22 | #lex.yy.c: tiger.lex 23 | # lex tiger.lex 24 | 25 | util.o: util.c util.h 26 | cc -g -c util.c 27 | 28 | clean: 29 | rm -f a.out util.o parsetest.o lex.yy.o errormsg.o y.tab.c y.tab.h y.tab.o 30 | -------------------------------------------------------------------------------- /module_bundle/chap4/makefile: -------------------------------------------------------------------------------- 1 | a.out: parsetest.o y.tab.o lex.yy.o errormsg.o util.o 2 | cc -g parsetest.o y.tab.o lex.yy.o errormsg.o util.o 3 | 4 | parsetest.o: parsetest.c errormsg.h util.h 5 | cc -g -c parsetest.c 6 | 7 | y.tab.o: y.tab.c 8 | cc -g -c y.tab.c 9 | 10 | y.tab.c: tiger.grm 11 | yacc -dv tiger.grm 12 | 13 | y.tab.h: y.tab.c 14 | echo "y.tab.h was created at the same time as y.tab.c" 15 | 16 | errormsg.o: errormsg.c errormsg.h util.h 17 | cc -g -c errormsg.c 18 | 19 | lex.yy.o: lex.yy.c y.tab.h errormsg.h util.h 20 | cc -g -c lex.yy.c 21 | 22 | #lex.yy.c: tiger.lex 23 | # lex tiger.lex 24 | 25 | util.o: util.c util.h 26 | cc -g -c util.c 27 | 28 | clean: 29 | rm -f a.out util.o parsetest.o lex.yy.o errormsg.o y.tab.c y.tab.h y.tab.o 30 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | Language: Cpp 2 | BasedOnStyle: LLVM 3 | AlignConsecutiveAssignments: true 4 | AllowAllParametersOfDeclarationOnNextLine: false 5 | AllowShortBlocksOnASingleLine: true 6 | AlwaysBreakTemplateDeclarations: false 7 | BraceWrapping: 8 | IndentBraces: false 9 | SplitEmptyFunction: false 10 | SplitEmptyRecord: false 11 | SplitEmptyNamespace: false 12 | BreakBeforeBinaryOperators: NonAssignment 13 | BreakBeforeBraces: Custom 14 | BreakConstructorInitializers: AfterColon 15 | BreakStringLiterals: false 16 | ColumnLimit: 80 17 | ContinuationIndentWidth: 2 18 | IncludeBlocks: Merge 19 | IndentCaseLabels: true 20 | IndentWrappedFunctionNames: true 21 | KeepEmptyLinesAtTheStartOfBlocks: false 22 | MaxEmptyLinesToKeep: 1 23 | Standard: Cpp11 24 | -------------------------------------------------------------------------------- /Chapter06/Frame.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "TempMap.h" 3 | #include 4 | #include 5 | #include 6 | 7 | namespace tiger { 8 | 9 | using BoolList = boost::dynamic_bitset<>; 10 | 11 | struct InFrame { 12 | int m_offset; 13 | }; 14 | 15 | struct InReg { 16 | Temporary m_reg; 17 | }; 18 | 19 | using VariableAccess = boost::variant; 20 | using AccessList = std::vector; 21 | 22 | class Frame { 23 | public: 24 | virtual ~Frame() noexcept = default; 25 | virtual Label name() const = 0; 26 | virtual AccessList formals() const = 0; 27 | virtual VariableAccess allocateLocal(bool escapes) = 0; 28 | }; 29 | 30 | } // namespace tiger -------------------------------------------------------------------------------- /Chapter10/test/array.cpp: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | TEST_CASE_METHOD(TestFixture, "array") { 4 | auto results = checkedCompile(R"( 5 | let 6 | type t = array of int 7 | in 8 | t[2] of 3 9 | end 10 | )"); 11 | OptReg regs[4]; 12 | OptLabel end; 13 | OptIndex endIndex; 14 | checkProgram( 15 | results, checkMain(), checkMove(regs[0], wordSize()), checkMove(regs[1], 2, {regs[0]}), 16 | checkBinaryOperation(ir::BinOp::MUL, regs[0], regs[1], regs[2]), 17 | checkCall("malloc", {returnReg()}, regs[2]), 18 | checkMove(regs[3], returnReg()), // move result of malloc(array_size) to r 19 | checkCall("initArray", {regs[3]}, 2, 3), // call initArray(array_size, init_val), 20 | checkMove(returnReg(), regs[3]), branchToEnd(end, endIndex), 21 | checkFunctionExit()); 22 | } -------------------------------------------------------------------------------- /include/testsHelper.h.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace tiger { 6 | 7 | template 8 | void forEachTigerTest(F&& f) { 9 | namespace fs = boost::filesystem; 10 | static const fs::path testsLocation = "@TESTS_LOCATION@"; 11 | auto iterateTests = [&f](const fs::path& folder, bool parseError, bool compilationError) 12 | { 13 | for (fs::directory_entry& file : fs::directory_iterator(folder)) 14 | { 15 | if (file.path().extension() == ".tig") 16 | { 17 | f(file.path(), parseError, compilationError); 18 | } 19 | } 20 | }; 21 | 22 | iterateTests(testsLocation, false, false); 23 | iterateTests(testsLocation / "compilation_error", false, true); 24 | iterateTests(testsLocation / "parse_error", true, true); 25 | } 26 | 27 | } // namespace tiger -------------------------------------------------------------------------------- /Chapter10/Program.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "TempRegister.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace tiger { 11 | 12 | struct CompileResults { 13 | std::string m_assembly; 14 | using InterferenceGraph = std::map>; 15 | std::vector m_interferenceGraphs; 16 | 17 | friend std::ostream &operator<<(std::ostream &ost, 18 | const CompileResults &results); 19 | }; 20 | 21 | using CompileResult = boost::optional; 22 | 23 | CompileResult compileFile(const std::string &arch, const std::string &filename); 24 | 25 | CompileResult compile(const std::string &arch, const std::string &string); 26 | 27 | } // namespace tiger 28 | -------------------------------------------------------------------------------- /module_bundle/testcases/test42.tig: -------------------------------------------------------------------------------- 1 | /* correct declarations */ 2 | let 3 | 4 | type arrtype1 = array of int 5 | type rectype1 = {name:string, address:string, id: int , age: int} 6 | type arrtype2 = array of rectype1 7 | type rectype2 = {name : string, dates: arrtype1} 8 | 9 | type arrtype3 = array of string 10 | 11 | var arr1 := arrtype1 [10] of 0 12 | var arr2 := arrtype2 [5] of rectype1 {name="aname", address="somewhere", id=0, age=0} 13 | var arr3:arrtype3 := arrtype3 [100] of "" 14 | 15 | var rec1 := rectype1 {name="Kapoios", address="Kapou", id=02432, age=44} 16 | var rec2 := rectype2 {name="Allos", dates= arrtype1 [3] of 1900} 17 | 18 | in 19 | 20 | arr1[0] := 1; 21 | arr1[9] := 3; 22 | arr2[3].name := "kati"; 23 | arr2[1].age := 23; 24 | arr3[34] := "sfd"; 25 | 26 | rec1.name := "sdf"; 27 | rec2.dates[0] := 2323; 28 | rec2.dates[2] := 2323 29 | 30 | end 31 | -------------------------------------------------------------------------------- /Chapter09/test/array.cpp: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | 3 | TEST_CASE("array") { 4 | auto program = checkedCompile(R"( 5 | let 6 | type t = array of int 7 | in 8 | t[2] of 3 9 | end 10 | )"); 11 | OptReg regs[4]; 12 | OptLabel end; 13 | checkProgram( 14 | program, checkMain(), checkMove(checkReg(regs[0]), checkImm(wordSize())), 15 | checkMove(checkReg(regs[1]), checkImm(2)), 16 | checkBinaryOperation(ir::BinOp::MUL, checkReg(regs[0]), checkReg(regs[1]), 17 | regs[2]), 18 | checkCall("malloc", checkArg(0, checkReg(regs[2]))), 19 | checkMove( // move result of malloc(array_size) to r 20 | checkReg(regs[3]), returnReg()), 21 | checkCall( // call initArray(array_size, init_val) 22 | "initArray", checkArg(0, checkImm(2)) > checkArg(1, checkImm(3))), 23 | checkMove(returnReg(), checkReg(regs[3])), branchToEnd(end)); 24 | } -------------------------------------------------------------------------------- /Chapter09/x64/x64Machine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Machine.h" 4 | #include "x64CallingConvention.h" 5 | #include "x64CodeGenerator.h" 6 | 7 | namespace tiger { 8 | namespace x64 { 9 | 10 | class Machine : public tiger::Machine { 11 | public: 12 | // Inherited via Machine 13 | virtual frame::CallingConvention &callingConvention() override; 14 | virtual const frame::CallingConvention &callingConvention() const override; 15 | virtual assembly::CodeGenerator &codeGenerator() override; 16 | virtual const assembly::CodeGenerator &codeGenerator() const override; 17 | 18 | private: 19 | frame::x64::CallingConvention m_callingConvention; 20 | assembly::x64::CodeGenerator m_codeGenerator{m_callingConvention}; 21 | 22 | // Inherited via Machine 23 | virtual temp::PredefinedRegisters predefinedRegisters() override; 24 | }; 25 | } // namespace x64 26 | } // namespace tiger -------------------------------------------------------------------------------- /Chapter10/TempRegister.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace tiger { 6 | namespace temp { 7 | 8 | // a register is just a number 9 | struct Register : type_safe::strong_typedef, 10 | type_safe::strong_typedef_op::equality_comparison, 11 | type_safe::strong_typedef_op::relational_comparison, 12 | type_safe::strong_typedef_op::output_operator { 13 | using strong_typedef::strong_typedef; 14 | }; 15 | 16 | using Registers = std::vector; 17 | 18 | } // namespace temp 19 | } // namespace tiger 20 | 21 | namespace std { 22 | // we want to use it with the std::unordered_* containers 23 | template <> 24 | struct hash 25 | : type_safe::hashable {}; 26 | } // namespace std 27 | -------------------------------------------------------------------------------- /Chapter10/x64/x64Machine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Machine.h" 4 | #include "x64CallingConvention.h" 5 | #include "x64CodeGenerator.h" 6 | 7 | namespace tiger { 8 | namespace x64 { 9 | 10 | class Machine : public tiger::Machine { 11 | public: 12 | // Inherited via Machine 13 | virtual frame::CallingConvention &callingConvention() override; 14 | virtual const frame::CallingConvention &callingConvention() const override; 15 | virtual assembly::CodeGenerator &codeGenerator() override; 16 | virtual const assembly::CodeGenerator &codeGenerator() const override; 17 | 18 | private: 19 | frame::x64::CallingConvention m_callingConvention; 20 | assembly::x64::CodeGenerator m_codeGenerator{m_callingConvention}; 21 | 22 | // Inherited via Machine 23 | virtual temp::PredefinedRegisters predefinedRegisters() const override; 24 | }; 25 | } // namespace x64 26 | } // namespace tiger -------------------------------------------------------------------------------- /module_bundle/chap3/y.output: -------------------------------------------------------------------------------- 1 | 2 | state 0 3 | $accept : _program $end 4 | 5 | ID shift 3 6 | . error 7 | 8 | program goto 1 9 | exp goto 2 10 | 11 | state 1 12 | $accept : program_$end 13 | 14 | $end accept 15 | . error 16 | 17 | 18 | state 2 19 | program : exp_ (1) 20 | 21 | . reduce 1 22 | 23 | 24 | state 3 25 | exp : ID_ (2) 26 | 27 | . reduce 2 28 | 29 | 30 | 45/3000 terminals, 2/1000 nonterminals 31 | 3/2000 grammar rules, 4/5000 states 32 | 0 shift/reduce, 0 reduce/reduce conflicts reported 33 | 3/1400 working sets used 34 | memory: states,etc. 30/40000, parser 1/70000 35 | 3/600 distinct lookahead sets 36 | 0 extra closures 37 | 1 shift entries, 1 exceptions 38 | 2 goto entries 39 | 0 entries saved by goto default 40 | Optimizer space used: input 6/40000, output 3/70000 41 | 3 table entries, 0 zero 42 | maximum spread: 257, maximum offset: 257 43 | -------------------------------------------------------------------------------- /Chapter09/m68k/m68kMachine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Machine.h" 4 | #include "m68kCallingConvention.h" 5 | #include "m68kCodeGenerator.h" 6 | 7 | namespace tiger { 8 | namespace m68k { 9 | 10 | class Machine : public tiger::Machine { 11 | public: 12 | // Inherited via Machine 13 | virtual frame::CallingConvention &callingConvention() override; 14 | virtual const frame::CallingConvention &callingConvention() const override; 15 | 16 | virtual assembly::CodeGenerator &codeGenerator() override; 17 | virtual const assembly::CodeGenerator &codeGenerator() const override; 18 | 19 | private: 20 | frame::m68k::CallingConvention m_callingConvention; 21 | assembly::m68k::CodeGenerator m_codeGenerator{m_callingConvention}; 22 | 23 | // Inherited via Machine 24 | virtual temp::PredefinedRegisters predefinedRegisters() override; 25 | }; 26 | } // namespace m68k 27 | } // namespace tiger -------------------------------------------------------------------------------- /Chapter10/m68k/m68kMachine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Machine.h" 4 | #include "m68kCallingConvention.h" 5 | #include "m68kCodeGenerator.h" 6 | 7 | namespace tiger { 8 | namespace m68k { 9 | 10 | class Machine : public tiger::Machine { 11 | public: 12 | // Inherited via Machine 13 | virtual frame::CallingConvention &callingConvention() override; 14 | virtual const frame::CallingConvention &callingConvention() const override; 15 | 16 | virtual assembly::CodeGenerator &codeGenerator() override; 17 | virtual const assembly::CodeGenerator &codeGenerator() const override; 18 | 19 | private: 20 | frame::m68k::CallingConvention m_callingConvention; 21 | assembly::m68k::CodeGenerator m_codeGenerator{m_callingConvention}; 22 | 23 | // Inherited via Machine 24 | virtual temp::PredefinedRegisters predefinedRegisters() const override; 25 | }; 26 | } // namespace m68k 27 | } // namespace tiger -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GreenTiger 2 | Solutions to exercises of [Modern Compiler Implementation in C](https://www.amazon.com/Modern-Compiler-Implementation-Andrew-Appel/dp/0521607655) book 3 | 4 | ## Build status 5 | [![AppVeyor](https://ci.appveyor.com/api/projects/status/f2d26mo5vi2ds2sl?svg=true)](https://ci.appveyor.com/project/dvirtz/greentiger) 6 | [![Travis CI](https://travis-ci.org/dvirtz/GreenTiger.svg?branch=master)](https://travis-ci.org/dvirtz/GreenTiger) 7 | 8 | ## Overview 9 | Each chapter contains a program which is a step towards building a compiler for the [Tiger](https://www.lrde.epita.fr/~tiger/tiger.html#Tiger-Language-Reference-Manual) 10 | programming language as well as some solutions to other exercises from the book. 11 | 12 | The compiler is written in C++ and uses [Boost Spirit](http://www.boost.org/doc/libs/1_64_0/libs/spirit/doc/html/index.html) to parse source code and genarate AST. 13 | -------------------------------------------------------------------------------- /Chapter10/m68k/m68kFrame.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Frame.h" 4 | #include "m68kRegisters.h" 5 | #include 6 | 7 | namespace tiger { 8 | namespace frame { 9 | namespace m68k { 10 | // implements 11 | // https://docs.microsoft.com/en-gb/cpp/build/overview-of-x64-calling-conventions 12 | class Frame final : public frame::Frame { 13 | public: 14 | 15 | Frame(temp::Map &tempMap, const frame::CallingConvention &callingConvention, 16 | const temp::Label &name, const BoolList &formals); 17 | 18 | // Inherited via Frame 19 | temp::Label name() const override; 20 | 21 | const AccessList &formals() const override; 22 | 23 | VariableAccess allocateLocal(bool escapes) override; 24 | 25 | private: 26 | temp::Label m_name; 27 | AccessList m_formals; 28 | int m_wordSize; 29 | int m_frameOffset; 30 | }; 31 | } // namespace m68k 32 | } // namespace frame 33 | } // namespace tiger 34 | -------------------------------------------------------------------------------- /Chapter10/x64/x64Frame.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Frame.h" 4 | #include "x64Registers.h" 5 | #include 6 | 7 | namespace tiger { 8 | namespace frame { 9 | namespace x64 { 10 | // implements 11 | // https://docs.microsoft.com/en-gb/cpp/build/overview-of-x64-calling-conventions 12 | class Frame final : public frame::Frame { 13 | public: 14 | 15 | Frame(temp::Map &tempMap, const frame::CallingConvention &callingConvention, 16 | const temp::Label &name, const BoolList &formals); 17 | 18 | // Inherited via Frame 19 | virtual temp::Label name() const override; 20 | 21 | virtual const AccessList &formals() const override; 22 | 23 | virtual VariableAccess allocateLocal(bool escapes) override; 24 | 25 | private: 26 | temp::Label m_name; 27 | AccessList m_formals; 28 | int m_wordSize; 29 | int m_frameOffset; 30 | }; 31 | } // namespace x64 32 | } // namespace frame 33 | } // namespace tiger 34 | -------------------------------------------------------------------------------- /Chapter06/x64FastCall/Frame.cpp: -------------------------------------------------------------------------------- 1 | #include "Frame.h" 2 | #include 3 | #include 4 | 5 | namespace tiger { 6 | namespace x64FastCall { 7 | 8 | Frame::Frame(TempMap &tempMap, const Label &name, const BoolList &formals) : 9 | m_tempMap(tempMap), m_name(name) { 10 | for (size_t i = 0; i < formals.size(); ++i) { 11 | m_formals.push_back(allocateLocal(formals[i])); 12 | } 13 | } 14 | 15 | Label Frame::name() const { return m_name; } 16 | 17 | AccessList Frame::formals() const { return m_formals; } 18 | 19 | VariableAccess Frame::allocateLocal(bool escapes) { 20 | if (escapes || m_allocatedRegs == MAX_REGS) { 21 | auto res = InFrame{m_frameOffset}; 22 | m_frameOffset += FRAME_INC; 23 | return res; 24 | } 25 | 26 | assert(m_allocatedRegs < MAX_REGS); 27 | ++m_allocatedRegs; 28 | return InReg{m_tempMap.newTemp()}; 29 | } 30 | 31 | } // namespace x64FastCall 32 | } // namespace tiger 33 | -------------------------------------------------------------------------------- /Chapter06/x64FastCall/Frame.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../Frame.h" 4 | 5 | namespace tiger { 6 | namespace x64FastCall { 7 | // implements 8 | // https://docs.microsoft.com/en-gb/cpp/build/overview-of-x64-calling-conventions 9 | class Frame : public tiger::Frame { 10 | public: 11 | Frame(TempMap &tempMap, const Label &name, const BoolList &formals); 12 | // Inherited via Frame 13 | virtual Label name() const override; 14 | virtual AccessList formals() const override; 15 | virtual VariableAccess allocateLocal(bool escapes) override; 16 | 17 | private: 18 | TempMap &m_tempMap; 19 | Label m_name; 20 | AccessList m_formals; 21 | static const int FRAME_INC = 4; 22 | int m_frameOffset = -FRAME_INC; 23 | // The __fastcall convention uses registers for the first four arguments 24 | static const size_t MAX_REGS = 4; 25 | size_t m_allocatedRegs = 0; 26 | }; 27 | } // namespace x64FastCall 28 | } // namespace tiger 29 | -------------------------------------------------------------------------------- /Chapter10/TempLabel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace tiger { 6 | namespace temp { 7 | 8 | // a label is just a string 9 | struct Label : type_safe::strong_typedef, 10 | type_safe::strong_typedef_op::equality_comparison