= INTRODUCTION = Welcome reader, You will find our solution on assignment 5 of Compiler Constructions 2008 giving at LIACS University. First we will you a grand overview of the files altered, next we will bullet point the most important design decisions. And the grand finale will show the usage of the program. Enjoy! Johan and Rick = FILES EDITED/ADDED = E ICGenerator.cc = Intermidiate code generator C++ source E ICGenerator.h = Intermidiate code generator C++ source E main.cc = Main program function, argument parsing = DESIGN DECISIONS = * Constants are evaluated upfront, also nested ones. Optimalisations are included into the tree and generated on the fly * In order to keep the code readable human-readable tests are defined like IsZero, IsConstant. * Made icode, symtab global to avoid calling the Treewalk with a whole lot of arguments every time. * Recursive walking of Tree using Treewalk allowing us to generate code on the fly on three different 'location' e.g. first encounter, midle pass, last visit. * Tried various optimatisations on PostProcess, by changing variable names, removing assignments, but yet all led to race conditions. * Wrote some theoritical tests PostProcess which could be implemented. * Constants in multiple additions (e.g. 10 + a + 20 + b) will be simplified 30 + a + b * Constants in multiple combinations of additions and substractions will be simplyfied (e.g. 10 + a - 20 + b) will be simplified -10 + a + b * In order to allow the full folding, NODE_ADD and NODE_SUB are evaluated differently, Like first right child, then left child. * Full constant folding on NODE_MUL has not been implemented, but will goes more and less the same as the code at NODE_ADD = SAMPLE GENERATED CODE = C01) program example; C02) C03) var x, y, z: integer; C04) function foo(a,b: integer): integer; C05) begin C06) foo := 1 C07) end; C08) C09) begin C10) x := readinteger; C11) y := 20; C12) z := x + 20; C13) z := z + foo(0,0) C14) end. Program: example # operator | operand1 | operand2 | result ------------------+-------------------+-------------------+------------------- 0: CALL FUNC | sym: readinteger | | sym: t1 1: ASSIGN_I | sym: t1 | | sym: x 2: ASSIGN_I | int: 20 | | sym: y 3: ADD_I | sym: x | int: 20 | sym: t2 4: ASSIGN_I | sym: t2 | | sym: z 5: PARAM_I | int: 0 | | 6: PARAM_I | int: 0 | | 7: CALL FUNC | sym: foo | | sym: t3 8: ADD_I | sym: z | sym: t3 | sym: t4 9: ASSIGN_I | sym: t4 | | sym: z 10: RETURN | | | 11: SUBPROG | sym: foo | | 12: ASSIGN_I | int: 1 | | sym: foo 13: RETURN_I | sym: foo | | ------------------+-------------------+-------------------+------------------- Line 0,1 will be line C10. Direct assignments like line C11 will only use one line 3. When calling functions (C13), first the parameters will be set on place at line 5,6 then the function itself will be caled at line 7. Some book keeping could be found at line 13 (return) = USAGE = # Compile $ make dirs $ make # Call without optimalisation $ ./comp -w -00