From a607f09f6b8940ff662c3e20ea80217db6698619 Mon Sep 17 00:00:00 2001 From: simonkellet Date: Thu, 19 Oct 2023 15:00:09 +0100 Subject: [PATCH] initial push with task5b done --- .gitignore | 62 ++ .project | 17 + LICENSE | 21 + .../.gitignore | 3 + .../.project | 23 + .../build.gradle | 12 + Triangle.AbstractMachine.Disassembler/pom.xml | 18 + .../abstractMachine/Disassembler.java | 355 +++++++ .../.gitignore | 3 + Triangle.AbstractMachine.Interpreter/.project | 23 + .../build.gradle | 12 + Triangle.AbstractMachine.Interpreter/pom.xml | 18 + .../triangle/abstractMachine/Interpreter.java | 649 ++++++++++++ Triangle.AbstractMachine/.gitignore | 3 + Triangle.AbstractMachine/.project | 23 + Triangle.AbstractMachine/build.gradle | 4 + Triangle.AbstractMachine/pom.xml | 12 + .../triangle/abstractMachine/Instruction.java | 71 ++ .../triangle/abstractMachine/Machine.java | 58 ++ .../java/triangle/abstractMachine/OpCode.java | 5 + .../triangle/abstractMachine/Primitive.java | 6 + .../triangle/abstractMachine/Register.java | 5 + Triangle.Compiler/.gitignore | 4 + Triangle.Compiler/.project | 23 + Triangle.Compiler/build.gradle | 24 + Triangle.Compiler/pom.xml | 18 + .../src/main/java/triangle/Compiler.java | 183 ++++ .../src/main/java/triangle/ErrorReporter.java | 65 ++ .../main/java/triangle/StdEnvironment.java | 50 + .../AbstractSyntaxTree.java | 38 + .../triangle/abstractSyntaxTrees/Program.java | 41 + .../actuals/ActualParameter.java | 36 + .../actuals/ActualParameterSequence.java | 36 + .../actuals/ConstActualParameter.java | 37 + .../actuals/EmptyActualParameterSequence.java | 33 + .../actuals/FuncActualParameter.java | 37 + .../MultipleActualParameterSequence.java | 39 + .../actuals/ProcActualParameter.java | 37 + .../SingleActualParameterSequence.java | 36 + .../actuals/VarActualParameter.java | 37 + .../aggregates/ArrayAggregate.java | 39 + .../aggregates/MultipleArrayAggregate.java | 39 + .../aggregates/MultipleRecordAggregate.java | 42 + .../aggregates/RecordAggregate.java | 40 + .../aggregates/SingleArrayAggregate.java | 37 + .../aggregates/SingleRecordAggregate.java | 40 + .../commands/AssignCommand.java | 40 + .../commands/CallCommand.java | 40 + .../abstractSyntaxTrees/commands/Command.java | 36 + .../commands/EmptyCommand.java | 33 + .../commands/IfCommand.java | 40 + .../commands/LetCommand.java | 39 + .../commands/SequentialCommand.java | 37 + .../commands/WhileCommand.java | 39 + .../BinaryOperatorDeclaration.java | 43 + .../declarations/ConstDeclaration.java | 46 + .../declarations/ConstantDeclaration.java | 9 + .../declarations/Declaration.java | 39 + .../declarations/FuncDeclaration.java | 57 + .../declarations/FunctionDeclaration.java | 12 + .../declarations/ProcDeclaration.java | 48 + .../declarations/ProcedureDeclaration.java | 9 + .../declarations/SequentialDeclaration.java | 37 + .../UnaryOperatorDeclaration.java | 41 + .../declarations/VarDeclaration.java | 45 + .../declarations/VariableDeclaration.java | 9 + .../expressions/ArrayExpression.java | 37 + .../expressions/BinaryExpression.java | 41 + .../expressions/CallExpression.java | 40 + .../expressions/CharacterExpression.java | 47 + .../expressions/EmptyExpression.java | 33 + .../expressions/Expression.java | 48 + .../expressions/IfExpression.java | 40 + .../expressions/IntegerExpression.java | 47 + .../expressions/LetExpression.java | 39 + .../expressions/RecordExpression.java | 37 + .../expressions/UnaryExpression.java | 39 + .../expressions/VnameExpression.java | 37 + .../formals/ConstFormalParameter.java | 55 + .../formals/EmptyFormalParameterSequence.java | 38 + .../formals/FormalParameter.java | 39 + .../formals/FormalParameterSequence.java | 39 + .../formals/FuncFormalParameter.java | 63 ++ .../MultipleFormalParameterSequence.java | 49 + .../formals/ProcFormalParameter.java | 55 + .../SingleFormalParameterSequence.java | 46 + .../formals/VarFormalParameter.java | 55 + .../terminals/CharacterLiteral.java | 41 + .../terminals/Identifier.java | 44 + .../terminals/IntegerLiteral.java | 41 + .../terminals/Operator.java | 41 + .../terminals/Terminal.java | 32 + .../types/AnyTypeDenoter.java | 43 + .../types/ArrayTypeDenoter.java | 56 + .../types/BoolTypeDenoter.java | 48 + .../types/CharTypeDenoter.java | 48 + .../types/ErrorTypeDenoter.java | 43 + .../types/FieldTypeDenoter.java | 28 + .../types/IntTypeDenoter.java | 48 + .../types/MultipleFieldTypeDenoter.java | 57 + .../types/RecordTypeDenoter.java | 52 + .../types/SimpleTypeDenoter.java | 47 + .../types/SingleFieldTypeDenoter.java | 54 + .../types/TypeDeclaration.java | 40 + .../types/TypeDenoter.java | 41 + .../ActualParameterSequenceVisitor.java | 15 + .../visitors/ActualParameterVisitor.java | 18 + .../visitors/ArrayAggregateVisitor.java | 12 + .../visitors/CommandVisitor.java | 27 + .../visitors/DeclarationVisitor.java | 30 + .../visitors/ExpressionVisitor.java | 39 + .../visitors/FieldTypeDenoterVisitor.java | 12 + .../FormalParameterSequenceVisitor.java | 15 + .../visitors/FormalParameterVisitor.java | 18 + .../visitors/IdentifierVisitor.java | 9 + .../visitors/LiteralVisitor.java | 12 + .../visitors/OperatorVisitor.java | 9 + .../visitors/ProgramVisitor.java | 9 + .../visitors/RecordAggregateVisitor.java | 12 + .../visitors/TypeDenoterVisitor.java | 30 + .../visitors/VnameVisitor.java | 15 + .../abstractSyntaxTrees/vnames/DotVname.java | 39 + .../vnames/SimpleVname.java | 37 + .../vnames/SubscriptVname.java | 39 + .../abstractSyntaxTrees/vnames/Vname.java | 43 + .../java/triangle/codeGenerator/Emitter.java | 120 +++ .../java/triangle/codeGenerator/Encoder.java | 796 ++++++++++++++ .../java/triangle/codeGenerator/Frame.java | 77 ++ .../entities/AddressableEntity.java | 29 + .../entities/EqualityRoutine.java | 50 + .../entities/FetchableEntity.java | 11 + .../codeGenerator/entities/Field.java | 33 + .../codeGenerator/entities/KnownAddress.java | 66 ++ .../codeGenerator/entities/KnownRoutine.java | 48 + .../codeGenerator/entities/KnownValue.java | 43 + .../codeGenerator/entities/ObjectAddress.java | 39 + .../entities/PrimitiveRoutine.java | 51 + .../codeGenerator/entities/RoutineEntity.java | 11 + .../codeGenerator/entities/RuntimeEntity.java | 34 + .../entities/TypeRepresentation.java | 27 + .../entities/UnknownAddress.java | 78 ++ .../entities/UnknownRoutine.java | 48 + .../codeGenerator/entities/UnknownValue.java | 55 + .../triangle/contextualAnalyzer/Checker.java | 984 ++++++++++++++++++ .../triangle/contextualAnalyzer/IdEntry.java | 37 + .../IdentificationTable.java | 91 ++ .../triangle/optimiser/ConstantFolder.java | 599 +++++++++++ .../java/triangle/optimiser/SummaryStats.java | 614 +++++++++++ .../triangle/syntacticAnalyzer/Parser.java | 948 +++++++++++++++++ .../triangle/syntacticAnalyzer/Scanner.java | 276 +++++ .../syntacticAnalyzer/SourceFile.java | 72 ++ .../syntacticAnalyzer/SourcePosition.java | 39 + .../syntacticAnalyzer/SyntaxError.java | 33 + .../triangle/syntacticAnalyzer/Token.java | 88 ++ .../main/java/triangle/treeDrawer/Drawer.java | 72 ++ .../java/triangle/treeDrawer/DrawerFrame.java | 78 ++ .../java/triangle/treeDrawer/DrawerPanel.java | 43 + .../java/triangle/treeDrawer/DrawingTree.java | 88 ++ .../triangle/treeDrawer/LayoutVisitor.java | 684 ++++++++++++ .../java/triangle/treeDrawer/Polygon.java | 24 + .../java/triangle/treeDrawer/Polyline.java | 33 + .../syntacticAnalyser/TestScanner.java | 92 ++ build.gradle | 26 + build/libs/Triangle-Tools.jar | Bin 0 -> 197392 bytes curl.tam | Bin 0 -> 256 bytes double.tam | Bin 0 -> 304 bytes gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 63721 bytes gradle/wrapper/gradle-wrapper.properties | 7 + gradlew | 249 +++++ gradlew.bat | 92 ++ hi.tam | Bin 0 -> 192 bytes pom.xml | 19 + programs/adddeep.tri | 12 + programs/arrays.tri | 47 + programs/assignments.tri | 9 + programs/bank.tri | 86 ++ programs/bardemo.tri | 19 + programs/control.tri | 26 + programs/deepnest.tri | 16 + programs/directories.tri | 117 +++ programs/double.tri | 16 + programs/errors.tri | 30 + programs/every.tri | 148 +++ programs/factorials.tri | 15 + programs/functions.tri | 28 + programs/hi-newcomment.tri | 7 + programs/hi-newcomment2.tri | 11 + programs/hi.tam | Bin 0 -> 112 bytes programs/hi.tri | 3 + programs/hullo.tri | 53 + programs/ifdemo.tri | 9 + programs/increment.tri | 14 + programs/names.tri | 52 + programs/nesting.tri | 31 + programs/procedural.tri | 56 + programs/procedures.tri | 31 + programs/records.tri | 24 + programs/repeatuntil.tri | 14 + programs/repl.tri | 13 + programs/simpleadding.tri | 10 + programs/starstart.tri | 10 + programs/triangle.tri | 32 + programs/while-curly.tri | 13 + programs/while-longloop.tri | 22 + programs/while.tri | 11 + settings.gradle | 7 + star.tam | Bin 0 -> 192 bytes while.tam | Bin 0 -> 256 bytes 208 files changed, 13177 insertions(+) create mode 100644 .gitignore create mode 100644 .project create mode 100644 LICENSE create mode 100644 Triangle.AbstractMachine.Disassembler/.gitignore create mode 100644 Triangle.AbstractMachine.Disassembler/.project create mode 100644 Triangle.AbstractMachine.Disassembler/build.gradle create mode 100644 Triangle.AbstractMachine.Disassembler/pom.xml create mode 100644 Triangle.AbstractMachine.Disassembler/src/main/java/triangle/abstractMachine/Disassembler.java create mode 100644 Triangle.AbstractMachine.Interpreter/.gitignore create mode 100644 Triangle.AbstractMachine.Interpreter/.project create mode 100644 Triangle.AbstractMachine.Interpreter/build.gradle create mode 100644 Triangle.AbstractMachine.Interpreter/pom.xml create mode 100644 Triangle.AbstractMachine.Interpreter/src/main/java/triangle/abstractMachine/Interpreter.java create mode 100644 Triangle.AbstractMachine/.gitignore create mode 100644 Triangle.AbstractMachine/.project create mode 100644 Triangle.AbstractMachine/build.gradle create mode 100644 Triangle.AbstractMachine/pom.xml create mode 100644 Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Instruction.java create mode 100644 Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Machine.java create mode 100644 Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/OpCode.java create mode 100644 Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Primitive.java create mode 100644 Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Register.java create mode 100644 Triangle.Compiler/.gitignore create mode 100644 Triangle.Compiler/.project create mode 100644 Triangle.Compiler/build.gradle create mode 100644 Triangle.Compiler/pom.xml create mode 100644 Triangle.Compiler/src/main/java/triangle/Compiler.java create mode 100644 Triangle.Compiler/src/main/java/triangle/ErrorReporter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/StdEnvironment.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/AbstractSyntaxTree.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/Program.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ActualParameter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ActualParameterSequence.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ConstActualParameter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/EmptyActualParameterSequence.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/FuncActualParameter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/MultipleActualParameterSequence.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ProcActualParameter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/SingleActualParameterSequence.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/VarActualParameter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/ArrayAggregate.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/MultipleArrayAggregate.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/MultipleRecordAggregate.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/RecordAggregate.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/SingleArrayAggregate.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/SingleRecordAggregate.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/AssignCommand.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/CallCommand.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/Command.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/EmptyCommand.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/IfCommand.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/LetCommand.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/SequentialCommand.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/WhileCommand.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/BinaryOperatorDeclaration.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ConstDeclaration.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ConstantDeclaration.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/Declaration.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/FuncDeclaration.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/FunctionDeclaration.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ProcDeclaration.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ProcedureDeclaration.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/SequentialDeclaration.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/UnaryOperatorDeclaration.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/VarDeclaration.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/VariableDeclaration.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/ArrayExpression.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/BinaryExpression.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/CallExpression.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/CharacterExpression.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/EmptyExpression.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/Expression.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/IfExpression.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/IntegerExpression.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/LetExpression.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/RecordExpression.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/UnaryExpression.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/VnameExpression.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/ConstFormalParameter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/EmptyFormalParameterSequence.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FormalParameter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FormalParameterSequence.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FuncFormalParameter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/MultipleFormalParameterSequence.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/ProcFormalParameter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/SingleFormalParameterSequence.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/VarFormalParameter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/CharacterLiteral.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Identifier.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/IntegerLiteral.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Operator.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Terminal.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/AnyTypeDenoter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/ArrayTypeDenoter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/BoolTypeDenoter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/CharTypeDenoter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/ErrorTypeDenoter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/FieldTypeDenoter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/IntTypeDenoter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/MultipleFieldTypeDenoter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/RecordTypeDenoter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/SimpleTypeDenoter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/SingleFieldTypeDenoter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/TypeDeclaration.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/TypeDenoter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ActualParameterSequenceVisitor.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ActualParameterVisitor.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ArrayAggregateVisitor.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/CommandVisitor.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/DeclarationVisitor.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ExpressionVisitor.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FieldTypeDenoterVisitor.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FormalParameterSequenceVisitor.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FormalParameterVisitor.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/IdentifierVisitor.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/LiteralVisitor.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/OperatorVisitor.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ProgramVisitor.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/RecordAggregateVisitor.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/TypeDenoterVisitor.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/VnameVisitor.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/DotVname.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/SimpleVname.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/SubscriptVname.java create mode 100644 Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/Vname.java create mode 100644 Triangle.Compiler/src/main/java/triangle/codeGenerator/Emitter.java create mode 100644 Triangle.Compiler/src/main/java/triangle/codeGenerator/Encoder.java create mode 100644 Triangle.Compiler/src/main/java/triangle/codeGenerator/Frame.java create mode 100644 Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/AddressableEntity.java create mode 100644 Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/EqualityRoutine.java create mode 100644 Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/FetchableEntity.java create mode 100644 Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/Field.java create mode 100644 Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownAddress.java create mode 100644 Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownRoutine.java create mode 100644 Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownValue.java create mode 100644 Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/ObjectAddress.java create mode 100644 Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/PrimitiveRoutine.java create mode 100644 Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/RoutineEntity.java create mode 100644 Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/RuntimeEntity.java create mode 100644 Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/TypeRepresentation.java create mode 100644 Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownAddress.java create mode 100644 Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownRoutine.java create mode 100644 Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownValue.java create mode 100644 Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/Checker.java create mode 100644 Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/IdEntry.java create mode 100644 Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/IdentificationTable.java create mode 100644 Triangle.Compiler/src/main/java/triangle/optimiser/ConstantFolder.java create mode 100644 Triangle.Compiler/src/main/java/triangle/optimiser/SummaryStats.java create mode 100644 Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Parser.java create mode 100644 Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Scanner.java create mode 100644 Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SourceFile.java create mode 100644 Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SourcePosition.java create mode 100644 Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SyntaxError.java create mode 100644 Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Token.java create mode 100644 Triangle.Compiler/src/main/java/triangle/treeDrawer/Drawer.java create mode 100644 Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawerFrame.java create mode 100644 Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawerPanel.java create mode 100644 Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawingTree.java create mode 100644 Triangle.Compiler/src/main/java/triangle/treeDrawer/LayoutVisitor.java create mode 100644 Triangle.Compiler/src/main/java/triangle/treeDrawer/Polygon.java create mode 100644 Triangle.Compiler/src/main/java/triangle/treeDrawer/Polyline.java create mode 100644 Triangle.Compiler/src/test/java/triangle/syntacticAnalyser/TestScanner.java create mode 100644 build.gradle create mode 100644 build/libs/Triangle-Tools.jar create mode 100644 curl.tam create mode 100644 double.tam create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 hi.tam create mode 100644 pom.xml create mode 100644 programs/adddeep.tri create mode 100644 programs/arrays.tri create mode 100644 programs/assignments.tri create mode 100644 programs/bank.tri create mode 100644 programs/bardemo.tri create mode 100644 programs/control.tri create mode 100644 programs/deepnest.tri create mode 100644 programs/directories.tri create mode 100644 programs/double.tri create mode 100644 programs/errors.tri create mode 100644 programs/every.tri create mode 100644 programs/factorials.tri create mode 100644 programs/functions.tri create mode 100644 programs/hi-newcomment.tri create mode 100644 programs/hi-newcomment2.tri create mode 100644 programs/hi.tam create mode 100644 programs/hi.tri create mode 100644 programs/hullo.tri create mode 100644 programs/ifdemo.tri create mode 100644 programs/increment.tri create mode 100644 programs/names.tri create mode 100644 programs/nesting.tri create mode 100644 programs/procedural.tri create mode 100644 programs/procedures.tri create mode 100644 programs/records.tri create mode 100644 programs/repeatuntil.tri create mode 100644 programs/repl.tri create mode 100644 programs/simpleadding.tri create mode 100644 programs/starstart.tri create mode 100644 programs/triangle.tri create mode 100644 programs/while-curly.tri create mode 100644 programs/while-longloop.tri create mode 100644 programs/while.tri create mode 100644 settings.gradle create mode 100644 star.tam create mode 100644 while.tam diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7ff3503 --- /dev/null +++ b/.gitignore @@ -0,0 +1,62 @@ +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders +.vscode + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# PyDev specific (Python IDE for Eclipse) +*.pydevproject + +# CDT-specific (C/C++ Development Tooling) +.cproject + +# CDT- autotools +.autotools + +# Java annotation processor (APT) +.factorypath + +# PDT-specific (PHP Development Tools) +.buildpath + +# sbteclipse plugin +.target + +# Tern plugin +.tern-project + +# TeXlipse plugin +.texlipse + +# STS (Spring Tool Suite) +.springBeans + +# Code Recommenders +.recommenders/ + +# Annotation Processing +.apt_generated/ +.apt_generated_test/ + +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet + +# Uncomment this line if you wish to ignore the project description file. +# Typically, this file would be tracked if it contains build/dependency configurations: +#.project +/.gradle/ diff --git a/.project b/.project new file mode 100644 index 0000000..4beb8b6 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + a5-triangle-tools + Project a5-triangle-tools created by Buildship. + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f4c2b81 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 deryckb + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Triangle.AbstractMachine.Disassembler/.gitignore b/Triangle.AbstractMachine.Disassembler/.gitignore new file mode 100644 index 0000000..8c107fe --- /dev/null +++ b/Triangle.AbstractMachine.Disassembler/.gitignore @@ -0,0 +1,3 @@ +/target/ +/.classpath +/build/ diff --git a/Triangle.AbstractMachine.Disassembler/.project b/Triangle.AbstractMachine.Disassembler/.project new file mode 100644 index 0000000..7024cd7 --- /dev/null +++ b/Triangle.AbstractMachine.Disassembler/.project @@ -0,0 +1,23 @@ + + + Triangle.AbstractMachine.Disassembler + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/Triangle.AbstractMachine.Disassembler/build.gradle b/Triangle.AbstractMachine.Disassembler/build.gradle new file mode 100644 index 0000000..90e01e7 --- /dev/null +++ b/Triangle.AbstractMachine.Disassembler/build.gradle @@ -0,0 +1,12 @@ +apply plugin: 'java' +apply plugin: 'application' + +sourceCompatibility = 11 + +dependencies { + implementation project(':Triangle.AbstractMachine') +} + +application { + mainClass = 'Triangle.AbstractMachine.Disassembler' +} \ No newline at end of file diff --git a/Triangle.AbstractMachine.Disassembler/pom.xml b/Triangle.AbstractMachine.Disassembler/pom.xml new file mode 100644 index 0000000..847d0fc --- /dev/null +++ b/Triangle.AbstractMachine.Disassembler/pom.xml @@ -0,0 +1,18 @@ + + 4.0.0 + triangle-disassembler + + triangle.tools + triangle-tools + 2.1 + ../ + + + + triangle.tools + triangle-abstractmachine + 2.1 + + + diff --git a/Triangle.AbstractMachine.Disassembler/src/main/java/triangle/abstractMachine/Disassembler.java b/Triangle.AbstractMachine.Disassembler/src/main/java/triangle/abstractMachine/Disassembler.java new file mode 100644 index 0000000..0b564b1 --- /dev/null +++ b/Triangle.AbstractMachine.Disassembler/src/main/java/triangle/abstractMachine/Disassembler.java @@ -0,0 +1,355 @@ +/* + * @(#)Disassembler.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractMachine; + +import java.io.DataInputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +/** + * Disassembles the TAM code in the given file, and displays the instructions on + * standard output. + * + * For example: + * + *
+ *   java TAM.Disassembler obj.tam
+ * 
+ * + *

+ * Copyright 1991 David A. Watt, University of Glasgow
+ * Copyright 1998 Deryck F. Brown, The Robert Gordon University
+ *

+ * + */ + +public class Disassembler { + + static String objectName; + + static int CT; + + /** + * Writes the r-field of an instruction in the form "lregr", where l and + * r are the bracket characters to use. + * + * @param leftbracket the character to print before the register. + * @param r the number of the register. + * @param rightbracket the character to print after the register. + */ + private static void writeR(char leftbracket, Register r, char rightbracket) { + + System.out.print(leftbracket); + System.out.print(r.toString()); + System.out.print(rightbracket); + } + + private static void writeR(char leftBracket, int r, char rightBracket) { + var register = Register.values()[r]; + writeR(leftBracket, register, rightBracket); + } + + /** + * Writes a void n-field of an instruction. + */ + private static void blankN() { + System.out.print(" "); + } + + // Writes the n-field of an instruction. + /** + * Writes the n-field of an instruction in the form "(n)". + * + * @param n the integer to write. + */ + private static void writeN(int n) { + System.out.print("(" + n + ") "); + if (n < 10) { + System.out.print(" "); + } else if (n < 100) { + System.out.print(" "); + } + } + + /** + * Writes the d-field of an instruction. + * + * @param d the integer to write. + */ + private static void writeD(int d) { + System.out.print(d); + } + + /** + * Writes the name of primitive routine with relative address d. + * + * @param d the displacement of the primitive routine. + */ + private static void writePrimitive(int d) { + var primitive = Primitive.values()[d]; + switch (primitive) { + case ID: + System.out.print("id "); + break; + case NOT: + System.out.print("not "); + break; + case AND: + System.out.print("and "); + break; + case OR: + System.out.print("or "); + break; + case SUCC: + System.out.print("succ "); + break; + case PRED: + System.out.print("pred "); + break; + case NEG: + System.out.print("neg "); + break; + case ADD: + System.out.print("add "); + break; + case SUB: + System.out.print("sub "); + break; + case MULT: + System.out.print("mult "); + break; + case DIV: + System.out.print("div "); + break; + case MOD: + System.out.print("mod "); + break; + case LT: + System.out.print("lt "); + break; + case LE: + System.out.print("le "); + break; + case GE: + System.out.print("ge "); + break; + case GT: + System.out.print("gt "); + break; + case EQ: + System.out.print("eq "); + break; + case NE: + System.out.print("ne "); + break; + case EOL: + System.out.print("eol "); + break; + case EOF: + System.out.print("eof "); + break; + case GET: + System.out.print("get "); + break; + case PUT: + System.out.print("put "); + break; + case GETEOL: + System.out.print("geteol "); + break; + case PUTEOL: + System.out.print("puteol "); + break; + case GETINT: + System.out.print("getint "); + break; + case PUTINT: + System.out.print("putint "); + break; + case NEW: + System.out.print("new "); + break; + case DISPOSE: + System.out.print("dispose "); + break; + } + } + + /** + * Writes the given instruction in assembly-code format. + * + * @param instr the instruction to display. + */ + private static void writeInstruction(Instruction instr) { + + switch (instr.opCode) { + case LOAD: + System.out.print("LOAD "); + writeN(instr.length); + writeD(instr.operand); + writeR('[', instr.register, ']'); + break; + + case LOADA: + System.out.print("LOADA "); + blankN(); + writeD(instr.operand); + writeR('[', instr.register, ']'); + break; + + case LOADI: + System.out.print("LOADI "); + writeN(instr.length); + break; + + case LOADL: + System.out.print("LOADL "); + blankN(); + writeD(instr.operand); + break; + + case STORE: + System.out.print("STORE "); + writeN(instr.length); + writeD(instr.operand); + writeR('[', instr.register, ']'); + break; + + case STOREI: + System.out.print("STOREI"); + writeN(instr.length); + break; + + case CALL: + System.out.print("CALL "); + if (instr.register == Register.PB) { + blankN(); + writePrimitive(instr.operand); + } else { + writeR('(', instr.length, ')'); + System.out.print(" "); + writeD(instr.operand); + writeR('[', instr.register, ']'); + } + break; + + case CALLI: + System.out.print("CALLI "); + break; + + case RETURN: + System.out.print("RETURN"); + writeN(instr.length); + writeD(instr.operand); + break; + + case PUSH: + System.out.print("PUSH "); + blankN(); + writeD(instr.operand); + break; + + case POP: + System.out.print("POP "); + writeN(instr.length); + writeD(instr.operand); + break; + + case JUMP: + System.out.print("JUMP "); + blankN(); + writeD(instr.operand); + writeR('[', instr.register, ']'); + break; + + case JUMPI: + System.out.print("JUMPI "); + break; + + case JUMPIF: + System.out.print("JUMPIF"); + writeN(instr.length); + writeD(instr.operand); + writeR('[', instr.register, ']'); + break; + + case HALT: + System.out.print("HALT "); + } + } + + /** + * Writes all instructions of the program in code store. + */ + private static void disassembleProgram() { + for (int addr = Machine.CB; addr < CT; addr++) { + System.out.print(addr + ": "); + writeInstruction(Machine.code[addr]); + System.out.println(); + } + } + + // LOADING + + /** + * Loads the TAM object program into code store from the named file. + * + * @param objectName the name of the file containing the program. + */ + static void loadObjectProgram(String objectName) { + + var finished = false; + + try (var objectFile = new FileInputStream(objectName)) { + var objectStream = new DataInputStream(objectFile); + var addr = Machine.CB; + while (!finished) { + Machine.code[addr] = Instruction.read(objectStream); + if (Machine.code[addr] == null) { + finished = true; + } else { + addr = addr + 1; + } + } + CT = addr; + } catch (FileNotFoundException s) { + CT = Machine.CB; + System.err.println("Error opening object file: " + s); + } catch (IOException s) { + CT = Machine.CB; + System.err.println("Error reading object file: " + s); + } + } + + // DISASSEMBLE + + public static void main(String[] args) { + System.out.println("********** TAM Disassembler (Sun Version 2.1) **********"); + + if (args.length == 1) { + objectName = args[0]; + } else { + objectName = "obj.tam"; + } + + loadObjectProgram(objectName); + disassembleProgram(); + } +} diff --git a/Triangle.AbstractMachine.Interpreter/.gitignore b/Triangle.AbstractMachine.Interpreter/.gitignore new file mode 100644 index 0000000..8c107fe --- /dev/null +++ b/Triangle.AbstractMachine.Interpreter/.gitignore @@ -0,0 +1,3 @@ +/target/ +/.classpath +/build/ diff --git a/Triangle.AbstractMachine.Interpreter/.project b/Triangle.AbstractMachine.Interpreter/.project new file mode 100644 index 0000000..a22beaa --- /dev/null +++ b/Triangle.AbstractMachine.Interpreter/.project @@ -0,0 +1,23 @@ + + + Triangle.AbstractMachine.Interpreter + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/Triangle.AbstractMachine.Interpreter/build.gradle b/Triangle.AbstractMachine.Interpreter/build.gradle new file mode 100644 index 0000000..38c7835 --- /dev/null +++ b/Triangle.AbstractMachine.Interpreter/build.gradle @@ -0,0 +1,12 @@ +apply plugin: 'java' +apply plugin: 'application' + +sourceCompatibility = 11 + +dependencies { + implementation project(':Triangle.AbstractMachine') +} + +application { + mainClass = 'Triangle.AbstractMachine.Interpreter' +} \ No newline at end of file diff --git a/Triangle.AbstractMachine.Interpreter/pom.xml b/Triangle.AbstractMachine.Interpreter/pom.xml new file mode 100644 index 0000000..551e835 --- /dev/null +++ b/Triangle.AbstractMachine.Interpreter/pom.xml @@ -0,0 +1,18 @@ + + 4.0.0 + triangle-interpreter + + triangle.tools + triangle-tools + 2.1 + ../ + + + + triangle.tools + triangle-abstractmachine + 2.1 + + + diff --git a/Triangle.AbstractMachine.Interpreter/src/main/java/triangle/abstractMachine/Interpreter.java b/Triangle.AbstractMachine.Interpreter/src/main/java/triangle/abstractMachine/Interpreter.java new file mode 100644 index 0000000..973baf5 --- /dev/null +++ b/Triangle.AbstractMachine.Interpreter/src/main/java/triangle/abstractMachine/Interpreter.java @@ -0,0 +1,649 @@ +/* + * @(#)Interpreter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractMachine; + +import java.io.DataInputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +public class Interpreter { + + static long startTimeNanos = 0; + + static String objectName; + + // DATA STORE + + static int[] data = new int[1024]; + + // DATA STORE REGISTERS AND OTHER REGISTERS + + final static int CB = 0, SB = 0, HB = 1024; // = upper bound of data array + 1 + + static int CT, CP, ST, HT, LB, status; + + // status values + final static int running = 0, halted = 1, failedDataStoreFull = 2, failedInvalidCodeAddress = 3, + failedInvalidInstruction = 4, failedOverflow = 5, failedZeroDivide = 6, failedIOError = 7; + + static long accumulator; + + static int content(int r) { + var register = Register.values()[r]; + return content(register); + } + + static int content(Register r) { + // Returns the current content of register r, + // even if r is one of the pseudo-registers L1..L6. + + switch (r) { + case CB: + return CB; + case CT: + return CT; + case PB: + return Machine.PB; + case PT: + return Machine.PT; + case SB: + return SB; + case ST: + return ST; + case HB: + return HB; + case HT: + return HT; + case LB: + return LB; + case L1: + return data[LB]; + case L2: + return data[data[LB]]; + case L3: + return data[data[data[LB]]]; + case L4: + return data[data[data[data[LB]]]]; + case L5: + return data[data[data[data[data[LB]]]]]; + case L6: + return data[data[data[data[data[data[LB]]]]]]; + case CP: + return CP; + default: + return 0; + } + } + + // PROGRAM STATUS + + static void dump() { + // Writes a summary of the machine state. + + System.out.println(""); + System.out.println("State of data store and registers:"); + System.out.println(""); + if (HT == HB) { + System.out.println(" |--------| (heap is empty)"); + } else { + System.out.println(" HB-->"); + System.out.println(" |--------|"); + for (var addr = HB - 1; addr >= HT; addr--) { + System.out.print(addr + ":"); + if (addr == HT) { + System.out.print(" HT-->"); + } else { + System.out.print(" "); + } + System.out.println("|" + data[addr] + "|"); + } + System.out.println(" |--------|"); + } + System.out.println(" |////////|"); + System.out.println(" |////////|"); + if (ST == SB) { + System.out.println(" |--------| (stack is empty)"); + } else { + var dynamicLink = LB; + var staticLink = LB; + var localRegNum = Register.LB; + System.out.println(" ST--> |////////|"); + System.out.println(" |--------|"); + for (var addr = ST - 1; addr >= SB; addr--) { + System.out.print(addr + ":"); + if (addr == SB) { + System.out.print(" SB-->"); + } else if (addr == staticLink) { + switch (localRegNum) { + case LB: + System.out.print(" LB-->"); + break; + case L1: + System.out.print(" L1-->"); + break; + case L2: + System.out.print(" L2-->"); + break; + case L3: + System.out.print(" L3-->"); + break; + case L4: + System.out.print(" L4-->"); + break; + case L5: + System.out.print(" L5-->"); + break; + case L6: + System.out.print(" L6-->"); + break; + default: + break; + } + staticLink = data[addr]; + localRegNum = Register.values()[localRegNum.ordinal() + 1]; + } else { + System.out.print(" "); + } + if (addr == dynamicLink && dynamicLink != SB) { + System.out.print("|SL=" + data[addr] + "|"); + } else if (addr == dynamicLink + 1 && dynamicLink != SB) { + System.out.print("|DL=" + data[addr] + "|"); + } else if (addr == dynamicLink + 2 && dynamicLink != SB) { + System.out.print("|RA=" + data[addr] + "|"); + } else { + System.out.print("|" + data[addr] + "|"); + } + System.out.println(""); + if (addr == dynamicLink) { + System.out.println(" |--------|"); + dynamicLink = data[addr + 1]; + } + } + } + System.out.println(""); + } + + static void showStatus() { + // Writes an indication of whether and why the program has terminated. + System.out.println(""); + switch (status) { + case running: + System.out.println("Program is running."); + break; + case halted: + System.out.println("Program has halted normally."); + System.out.println("Total execution time (ns): " + (System.nanoTime() - startTimeNanos)); + break; + case failedDataStoreFull: + System.out.println("Program has failed due to exhaustion of Data Store."); + break; + case failedInvalidCodeAddress: + System.out.println("Program has failed due to an invalid code address."); + break; + case failedInvalidInstruction: + System.out.println("Program has failed due to an invalid instruction."); + break; + case failedOverflow: + System.out.println("Program has failed due to overflow."); + break; + case failedZeroDivide: + System.out.println("Program has failed due to division by zero."); + break; + case failedIOError: + System.out.println("Program has failed due to an IO error."); + break; + } + if (status != halted) { + dump(); + } + } + + // INTERPRETATION + + static void checkSpace(int spaceNeeded) { + // Signals failure if there is not enough space to expand the stack or + // heap by spaceNeeded. + + if (HT - ST < spaceNeeded) { + status = failedDataStoreFull; + } + } + + static boolean isTrue(int datum) { + // Tests whether the given datum represents true. + return (datum == Machine.trueRep); + } + + static boolean equal(int size, int addr1, int addr2) { + // Tests whether two multi-word objects are equal, given their common + // size and their base addresses. + + boolean eq; + int index; + + eq = true; + index = 0; + while (eq && (index < size)) { + if (data[addr1 + index] == data[addr2 + index]) { + index = index + 1; + } else { + eq = false; + } + } + + return eq; + } + + static int overflowChecked(long datum) { + // Signals failure if the datum is too large to fit into a single word, + // otherwise returns the datum as a single word. + + if ((-Machine.maxintRep <= datum) && (datum <= Machine.maxintRep)) { + return (int) datum; + } else { + status = failedOverflow; + return 0; + } + } + + static int toInt(boolean b) { + return b ? Machine.trueRep : Machine.falseRep; + } + + static int currentChar; + + static int readInt() throws java.io.IOException { + int temp = 0; + int sign = 1; + + do { + currentChar = System.in.read(); + } while (Character.isWhitespace((char) currentChar)); + + if ((currentChar == '-') || (currentChar == '+')) { + do { + sign = (currentChar == '-') ? -1 : 1; + currentChar = System.in.read(); + } while ((currentChar == '-') || currentChar == '+'); + } + + if (Character.isDigit((char) currentChar)) { + do { + temp = temp * 10 + (currentChar - '0'); + currentChar = System.in.read(); + } while (Character.isDigit((char) currentChar)); + } + + return sign * temp; + } + + static void callPrimitive(int primitiveDisplacement) { + // Invokes the given primitive routine. + + int addr, size; + char ch; + + var primitive = Primitive.values()[primitiveDisplacement]; + switch (primitive) { + case ID: + break; // nothing to be done + case NOT: + data[ST - 1] = toInt(!isTrue(data[ST - 1])); + break; + case AND: + ST = ST - 1; + data[ST - 1] = toInt(isTrue(data[ST - 1]) & isTrue(data[ST])); + break; + case OR: + ST = ST - 1; + data[ST - 1] = toInt(isTrue(data[ST - 1]) | isTrue(data[ST])); + break; + case SUCC: + data[ST - 1] = overflowChecked(data[ST - 1] + 1); + break; + case PRED: + data[ST - 1] = overflowChecked(data[ST - 1] - 1); + break; + case NEG: + data[ST - 1] = -data[ST - 1]; + break; + case ADD: + ST = ST - 1; + accumulator = data[ST - 1]; + data[ST - 1] = overflowChecked(accumulator + data[ST]); + break; + case SUB: + ST = ST - 1; + accumulator = data[ST - 1]; + data[ST - 1] = overflowChecked(accumulator - data[ST]); + break; + case MULT: + ST = ST - 1; + accumulator = data[ST - 1]; + data[ST - 1] = overflowChecked(accumulator * data[ST]); + break; + case DIV: + ST = ST - 1; + accumulator = data[ST - 1]; + if (data[ST] != 0) { + data[ST - 1] = (int) (accumulator / data[ST]); + } else { + status = failedZeroDivide; + } + break; + case MOD: + ST = ST - 1; + accumulator = data[ST - 1]; + if (data[ST] != 0) { + data[ST - 1] = (int) (accumulator % data[ST]); + } else { + status = failedZeroDivide; + } + break; + case LT: + ST = ST - 1; + data[ST - 1] = toInt(data[ST - 1] < data[ST]); + break; + case LE: + ST = ST - 1; + data[ST - 1] = toInt(data[ST - 1] <= data[ST]); + break; + case GE: + ST = ST - 1; + data[ST - 1] = toInt(data[ST - 1] >= data[ST]); + break; + case GT: + ST = ST - 1; + data[ST - 1] = toInt(data[ST - 1] > data[ST]); + break; + case EQ: + size = data[ST - 1]; // size of each comparand + ST = ST - 2 * size; + data[ST - 1] = toInt(equal(size, ST - 1, ST - 1 + size)); + break; + case NE: + size = data[ST - 1]; // size of each comparand + ST = ST - 2 * size; + data[ST - 1] = toInt(!equal(size, ST - 1, ST - 1 + size)); + break; + case EOL: + data[ST] = toInt(currentChar == '\n'); + ST = ST + 1; + break; + case EOF: + data[ST] = toInt(currentChar == -1); + ST = ST + 1; + break; + case GET: + ST = ST - 1; + addr = data[ST]; + try { + currentChar = System.in.read(); + } catch (java.io.IOException s) { + status = failedIOError; + } + data[addr] = currentChar; + break; + case PUT: + ST = ST - 1; + ch = (char) data[ST]; + System.out.print(ch); + break; + case GETEOL: + try { + while ((currentChar = System.in.read()) != '\n') + ; + } catch (java.io.IOException s) { + status = failedIOError; + } + break; + case PUTEOL: + System.out.println(""); + break; + case GETINT: + ST = ST - 1; + addr = data[ST]; + try { + accumulator = readInt(); + } catch (java.io.IOException s) { + status = failedIOError; + } + data[addr] = (int) accumulator; + break; + case PUTINT: + ST = ST - 1; + accumulator = data[ST]; + System.out.print(accumulator); + break; + case NEW: + size = data[ST - 1]; + checkSpace(size); + HT = HT - size; + data[ST - 1] = HT; + break; + case DISPOSE: + ST = ST - 1; // no action taken at present + break; + } + } + + static void interpretProgram() { + // Runs the program in code store. + + Instruction currentInstr; + + // Initialize registers ... + ST = SB; + HT = HB; + LB = SB; + CP = CB; + status = running; + do { + // Fetch instruction ... + currentInstr = Machine.code[CP]; + // Decode instruction ... + var op = currentInstr.opCode; + var r = currentInstr.register; + var n = currentInstr.length; + var d = currentInstr.operand; + int addr; + + // Execute instruction ... + switch (op) { + case LOAD: + addr = d + content(r); + checkSpace(n); + for (var index = 0; index < n; index++) { + data[ST + index] = data[addr + index]; + } + ST = ST + n; + CP = CP + 1; + break; + case LOADA: + addr = d + content(r); + checkSpace(1); + data[ST] = addr; + ST = ST + 1; + CP = CP + 1; + break; + case LOADI: + ST = ST - 1; + addr = data[ST]; + checkSpace(n); + for (var index = 0; index < n; index++) { + data[ST + index] = data[addr + index]; + } + ST = ST + n; + CP = CP + 1; + break; + case LOADL: + checkSpace(1); + data[ST] = d; + ST = ST + 1; + CP = CP + 1; + break; + case STORE: + addr = d + content(r); + ST = ST - n; + for (var index = 0; index < n; index++) { + data[addr + index] = data[ST + index]; + } + CP = CP + 1; + break; + case STOREI: + ST = ST - 1; + addr = data[ST]; + ST = ST - n; + for (var index = 0; index < n; index++) { + data[addr + index] = data[ST + index]; + } + CP = CP + 1; + break; + case CALL: + addr = d + content(r); + if (addr >= Machine.PB) { + callPrimitive(addr - Machine.PB); + CP = CP + 1; + } else { + checkSpace(3); + if (0 <= n && n <= 15) { + data[ST] = content(n); // static link + } else { + status = failedInvalidInstruction; + } + data[ST + 1] = LB; // dynamic link + data[ST + 2] = CP + 1; // return address + LB = ST; + ST = ST + 3; + CP = addr; + } + break; + case CALLI: + ST = ST - 2; + addr = data[ST + 1]; + if (addr >= Machine.PB) { + callPrimitive(addr - Machine.PB); + CP = CP + 1; + } else { + // data[ST] = static link already + data[ST + 1] = LB; // dynamic link + data[ST + 2] = CP + 1; // return address + LB = ST; + ST = ST + 3; + CP = addr; + } + break; + case RETURN: + addr = LB - d; + CP = data[LB + 2]; + LB = data[LB + 1]; + ST = ST - n; + for (var index = 0; index < n; index++) { + data[addr + index] = data[ST + index]; + } + ST = addr + n; + break; + case PUSH: + checkSpace(d); + ST = ST + d; + CP = CP + 1; + break; + case POP: + addr = ST - n - d; + ST = ST - n; + for (var index = 0; index < n; index++) { + data[addr + index] = data[ST + index]; + } + ST = addr + n; + CP = CP + 1; + break; + case JUMP: + CP = d + content(r); + break; + case JUMPI: + ST = ST - 1; + CP = data[ST]; + break; + case JUMPIF: + ST = ST - 1; + if (data[ST] == n) { + CP = d + content(r); + } else { + CP = CP + 1; + } + break; + case HALT: + status = halted; + break; + } + if (CP < CB || CP >= CT) { + status = failedInvalidCodeAddress; + } + } while (status == running); + } + + // LOADING + + static void loadObjectProgram(String objectName) { + // Loads the TAM object program into code store from the named file. + + boolean finished = false; + + try (var objectFile = new FileInputStream(objectName)) { + var objectStream = new DataInputStream(objectFile); + + var addr = Machine.CB; + while (!finished) { + Machine.code[addr] = Instruction.read(objectStream); + if (Machine.code[addr] == null) { + finished = true; + } else { + addr = addr + 1; + } + } + CT = addr; + } catch (FileNotFoundException s) { + CT = CB; + System.err.println("Error opening object file: " + s); + } catch (IOException s) { + CT = CB; + System.err.println("Error reading object file: " + s); + } + } + + // RUNNING + + public static void main(String[] args) { + System.out.println("********** TAM Interpreter (Java Version 2.1) **********"); + + if (args.length == 1) { + objectName = args[0]; + } else { + objectName = "obj.tam"; + } + + loadObjectProgram(objectName); + if (CT != CB) { + startTimeNanos = System.nanoTime(); + interpretProgram(); + showStatus(); + } + } +} diff --git a/Triangle.AbstractMachine/.gitignore b/Triangle.AbstractMachine/.gitignore new file mode 100644 index 0000000..8c107fe --- /dev/null +++ b/Triangle.AbstractMachine/.gitignore @@ -0,0 +1,3 @@ +/target/ +/.classpath +/build/ diff --git a/Triangle.AbstractMachine/.project b/Triangle.AbstractMachine/.project new file mode 100644 index 0000000..42358c2 --- /dev/null +++ b/Triangle.AbstractMachine/.project @@ -0,0 +1,23 @@ + + + Triangle.AbstractMachine + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/Triangle.AbstractMachine/build.gradle b/Triangle.AbstractMachine/build.gradle new file mode 100644 index 0000000..80f98eb --- /dev/null +++ b/Triangle.AbstractMachine/build.gradle @@ -0,0 +1,4 @@ +apply plugin: 'java-library' +apply plugin: 'eclipse' + +sourceCompatibility = 11 \ No newline at end of file diff --git a/Triangle.AbstractMachine/pom.xml b/Triangle.AbstractMachine/pom.xml new file mode 100644 index 0000000..c7675fa --- /dev/null +++ b/Triangle.AbstractMachine/pom.xml @@ -0,0 +1,12 @@ + + 4.0.0 + triangle-abstractmachine + jar + + triangle.tools + triangle-tools + 2.1 + ../ + + \ No newline at end of file diff --git a/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Instruction.java b/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Instruction.java new file mode 100644 index 0000000..16f3fe9 --- /dev/null +++ b/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Instruction.java @@ -0,0 +1,71 @@ +/* + * @(#)Instruction.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractMachine; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.IOException; + +public class Instruction { + + // Java has no type synonyms, so the following representations are + // assumed: + // + // type + // OpCode = 0..15; {4 bits unsigned} + // Length = 0..255; {8 bits unsigned} + // Operand = -32767..+32767; {16 bits signed} + + // Represents TAM instructions. + final OpCode opCode; + final Register register; + final int length; + int operand; // Not final to allow for patching jump address + + public Instruction(OpCode opcode, Register register, int length, int operand) { + this.opCode = opcode; + this.register = register; + this.length = length; + this.operand = operand; + } + + public void setOperand(int operand) { + this.operand = operand; + } + + public void write(DataOutputStream output) throws IOException { + output.writeInt(opCode.ordinal()); + output.writeInt(register.ordinal()); + output.writeInt(length); + output.writeInt(operand); + } + + public static Instruction read(DataInputStream input) throws IOException { + try { + var opCode = OpCode.values()[input.readInt()]; + var register = Register.values()[input.readInt()]; + var length = input.readInt(); + var operand = input.readInt(); + return new Instruction(opCode, register, length, operand); + } catch (EOFException s) { + return null; + } + } +} diff --git a/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Machine.java b/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Machine.java new file mode 100644 index 0000000..1bcfd6b --- /dev/null +++ b/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Machine.java @@ -0,0 +1,58 @@ +/* + * @(#)Machine.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractMachine; + +public final class Machine { + + public final static int maxRoutineLevel = 7; + + // WORDS AND ADDRESSES + + // Java has no type synonyms, so the following representations are + // assumed: + // + // type + // Word = -32767..+32767; {16 bits signed} + // DoubleWord = -2147483648..+2147483647; {32 bits signed} + // CodeAddress = 0..+32767; {15 bits unsigned} + // DataAddress = 0..+32767; {15 bits unsigned} + + // INSTRUCTIONS + + // CODE STORE + + public static Instruction[] code = new Instruction[1024]; + + // CODE STORE REGISTERS + + public final static int CB = 0, PB = 1024, // = upper bound of code array + 1 + PT = 1052; // = PB + 28 + + // REGISTER NUMBERS + + // DATA REPRESENTATION + + public final static int booleanSize = 1, characterSize = 1, integerSize = 1, addressSize = 1, + closureSize = 2 * addressSize, + + linkDataSize = 3 * addressSize, + + falseRep = 0, trueRep = 1, maxintRep = 32767; + +} diff --git a/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/OpCode.java b/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/OpCode.java new file mode 100644 index 0000000..23ca257 --- /dev/null +++ b/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/OpCode.java @@ -0,0 +1,5 @@ +package triangle.abstractMachine; + +public enum OpCode { + LOAD, LOADA, LOADI, LOADL, STORE, STOREI, CALL, CALLI, RETURN, NOP, PUSH, POP, JUMP, JUMPI, JUMPIF, HALT +} diff --git a/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Primitive.java b/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Primitive.java new file mode 100644 index 0000000..11bb5bc --- /dev/null +++ b/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Primitive.java @@ -0,0 +1,6 @@ +package triangle.abstractMachine; + +public enum Primitive { + ID, NOT, AND, OR, SUCC, PRED, NEG, ADD, SUB, MULT, DIV, MOD, LT, LE, GE, GT, EQ, NE, EOL, EOF, GET, PUT, GETEOL, + PUTEOL, GETINT, PUTINT, NEW, DISPOSE +} diff --git a/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Register.java b/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Register.java new file mode 100644 index 0000000..0b36262 --- /dev/null +++ b/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Register.java @@ -0,0 +1,5 @@ +package triangle.abstractMachine; + +public enum Register { + CB, CT, PB, PT, SB, ST, HB, HT, LB, L1, L2, L3, L4, L5, L6, CP +} diff --git a/Triangle.Compiler/.gitignore b/Triangle.Compiler/.gitignore new file mode 100644 index 0000000..55f062a --- /dev/null +++ b/Triangle.Compiler/.gitignore @@ -0,0 +1,4 @@ +/target/ +/.classpath +/.editorconfig +/build/ diff --git a/Triangle.Compiler/.project b/Triangle.Compiler/.project new file mode 100644 index 0000000..dca5b8c --- /dev/null +++ b/Triangle.Compiler/.project @@ -0,0 +1,23 @@ + + + Triangle.Compiler + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/Triangle.Compiler/build.gradle b/Triangle.Compiler/build.gradle new file mode 100644 index 0000000..1134923 --- /dev/null +++ b/Triangle.Compiler/build.gradle @@ -0,0 +1,24 @@ +apply plugin: 'java' +apply plugin: 'application' + +sourceCompatibility = 11 + +repositories { + mavenCentral() +} + + +dependencies { + implementation project(':Triangle.AbstractMachine') + // Task 2 + implementation group: 'com.github.spullara.cli-parser', name: 'cli-parser', version: '1.1.5' + // + testImplementation group: 'junit', name: 'junit', version: '4.13.2' +} + +application { + mainClass = 'Triangle.Compiler' +} + +// allow access to programs for unit tests +sourceSets.test.resources.srcDir file("$rootDir/programs") diff --git a/Triangle.Compiler/pom.xml b/Triangle.Compiler/pom.xml new file mode 100644 index 0000000..17b97da --- /dev/null +++ b/Triangle.Compiler/pom.xml @@ -0,0 +1,18 @@ + + 4.0.0 + triangle-compiler + + triangle.tools + triangle-tools + 2.1 + ../ + + + + triangle.tools + triangle-abstractmachine + 2.1 + + + diff --git a/Triangle.Compiler/src/main/java/triangle/Compiler.java b/Triangle.Compiler/src/main/java/triangle/Compiler.java new file mode 100644 index 0000000..8416466 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/Compiler.java @@ -0,0 +1,183 @@ +/* + * @(#)Compiler.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle; + +import triangle.abstractSyntaxTrees.Program; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Encoder; +import triangle.contextualAnalyzer.Checker; +import triangle.optimiser.ConstantFolder; +import triangle.syntacticAnalyzer.Parser; +import triangle.syntacticAnalyzer.Scanner; +import triangle.syntacticAnalyzer.SourceFile; +import triangle.treeDrawer.Drawer; + +// Task 2 +import com.sampullara.cli.Args; +import com.sampullara.cli.Argument; + +/** + * The main driver class for the Triangle compiler. + * + * @version 2.1 7 Oct 2003 + * @author Deryck F. Brown + */ +public class Compiler { + + /** The filename for the object program, normally obj.tam. */ + //static String objectNIame = "obj.tam"; + //static boolean showTree = false; + //static boolean folding = false; //Better implementation below + + private static Scanner scanner; + private static Parser parser; + private static Checker checker; + private static Encoder encoder; + private static Emitter emitter; + private static ErrorReporter reporter; + private static Drawer drawer; + + /** The AST representing the source program. */ + private static Program theAST; + + //Task 2 + + @Argument(alias = "file", description="Name of file you want to compile", required = true) + static String sourceName = ""; + + @Argument(alias = "obj", description="Object file name", required = true) + static String objectName = "obj.tam"; //default + + @Argument(alias = "tree", description="Enable AST") + static boolean showTree = false; + + @Argument(alias = "fold", description="Enable folding") + static boolean folding = false; + + @Argument(alias = "tfold", description="Enable AST after folding") + static boolean showTreeAfterFolding = false; + + //Task 5b + @Argument(alias = "stats", description="Enable stats (Char and Int Expr count)") + static boolean showStats = false; + + /** + * Compile the source program to TAM machine code. + * + * @param sourceName the name of the file containing the source program. + * @param objectName the name of the file containing the object program. + * @param showingAST true iff the AST is to be displayed after contextual + * analysis + * @param showingTable true iff the object description details are to be + * displayed during code generation (not currently + * implemented). + * @param showAfterFolding show the AST after folding is complete + * @param showStats show stats, these only (so far) inlcude char and int expressions + * @return true iff the source program is free of compile-time errors, otherwise + * false. + */ + static boolean compileProgram(String sourceName, String objectName, boolean showingAST, boolean showingTable, boolean showAfterFolding, boolean showStats) { + + System.out.println("********** " + "Triangle Compiler (Java Version 2.1)" + " **********"); + + System.out.println("Syntactic Analysis ..."); + SourceFile source = SourceFile.ofPath(sourceName); + + if (source == null) { + System.out.println("Can't access source file " + sourceName); + System.exit(1); + } + + scanner = new Scanner(source); + reporter = new ErrorReporter(false); + parser = new Parser(scanner, reporter); + checker = new Checker(reporter); + emitter = new Emitter(reporter); + encoder = new Encoder(emitter, reporter); + drawer = new Drawer(); + + //Task 5b + stats = new SummaryStats(); + + theAST = parser.parseProgram(); // 1st pass + if (reporter.getNumErrors() == 0) { + System.out.println("Contextual Analysis ..."); + checker.check(theAST); // 2nd pass + + if (showingAST && !showAfterFolding) { + drawer.draw(theAST); + } + if (folding) { + theAST.visit(new ConstantFolder()); + if (showingAST && showAfterFolding) { + drawer.draw(theAST); //if folding then also show tree + } + } + + + if (reporter.getNumErrors() == 0) { + System.out.println("Code Generation ..."); + encoder.encodeRun(theAST, showingTable); // 3rd pass + } + } + + boolean successful = (reporter.getNumErrors() == 0); + if (successful) { + emitter.saveObjectProgram(objectName); + System.out.println("Compilation was successful."); + //Task 5b + System.out.println("[STATS] CharExpr: " + stats.getCharExprCount() + "!"); + System.out.println("[STATS] IntExpr: " + stats.getIntExprCount() + "!"); + } else { + System.out.println("Compilation was unsuccessful."); + } + return successful; + } + + /** + * Triangle compiler main program. + * + * @param args the only command-line argument to the program specifies the + * source filename. + */ + public static void main(String[] args) { + + //Task 2 + Args.parseOrExit(Compiler.class, args); + var compiledOK = compileProgram(Compiler.sourceName, Compiler.objectName, Compiler.showTree, false, Compiler.showTreeAfterFolding); + + if (!showTree) { + System.exit(compiledOK ? 0 : 1); + } + } + + /* No longer needed */ + private static void parseArgs(String[] args) { + for (String s : args) { + var sl = s.toLowerCase(); + if (sl.equals("tree")) { + showTree = true; + } else if (sl.startsWith("-o=")) { + objectName = s.substring(3); + } else if (sl.equals("folding")) { + folding = true; + } + } + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/ErrorReporter.java b/Triangle.Compiler/src/main/java/triangle/ErrorReporter.java new file mode 100644 index 0000000..35a813d --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/ErrorReporter.java @@ -0,0 +1,65 @@ +/* + * @(#)ErrorReporter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle; + +import triangle.syntacticAnalyzer.SourcePosition; + +public class ErrorReporter { + + private int numErrors; + + private boolean throwExceptions; + + /** + * @param throwExceptions if true, throw exceptions (good for unit tests) otherwise write to stdout + */ + public ErrorReporter(boolean throwExceptions) { + numErrors = 0; + this.throwExceptions = throwExceptions; + } + + public void reportError(String message, String tokenName, SourcePosition pos) { + + numErrors++; + + String s = ("ERROR: "); + + for (int p = 0; p < message.length(); p++) + if (message.charAt(p) == '%') + s += tokenName; + else + s += message.charAt(p); + s += (" " + pos.start + ".." + pos.finish); + + if (throwExceptions) { + throw new RuntimeException(s); + } else { + System.out.println(s); + } + + } + + public void reportRestriction(String message) { + System.out.println("RESTRICTION: " + message); + } + + public int getNumErrors() { + return numErrors; + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/StdEnvironment.java b/Triangle.Compiler/src/main/java/triangle/StdEnvironment.java new file mode 100644 index 0000000..6b86b48 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/StdEnvironment.java @@ -0,0 +1,50 @@ +/* + * @(#)StdEnvironment.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle; + +import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration; +import triangle.abstractSyntaxTrees.declarations.ConstDeclaration; +import triangle.abstractSyntaxTrees.declarations.FuncDeclaration; +import triangle.abstractSyntaxTrees.declarations.ProcDeclaration; +import triangle.abstractSyntaxTrees.declarations.UnaryOperatorDeclaration; +import triangle.abstractSyntaxTrees.types.TypeDeclaration; +import triangle.abstractSyntaxTrees.types.TypeDenoter; + +public final class StdEnvironment { + + // These are small ASTs representing standard types. + + public static TypeDenoter booleanType, charType, integerType, anyType, errorType; + + public static TypeDeclaration booleanDecl, charDecl, integerDecl; + + // These are small ASTs representing "declarations" of standard entities. + + public static ConstDeclaration falseDecl, trueDecl, maxintDecl; + + public static UnaryOperatorDeclaration notDecl; + + public static BinaryOperatorDeclaration andDecl, orDecl, addDecl, subtractDecl, multiplyDecl, divideDecl, + moduloDecl, equalDecl, unequalDecl, lessDecl, notlessDecl, greaterDecl, notgreaterDecl; + + public static ProcDeclaration getDecl, putDecl, getintDecl, putintDecl, geteolDecl, puteolDecl; + + public static FuncDeclaration chrDecl, ordDecl, eolDecl, eofDecl; + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/AbstractSyntaxTree.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/AbstractSyntaxTree.java new file mode 100644 index 0000000..8bccf00 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/AbstractSyntaxTree.java @@ -0,0 +1,38 @@ +/* + * @(#)AST.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees; + +import triangle.codeGenerator.entities.RuntimeEntity; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class AbstractSyntaxTree { + + private final SourcePosition position; + + public AbstractSyntaxTree(SourcePosition position) { + this.position = position; + entity = null; + } + + public SourcePosition getPosition() { + return position; + } + + public RuntimeEntity entity; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/Program.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/Program.java new file mode 100644 index 0000000..92dfa7e --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/Program.java @@ -0,0 +1,41 @@ +/* + * @(#)Program.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees; + +import triangle.abstractSyntaxTrees.commands.Command; +import triangle.abstractSyntaxTrees.visitors.ProgramVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class Program extends AbstractSyntaxTree { + + public Program(Command cAST, SourcePosition position) { + super(position); + C = cAST; + } + + public Command C; + + public TResult visit(ProgramVisitor visitor, TArg arg) { + return visitor.visitProgram(this, arg); + } + + public TResult visit(ProgramVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ActualParameter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ActualParameter.java new file mode 100644 index 0000000..404766a --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ActualParameter.java @@ -0,0 +1,36 @@ +/* + * @(#)ActualParameter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.actuals; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.visitors.ActualParameterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class ActualParameter extends AbstractSyntaxTree { + + public ActualParameter(SourcePosition position) { + super(position); + } + + public abstract TResult visit(ActualParameterVisitor visitor, TArg arg); + + public TResult visit(ActualParameterVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ActualParameterSequence.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ActualParameterSequence.java new file mode 100644 index 0000000..d4f3aaa --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ActualParameterSequence.java @@ -0,0 +1,36 @@ +/* + * @(#)ActualParameterSequence.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.actuals; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.visitors.ActualParameterSequenceVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class ActualParameterSequence extends AbstractSyntaxTree { + + public ActualParameterSequence(SourcePosition position) { + super(position); + } + + public abstract TResult visit(ActualParameterSequenceVisitor v, TArg arg); + + public TResult visit(ActualParameterSequenceVisitor v) { + return visit(v, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ConstActualParameter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ConstActualParameter.java new file mode 100644 index 0000000..ca93044 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ConstActualParameter.java @@ -0,0 +1,37 @@ +/* + * @(#)ConstActualParameter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.actuals; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.visitors.ActualParameterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class ConstActualParameter extends ActualParameter { + + public ConstActualParameter(Expression eAST, SourcePosition position) { + super(position); + E = eAST; + } + + public TResult visit(ActualParameterVisitor v, TArg arg) { + return v.visitConstActualParameter(this, arg); + } + + public Expression E; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/EmptyActualParameterSequence.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/EmptyActualParameterSequence.java new file mode 100644 index 0000000..46c4d4e --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/EmptyActualParameterSequence.java @@ -0,0 +1,33 @@ +/* + * @(#)EmptyActualParameterSequence.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.actuals; + +import triangle.abstractSyntaxTrees.visitors.ActualParameterSequenceVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class EmptyActualParameterSequence extends ActualParameterSequence { + + public EmptyActualParameterSequence(SourcePosition position) { + super(position); + } + + public TResult visit(ActualParameterSequenceVisitor v, TArg arg) { + return v.visitEmptyActualParameterSequence(this, arg); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/FuncActualParameter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/FuncActualParameter.java new file mode 100644 index 0000000..40c7f1f --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/FuncActualParameter.java @@ -0,0 +1,37 @@ +/* + * @(#)FuncActualParameter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.actuals; + +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.ActualParameterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class FuncActualParameter extends ActualParameter { + + public FuncActualParameter(Identifier iAST, SourcePosition position) { + super(position); + I = iAST; + } + + public TResult visit(ActualParameterVisitor v, TArg arg) { + return v.visitFuncActualParameter(this, arg); + } + + public final Identifier I; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/MultipleActualParameterSequence.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/MultipleActualParameterSequence.java new file mode 100644 index 0000000..b26b9d3 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/MultipleActualParameterSequence.java @@ -0,0 +1,39 @@ +/* + * @(#)MultipleActualParameterSequence.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.actuals; + +import triangle.abstractSyntaxTrees.visitors.ActualParameterSequenceVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class MultipleActualParameterSequence extends ActualParameterSequence { + + public MultipleActualParameterSequence(ActualParameter apAST, ActualParameterSequence apsAST, + SourcePosition position) { + super(position); + AP = apAST; + APS = apsAST; + } + + public TResult visit(ActualParameterSequenceVisitor v, TArg arg) { + return v.visitMultipleActualParameterSequence(this, arg); + } + + public final ActualParameter AP; + public final ActualParameterSequence APS; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ProcActualParameter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ProcActualParameter.java new file mode 100644 index 0000000..a525a4e --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ProcActualParameter.java @@ -0,0 +1,37 @@ +/* + * @(#)ProcActualParameter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.actuals; + +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.ActualParameterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class ProcActualParameter extends ActualParameter { + + public ProcActualParameter(Identifier iAST, SourcePosition position) { + super(position); + I = iAST; + } + + public TResult visit(ActualParameterVisitor v, TArg arg) { + return v.visitProcActualParameter(this, arg); + } + + public final Identifier I; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/SingleActualParameterSequence.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/SingleActualParameterSequence.java new file mode 100644 index 0000000..5ec7087 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/SingleActualParameterSequence.java @@ -0,0 +1,36 @@ +/* + * @(#)SingleActualParameterSequence.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.actuals; + +import triangle.abstractSyntaxTrees.visitors.ActualParameterSequenceVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class SingleActualParameterSequence extends ActualParameterSequence { + + public SingleActualParameterSequence(ActualParameter apAST, SourcePosition position) { + super(position); + AP = apAST; + } + + public TResult visit(ActualParameterSequenceVisitor v, TArg arg) { + return v.visitSingleActualParameterSequence(this, arg); + } + + public final ActualParameter AP; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/VarActualParameter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/VarActualParameter.java new file mode 100644 index 0000000..2ffc54e --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/VarActualParameter.java @@ -0,0 +1,37 @@ +/* + * @(#)VarActualParameter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.actuals; + +import triangle.abstractSyntaxTrees.visitors.ActualParameterVisitor; +import triangle.abstractSyntaxTrees.vnames.Vname; +import triangle.syntacticAnalyzer.SourcePosition; + +public class VarActualParameter extends ActualParameter { + + public VarActualParameter(Vname vAST, SourcePosition position) { + super(position); + V = vAST; + } + + public TResult visit(ActualParameterVisitor v, TArg arg) { + return v.visitVarActualParameter(this, arg); + } + + public final Vname V; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/ArrayAggregate.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/ArrayAggregate.java new file mode 100644 index 0000000..359cd1b --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/ArrayAggregate.java @@ -0,0 +1,39 @@ +/* + * @(#)ArrayAggregate.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.aggregates; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.visitors.ArrayAggregateVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class ArrayAggregate extends AbstractSyntaxTree { + + public ArrayAggregate(SourcePosition position) { + super(position); + elemCount = 0; + } + + public int elemCount; + + public abstract TResult visit(ArrayAggregateVisitor visitor, TArg arg); + + public TResult visit(ArrayAggregateVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/MultipleArrayAggregate.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/MultipleArrayAggregate.java new file mode 100644 index 0000000..c554b77 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/MultipleArrayAggregate.java @@ -0,0 +1,39 @@ +/* + * @(#)MultipleArrayAggregate.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.aggregates; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.visitors.ArrayAggregateVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class MultipleArrayAggregate extends ArrayAggregate { + + public MultipleArrayAggregate(Expression eAST, ArrayAggregate aaAST, SourcePosition position) { + super(position); + E = eAST; + AA = aaAST; + } + + public TResult visit(ArrayAggregateVisitor v, TArg arg) { + return v.visitMultipleArrayAggregate(this, arg); + } + + public Expression E; + public final ArrayAggregate AA; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/MultipleRecordAggregate.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/MultipleRecordAggregate.java new file mode 100644 index 0000000..5b12468 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/MultipleRecordAggregate.java @@ -0,0 +1,42 @@ +/* + * @(#)MultipleRecordAggregate.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.aggregates; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.RecordAggregateVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class MultipleRecordAggregate extends RecordAggregate { + + public MultipleRecordAggregate(Identifier iAST, Expression eAST, RecordAggregate raAST, SourcePosition position) { + super(position); + I = iAST; + E = eAST; + RA = raAST; + } + + public TResult visit(RecordAggregateVisitor v, TArg arg) { + return v.visitMultipleRecordAggregate(this, arg); + } + + public final Identifier I; + public Expression E; + public final RecordAggregate RA; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/RecordAggregate.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/RecordAggregate.java new file mode 100644 index 0000000..153a367 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/RecordAggregate.java @@ -0,0 +1,40 @@ +/* + * @(#)RecordAggregate.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.aggregates; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.types.FieldTypeDenoter; +import triangle.abstractSyntaxTrees.visitors.RecordAggregateVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class RecordAggregate extends AbstractSyntaxTree { + + public RecordAggregate(SourcePosition position) { + super(position); + type = null; + } + + public FieldTypeDenoter type; + + public abstract TResult visit(RecordAggregateVisitor visitor, TArg arg); + + public TResult visit(RecordAggregateVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/SingleArrayAggregate.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/SingleArrayAggregate.java new file mode 100644 index 0000000..8ccf165 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/SingleArrayAggregate.java @@ -0,0 +1,37 @@ +/* + * @(#)SingleArrayAggregate.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.aggregates; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.visitors.ArrayAggregateVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class SingleArrayAggregate extends ArrayAggregate { + + public SingleArrayAggregate(Expression eAST, SourcePosition position) { + super(position); + E = eAST; + } + + public TResult visit(ArrayAggregateVisitor v, TArg arg) { + return v.visitSingleArrayAggregate(this, arg); + } + + public Expression E; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/SingleRecordAggregate.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/SingleRecordAggregate.java new file mode 100644 index 0000000..f4f18d1 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/SingleRecordAggregate.java @@ -0,0 +1,40 @@ +/* + * @(#)SingleRecordAggregate.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.aggregates; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.RecordAggregateVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class SingleRecordAggregate extends RecordAggregate { + + public SingleRecordAggregate(Identifier iAST, Expression eAST, SourcePosition position) { + super(position); + I = iAST; + E = eAST; + } + + public TResult visit(RecordAggregateVisitor v, TArg arg) { + return v.visitSingleRecordAggregate(this, arg); + } + + public final Identifier I; + public Expression E; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/AssignCommand.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/AssignCommand.java new file mode 100644 index 0000000..030f513 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/AssignCommand.java @@ -0,0 +1,40 @@ +/* + * @(#)AssignCommand.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.commands; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.abstractSyntaxTrees.vnames.Vname; +import triangle.syntacticAnalyzer.SourcePosition; + +public class AssignCommand extends Command { + + public AssignCommand(Vname vAST, Expression eAST, SourcePosition position) { + super(position); + V = vAST; + E = eAST; + } + + public TResult visit(CommandVisitor v, TArg arg) { + return v.visitAssignCommand(this, arg); + } + + public final Vname V; + public Expression E; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/CallCommand.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/CallCommand.java new file mode 100644 index 0000000..1fa3d58 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/CallCommand.java @@ -0,0 +1,40 @@ +/* + * @(#)CallCommand.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.commands; + +import triangle.abstractSyntaxTrees.actuals.ActualParameterSequence; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class CallCommand extends Command { + + public CallCommand(Identifier iAST, ActualParameterSequence apsAST, SourcePosition position) { + super(position); + I = iAST; + APS = apsAST; + } + + public TResult visit(CommandVisitor v, TArg arg) { + return v.visitCallCommand(this, arg); + } + + public final Identifier I; + public final ActualParameterSequence APS; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/Command.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/Command.java new file mode 100644 index 0000000..e4d06ce --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/Command.java @@ -0,0 +1,36 @@ +/* + * @(#)Command.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.commands; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class Command extends AbstractSyntaxTree { + + public Command(SourcePosition position) { + super(position); + } + + public abstract TResult visit(CommandVisitor visitor, TArg arg); + + public TResult visit(CommandVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/EmptyCommand.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/EmptyCommand.java new file mode 100644 index 0000000..8e4ac82 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/EmptyCommand.java @@ -0,0 +1,33 @@ +/* + * @(#)EmptyCommand.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.commands; + +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class EmptyCommand extends Command { + + public EmptyCommand(SourcePosition position) { + super(position); + } + + public TResult visit(CommandVisitor v, TArg arg) { + return v.visitEmptyCommand(this, arg); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/IfCommand.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/IfCommand.java new file mode 100644 index 0000000..bde0333 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/IfCommand.java @@ -0,0 +1,40 @@ +/* + * @(#)IfCommand.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.commands; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class IfCommand extends Command { + + public IfCommand(Expression eAST, Command c1AST, Command c2AST, SourcePosition position) { + super(position); + E = eAST; + C1 = c1AST; + C2 = c2AST; + } + + public TResult visit(CommandVisitor v, TArg arg) { + return v.visitIfCommand(this, arg); + } + + public Expression E; + public final Command C1, C2; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/LetCommand.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/LetCommand.java new file mode 100644 index 0000000..d00d873 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/LetCommand.java @@ -0,0 +1,39 @@ +/* + * @(#)LetCommand.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.commands; + +import triangle.abstractSyntaxTrees.declarations.Declaration; +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class LetCommand extends Command { + + public LetCommand(Declaration dAST, Command cAST, SourcePosition position) { + super(position); + D = dAST; + C = cAST; + } + + public TResult visit(CommandVisitor v, TArg arg) { + return v.visitLetCommand(this, arg); + } + + public final Declaration D; + public final Command C; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/SequentialCommand.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/SequentialCommand.java new file mode 100644 index 0000000..2922f65 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/SequentialCommand.java @@ -0,0 +1,37 @@ +/* + * @(#)SequentialCommand.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.commands; + +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class SequentialCommand extends Command { + + public SequentialCommand(Command c1AST, Command c2AST, SourcePosition position) { + super(position); + C1 = c1AST; + C2 = c2AST; + } + + public TResult visit(CommandVisitor v, TArg arg) { + return v.visitSequentialCommand(this, arg); + } + + public final Command C1, C2; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/WhileCommand.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/WhileCommand.java new file mode 100644 index 0000000..a0e69ee --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/WhileCommand.java @@ -0,0 +1,39 @@ +/* + * @(#)WhileCommand.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.commands; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class WhileCommand extends Command { + + public WhileCommand(Expression eAST, Command cAST, SourcePosition position) { + super(position); + E = eAST; + C = cAST; + } + + public TResult visit(CommandVisitor v, TArg arg) { + return v.visitWhileCommand(this, arg); + } + + public Expression E; + public final Command C; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/BinaryOperatorDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/BinaryOperatorDeclaration.java new file mode 100644 index 0000000..ba3497c --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/BinaryOperatorDeclaration.java @@ -0,0 +1,43 @@ +/* + * @(#)BinaryOperatorDeclaration.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.terminals.Operator; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class BinaryOperatorDeclaration extends Declaration { + + public BinaryOperatorDeclaration(Operator oAST, TypeDenoter arg1AST, TypeDenoter arg2AST, TypeDenoter resultAST, + SourcePosition position) { + super(position); + O = oAST; + ARG1 = arg1AST; + ARG2 = arg2AST; + RES = resultAST; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitBinaryOperatorDeclaration(this, arg); + } + + public final Operator O; + public final TypeDenoter ARG1, ARG2, RES; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ConstDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ConstDeclaration.java new file mode 100644 index 0000000..b60c3ba --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ConstDeclaration.java @@ -0,0 +1,46 @@ +/* + * @(#)ConstDeclaration.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class ConstDeclaration extends Declaration implements ConstantDeclaration { + + public ConstDeclaration(Identifier iAST, Expression eAST, SourcePosition position) { + super(position); + I = iAST; + E = eAST; + } + + @Override + public TypeDenoter getType() { + return E.type; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitConstDeclaration(this, arg); + } + + public final Identifier I; + public Expression E; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ConstantDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ConstantDeclaration.java new file mode 100644 index 0000000..5241bfc --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ConstantDeclaration.java @@ -0,0 +1,9 @@ +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.types.TypeDenoter; + +public interface ConstantDeclaration { + + TypeDenoter getType(); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/Declaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/Declaration.java new file mode 100644 index 0000000..b20340b --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/Declaration.java @@ -0,0 +1,39 @@ +/* + * @(#)Declaration.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class Declaration extends AbstractSyntaxTree { + + public Declaration(SourcePosition position) { + super(position); + duplicated = false; + } + + public boolean duplicated; + + public abstract TResult visit(DeclarationVisitor visitor, TArg arg); + + public TResult visit(DeclarationVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/FuncDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/FuncDeclaration.java new file mode 100644 index 0000000..fb0b6b1 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/FuncDeclaration.java @@ -0,0 +1,57 @@ +/* + * @(#)FuncDeclaration.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.formals.FormalParameterSequence; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class FuncDeclaration extends Declaration implements FunctionDeclaration { + + public FuncDeclaration(Identifier iAST, FormalParameterSequence fpsAST, TypeDenoter tAST, Expression eAST, + SourcePosition position) { + super(position); + I = iAST; + FPS = fpsAST; + T = tAST; + E = eAST; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitFuncDeclaration(this, arg); + } + + @Override + public FormalParameterSequence getFormals() { + return FPS; + } + + @Override + public TypeDenoter getType() { + return T; + } + + public final Identifier I; + public final FormalParameterSequence FPS; + public TypeDenoter T; + public Expression E; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/FunctionDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/FunctionDeclaration.java new file mode 100644 index 0000000..425fd7c --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/FunctionDeclaration.java @@ -0,0 +1,12 @@ +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.formals.FormalParameterSequence; +import triangle.abstractSyntaxTrees.types.TypeDenoter; + +public interface FunctionDeclaration { + + FormalParameterSequence getFormals(); + + TypeDenoter getType(); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ProcDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ProcDeclaration.java new file mode 100644 index 0000000..fb1ba97 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ProcDeclaration.java @@ -0,0 +1,48 @@ +/* + * @(#)ProcDeclaration.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.commands.Command; +import triangle.abstractSyntaxTrees.formals.FormalParameterSequence; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class ProcDeclaration extends Declaration implements ProcedureDeclaration { + + public ProcDeclaration(Identifier iAST, FormalParameterSequence fpsAST, Command cAST, SourcePosition position) { + super(position); + I = iAST; + FPS = fpsAST; + C = cAST; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitProcDeclaration(this, arg); + } + + @Override + public FormalParameterSequence getFormals() { + return FPS; + } + + public final Identifier I; + public final FormalParameterSequence FPS; + public final Command C; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ProcedureDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ProcedureDeclaration.java new file mode 100644 index 0000000..94dee6f --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ProcedureDeclaration.java @@ -0,0 +1,9 @@ +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.formals.FormalParameterSequence; + +public interface ProcedureDeclaration { + + FormalParameterSequence getFormals(); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/SequentialDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/SequentialDeclaration.java new file mode 100644 index 0000000..1f5b1e7 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/SequentialDeclaration.java @@ -0,0 +1,37 @@ +/* + * @(#)SequentialDeclaration.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class SequentialDeclaration extends Declaration { + + public SequentialDeclaration(Declaration d1AST, Declaration d2AST, SourcePosition position) { + super(position); + D1 = d1AST; + D2 = d2AST; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitSequentialDeclaration(this, arg); + } + + public final Declaration D1, D2; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/UnaryOperatorDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/UnaryOperatorDeclaration.java new file mode 100644 index 0000000..185647c --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/UnaryOperatorDeclaration.java @@ -0,0 +1,41 @@ +/* + * @(#)UnaryOperatorDeclaration.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.terminals.Operator; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class UnaryOperatorDeclaration extends Declaration { + + public UnaryOperatorDeclaration(Operator oAST, TypeDenoter argAST, TypeDenoter resultAST, SourcePosition position) { + super(position); + O = oAST; + ARG = argAST; + RES = resultAST; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitUnaryOperatorDeclaration(this, arg); + } + + public final Operator O; + public final TypeDenoter ARG, RES; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/VarDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/VarDeclaration.java new file mode 100644 index 0000000..bb29245 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/VarDeclaration.java @@ -0,0 +1,45 @@ +/* + * @(#)VarDeclaration.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class VarDeclaration extends Declaration implements VariableDeclaration { + + public VarDeclaration(Identifier iAST, TypeDenoter tAST, SourcePosition position) { + super(position); + I = iAST; + T = tAST; + } + + @Override + public TypeDenoter getType() { + return T; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitVarDeclaration(this, arg); + } + + public final Identifier I; + public TypeDenoter T; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/VariableDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/VariableDeclaration.java new file mode 100644 index 0000000..4c4bfd4 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/VariableDeclaration.java @@ -0,0 +1,9 @@ +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.types.TypeDenoter; + +public interface VariableDeclaration { + + TypeDenoter getType(); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/ArrayExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/ArrayExpression.java new file mode 100644 index 0000000..1306df4 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/ArrayExpression.java @@ -0,0 +1,37 @@ +/* + * @(#)ArrayExpression.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.aggregates.ArrayAggregate; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class ArrayExpression extends Expression { + + public ArrayExpression(ArrayAggregate aaAST, SourcePosition position) { + super(position); + AA = aaAST; + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitArrayExpression(this, arg); + } + + public final ArrayAggregate AA; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/BinaryExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/BinaryExpression.java new file mode 100644 index 0000000..eee1e0e --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/BinaryExpression.java @@ -0,0 +1,41 @@ +/* + * @(#)BinaryExpression.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.terminals.Operator; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class BinaryExpression extends Expression { + + public BinaryExpression(Expression e1AST, Operator oAST, Expression e2AST, SourcePosition position) { + super(position); + O = oAST; + E1 = e1AST; + E2 = e2AST; + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitBinaryExpression(this, arg); + } + + public Expression E1; + public Expression E2; + public final Operator O; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/CallExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/CallExpression.java new file mode 100644 index 0000000..0aeb2e2 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/CallExpression.java @@ -0,0 +1,40 @@ +/* + * @(#)CallExpression.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.actuals.ActualParameterSequence; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class CallExpression extends Expression { + + public CallExpression(Identifier iAST, ActualParameterSequence apsAST, SourcePosition position) { + super(position); + I = iAST; + APS = apsAST; + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitCallExpression(this, arg); + } + + public final Identifier I; + public final ActualParameterSequence APS; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/CharacterExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/CharacterExpression.java new file mode 100644 index 0000000..e8b549b --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/CharacterExpression.java @@ -0,0 +1,47 @@ +/* + * @(#)CharacterExpression.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.terminals.CharacterLiteral; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class CharacterExpression extends Expression { + + public CharacterExpression(CharacterLiteral clAST, SourcePosition position) { + super(position); + CL = clAST; + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitCharacterExpression(this, arg); + } + + public final CharacterLiteral CL; + + @Override + public boolean isLiteral() { + return true; + } + + @Override + public int getValue() { + return CL.getValue(); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/EmptyExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/EmptyExpression.java new file mode 100644 index 0000000..ed67191 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/EmptyExpression.java @@ -0,0 +1,33 @@ +/* + * @(#)EmptyExpression.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class EmptyExpression extends Expression { + + public EmptyExpression(SourcePosition position) { + super(position); + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitEmptyExpression(this, arg); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/Expression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/Expression.java new file mode 100644 index 0000000..a3f6f27 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/Expression.java @@ -0,0 +1,48 @@ +/* + * @(#)Expression.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class Expression extends AbstractSyntaxTree { + + public Expression(SourcePosition position) { + super(position); + type = null; + } + + public TypeDenoter type; + + public boolean isLiteral() { + return false; + } + + public int getValue() { + throw new UnsupportedOperationException(); + } + + public abstract TResult visit(ExpressionVisitor visitor, TArg arg); + + public TResult visit(ExpressionVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/IfExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/IfExpression.java new file mode 100644 index 0000000..059fb78 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/IfExpression.java @@ -0,0 +1,40 @@ +/* + * @(#)IfExpression.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class IfExpression extends Expression { + + public IfExpression(Expression e1AST, Expression e2AST, Expression e3AST, SourcePosition position) { + super(position); + E1 = e1AST; + E2 = e2AST; + E3 = e3AST; + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitIfExpression(this, arg); + } + + public Expression E1; + public Expression E2; + public Expression E3; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/IntegerExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/IntegerExpression.java new file mode 100644 index 0000000..b0c8406 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/IntegerExpression.java @@ -0,0 +1,47 @@ +/* + * @(#)IntegerExpression.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.terminals.IntegerLiteral; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class IntegerExpression extends Expression { + + public IntegerExpression(IntegerLiteral ilAST, SourcePosition position) { + super(position); + IL = ilAST; + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitIntegerExpression(this, arg); + } + + public final IntegerLiteral IL; + + @Override + public boolean isLiteral() { + return true; + } + + @Override + public int getValue() { + return IL.getValue(); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/LetExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/LetExpression.java new file mode 100644 index 0000000..2e2e144 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/LetExpression.java @@ -0,0 +1,39 @@ +/* + * @(#)LetExpression.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.declarations.Declaration; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class LetExpression extends Expression { + + public LetExpression(Declaration dAST, Expression eAST, SourcePosition position) { + super(position); + D = dAST; + E = eAST; + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitLetExpression(this, arg); + } + + public final Declaration D; + public Expression E; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/RecordExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/RecordExpression.java new file mode 100644 index 0000000..e9467e4 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/RecordExpression.java @@ -0,0 +1,37 @@ +/* + * @(#)RecordExpression.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.aggregates.RecordAggregate; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class RecordExpression extends Expression { + + public RecordExpression(RecordAggregate raAST, SourcePosition position) { + super(position); + RA = raAST; + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitRecordExpression(this, arg); + } + + public final RecordAggregate RA; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/UnaryExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/UnaryExpression.java new file mode 100644 index 0000000..836e8f7 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/UnaryExpression.java @@ -0,0 +1,39 @@ +/* + * @(#)UnaryExpression.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.terminals.Operator; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class UnaryExpression extends Expression { + + public UnaryExpression(Operator oAST, Expression eAST, SourcePosition position) { + super(position); + O = oAST; + E = eAST; + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitUnaryExpression(this, arg); + } + + public Expression E; + public final Operator O; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/VnameExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/VnameExpression.java new file mode 100644 index 0000000..8a04c73 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/VnameExpression.java @@ -0,0 +1,37 @@ +/* + * @(#)VnameExpression.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.abstractSyntaxTrees.vnames.Vname; +import triangle.syntacticAnalyzer.SourcePosition; + +public class VnameExpression extends Expression { + + public VnameExpression(Vname vAST, SourcePosition position) { + super(position); + V = vAST; + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitVnameExpression(this, arg); + } + + public final Vname V; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/ConstFormalParameter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/ConstFormalParameter.java new file mode 100644 index 0000000..9d66e10 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/ConstFormalParameter.java @@ -0,0 +1,55 @@ +/* + * @(#)ConstFormalParameter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.formals; + +import triangle.abstractSyntaxTrees.declarations.ConstantDeclaration; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class ConstFormalParameter extends FormalParameter implements ConstantDeclaration { + + public ConstFormalParameter(Identifier iAST, TypeDenoter tAST, SourcePosition position) { + super(position); + I = iAST; + T = tAST; + } + + @Override + public TypeDenoter getType() { + return T; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitConstFormalParameter(this, arg); + } + + @Override + public boolean equals(Object fpAST) { + if (fpAST instanceof ConstFormalParameter) { + return T.equals(((ConstFormalParameter)fpAST).T); + } else { + return false; + } + } + + public final Identifier I; + public TypeDenoter T; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/EmptyFormalParameterSequence.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/EmptyFormalParameterSequence.java new file mode 100644 index 0000000..d844880 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/EmptyFormalParameterSequence.java @@ -0,0 +1,38 @@ +/* + * @(#)EmptyFormalParameterSequence.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.formals; + +import triangle.abstractSyntaxTrees.visitors.FormalParameterSequenceVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class EmptyFormalParameterSequence extends FormalParameterSequence { + + public EmptyFormalParameterSequence(SourcePosition position) { + super(position); + } + + public TResult visit(FormalParameterSequenceVisitor v, TArg arg) { + return v.visitEmptyFormalParameterSequence(this, arg); + } + + @Override + public boolean equals(Object fpsAST) { + return (fpsAST instanceof EmptyFormalParameterSequence); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FormalParameter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FormalParameter.java new file mode 100644 index 0000000..9248f7f --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FormalParameter.java @@ -0,0 +1,39 @@ +/* + * @(#)FormalParameter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.formals; + +import triangle.abstractSyntaxTrees.declarations.Declaration; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class FormalParameter extends Declaration { + + public FormalParameter(SourcePosition position) { + super(position); + } + + @Override + public abstract boolean equals(Object fpAST); + + public abstract TResult visit(DeclarationVisitor visitor, TArg arg); + + public TResult visit(DeclarationVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FormalParameterSequence.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FormalParameterSequence.java new file mode 100644 index 0000000..dc08d07 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FormalParameterSequence.java @@ -0,0 +1,39 @@ +/* + * @(#)FormalParameterSequence.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.formals; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.visitors.FormalParameterSequenceVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class FormalParameterSequence extends AbstractSyntaxTree { + + public FormalParameterSequence(SourcePosition position) { + super(position); + } + + @Override + public abstract boolean equals(Object fpsAST); + + public abstract TResult visit(FormalParameterSequenceVisitor visitor, TArg arg); + + public TResult visit(FormalParameterSequenceVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FuncFormalParameter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FuncFormalParameter.java new file mode 100644 index 0000000..eeb62e7 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FuncFormalParameter.java @@ -0,0 +1,63 @@ +/* + * @(#)FuncFormalParameter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.formals; + +import triangle.abstractSyntaxTrees.declarations.FunctionDeclaration; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class FuncFormalParameter extends FormalParameter implements FunctionDeclaration { + + public FuncFormalParameter(Identifier iAST, FormalParameterSequence fpsAST, TypeDenoter tAST, + SourcePosition position) { + super(position); + I = iAST; + FPS = fpsAST; + T = tAST; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitFuncFormalParameter(this, arg); + } + + @Override + public FormalParameterSequence getFormals() { + return FPS; + } + + @Override + public TypeDenoter getType() { + return T; + } + + @Override + public boolean equals(Object fpAST) { + if (fpAST instanceof FuncFormalParameter) { + FuncFormalParameter ffpAST = (FuncFormalParameter) fpAST; + return FPS.equals(ffpAST.FPS) && T.equals(ffpAST.T); + } else + return false; + } + + public final Identifier I; + public final FormalParameterSequence FPS; + public TypeDenoter T; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/MultipleFormalParameterSequence.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/MultipleFormalParameterSequence.java new file mode 100644 index 0000000..d6c5a9a --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/MultipleFormalParameterSequence.java @@ -0,0 +1,49 @@ +/* + * @(#)MultipleFormalParameterSequence.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.formals; + +import triangle.abstractSyntaxTrees.visitors.FormalParameterSequenceVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class MultipleFormalParameterSequence extends FormalParameterSequence { + + public MultipleFormalParameterSequence(FormalParameter fpAST, FormalParameterSequence fpsAST, + SourcePosition position) { + super(position); + FP = fpAST; + FPS = fpsAST; + } + + public TResult visit(FormalParameterSequenceVisitor v, TArg arg) { + return v.visitMultipleFormalParameterSequence(this, arg); + } + + @Override + public boolean equals(Object fpsAST) { + if (fpsAST instanceof MultipleFormalParameterSequence) { + MultipleFormalParameterSequence mfpsAST = (MultipleFormalParameterSequence) fpsAST; + return FP.equals(mfpsAST.FP) && FPS.equals(mfpsAST.FPS); + } else { + return false; + } + } + + public final FormalParameter FP; + public final FormalParameterSequence FPS; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/ProcFormalParameter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/ProcFormalParameter.java new file mode 100644 index 0000000..80a49e1 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/ProcFormalParameter.java @@ -0,0 +1,55 @@ +/* + * @(#)ProcFormalParameter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.formals; + +import triangle.abstractSyntaxTrees.declarations.ProcedureDeclaration; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class ProcFormalParameter extends FormalParameter implements ProcedureDeclaration { + + public ProcFormalParameter(Identifier iAST, FormalParameterSequence fpsAST, SourcePosition position) { + super(position); + I = iAST; + FPS = fpsAST; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitProcFormalParameter(this, arg); + } + + @Override + public FormalParameterSequence getFormals() { + return FPS; + } + + @Override + public boolean equals(Object fpAST) { + if (fpAST instanceof ProcFormalParameter) { + ProcFormalParameter pfpAST = (ProcFormalParameter) fpAST; + return FPS.equals(pfpAST.FPS); + } else { + return false; + } + } + + public final Identifier I; + public final FormalParameterSequence FPS; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/SingleFormalParameterSequence.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/SingleFormalParameterSequence.java new file mode 100644 index 0000000..cd624c1 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/SingleFormalParameterSequence.java @@ -0,0 +1,46 @@ +/* + * @(#)SingleFormalParameterSequence.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.formals; + +import triangle.abstractSyntaxTrees.visitors.FormalParameterSequenceVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class SingleFormalParameterSequence extends FormalParameterSequence { + + public SingleFormalParameterSequence(FormalParameter fpAST, SourcePosition position) { + super(position); + FP = fpAST; + } + + public TResult visit(FormalParameterSequenceVisitor v, TArg arg) { + return v.visitSingleFormalParameterSequence(this, arg); + } + + @Override + public boolean equals(Object fpsAST) { + if (fpsAST instanceof SingleFormalParameterSequence) { + SingleFormalParameterSequence sfpsAST = (SingleFormalParameterSequence) fpsAST; + return FP.equals(sfpsAST.FP); + } else { + return false; + } + } + + public final FormalParameter FP; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/VarFormalParameter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/VarFormalParameter.java new file mode 100644 index 0000000..5bbdbbd --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/VarFormalParameter.java @@ -0,0 +1,55 @@ +/* + * @(#)ValFormalParameter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.formals; + +import triangle.abstractSyntaxTrees.declarations.VariableDeclaration; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class VarFormalParameter extends FormalParameter implements VariableDeclaration { + + public VarFormalParameter(Identifier iAST, TypeDenoter tAST, SourcePosition position) { + super(position); + I = iAST; + T = tAST; + } + + @Override + public TypeDenoter getType() { + return T; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitVarFormalParameter(this, arg); + } + + @Override + public boolean equals(Object fpAST) { + if (fpAST instanceof VarFormalParameter) { + return T.equals(((VarFormalParameter)fpAST).T); + } else { + return false; + } + } + + public final Identifier I; + public TypeDenoter T; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/CharacterLiteral.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/CharacterLiteral.java new file mode 100644 index 0000000..6fe99ca --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/CharacterLiteral.java @@ -0,0 +1,41 @@ +/* + * @(#)CharacterLiteral.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.terminals; + +import triangle.abstractSyntaxTrees.visitors.LiteralVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class CharacterLiteral extends Terminal { + + public CharacterLiteral(String spelling, SourcePosition position) { + super(spelling, position); + } + + public TResult visit(LiteralVisitor v, TArg arg) { + return v.visitCharacterLiteral(this, arg); + } + + public TResult visit(LiteralVisitor visitor) { + return visit(visitor, null); + } + + public int getValue() { + return spelling.charAt(1); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Identifier.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Identifier.java new file mode 100644 index 0000000..f8fec82 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Identifier.java @@ -0,0 +1,44 @@ +/* + * @(#)Identifier.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.terminals; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.IdentifierVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class Identifier extends Terminal { + + public Identifier(String spelling, SourcePosition position) { + super(spelling, position); + type = null; + decl = null; + } + + public TypeDenoter type; + public AbstractSyntaxTree decl; // Either a Declaration or a FieldTypeDenoter + + public TResult visit(IdentifierVisitor visitor, TArg arg) { + return visitor.visitIdentifier(this, arg); + } + + public TResult visit(IdentifierVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/IntegerLiteral.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/IntegerLiteral.java new file mode 100644 index 0000000..e15bab2 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/IntegerLiteral.java @@ -0,0 +1,41 @@ +/* + * @(#)IntegerLiteral.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.terminals; + +import triangle.abstractSyntaxTrees.visitors.LiteralVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class IntegerLiteral extends Terminal { + + public IntegerLiteral(String spelling, SourcePosition position) { + super(spelling, position); + } + + public TResult visit(LiteralVisitor v, TArg arg) { + return v.visitIntegerLiteral(this, arg); + } + + public TResult visit(LiteralVisitor visitor) { + return visit(visitor, null); + } + + public int getValue() { + return Integer.parseInt(spelling); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Operator.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Operator.java new file mode 100644 index 0000000..9dccdb8 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Operator.java @@ -0,0 +1,41 @@ +/* + * @(#)Operator.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.terminals; + +import triangle.abstractSyntaxTrees.declarations.Declaration; +import triangle.abstractSyntaxTrees.visitors.OperatorVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class Operator extends Terminal { + + public Operator(String spelling, SourcePosition position) { + super(spelling, position); + decl = null; + } + + public Declaration decl; + + public TResult visit(OperatorVisitor v, TArg arg) { + return v.visitOperator(this, arg); + } + + public TResult visit(OperatorVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Terminal.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Terminal.java new file mode 100644 index 0000000..b970211 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Terminal.java @@ -0,0 +1,32 @@ +/* + * @(#)Terminal.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.terminals; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class Terminal extends AbstractSyntaxTree { + + public Terminal(String spelling, SourcePosition position) { + super(position); + this.spelling = spelling; + } + + public final String spelling; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/AnyTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/AnyTypeDenoter.java new file mode 100644 index 0000000..2975ed0 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/AnyTypeDenoter.java @@ -0,0 +1,43 @@ +/* + * @(#)AnyTypeDenoter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class AnyTypeDenoter extends TypeDenoter { + + public AnyTypeDenoter(SourcePosition position) { + super(position); + } + + public TResult visit(TypeDenoterVisitor v, TArg arg) { + return v.visitAnyTypeDenoter(this, arg); + } + + @Override + public boolean equals(Object obj) { + return false; + } + + @Override + public int getSize() { + return 0; + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/ArrayTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/ArrayTypeDenoter.java new file mode 100644 index 0000000..39c474a --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/ArrayTypeDenoter.java @@ -0,0 +1,56 @@ +/* + * @(#)ArrayTypeDenoter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractSyntaxTrees.terminals.IntegerLiteral; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class ArrayTypeDenoter extends TypeDenoter { + + public ArrayTypeDenoter(IntegerLiteral ilAST, TypeDenoter tAST, SourcePosition position) { + super(position); + IL = ilAST; + T = tAST; + } + + public TResult visit(TypeDenoterVisitor v, TArg arg) { + return v.visitArrayTypeDenoter(this, arg); + } + + @Override + public boolean equals(Object obj) { + if (obj != null && obj instanceof ErrorTypeDenoter) { + return true; + } else if (obj != null && obj instanceof ArrayTypeDenoter) { + return this.IL.spelling.compareTo(((ArrayTypeDenoter) obj).IL.spelling) == 0 + && this.T.equals(((ArrayTypeDenoter) obj).T); + } else { + return false; + } + } + + @Override + public int getSize() { + return IL.getValue() * T.getSize(); + } + + public final IntegerLiteral IL; + public TypeDenoter T; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/BoolTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/BoolTypeDenoter.java new file mode 100644 index 0000000..ee24e5a --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/BoolTypeDenoter.java @@ -0,0 +1,48 @@ +/* + * @(#)BoolTypeDenoter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractMachine.Machine; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class BoolTypeDenoter extends TypeDenoter { + + public BoolTypeDenoter(SourcePosition position) { + super(position); + } + + public TResult visit(TypeDenoterVisitor v, TArg arg) { + return v.visitBoolTypeDenoter(this, arg); + } + + @Override + public int getSize() { + return Machine.booleanSize; + } + + @Override + public boolean equals(Object obj) { + if ((obj != null) && (obj instanceof ErrorTypeDenoter)) { + return true; + } else { + return ((obj != null) && (obj instanceof BoolTypeDenoter)); + } + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/CharTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/CharTypeDenoter.java new file mode 100644 index 0000000..c01d7f2 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/CharTypeDenoter.java @@ -0,0 +1,48 @@ +/* + * @(#)CharTypeDenoter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractMachine.Machine; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class CharTypeDenoter extends TypeDenoter { + + public CharTypeDenoter(SourcePosition position) { + super(position); + } + + public TResult visit(TypeDenoterVisitor v, TArg arg) { + return v.visitCharTypeDenoter(this, arg); + } + + @Override + public int getSize() { + return Machine.characterSize; + } + + @Override + public boolean equals(Object obj) { + if (obj != null && obj instanceof ErrorTypeDenoter) { + return true; + } else { + return (obj != null && obj instanceof CharTypeDenoter); + } + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/ErrorTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/ErrorTypeDenoter.java new file mode 100644 index 0000000..3e0e7e4 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/ErrorTypeDenoter.java @@ -0,0 +1,43 @@ +/* + * @(#)ErrorTypeDenoter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class ErrorTypeDenoter extends TypeDenoter { + + public ErrorTypeDenoter(SourcePosition position) { + super(position); + } + + public TResult visit(TypeDenoterVisitor v, TArg arg) { + return v.visitErrorTypeDenoter(this, arg); + } + + @Override + public int getSize() { + return 0; + } + + @Override + public boolean equals(Object obj) { + return true; + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/FieldTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/FieldTypeDenoter.java new file mode 100644 index 0000000..8a9eecf --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/FieldTypeDenoter.java @@ -0,0 +1,28 @@ +/* + * @(#)FieldTypeDenoter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class FieldTypeDenoter extends TypeDenoter { + + public FieldTypeDenoter(SourcePosition position) { + super(position); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/IntTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/IntTypeDenoter.java new file mode 100644 index 0000000..5b593c3 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/IntTypeDenoter.java @@ -0,0 +1,48 @@ +/* + * @(#)IntTypeDenoter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractMachine.Machine; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class IntTypeDenoter extends TypeDenoter { + + public IntTypeDenoter(SourcePosition position) { + super(position); + } + + public TResult visit(TypeDenoterVisitor v, TArg arg) { + return v.visitIntTypeDenoter(this, arg); + } + + @Override + public int getSize() { + return Machine.integerSize; + } + + @Override + public boolean equals(Object obj) { + if (obj != null && obj instanceof ErrorTypeDenoter) { + return true; + } else { + return (obj != null && obj instanceof IntTypeDenoter); + } + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/MultipleFieldTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/MultipleFieldTypeDenoter.java new file mode 100644 index 0000000..3a77a3a --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/MultipleFieldTypeDenoter.java @@ -0,0 +1,57 @@ +/* + * @(#)MultipleFieldTypeDenoter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class MultipleFieldTypeDenoter extends FieldTypeDenoter { + + public MultipleFieldTypeDenoter(Identifier iAST, TypeDenoter tAST, FieldTypeDenoter ftAST, + SourcePosition position) { + super(position); + I = iAST; + T = tAST; + FT = ftAST; + } + + public TResult visit(TypeDenoterVisitor v, TArg arg) { + return v.visitMultipleFieldTypeDenoter(this, arg); + } + + @Override + public int getSize() { + return T.getSize() + FT.getSize(); + } + + @Override + public boolean equals(Object obj) { + if (obj != null && obj instanceof MultipleFieldTypeDenoter) { + MultipleFieldTypeDenoter ft = (MultipleFieldTypeDenoter) obj; + return (this.I.spelling.compareTo(ft.I.spelling) == 0) && this.T.equals(ft.T) && this.FT.equals(ft.FT); + } else { + return false; + } + } + + public final Identifier I; + public TypeDenoter T; + public FieldTypeDenoter FT; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/RecordTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/RecordTypeDenoter.java new file mode 100644 index 0000000..3907a5a --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/RecordTypeDenoter.java @@ -0,0 +1,52 @@ +/* + * @(#)RecordTypeDenoter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class RecordTypeDenoter extends TypeDenoter { + + public RecordTypeDenoter(FieldTypeDenoter ftAST, SourcePosition position) { + super(position); + FT = ftAST; + } + + public TResult visit(TypeDenoterVisitor v, TArg arg) { + return v.visitRecordTypeDenoter(this, arg); + } + + @Override + public int getSize() { + return FT.getSize(); + } + + @Override + public boolean equals(Object obj) { + if (obj != null && obj instanceof ErrorTypeDenoter) { + return true; + } else if (obj != null && obj instanceof RecordTypeDenoter) { + return this.FT.equals(((RecordTypeDenoter) obj).FT); + } else { + return false; + } + } + + public FieldTypeDenoter FT; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/SimpleTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/SimpleTypeDenoter.java new file mode 100644 index 0000000..198814b --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/SimpleTypeDenoter.java @@ -0,0 +1,47 @@ +/* + * @(#)SimpleTypeDenoter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class SimpleTypeDenoter extends TypeDenoter { + + public SimpleTypeDenoter(Identifier iAST, SourcePosition position) { + super(position); + I = iAST; + } + + public TResult visit(TypeDenoterVisitor v, TArg arg) { + return v.visitSimpleTypeDenoter(this, arg); + } + + @Override + public int getSize() { + return 0; + } + + @Override + public boolean equals(Object obj) { + return false; // should not happen + } + + public final Identifier I; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/SingleFieldTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/SingleFieldTypeDenoter.java new file mode 100644 index 0000000..16cd5cb --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/SingleFieldTypeDenoter.java @@ -0,0 +1,54 @@ +/* + * @(#)SingleFieldTypeDenoter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class SingleFieldTypeDenoter extends FieldTypeDenoter { + + public SingleFieldTypeDenoter(Identifier iAST, TypeDenoter tAST, SourcePosition position) { + super(position); + I = iAST; + T = tAST; + } + + public TResult visit(TypeDenoterVisitor v, TArg arg) { + return v.visitSingleFieldTypeDenoter(this, arg); + } + + @Override + public int getSize() { + return T.getSize(); + } + + @Override + public boolean equals(Object obj) { + if (obj != null && obj instanceof SingleFieldTypeDenoter) { + SingleFieldTypeDenoter ft = (SingleFieldTypeDenoter) obj; + return (this.I.spelling.compareTo(ft.I.spelling) == 0) && this.T.equals(ft.T); + } else { + return false; + } + } + + public final Identifier I; + public TypeDenoter T; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/TypeDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/TypeDeclaration.java new file mode 100644 index 0000000..0a90928 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/TypeDeclaration.java @@ -0,0 +1,40 @@ +/* + * @(#)TypeDeclaration.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractSyntaxTrees.declarations.Declaration; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class TypeDeclaration extends Declaration { + + public TypeDeclaration(Identifier iAST, TypeDenoter tAST, SourcePosition position) { + super(position); + I = iAST; + T = tAST; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitTypeDeclaration(this, arg); + } + + public final Identifier I; + public TypeDenoter T; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/TypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/TypeDenoter.java new file mode 100644 index 0000000..977fc7c --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/TypeDenoter.java @@ -0,0 +1,41 @@ +/* + * @(#)TypeDenoter.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class TypeDenoter extends AbstractSyntaxTree { + + public TypeDenoter(SourcePosition position) { + super(position); + } + + @Override + public abstract boolean equals(Object obj); + + public abstract TResult visit(TypeDenoterVisitor visitor, TArg arg); + + public TResult visit(TypeDenoterVisitor visitor) { + return visit(visitor, null); + } + + public abstract int getSize(); +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ActualParameterSequenceVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ActualParameterSequenceVisitor.java new file mode 100644 index 0000000..66e68a3 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ActualParameterSequenceVisitor.java @@ -0,0 +1,15 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.actuals.EmptyActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.MultipleActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.SingleActualParameterSequence; + +public interface ActualParameterSequenceVisitor { + + TResult visitEmptyActualParameterSequence(EmptyActualParameterSequence ast, TArg arg); + + TResult visitMultipleActualParameterSequence(MultipleActualParameterSequence ast, TArg arg); + + TResult visitSingleActualParameterSequence(SingleActualParameterSequence ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ActualParameterVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ActualParameterVisitor.java new file mode 100644 index 0000000..9e9630b --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ActualParameterVisitor.java @@ -0,0 +1,18 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.actuals.ConstActualParameter; +import triangle.abstractSyntaxTrees.actuals.FuncActualParameter; +import triangle.abstractSyntaxTrees.actuals.ProcActualParameter; +import triangle.abstractSyntaxTrees.actuals.VarActualParameter; + +public interface ActualParameterVisitor { + + TResult visitConstActualParameter(ConstActualParameter ast, TArg arg); + + TResult visitFuncActualParameter(FuncActualParameter ast, TArg arg); + + TResult visitProcActualParameter(ProcActualParameter ast, TArg arg); + + TResult visitVarActualParameter(VarActualParameter ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ArrayAggregateVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ArrayAggregateVisitor.java new file mode 100644 index 0000000..8d7abec --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ArrayAggregateVisitor.java @@ -0,0 +1,12 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.aggregates.MultipleArrayAggregate; +import triangle.abstractSyntaxTrees.aggregates.SingleArrayAggregate; + +public interface ArrayAggregateVisitor { + + TResult visitMultipleArrayAggregate(MultipleArrayAggregate ast, TArg arg); + + TResult visitSingleArrayAggregate(SingleArrayAggregate ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/CommandVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/CommandVisitor.java new file mode 100644 index 0000000..336c97d --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/CommandVisitor.java @@ -0,0 +1,27 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.commands.AssignCommand; +import triangle.abstractSyntaxTrees.commands.CallCommand; +import triangle.abstractSyntaxTrees.commands.EmptyCommand; +import triangle.abstractSyntaxTrees.commands.IfCommand; +import triangle.abstractSyntaxTrees.commands.LetCommand; +import triangle.abstractSyntaxTrees.commands.SequentialCommand; +import triangle.abstractSyntaxTrees.commands.WhileCommand; + +public interface CommandVisitor { + + TResult visitAssignCommand(AssignCommand ast, TArg arg); + + TResult visitCallCommand(CallCommand ast, TArg arg); + + TResult visitEmptyCommand(EmptyCommand ast, TArg arg); + + TResult visitIfCommand(IfCommand ast, TArg arg); + + TResult visitLetCommand(LetCommand ast, TArg arg); + + TResult visitSequentialCommand(SequentialCommand ast, TArg arg); + + TResult visitWhileCommand(WhileCommand ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/DeclarationVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/DeclarationVisitor.java new file mode 100644 index 0000000..7ce845d --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/DeclarationVisitor.java @@ -0,0 +1,30 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration; +import triangle.abstractSyntaxTrees.declarations.ConstDeclaration; +import triangle.abstractSyntaxTrees.declarations.FuncDeclaration; +import triangle.abstractSyntaxTrees.declarations.ProcDeclaration; +import triangle.abstractSyntaxTrees.declarations.SequentialDeclaration; +import triangle.abstractSyntaxTrees.declarations.UnaryOperatorDeclaration; +import triangle.abstractSyntaxTrees.declarations.VarDeclaration; +import triangle.abstractSyntaxTrees.types.TypeDeclaration; + +public interface DeclarationVisitor extends FormalParameterVisitor { + + TResult visitBinaryOperatorDeclaration(BinaryOperatorDeclaration ast, TArg arg); + + TResult visitConstDeclaration(ConstDeclaration ast, TArg arg); + + TResult visitFuncDeclaration(FuncDeclaration ast, TArg arg); + + TResult visitProcDeclaration(ProcDeclaration ast, TArg arg); + + TResult visitSequentialDeclaration(SequentialDeclaration ast, TArg arg); + + TResult visitTypeDeclaration(TypeDeclaration ast, TArg arg); + + TResult visitUnaryOperatorDeclaration(UnaryOperatorDeclaration ast, TArg arg); + + TResult visitVarDeclaration(VarDeclaration ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ExpressionVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ExpressionVisitor.java new file mode 100644 index 0000000..ebb76f4 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ExpressionVisitor.java @@ -0,0 +1,39 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.expressions.ArrayExpression; +import triangle.abstractSyntaxTrees.expressions.BinaryExpression; +import triangle.abstractSyntaxTrees.expressions.CallExpression; +import triangle.abstractSyntaxTrees.expressions.CharacterExpression; +import triangle.abstractSyntaxTrees.expressions.EmptyExpression; +import triangle.abstractSyntaxTrees.expressions.IfExpression; +import triangle.abstractSyntaxTrees.expressions.IntegerExpression; +import triangle.abstractSyntaxTrees.expressions.LetExpression; +import triangle.abstractSyntaxTrees.expressions.RecordExpression; +import triangle.abstractSyntaxTrees.expressions.UnaryExpression; +import triangle.abstractSyntaxTrees.expressions.VnameExpression; + +public interface ExpressionVisitor { + + TResult visitArrayExpression(ArrayExpression ast, TArg arg); + + TResult visitBinaryExpression(BinaryExpression ast, TArg arg); + + TResult visitCallExpression(CallExpression ast, TArg arg); + + TResult visitCharacterExpression(CharacterExpression ast, TArg arg); + + TResult visitEmptyExpression(EmptyExpression ast, TArg arg); + + TResult visitIfExpression(IfExpression ast, TArg arg); + + TResult visitIntegerExpression(IntegerExpression ast, TArg arg); + + TResult visitLetExpression(LetExpression ast, TArg arg); + + TResult visitRecordExpression(RecordExpression ast, TArg arg); + + TResult visitUnaryExpression(UnaryExpression ast, TArg arg); + + TResult visitVnameExpression(VnameExpression ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FieldTypeDenoterVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FieldTypeDenoterVisitor.java new file mode 100644 index 0000000..2bd3f0d --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FieldTypeDenoterVisitor.java @@ -0,0 +1,12 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.types.MultipleFieldTypeDenoter; +import triangle.abstractSyntaxTrees.types.SingleFieldTypeDenoter; + +public interface FieldTypeDenoterVisitor { + + TResult visitMultipleFieldTypeDenoter(MultipleFieldTypeDenoter ast, TArg arg); + + TResult visitSingleFieldTypeDenoter(SingleFieldTypeDenoter ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FormalParameterSequenceVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FormalParameterSequenceVisitor.java new file mode 100644 index 0000000..3505451 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FormalParameterSequenceVisitor.java @@ -0,0 +1,15 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.formals.EmptyFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.MultipleFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.SingleFormalParameterSequence; + +public interface FormalParameterSequenceVisitor { + + TResult visitEmptyFormalParameterSequence(EmptyFormalParameterSequence ast, TArg arg); + + TResult visitMultipleFormalParameterSequence(MultipleFormalParameterSequence ast, TArg arg); + + TResult visitSingleFormalParameterSequence(SingleFormalParameterSequence ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FormalParameterVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FormalParameterVisitor.java new file mode 100644 index 0000000..cddb0e7 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FormalParameterVisitor.java @@ -0,0 +1,18 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.formals.ConstFormalParameter; +import triangle.abstractSyntaxTrees.formals.FuncFormalParameter; +import triangle.abstractSyntaxTrees.formals.ProcFormalParameter; +import triangle.abstractSyntaxTrees.formals.VarFormalParameter; + +public interface FormalParameterVisitor { + + TResult visitConstFormalParameter(ConstFormalParameter ast, TArg arg); + + TResult visitFuncFormalParameter(FuncFormalParameter ast, TArg arg); + + TResult visitProcFormalParameter(ProcFormalParameter ast, TArg arg); + + TResult visitVarFormalParameter(VarFormalParameter ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/IdentifierVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/IdentifierVisitor.java new file mode 100644 index 0000000..b303b8e --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/IdentifierVisitor.java @@ -0,0 +1,9 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.terminals.Identifier; + +public interface IdentifierVisitor { + + TResult visitIdentifier(Identifier ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/LiteralVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/LiteralVisitor.java new file mode 100644 index 0000000..1ca4fa4 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/LiteralVisitor.java @@ -0,0 +1,12 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.terminals.CharacterLiteral; +import triangle.abstractSyntaxTrees.terminals.IntegerLiteral; + +public interface LiteralVisitor { + + TResult visitCharacterLiteral(CharacterLiteral ast, TArg arg); + + TResult visitIntegerLiteral(IntegerLiteral ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/OperatorVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/OperatorVisitor.java new file mode 100644 index 0000000..989a653 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/OperatorVisitor.java @@ -0,0 +1,9 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.terminals.Operator; + +public interface OperatorVisitor { + + TResult visitOperator(Operator ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ProgramVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ProgramVisitor.java new file mode 100644 index 0000000..aca855c --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ProgramVisitor.java @@ -0,0 +1,9 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.Program; + +public interface ProgramVisitor { + + TResult visitProgram(Program ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/RecordAggregateVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/RecordAggregateVisitor.java new file mode 100644 index 0000000..20ed097 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/RecordAggregateVisitor.java @@ -0,0 +1,12 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.aggregates.MultipleRecordAggregate; +import triangle.abstractSyntaxTrees.aggregates.SingleRecordAggregate; + +public interface RecordAggregateVisitor { + + TResult visitMultipleRecordAggregate(MultipleRecordAggregate ast, TArg arg); + + TResult visitSingleRecordAggregate(SingleRecordAggregate ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/TypeDenoterVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/TypeDenoterVisitor.java new file mode 100644 index 0000000..79b47e3 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/TypeDenoterVisitor.java @@ -0,0 +1,30 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.types.AnyTypeDenoter; +import triangle.abstractSyntaxTrees.types.ArrayTypeDenoter; +import triangle.abstractSyntaxTrees.types.BoolTypeDenoter; +import triangle.abstractSyntaxTrees.types.CharTypeDenoter; +import triangle.abstractSyntaxTrees.types.ErrorTypeDenoter; +import triangle.abstractSyntaxTrees.types.IntTypeDenoter; +import triangle.abstractSyntaxTrees.types.RecordTypeDenoter; +import triangle.abstractSyntaxTrees.types.SimpleTypeDenoter; + +public interface TypeDenoterVisitor extends FieldTypeDenoterVisitor { + + TResult visitAnyTypeDenoter(AnyTypeDenoter ast, TArg arg); + + TResult visitArrayTypeDenoter(ArrayTypeDenoter ast, TArg arg); + + TResult visitBoolTypeDenoter(BoolTypeDenoter ast, TArg arg); + + TResult visitCharTypeDenoter(CharTypeDenoter ast, TArg arg); + + TResult visitErrorTypeDenoter(ErrorTypeDenoter ast, TArg arg); + + TResult visitSimpleTypeDenoter(SimpleTypeDenoter ast, TArg arg); + + TResult visitIntTypeDenoter(IntTypeDenoter ast, TArg arg); + + TResult visitRecordTypeDenoter(RecordTypeDenoter ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/VnameVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/VnameVisitor.java new file mode 100644 index 0000000..6936a54 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/VnameVisitor.java @@ -0,0 +1,15 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.vnames.DotVname; +import triangle.abstractSyntaxTrees.vnames.SimpleVname; +import triangle.abstractSyntaxTrees.vnames.SubscriptVname; + +public interface VnameVisitor { + + TResult visitDotVname(DotVname ast, TArg arg); + + TResult visitSimpleVname(SimpleVname ast, TArg arg); + + TResult visitSubscriptVname(SubscriptVname ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/DotVname.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/DotVname.java new file mode 100644 index 0000000..7a0538c --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/DotVname.java @@ -0,0 +1,39 @@ +/* + * @(#)DotVname.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.vnames; + +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.VnameVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class DotVname extends Vname { + + public DotVname(Vname vAST, Identifier iAST, SourcePosition position) { + super(position); + V = vAST; + I = iAST; + } + + public TResult visit(VnameVisitor v, TArg arg) { + return v.visitDotVname(this, arg); + } + + public final Identifier I; + public final Vname V; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/SimpleVname.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/SimpleVname.java new file mode 100644 index 0000000..05354af --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/SimpleVname.java @@ -0,0 +1,37 @@ +/* + * @(#)SimpleVname.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.vnames; + +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.VnameVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class SimpleVname extends Vname { + + public SimpleVname(Identifier iAST, SourcePosition position) { + super(position); + I = iAST; + } + + public TResult visit(VnameVisitor v, TArg arg) { + return v.visitSimpleVname(this, arg); + } + + public final Identifier I; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/SubscriptVname.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/SubscriptVname.java new file mode 100644 index 0000000..010d194 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/SubscriptVname.java @@ -0,0 +1,39 @@ +/* + * @(#)SubscriptVname.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.vnames; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.visitors.VnameVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class SubscriptVname extends Vname { + + public SubscriptVname(Vname vAST, Expression eAST, SourcePosition position) { + super(position); + V = vAST; + E = eAST; + } + + public TResult visit(VnameVisitor v, TArg arg) { + return v.visitSubscriptVname(this, arg); + } + + public Expression E; + public final Vname V; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/Vname.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/Vname.java new file mode 100644 index 0000000..0b701fc --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/Vname.java @@ -0,0 +1,43 @@ +/* + * @(#)Vname.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.vnames; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.VnameVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class Vname extends AbstractSyntaxTree { + + public Vname(SourcePosition position) { + super(position); + variable = false; + type = null; + } + + public boolean variable, indexed; + public int offset; + public TypeDenoter type; + + public abstract TResult visit(VnameVisitor visitor, TArg arg); + + public TResult visit(VnameVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/Emitter.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/Emitter.java new file mode 100644 index 0000000..e0b037a --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/Emitter.java @@ -0,0 +1,120 @@ +package triangle.codeGenerator; + +import java.io.DataOutputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +import triangle.ErrorReporter; +import triangle.abstractMachine.Instruction; +import triangle.abstractMachine.Machine; +import triangle.abstractMachine.OpCode; +import triangle.abstractMachine.Primitive; +import triangle.abstractMachine.Register; + +public class Emitter { + + // OBJECT CODE + + // Implementation notes: + // Object code is generated directly into the TAM Code Store, starting at + // CB. + // The address of the next instruction is held in nextInstrAddr. + + ErrorReporter errorReporter; + + int nextInstrAddr; + + public Emitter(ErrorReporter errorReporter) { + this.errorReporter = errorReporter; + nextInstrAddr = Machine.CB; + } + + public int getNextInstrAddr() { + return nextInstrAddr; + } + + public int emit(OpCode op) { + return emit(op, 0, Register.CB, 0); + } + + public int emit(OpCode op, int operand) { + return emit(op, 0, Register.CB, operand); + } + + public int emit(OpCode op, int length, int operand) { + return emit(op, length, Register.CB, operand); + } + + public int emit(OpCode op, Register staticRegister, Register register, int operand) { + return emit(op, staticRegister.ordinal(), register, operand); + } + + public int emit(OpCode op, Register register, int operand) { + return emit(op, 0, register, operand); + } + + public int emit(OpCode op, Register register) { + return emit(op, 0, register, 0); + } + + public int emit(OpCode op, int length, Register register) { + return emit(op, length, register, 0); + } + + public int emit(OpCode op, Register register, Primitive primitive) { + return emit(op, 0, register, primitive.ordinal()); + } + + /** + * Appends an instruction, with the given fields, to the object code. + * + * @param op the opcode + * @param length the length field + * @param register the register field + * @param operand the operand field + * @return the code address of the new instruction + **/ + public int emit(OpCode op, int length, Register register, int operand) { + + if (length > 255) { + errorReporter.reportRestriction("length of operand can't exceed 255 words"); + length = 255; // to allow code generation to continue + } + + var nextInstr = new Instruction(op, register, length, operand); + + var currentInstrAddr = nextInstrAddr; + if (nextInstrAddr == Machine.PB) { + errorReporter.reportRestriction("too many instructions for code segment"); + } else { + Machine.code[nextInstrAddr++] = nextInstr; + } + return currentInstrAddr; + + } + + // Patches the d-field of the instruction at address addr with the next + // instruction address. + public void patch(int addr) { + Machine.code[addr].setOperand(nextInstrAddr); + } + + /** + * Saves the object program in the given object file. + * + * @param objectFile the object file + */ + public void saveObjectProgram(String objectFileName) { + try (var objectFile = new FileOutputStream(objectFileName)) { + var objectStream = new DataOutputStream(objectFile); + for (var addr = Machine.CB; addr < nextInstrAddr; addr++) { + Machine.code[addr].write(objectStream); + } + } catch (FileNotFoundException fnfe) { + System.err.println("Error opening object file: " + fnfe); + } catch (IOException ioe) { + System.err.println("Error writing object file: " + ioe); + } + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/Encoder.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/Encoder.java new file mode 100644 index 0000000..c883070 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/Encoder.java @@ -0,0 +1,796 @@ +/* + * @(#)Encoder.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator; + +import triangle.ErrorReporter; +import triangle.StdEnvironment; +import triangle.abstractMachine.Machine; +import triangle.abstractMachine.OpCode; +import triangle.abstractMachine.Primitive; +import triangle.abstractMachine.Register; +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.Program; +import triangle.abstractSyntaxTrees.actuals.ConstActualParameter; +import triangle.abstractSyntaxTrees.actuals.EmptyActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.FuncActualParameter; +import triangle.abstractSyntaxTrees.actuals.MultipleActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.ProcActualParameter; +import triangle.abstractSyntaxTrees.actuals.SingleActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.VarActualParameter; +import triangle.abstractSyntaxTrees.aggregates.MultipleArrayAggregate; +import triangle.abstractSyntaxTrees.aggregates.MultipleRecordAggregate; +import triangle.abstractSyntaxTrees.aggregates.SingleArrayAggregate; +import triangle.abstractSyntaxTrees.aggregates.SingleRecordAggregate; +import triangle.abstractSyntaxTrees.commands.AssignCommand; +import triangle.abstractSyntaxTrees.commands.CallCommand; +import triangle.abstractSyntaxTrees.commands.EmptyCommand; +import triangle.abstractSyntaxTrees.commands.IfCommand; +import triangle.abstractSyntaxTrees.commands.LetCommand; +import triangle.abstractSyntaxTrees.commands.SequentialCommand; +import triangle.abstractSyntaxTrees.commands.WhileCommand; +import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration; +import triangle.abstractSyntaxTrees.declarations.ConstDeclaration; +import triangle.abstractSyntaxTrees.declarations.Declaration; +import triangle.abstractSyntaxTrees.declarations.FuncDeclaration; +import triangle.abstractSyntaxTrees.declarations.ProcDeclaration; +import triangle.abstractSyntaxTrees.declarations.SequentialDeclaration; +import triangle.abstractSyntaxTrees.declarations.UnaryOperatorDeclaration; +import triangle.abstractSyntaxTrees.declarations.VarDeclaration; +import triangle.abstractSyntaxTrees.expressions.ArrayExpression; +import triangle.abstractSyntaxTrees.expressions.BinaryExpression; +import triangle.abstractSyntaxTrees.expressions.CallExpression; +import triangle.abstractSyntaxTrees.expressions.CharacterExpression; +import triangle.abstractSyntaxTrees.expressions.EmptyExpression; +import triangle.abstractSyntaxTrees.expressions.IfExpression; +import triangle.abstractSyntaxTrees.expressions.IntegerExpression; +import triangle.abstractSyntaxTrees.expressions.LetExpression; +import triangle.abstractSyntaxTrees.expressions.RecordExpression; +import triangle.abstractSyntaxTrees.expressions.UnaryExpression; +import triangle.abstractSyntaxTrees.expressions.VnameExpression; +import triangle.abstractSyntaxTrees.formals.ConstFormalParameter; +import triangle.abstractSyntaxTrees.formals.EmptyFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.FuncFormalParameter; +import triangle.abstractSyntaxTrees.formals.MultipleFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.ProcFormalParameter; +import triangle.abstractSyntaxTrees.formals.SingleFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.VarFormalParameter; +import triangle.abstractSyntaxTrees.terminals.CharacterLiteral; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.terminals.IntegerLiteral; +import triangle.abstractSyntaxTrees.terminals.Operator; +import triangle.abstractSyntaxTrees.types.AnyTypeDenoter; +import triangle.abstractSyntaxTrees.types.ArrayTypeDenoter; +import triangle.abstractSyntaxTrees.types.BoolTypeDenoter; +import triangle.abstractSyntaxTrees.types.CharTypeDenoter; +import triangle.abstractSyntaxTrees.types.ErrorTypeDenoter; +import triangle.abstractSyntaxTrees.types.IntTypeDenoter; +import triangle.abstractSyntaxTrees.types.MultipleFieldTypeDenoter; +import triangle.abstractSyntaxTrees.types.RecordTypeDenoter; +import triangle.abstractSyntaxTrees.types.SimpleTypeDenoter; +import triangle.abstractSyntaxTrees.types.SingleFieldTypeDenoter; +import triangle.abstractSyntaxTrees.types.TypeDeclaration; +import triangle.abstractSyntaxTrees.visitors.ActualParameterSequenceVisitor; +import triangle.abstractSyntaxTrees.visitors.ActualParameterVisitor; +import triangle.abstractSyntaxTrees.visitors.ArrayAggregateVisitor; +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.abstractSyntaxTrees.visitors.FormalParameterSequenceVisitor; +import triangle.abstractSyntaxTrees.visitors.IdentifierVisitor; +import triangle.abstractSyntaxTrees.visitors.LiteralVisitor; +import triangle.abstractSyntaxTrees.visitors.OperatorVisitor; +import triangle.abstractSyntaxTrees.visitors.ProgramVisitor; +import triangle.abstractSyntaxTrees.visitors.RecordAggregateVisitor; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.abstractSyntaxTrees.visitors.VnameVisitor; +import triangle.abstractSyntaxTrees.vnames.DotVname; +import triangle.abstractSyntaxTrees.vnames.SimpleVname; +import triangle.abstractSyntaxTrees.vnames.SubscriptVname; +import triangle.abstractSyntaxTrees.vnames.Vname; +import triangle.codeGenerator.entities.AddressableEntity; +import triangle.codeGenerator.entities.EqualityRoutine; +import triangle.codeGenerator.entities.FetchableEntity; +import triangle.codeGenerator.entities.Field; +import triangle.codeGenerator.entities.KnownAddress; +import triangle.codeGenerator.entities.KnownRoutine; +import triangle.codeGenerator.entities.KnownValue; +import triangle.codeGenerator.entities.PrimitiveRoutine; +import triangle.codeGenerator.entities.RoutineEntity; +import triangle.codeGenerator.entities.RuntimeEntity; +import triangle.codeGenerator.entities.TypeRepresentation; +import triangle.codeGenerator.entities.UnknownAddress; +import triangle.codeGenerator.entities.UnknownRoutine; +import triangle.codeGenerator.entities.UnknownValue; + +public final class Encoder implements ActualParameterVisitor, + ActualParameterSequenceVisitor, ArrayAggregateVisitor, + CommandVisitor, DeclarationVisitor, ExpressionVisitor, + FormalParameterSequenceVisitor, IdentifierVisitor, LiteralVisitor, + OperatorVisitor, ProgramVisitor, RecordAggregateVisitor, + TypeDenoterVisitor, VnameVisitor { + + // Commands + @Override + public Void visitAssignCommand(AssignCommand ast, Frame frame) { + var valSize = ast.E.visit(this, frame); + encodeStore(ast.V, frame.expand(valSize), valSize); + return null; + } + + @Override + public Void visitCallCommand(CallCommand ast, Frame frame) { + var argsSize = ast.APS.visit(this, frame); + ast.I.visit(this, frame.replace(argsSize)); + return null; + } + + @Override + public Void visitEmptyCommand(EmptyCommand ast, Frame frame) { + return null; + } + + @Override + public Void visitIfCommand(IfCommand ast, Frame frame) { + ast.E.visit(this, frame); + var jumpifAddr = emitter.emit(OpCode.JUMPIF, Machine.falseRep, Register.CB, 0); + ast.C1.visit(this, frame); + var jumpAddr = emitter.emit(OpCode.JUMP, 0, Register.CB, 0); + emitter.patch(jumpifAddr); + ast.C2.visit(this, frame); + emitter.patch(jumpAddr); + return null; + } + + @Override + public Void visitLetCommand(LetCommand ast, Frame frame) { + var extraSize = ast.D.visit(this, frame); + ast.C.visit(this, frame.expand(extraSize)); + if (extraSize > 0) { + emitter.emit(OpCode.POP, extraSize); + } + return null; + } + + @Override + public Void visitSequentialCommand(SequentialCommand ast, Frame frame) { + ast.C1.visit(this, frame); + ast.C2.visit(this, frame); + return null; + } + + @Override + public Void visitWhileCommand(WhileCommand ast, Frame frame) { + var jumpAddr = emitter.emit(OpCode.JUMP, 0, Register.CB, 0); + var loopAddr = emitter.getNextInstrAddr(); + ast.C.visit(this, frame); + emitter.patch(jumpAddr); + ast.E.visit(this, frame); + emitter.emit(OpCode.JUMPIF, Machine.trueRep, Register.CB, loopAddr); + return null; + } + + // Expressions + @Override + public Integer visitArrayExpression(ArrayExpression ast, Frame frame) { + ast.type.visit(this, frame); + return ast.AA.visit(this, frame); + } + + @Override + public Integer visitBinaryExpression(BinaryExpression ast, Frame frame) { + var valSize = ast.type.visit(this); + var valSize1 = ast.E1.visit(this, frame); + var frame1 = frame.expand(valSize1); + var valSize2 = ast.E2.visit(this, frame1); + var frame2 = frame.replace(valSize1 + valSize2); + ast.O.visit(this, frame2); + return valSize; + } + + @Override + public Integer visitCallExpression(CallExpression ast, Frame frame) { + var valSize = ast.type.visit(this); + var argsSize = ast.APS.visit(this, frame); + ast.I.visit(this, frame.replace(argsSize)); + return valSize; + } + + @Override + public Integer visitCharacterExpression(CharacterExpression ast, Frame frame) { + var valSize = ast.type.visit(this); + emitter.emit(OpCode.LOADL, ast.CL.getValue()); + return valSize; + } + + @Override + public Integer visitEmptyExpression(EmptyExpression ast, Frame frame) { + return 0; + } + + @Override + public Integer visitIfExpression(IfExpression ast, Frame frame) { + ast.type.visit(this); + ast.E1.visit(this, frame); + var jumpifAddr = emitter.emit(OpCode.JUMPIF, Machine.falseRep, Register.CB, 0); + var valSize = ast.E2.visit(this, frame); + var jumpAddr = emitter.emit(OpCode.JUMP, 0, Register.CB, 0); + emitter.patch(jumpifAddr); + valSize = ast.E3.visit(this, frame); + emitter.patch(jumpAddr); + return valSize; + } + + @Override + public Integer visitIntegerExpression(IntegerExpression ast, Frame frame) { + var valSize = ast.type.visit(this); + emitter.emit(OpCode.LOADL, ast.IL.getValue()); + return valSize; + } + + @Override + public Integer visitLetExpression(LetExpression ast, Frame frame) { + ast.type.visit(this); + var extraSize = ast.D.visit(this, frame); + var frame1 = frame.expand(extraSize); + var valSize = ast.E.visit(this, frame1); + if (extraSize > 0) { + emitter.emit(OpCode.POP, valSize, extraSize); + } + return valSize; + } + + @Override + public Integer visitRecordExpression(RecordExpression ast, Frame frame) { + ast.type.visit(this); + return ast.RA.visit(this, frame); + } + + @Override + public Integer visitUnaryExpression(UnaryExpression ast, Frame frame) { + var valSize = ast.type.visit(this); + ast.E.visit(this, frame); + ast.O.visit(this, frame.replace(valSize)); + return valSize; + } + + @Override + public Integer visitVnameExpression(VnameExpression ast, Frame frame) { + var valSize = ast.type.visit(this); + encodeFetch(ast.V, frame, valSize); + return valSize; + } + + // Declarations + @Override + public Integer visitBinaryOperatorDeclaration(BinaryOperatorDeclaration ast, Frame frame) { + return 0; + } + + @Override + public Integer visitConstDeclaration(ConstDeclaration ast, Frame frame) { + var extraSize = 0; + if (ast.E.isLiteral()) { + ast.entity = new KnownValue(ast.E.type.getSize(), ast.E.getValue()); + } else { + var valSize = ast.E.visit(this, frame); + ast.entity = new UnknownValue(valSize, frame); + extraSize = valSize; + } + writeTableDetails(ast); + return extraSize; + } + + @Override + public Integer visitFuncDeclaration(FuncDeclaration ast, Frame frame) { + var argsSize = 0; + var valSize = 0; + + var jumpAddr = emitter.emit(OpCode.JUMP, 0, Register.CB, 0); + ast.entity = new KnownRoutine(Machine.closureSize, frame.getLevel(), emitter.getNextInstrAddr()); + writeTableDetails(ast); + if (frame.getLevel() == Machine.maxRoutineLevel) { + reporter.reportRestriction("can't nest routines more than 7 deep"); + } else { + var frame1 = frame.push(0); + argsSize = ast.FPS.visit(this, frame1); + var frame2 = frame.push(Machine.linkDataSize); + valSize = ast.E.visit(this, frame2); + } + emitter.emit(OpCode.RETURN, valSize, argsSize); + emitter.patch(jumpAddr); + return 0; + } + + @Override + public Integer visitProcDeclaration(ProcDeclaration ast, Frame frame) { + var argsSize = 0; + var jumpAddr = emitter.emit(OpCode.JUMP, 0, Register.CB, 0); + ast.entity = new KnownRoutine(Machine.closureSize, frame.getLevel(), emitter.getNextInstrAddr()); + writeTableDetails(ast); + if (frame.getLevel() == Machine.maxRoutineLevel) { + reporter.reportRestriction("can't nest routines so deeply"); + } else { + var frame1 = frame.push(0); + argsSize = ast.FPS.visit(this, frame1); + var frame2 = frame.push(Machine.linkDataSize); + ast.C.visit(this, frame2); + } + emitter.emit(OpCode.RETURN, argsSize); + emitter.patch(jumpAddr); + return 0; + } + + @Override + public Integer visitSequentialDeclaration(SequentialDeclaration ast, Frame frame) { + var extraSize1 = ast.D1.visit(this, frame); + var frame1 = frame.expand(extraSize1); + var extraSize2 = ast.D2.visit(this, frame1); + return extraSize1 + extraSize2; + } + + @Override + public Integer visitTypeDeclaration(TypeDeclaration ast, Frame frame) { + // just to ensure the type's representation is decided + ast.T.visit(this); + return 0; + } + + @Override + public Integer visitUnaryOperatorDeclaration(UnaryOperatorDeclaration ast, Frame frame) { + return 0; + } + + @Override + public Integer visitVarDeclaration(VarDeclaration ast, Frame frame) { + var extraSize = ast.T.visit(this); + emitter.emit(OpCode.PUSH, extraSize); + ast.entity = new KnownAddress(Machine.addressSize, frame); + writeTableDetails(ast); + return extraSize; + } + + // Array Aggregates + @Override + public Integer visitMultipleArrayAggregate(MultipleArrayAggregate ast, Frame frame) { + var elemSize = ast.E.visit(this, frame); + var frame1 = frame.expand(elemSize); + var arraySize = ast.AA.visit(this, frame1); + return elemSize + arraySize; + } + + @Override + public Integer visitSingleArrayAggregate(SingleArrayAggregate ast, Frame frame) { + return ast.E.visit(this, frame); + } + + // Record Aggregates + @Override + public Integer visitMultipleRecordAggregate(MultipleRecordAggregate ast, Frame frame) { + var fieldSize = ast.E.visit(this, frame); + var frame1 = frame.expand(fieldSize); + var recordSize = ast.RA.visit(this, frame1); + return fieldSize + recordSize; + } + + @Override + public Integer visitSingleRecordAggregate(SingleRecordAggregate ast, Frame frame) { + return ast.E.visit(this, frame); + } + + // Formal Parameters + @Override + public Integer visitConstFormalParameter(ConstFormalParameter ast, Frame frame) { + var valSize = ast.T.visit(this); + ast.entity = new UnknownValue(valSize, frame.getLevel(), -frame.getSize() - valSize); + writeTableDetails(ast); + return valSize; + } + + @Override + public Integer visitFuncFormalParameter(FuncFormalParameter ast, Frame frame) { + var argsSize = Machine.closureSize; + ast.entity = new UnknownRoutine(Machine.closureSize, frame.getLevel(), -frame.getSize() - argsSize); + writeTableDetails(ast); + return argsSize; + } + + @Override + public Integer visitProcFormalParameter(ProcFormalParameter ast, Frame frame) { + var argsSize = Machine.closureSize; + ast.entity = new UnknownRoutine(Machine.closureSize, frame.getLevel(), -frame.getSize() - argsSize); + writeTableDetails(ast); + return argsSize; + } + + @Override + public Integer visitVarFormalParameter(VarFormalParameter ast, Frame frame) { + ast.T.visit(this); + ast.entity = new UnknownAddress(Machine.addressSize, frame.getLevel(), -frame.getSize() - Machine.addressSize); + writeTableDetails(ast); + return Machine.addressSize; + } + + @Override + public Integer visitEmptyFormalParameterSequence(EmptyFormalParameterSequence ast, Frame frame) { + return 0; + } + + @Override + public Integer visitMultipleFormalParameterSequence(MultipleFormalParameterSequence ast, Frame frame) { + var argsSize1 = ast.FPS.visit(this, frame); + var frame1 = frame.expand(argsSize1); + var argsSize2 = ast.FP.visit(this, frame1); + return argsSize1 + argsSize2; + } + + @Override + public Integer visitSingleFormalParameterSequence(SingleFormalParameterSequence ast, Frame frame) { + return ast.FP.visit(this, frame); + } + + // Actual Parameters + @Override + public Integer visitConstActualParameter(ConstActualParameter ast, Frame frame) { + return ast.E.visit(this, frame); + } + + @Override + public Integer visitFuncActualParameter(FuncActualParameter ast, Frame frame) { + var routineEntity = (RoutineEntity) ast.I.decl.entity; + routineEntity.encodeFetch(emitter, frame); + return Machine.closureSize; + } + + @Override + public Integer visitProcActualParameter(ProcActualParameter ast, Frame frame) { + var routineEntity = (RoutineEntity) ast.I.decl.entity; + routineEntity.encodeFetch(emitter, frame); + return Machine.closureSize; + } + + @Override + public Integer visitVarActualParameter(VarActualParameter ast, Frame frame) { + encodeFetchAddress(ast.V, frame); + return Machine.addressSize; + } + + @Override + public Integer visitEmptyActualParameterSequence(EmptyActualParameterSequence ast, Frame frame) { + return 0; + } + + @Override + public Integer visitMultipleActualParameterSequence(MultipleActualParameterSequence ast, Frame frame) { + var argsSize1 = ast.AP.visit(this, frame); + var frame1 = frame.expand(argsSize1); + var argsSize2 = ast.APS.visit(this, frame1); + return argsSize1 + argsSize2; + } + + @Override + public Integer visitSingleActualParameterSequence(SingleActualParameterSequence ast, Frame frame) { + return ast.AP.visit(this, frame); + } + + // Type Denoters + @Override + public Integer visitAnyTypeDenoter(AnyTypeDenoter ast, Frame frame) { + return 0; + } + + @Override + public Integer visitArrayTypeDenoter(ArrayTypeDenoter ast, Frame frame) { + int typeSize; + if (ast.entity == null) { + var elemSize = ast.T.visit(this); + typeSize = ast.IL.getValue() * elemSize; + ast.entity = new TypeRepresentation(typeSize); + writeTableDetails(ast); + } else { + typeSize = ast.entity.getSize(); + } + return typeSize; + } + + @Override + public Integer visitBoolTypeDenoter(BoolTypeDenoter ast, Frame frame) { + if (ast.entity == null) { + ast.entity = new TypeRepresentation(Machine.booleanSize); + writeTableDetails(ast); + } + return Machine.booleanSize; + } + + @Override + public Integer visitCharTypeDenoter(CharTypeDenoter ast, Frame frame) { + if (ast.entity == null) { + ast.entity = new TypeRepresentation(Machine.characterSize); + writeTableDetails(ast); + } + return Machine.characterSize; + } + + @Override + public Integer visitErrorTypeDenoter(ErrorTypeDenoter ast, Frame frame) { + return 0; + } + + @Override + public Integer visitSimpleTypeDenoter(SimpleTypeDenoter ast, Frame frame) { + return 0; + } + + @Override + public Integer visitIntTypeDenoter(IntTypeDenoter ast, Frame frame) { + if (ast.entity == null) { + ast.entity = new TypeRepresentation(Machine.integerSize); + writeTableDetails(ast); + } + return Machine.integerSize; + } + + @Override + public Integer visitRecordTypeDenoter(RecordTypeDenoter ast, Frame frame) { + int typeSize; + if (ast.entity == null) { + typeSize = ast.FT.visit(this, frame); + ast.entity = new TypeRepresentation(typeSize); + writeTableDetails(ast); + } else { + typeSize = ast.entity.getSize(); + } + return typeSize; + } + + @Override + public Integer visitMultipleFieldTypeDenoter(MultipleFieldTypeDenoter ast, Frame frame) { + if (frame == null) { // in this case, we're just using the frame to wrap up the size + frame = Frame.Initial; + } + + var offset = frame.getSize(); + int fieldSize; + if (ast.entity == null) { + fieldSize = ast.T.visit(this); + ast.entity = new Field(fieldSize, offset); + writeTableDetails(ast); + } else { + fieldSize = ast.entity.getSize(); + } + + var offset1 = frame.replace(offset + fieldSize); + var recSize = ast.FT.visit(this, offset1); + return fieldSize + recSize; + } + + @Override + public Integer visitSingleFieldTypeDenoter(SingleFieldTypeDenoter ast, Frame frame) { + var offset = frame.getSize(); + int fieldSize; + if (ast.entity == null) { + fieldSize = ast.T.visit(this); + ast.entity = new Field(fieldSize, offset); + writeTableDetails(ast); + } else { + fieldSize = ast.entity.getSize(); + } + + return fieldSize; + } + + // Literals, Identifiers and Operators + @Override + public Void visitCharacterLiteral(CharacterLiteral ast, Void arg) { + return null; + } + + @Override + public Void visitIdentifier(Identifier ast, Frame frame) { + var routineEntity = (RoutineEntity) ast.decl.entity; + routineEntity.encodeCall(emitter, frame); + return null; + } + + @Override + public Void visitIntegerLiteral(IntegerLiteral ast, Void arg) { + return null; + } + + @Override + public Void visitOperator(Operator ast, Frame frame) { + var routineEntity = (RoutineEntity) ast.decl.entity; + routineEntity.encodeCall(emitter, frame); + return null; + } + + // Value-or-variable names + @Override + public RuntimeEntity visitDotVname(DotVname ast, Frame frame) { + var baseObject = ast.V.visit(this, frame); + ast.offset = ast.V.offset + ((Field) ast.I.decl.entity).getFieldOffset(); + // I.decl points to the appropriate record field + ast.indexed = ast.V.indexed; + return baseObject; + } + + @Override + public RuntimeEntity visitSimpleVname(SimpleVname ast, Frame frame) { + ast.offset = 0; + ast.indexed = false; + return ast.I.decl.entity; + } + + @Override + public RuntimeEntity visitSubscriptVname(SubscriptVname ast, Frame frame) { + var baseObject = ast.V.visit(this, frame); + ast.offset = ast.V.offset; + ast.indexed = ast.V.indexed; + var elemSize = ast.type.visit(this); + if (ast.E.isLiteral()) { + ast.offset = ast.offset + ast.E.getValue() * elemSize; + } else { + // v-name is indexed by a proper expression, not a literal + if (ast.indexed) { + frame = frame.expand(Machine.integerSize); + } + ast.E.visit(this, frame); + if (elemSize != 1) { + emitter.emit(OpCode.LOADL, 0, elemSize); + emitter.emit(OpCode.CALL, Register.PB, Primitive.MULT); + } + if (ast.indexed) + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + else { + ast.indexed = true; + } + } + return baseObject; + } + + // Programs + @Override + public Void visitProgram(Program ast, Frame frame) { + return ast.C.visit(this, frame); + } + + public Encoder(Emitter emitter, ErrorReporter reporter) { + this.emitter = emitter; + this.reporter = reporter; + + elaborateStdEnvironment(); + } + + private Emitter emitter; + + private ErrorReporter reporter; + + // Generates code to run a program. + // showingTable is true iff entity description details + // are to be displayed. + public final void encodeRun(Program program, boolean showingTable) { + tableDetailsReqd = showingTable; + // startCodeGeneration(); + program.visit(this, Frame.Initial); + emitter.emit(OpCode.HALT); + } + + // Decides run-time representation of a standard constant. + private final void elaborateStdConst(ConstDeclaration constDeclaration, int value) { + + var typeSize = constDeclaration.E.type.visit(this); + constDeclaration.entity = new KnownValue(typeSize, value); + writeTableDetails(constDeclaration); + } + + // Decides run-time representation of a standard routine. + private final void elaborateStdPrimRoutine(Declaration routineDeclaration, Primitive primitive) { + routineDeclaration.entity = new PrimitiveRoutine(Machine.closureSize, primitive); + writeTableDetails(routineDeclaration); + } + + private final void elaborateStdEqRoutine(Declaration routineDeclaration, Primitive primitive) { + routineDeclaration.entity = new EqualityRoutine(Machine.closureSize, primitive); + writeTableDetails(routineDeclaration); + } + + private final void elaborateStdEnvironment() { + tableDetailsReqd = false; + elaborateStdConst(StdEnvironment.falseDecl, Machine.falseRep); + elaborateStdConst(StdEnvironment.trueDecl, Machine.trueRep); + elaborateStdPrimRoutine(StdEnvironment.notDecl, Primitive.NOT); + elaborateStdPrimRoutine(StdEnvironment.andDecl, Primitive.AND); + elaborateStdPrimRoutine(StdEnvironment.orDecl, Primitive.OR); + elaborateStdConst(StdEnvironment.maxintDecl, Machine.maxintRep); + elaborateStdPrimRoutine(StdEnvironment.addDecl, Primitive.ADD); + elaborateStdPrimRoutine(StdEnvironment.subtractDecl, Primitive.SUB); + elaborateStdPrimRoutine(StdEnvironment.multiplyDecl, Primitive.MULT); + elaborateStdPrimRoutine(StdEnvironment.divideDecl, Primitive.DIV); + elaborateStdPrimRoutine(StdEnvironment.moduloDecl, Primitive.MOD); + elaborateStdPrimRoutine(StdEnvironment.lessDecl, Primitive.LT); + elaborateStdPrimRoutine(StdEnvironment.notgreaterDecl, Primitive.LE); + elaborateStdPrimRoutine(StdEnvironment.greaterDecl, Primitive.GT); + elaborateStdPrimRoutine(StdEnvironment.notlessDecl, Primitive.GE); + elaborateStdPrimRoutine(StdEnvironment.chrDecl, Primitive.ID); + elaborateStdPrimRoutine(StdEnvironment.ordDecl, Primitive.ID); + elaborateStdPrimRoutine(StdEnvironment.eolDecl, Primitive.EOL); + elaborateStdPrimRoutine(StdEnvironment.eofDecl, Primitive.EOF); + elaborateStdPrimRoutine(StdEnvironment.getDecl, Primitive.GET); + elaborateStdPrimRoutine(StdEnvironment.putDecl, Primitive.PUT); + elaborateStdPrimRoutine(StdEnvironment.getintDecl, Primitive.GETINT); + elaborateStdPrimRoutine(StdEnvironment.putintDecl, Primitive.PUTINT); + elaborateStdPrimRoutine(StdEnvironment.geteolDecl, Primitive.GETEOL); + elaborateStdPrimRoutine(StdEnvironment.puteolDecl, Primitive.PUTEOL); + elaborateStdEqRoutine(StdEnvironment.equalDecl, Primitive.EQ); + elaborateStdEqRoutine(StdEnvironment.unequalDecl, Primitive.NE); + } + + boolean tableDetailsReqd; + + public static void writeTableDetails(AbstractSyntaxTree ast) { + } + + // Generates code to pop the top off the stack + // and store the value in a named constant or variable + // frame the local stack frame when + // the constant or variable is fetched at run-time. + // valSize is the size of the constant or variable's value. + + private void encodeStore(Vname V, Frame frame, int valSize) { + + var baseObject = (AddressableEntity) V.visit(this, frame); + // If indexed = true, code will have been generated to load an index value. + if (valSize > 255) { + reporter.reportRestriction("can't store values larger than 255 words"); + valSize = 255; // to allow code generation to continue + } + + baseObject.encodeStore(emitter, frame, valSize, V); + } + + // Generates code to fetch the value of a named constant or variable + // and push it on to the stack. + // currentLevel is the routine level where the vname occurs. + // frameSize is the anticipated size of the local stack frame when + // the constant or variable is fetched at run-time. + // valSize is the size of the constant or variable's value. + + private void encodeFetch(Vname V, Frame frame, int valSize) { + + var baseObject = (FetchableEntity) V.visit(this, frame); + // If indexed = true, code will have been generated to load an index value. + if (valSize > 255) { + reporter.reportRestriction("can't load values larger than 255 words"); + valSize = 255; // to allow code generation to continue + } + + baseObject.encodeFetch(emitter, frame, valSize, V); + } + + // Generates code to compute and push the address of a named variable. + // vname is the program phrase that names this variable. + // currentLevel is the routine level where the vname occurs. + // frameSize is the anticipated size of the local stack frame when + // the variable is addressed at run-time. + + private void encodeFetchAddress(Vname V, Frame frame) { + + var baseObject = (AddressableEntity) V.visit(this, frame); + baseObject.encodeFetchAddress(emitter, frame, V); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/Frame.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/Frame.java new file mode 100644 index 0000000..ba5e217 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/Frame.java @@ -0,0 +1,77 @@ +/* + * @(#)Frame.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator; + +import triangle.abstractMachine.Register; +import triangle.codeGenerator.entities.ObjectAddress; + +public class Frame { + + public static final Frame Initial = new Frame(0, 0); + + private final int level; + + private final int size; + + private Frame(int level, int size) { + this.level = level; + this.size = size; + } + + public final int getLevel() { + return level; + } + + public final int getSize() { + return size; + } + + public Frame expand(int increment) { + return new Frame(level, size + increment); + } + + public Frame replace(int size) { + return new Frame(level, size); + } + + public Frame push(int size) { + return new Frame(level + 1, size); + } + + /** + * Returns the display register appropriate for object code at the current + * static level to access a data object at the static level of the given + * address. + * + * @param address the address of the data object + * @return the display register required for static addressing + */ + public Register getDisplayRegister(ObjectAddress address) { + if (address.getLevel() == 0) { + return Register.SB; + } + + if (level - address.getLevel() <= 6) { + return Register.values()[Register.LB.ordinal() + level - address.getLevel()]; // LB|L1|...|L6 + } + + // _errorReporter.ReportRestriction("can't access data more than 6 levels out"); + return Register.L6; // to allow code generation to continue + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/AddressableEntity.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/AddressableEntity.java new file mode 100644 index 0000000..3896e32 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/AddressableEntity.java @@ -0,0 +1,29 @@ +package triangle.codeGenerator.entities; + +import triangle.abstractSyntaxTrees.vnames.Vname; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public abstract class AddressableEntity extends RuntimeEntity implements FetchableEntity { + + protected final ObjectAddress address; + + protected AddressableEntity(int size, int level, int displacement) { + super(size); + address = new ObjectAddress(level, displacement); + } + + protected AddressableEntity(int size, Frame frame) { + this(size, frame.getLevel(), frame.getSize()); + } + + public ObjectAddress getAddress() { + return address; + } + + public abstract void encodeStore(Emitter emitter, Frame frame, int size, Vname vname); + + public abstract void encodeFetchAddress(Emitter emitter, Frame frame, Vname vname); + + public abstract void encodeFetch(Emitter emitter, Frame frame, int size, Vname vname); +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/EqualityRoutine.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/EqualityRoutine.java new file mode 100644 index 0000000..0b2c1da --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/EqualityRoutine.java @@ -0,0 +1,50 @@ +/* + * @(#)EqualityRoutine.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +import triangle.abstractMachine.OpCode; +import triangle.abstractMachine.Primitive; +import triangle.abstractMachine.Register; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public class EqualityRoutine extends RuntimeEntity implements RoutineEntity { + + private final Primitive primitive; + + public EqualityRoutine(int size, Primitive primitive) { + super(size); + this.primitive = primitive; + } + + public final Primitive getPrimitive() { + return primitive; + } + + public void encodeCall(Emitter emitter, Frame frame) { + emitter.emit(OpCode.LOADL, frame.getSize() / 2); + emitter.emit(OpCode.CALL, Register.PB, primitive); + } + + public void encodeFetch(Emitter emitter, Frame frame) { + emitter.emit(OpCode.LOADA, 0, Register.SB, 0); + emitter.emit(OpCode.LOADA, Register.PB, primitive); + } + +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/FetchableEntity.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/FetchableEntity.java new file mode 100644 index 0000000..1e4194c --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/FetchableEntity.java @@ -0,0 +1,11 @@ +package triangle.codeGenerator.entities; + +import triangle.abstractSyntaxTrees.vnames.Vname; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public interface FetchableEntity { + + void encodeFetch(Emitter emitter, Frame frame, int size, Vname vname); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/Field.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/Field.java new file mode 100644 index 0000000..b0daf9e --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/Field.java @@ -0,0 +1,33 @@ +/* + * @(#)Field.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +public class Field extends RuntimeEntity { + + private final int fieldOffset; + + public Field(int size, int fieldOffset) { + super(size); + this.fieldOffset = fieldOffset; + } + + public final int getFieldOffset() { + return fieldOffset; + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownAddress.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownAddress.java new file mode 100644 index 0000000..587d9df --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownAddress.java @@ -0,0 +1,66 @@ +/* + * @(#)KnownAddress.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +import triangle.abstractMachine.OpCode; +import triangle.abstractMachine.Primitive; +import triangle.abstractMachine.Register; +import triangle.abstractSyntaxTrees.vnames.Vname; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public class KnownAddress extends AddressableEntity { + + public KnownAddress(int size, int level, int displacement) { + super(size, level, displacement); + } + + public KnownAddress(int size, Frame frame) { + super(size, frame); + } + + public void encodeStore(Emitter emitter, Frame frame, int size, Vname vname) { + if (vname.indexed) { + emitter.emit(OpCode.LOADA, 0, frame.getDisplayRegister(address), address.getDisplacement() + vname.offset); + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + emitter.emit(OpCode.STOREI, size, 0); + } else { + emitter.emit(OpCode.STORE, size, frame.getDisplayRegister(address), + address.getDisplacement() + vname.offset); + } + } + + public void encodeFetch(Emitter emitter, Frame frame, int size, Vname vname) { + if (vname.indexed) { + emitter.emit(OpCode.LOADA, 0, frame.getDisplayRegister(address), address.getDisplacement() + vname.offset); + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + emitter.emit(OpCode.LOADI, size, 0); + } else { + emitter.emit(OpCode.LOAD, size, frame.getDisplayRegister(address), + address.getDisplacement() + vname.offset); + } + } + + public void encodeFetchAddress(Emitter emitter, Frame frame, Vname vname) { + emitter.emit(OpCode.LOADA, 0, frame.getDisplayRegister(address), address.getDisplacement() + vname.offset); + if (vname.indexed) { + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + } + } +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownRoutine.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownRoutine.java new file mode 100644 index 0000000..5a4c22b --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownRoutine.java @@ -0,0 +1,48 @@ +/* + * @(#)KnownRoutine.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +import triangle.abstractMachine.OpCode; +import triangle.abstractMachine.Register; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public class KnownRoutine extends RuntimeEntity implements RoutineEntity { + + private final ObjectAddress address; + + public KnownRoutine(int size, int level, int displacement) { + super(size); + address = new ObjectAddress(level, displacement); + } + + public final ObjectAddress getAddress() { + return address; + } + + public void encodeCall(Emitter emitter, Frame frame) { + emitter.emit(OpCode.CALL, frame.getDisplayRegister(address), Register.CB, address.getDisplacement()); + } + + public void encodeFetch(Emitter emitter, Frame frame) { + emitter.emit(OpCode.LOADA, frame.getDisplayRegister(address), 0); + emitter.emit(OpCode.LOADA, Register.CB, address.getDisplacement()); + } + +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownValue.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownValue.java new file mode 100644 index 0000000..f8147e8 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownValue.java @@ -0,0 +1,43 @@ +/* + * @(#)KnownValue.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +import triangle.abstractMachine.OpCode; +import triangle.abstractSyntaxTrees.vnames.Vname; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public class KnownValue extends RuntimeEntity implements FetchableEntity { + + private final int value; + + public KnownValue(int size, int value) { + super(size); + this.value = value; + } + + public final int getValue() { + return value; + } + + public void encodeFetch(Emitter emitter, Frame frame, int size, Vname vname) { + // presumably offset = 0 and indexed = false + emitter.emit(OpCode.LOADL, 0, value); + } +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/ObjectAddress.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/ObjectAddress.java new file mode 100644 index 0000000..791d028 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/ObjectAddress.java @@ -0,0 +1,39 @@ +/* + * @(#)ObjectAddress.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +public class ObjectAddress { + + private final int level; + + private final int displacement; + + public ObjectAddress(int level, int displacement) { + this.level = level; + this.displacement = displacement; + } + + public final int getLevel() { + return level; + } + + public int getDisplacement() { + return displacement; + } +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/PrimitiveRoutine.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/PrimitiveRoutine.java new file mode 100644 index 0000000..29424ac --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/PrimitiveRoutine.java @@ -0,0 +1,51 @@ +/* + * @(#)PrimitiveRoutine.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +import triangle.abstractMachine.OpCode; +import triangle.abstractMachine.Primitive; +import triangle.abstractMachine.Register; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public class PrimitiveRoutine extends RuntimeEntity implements RoutineEntity { + + private final Primitive primitive; + + public PrimitiveRoutine(int size, Primitive primitive) { + super(size); + this.primitive = primitive; + } + + public final Primitive getPrimitive() { + return primitive; + } + + public void encodeCall(Emitter emitter, Frame frame) { + if (primitive != Primitive.ID) { + emitter.emit(OpCode.CALL, Register.PB, primitive); + } + } + + public void encodeFetch(Emitter emitter, Frame frame) { + emitter.emit(OpCode.LOADA, 0, Register.SB, 0); + emitter.emit(OpCode.LOADA, Register.PB, primitive); + } + +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/RoutineEntity.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/RoutineEntity.java new file mode 100644 index 0000000..386aef5 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/RoutineEntity.java @@ -0,0 +1,11 @@ +package triangle.codeGenerator.entities; + +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public interface RoutineEntity { + + void encodeCall(Emitter emitter, Frame frame); + + void encodeFetch(Emitter emitter, Frame frame); +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/RuntimeEntity.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/RuntimeEntity.java new file mode 100644 index 0000000..273371c --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/RuntimeEntity.java @@ -0,0 +1,34 @@ +/* + * @(#)RuntimeEntity.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +// Run-time object + +public abstract class RuntimeEntity { + + private final int size; + + protected RuntimeEntity(int size) { + this.size = size; + } + + public final int getSize() { + return size; + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/TypeRepresentation.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/TypeRepresentation.java new file mode 100644 index 0000000..35c71e0 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/TypeRepresentation.java @@ -0,0 +1,27 @@ +/* + * @(#)TypeRepresentation.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +public class TypeRepresentation extends RuntimeEntity { + + public TypeRepresentation(int size) { + super(size); + } + +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownAddress.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownAddress.java new file mode 100644 index 0000000..c3d6054 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownAddress.java @@ -0,0 +1,78 @@ +/* + * @(#)UnknownAddress.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +import triangle.abstractMachine.Machine; +import triangle.abstractMachine.OpCode; +import triangle.abstractMachine.Primitive; +import triangle.abstractMachine.Register; +import triangle.abstractSyntaxTrees.vnames.Vname; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public class UnknownAddress extends AddressableEntity { + + public UnknownAddress(int size, int level, int displacement) { + super(size, level, displacement); + } + + public void encodeStore(Emitter emitter, Frame frame, int size, Vname vname) { + + emitter.emit(OpCode.LOAD, Machine.addressSize, frame.getDisplayRegister(address), address.getDisplacement()); + if (vname.indexed) { + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + } + + int offset = vname.offset; + if (offset != 0) { + emitter.emit(OpCode.LOADL, 0, offset); + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + } + emitter.emit(OpCode.STOREI, size, 0); + } + + public void encodeFetch(Emitter emitter, Frame frame, int size, Vname vname) { + emitter.emit(OpCode.LOAD, Machine.addressSize, frame.getDisplayRegister(address), address.getDisplacement()); + + if (vname.indexed) { + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + } + + int offset = vname.offset; + if (offset != 0) { + emitter.emit(OpCode.LOADL, offset); + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + } + emitter.emit(OpCode.LOADI, size); + } + + public void encodeFetchAddress(Emitter emitter, Frame frame, Vname vname) { + + emitter.emit(OpCode.LOAD, Machine.addressSize, frame.getDisplayRegister(address), address.getDisplacement()); + if (vname.indexed) { + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + } + + int offset = vname.offset; + if (offset != 0) { + emitter.emit(OpCode.LOADL, offset); + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + } + } +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownRoutine.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownRoutine.java new file mode 100644 index 0000000..c7a080d --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownRoutine.java @@ -0,0 +1,48 @@ +/* + * @(#)UnknownRoutine.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +import triangle.abstractMachine.Machine; +import triangle.abstractMachine.OpCode; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public class UnknownRoutine extends RuntimeEntity implements RoutineEntity { + + private final ObjectAddress address; + + public UnknownRoutine(int size, int level, int displacement) { + super(size); + address = new ObjectAddress(level, displacement); + } + + public final ObjectAddress getAddress() { + return address; + } + + public void encodeCall(Emitter emitter, Frame frame) { + emitter.emit(OpCode.LOAD, Machine.closureSize, frame.getDisplayRegister(address), address.getDisplacement()); + emitter.emit(OpCode.CALLI, 0); + } + + public void encodeFetch(Emitter emitter, Frame frame) { + emitter.emit(OpCode.LOAD, Machine.closureSize, frame.getDisplayRegister(address), address.getDisplacement()); + } + +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownValue.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownValue.java new file mode 100644 index 0000000..8077e69 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownValue.java @@ -0,0 +1,55 @@ +/* + * @(#)UnknownValue.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +import triangle.abstractMachine.OpCode; +import triangle.abstractMachine.Primitive; +import triangle.abstractMachine.Register; +import triangle.abstractSyntaxTrees.vnames.Vname; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public class UnknownValue extends RuntimeEntity implements FetchableEntity { + + private final ObjectAddress address; + + public UnknownValue(int size, int level, int displacement) { + super(size); + address = new ObjectAddress(level, displacement); + } + + public UnknownValue(int size, Frame frame) { + this(size, frame.getLevel(), frame.getSize()); + } + + public final ObjectAddress getAddress() { + return address; + } + + public void encodeFetch(Emitter emitter, Frame frame, int size, Vname vname) { + if (vname.indexed) { + emitter.emit(OpCode.LOADA, 0, frame.getDisplayRegister(address), address.getDisplacement() + vname.offset); + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + emitter.emit(OpCode.LOADI, size, 0); + } else { + emitter.emit(OpCode.LOAD, size, frame.getDisplayRegister(address), + address.getDisplacement() + vname.offset); + } + } +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/Checker.java b/Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/Checker.java new file mode 100644 index 0000000..d06813e --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/Checker.java @@ -0,0 +1,984 @@ +/* + * @(#)Checker.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.contextualAnalyzer; + +import triangle.ErrorReporter; +import triangle.StdEnvironment; +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.Program; +import triangle.abstractSyntaxTrees.actuals.ConstActualParameter; +import triangle.abstractSyntaxTrees.actuals.EmptyActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.FuncActualParameter; +import triangle.abstractSyntaxTrees.actuals.MultipleActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.ProcActualParameter; +import triangle.abstractSyntaxTrees.actuals.SingleActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.VarActualParameter; +import triangle.abstractSyntaxTrees.aggregates.MultipleArrayAggregate; +import triangle.abstractSyntaxTrees.aggregates.MultipleRecordAggregate; +import triangle.abstractSyntaxTrees.aggregates.SingleArrayAggregate; +import triangle.abstractSyntaxTrees.aggregates.SingleRecordAggregate; +import triangle.abstractSyntaxTrees.commands.AssignCommand; +import triangle.abstractSyntaxTrees.commands.CallCommand; +import triangle.abstractSyntaxTrees.commands.EmptyCommand; +import triangle.abstractSyntaxTrees.commands.IfCommand; +import triangle.abstractSyntaxTrees.commands.LetCommand; +import triangle.abstractSyntaxTrees.commands.SequentialCommand; +import triangle.abstractSyntaxTrees.commands.WhileCommand; +import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration; +import triangle.abstractSyntaxTrees.declarations.ConstDeclaration; +import triangle.abstractSyntaxTrees.declarations.ConstantDeclaration; +import triangle.abstractSyntaxTrees.declarations.Declaration; +import triangle.abstractSyntaxTrees.declarations.FuncDeclaration; +import triangle.abstractSyntaxTrees.declarations.FunctionDeclaration; +import triangle.abstractSyntaxTrees.declarations.ProcDeclaration; +import triangle.abstractSyntaxTrees.declarations.ProcedureDeclaration; +import triangle.abstractSyntaxTrees.declarations.SequentialDeclaration; +import triangle.abstractSyntaxTrees.declarations.UnaryOperatorDeclaration; +import triangle.abstractSyntaxTrees.declarations.VarDeclaration; +import triangle.abstractSyntaxTrees.declarations.VariableDeclaration; +import triangle.abstractSyntaxTrees.expressions.ArrayExpression; +import triangle.abstractSyntaxTrees.expressions.BinaryExpression; +import triangle.abstractSyntaxTrees.expressions.CallExpression; +import triangle.abstractSyntaxTrees.expressions.CharacterExpression; +import triangle.abstractSyntaxTrees.expressions.EmptyExpression; +import triangle.abstractSyntaxTrees.expressions.IfExpression; +import triangle.abstractSyntaxTrees.expressions.IntegerExpression; +import triangle.abstractSyntaxTrees.expressions.LetExpression; +import triangle.abstractSyntaxTrees.expressions.RecordExpression; +import triangle.abstractSyntaxTrees.expressions.UnaryExpression; +import triangle.abstractSyntaxTrees.expressions.VnameExpression; +import triangle.abstractSyntaxTrees.formals.ConstFormalParameter; +import triangle.abstractSyntaxTrees.formals.EmptyFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.FormalParameter; +import triangle.abstractSyntaxTrees.formals.FormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.FuncFormalParameter; +import triangle.abstractSyntaxTrees.formals.MultipleFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.ProcFormalParameter; +import triangle.abstractSyntaxTrees.formals.SingleFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.VarFormalParameter; +import triangle.abstractSyntaxTrees.terminals.CharacterLiteral; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.terminals.IntegerLiteral; +import triangle.abstractSyntaxTrees.terminals.Operator; +import triangle.abstractSyntaxTrees.terminals.Terminal; +import triangle.abstractSyntaxTrees.types.AnyTypeDenoter; +import triangle.abstractSyntaxTrees.types.ArrayTypeDenoter; +import triangle.abstractSyntaxTrees.types.BoolTypeDenoter; +import triangle.abstractSyntaxTrees.types.CharTypeDenoter; +import triangle.abstractSyntaxTrees.types.ErrorTypeDenoter; +import triangle.abstractSyntaxTrees.types.FieldTypeDenoter; +import triangle.abstractSyntaxTrees.types.IntTypeDenoter; +import triangle.abstractSyntaxTrees.types.MultipleFieldTypeDenoter; +import triangle.abstractSyntaxTrees.types.RecordTypeDenoter; +import triangle.abstractSyntaxTrees.types.SimpleTypeDenoter; +import triangle.abstractSyntaxTrees.types.SingleFieldTypeDenoter; +import triangle.abstractSyntaxTrees.types.TypeDeclaration; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.ActualParameterSequenceVisitor; +import triangle.abstractSyntaxTrees.visitors.ActualParameterVisitor; +import triangle.abstractSyntaxTrees.visitors.ArrayAggregateVisitor; +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.abstractSyntaxTrees.visitors.FormalParameterSequenceVisitor; +import triangle.abstractSyntaxTrees.visitors.IdentifierVisitor; +import triangle.abstractSyntaxTrees.visitors.LiteralVisitor; +import triangle.abstractSyntaxTrees.visitors.OperatorVisitor; +import triangle.abstractSyntaxTrees.visitors.ProgramVisitor; +import triangle.abstractSyntaxTrees.visitors.RecordAggregateVisitor; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.abstractSyntaxTrees.visitors.VnameVisitor; +import triangle.abstractSyntaxTrees.vnames.DotVname; +import triangle.abstractSyntaxTrees.vnames.SimpleVname; +import triangle.abstractSyntaxTrees.vnames.SubscriptVname; +import triangle.syntacticAnalyzer.SourcePosition; + +public final class Checker implements ActualParameterVisitor, + ActualParameterSequenceVisitor, ArrayAggregateVisitor, + CommandVisitor, DeclarationVisitor, ExpressionVisitor, + FormalParameterSequenceVisitor, IdentifierVisitor, + LiteralVisitor, OperatorVisitor, ProgramVisitor, + RecordAggregateVisitor, TypeDenoterVisitor, + VnameVisitor { + + // Commands + + // Always returns null. Does not use the given object. + + @Override + public Void visitAssignCommand(AssignCommand ast, Void arg) { + var vType = ast.V.visit(this); + var eType = ast.E.visit(this); + + checkAndReportError(ast.V.variable, "LHS of assignment is not a variable", ast.V); + checkAndReportError(eType.equals(vType), "assignment incompatibilty", ast); + + return null; + } + + @Override + public Void visitCallCommand(CallCommand ast, Void arg) { + var binding = ast.I.visit(this); + + if (binding instanceof ProcedureDeclaration) { + ProcedureDeclaration procedure = (ProcedureDeclaration)binding; + ast.APS.visit(this, procedure.getFormals()); + } else { + reportUndeclaredOrError(binding, ast.I, "\"%\" is not a procedure identifier"); + } + + return null; + } + + @Override + public Void visitEmptyCommand(EmptyCommand ast, Void arg) { + return null; + } + + @Override + public Void visitIfCommand(IfCommand ast, Void arg) { + var eType = ast.E.visit(this); + + checkAndReportError(eType.equals(StdEnvironment.booleanType), "Boolean expression expected here", ast.E); + + ast.C1.visit(this); + ast.C2.visit(this); + + return null; + } + + @Override + public Void visitLetCommand(LetCommand ast, Void arg) { + idTable.openScope(); + ast.D.visit(this); + ast.C.visit(this); + idTable.closeScope(); + return null; + } + + @Override + public Void visitSequentialCommand(SequentialCommand ast, Void arg) { + ast.C1.visit(this); + ast.C2.visit(this); + return null; + } + + @Override + public Void visitWhileCommand(WhileCommand ast, Void arg) { + var eType = ast.E.visit(this); + + checkAndReportError(eType.equals(StdEnvironment.booleanType), "Boolean expression expected here", ast.E); + ast.C.visit(this); + + return null; + } + + // Expressions + + // Returns the TypeDenoter denoting the type of the expression. Does + // not use the given object. + + @Override + public TypeDenoter visitArrayExpression(ArrayExpression ast, Void arg) { + var elemType = ast.AA.visit(this); + var il = new IntegerLiteral(Integer.toString(ast.AA.elemCount), ast.getPosition()); + ast.type = new ArrayTypeDenoter(il, elemType, ast.getPosition()); + return ast.type; + } + + @Override + public TypeDenoter visitBinaryExpression(BinaryExpression ast, Void arg) { + var e1Type = ast.E1.visit(this); + var e2Type = ast.E2.visit(this); + var binding = ast.O.visit(this); + + if (binding instanceof BinaryOperatorDeclaration) { + BinaryOperatorDeclaration bbinding = (BinaryOperatorDeclaration)binding; + if (bbinding.ARG1 == StdEnvironment.anyType) { + // this operator must be "=" or "\=" + checkAndReportError(e1Type.equals(e2Type), "incompatible argument types for \"%\"", ast.O, ast); + } else { + checkAndReportError(e1Type.equals(bbinding.ARG1), "wrong argument type for \"%\"", ast.O, ast.E1); + checkAndReportError(e2Type.equals(bbinding.ARG2), "wrong argument type for \"%\"", ast.O, ast.E2); + } + return ast.type = bbinding.RES; + } + + reportUndeclaredOrError(binding, ast.O, "\"%\" is not a binary operator"); + return ast.type = StdEnvironment.errorType; + } + + @Override + public TypeDenoter visitCallExpression(CallExpression ast, Void arg) { + var binding = ast.I.visit(this); + + if (binding instanceof FunctionDeclaration) { + FunctionDeclaration function = (FunctionDeclaration)binding; + ast.APS.visit(this, function.getFormals()); + return ast.type = function.getType(); + } + + reportUndeclaredOrError(binding, ast.I, "\"%\" is not a function identifier"); + return ast.type = StdEnvironment.errorType; + } + + @Override + public TypeDenoter visitCharacterExpression(CharacterExpression ast, Void arg) { + return ast.type = StdEnvironment.charType; + } + + @Override + public TypeDenoter visitEmptyExpression(EmptyExpression ast, Void arg) { + return ast.type = null; + } + + @Override + public TypeDenoter visitIfExpression(IfExpression ast, Void arg) { + var e1Type = ast.E1.visit(this); + checkAndReportError(e1Type.equals(StdEnvironment.booleanType), "Boolean expression expected here", ast.E1); + + var e2Type = ast.E2.visit(this); + var e3Type = ast.E3.visit(this); + checkAndReportError(e2Type.equals(e3Type), "incompatible limbs in if-expression", ast); + return ast.type = e2Type; + } + + @Override + public TypeDenoter visitIntegerExpression(IntegerExpression ast, Void arg) { + return ast.type = StdEnvironment.integerType; + } + + @Override + public TypeDenoter visitLetExpression(LetExpression ast, Void arg) { + idTable.openScope(); + ast.D.visit(this); + ast.type = ast.E.visit(this); + idTable.closeScope(); + return ast.type; + } + + @Override + public TypeDenoter visitRecordExpression(RecordExpression ast, Void arg) { + var rType = ast.RA.visit(this); + return ast.type = new RecordTypeDenoter(rType, ast.getPosition()); + } + + @Override + public TypeDenoter visitUnaryExpression(UnaryExpression ast, Void arg) { + var eType = ast.E.visit(this); + var binding = ast.O.visit(this); + + if (binding instanceof UnaryOperatorDeclaration) { + UnaryOperatorDeclaration ubinding = (UnaryOperatorDeclaration)binding; + checkAndReportError(eType.equals(ubinding.ARG), "wrong argument type for \"%\"", ast.O); + return ast.type = ubinding.RES; + } + + reportUndeclaredOrError(binding, ast.O, "\"%\" is not a unary operator"); + return ast.type = StdEnvironment.errorType; + } + + @Override + public TypeDenoter visitVnameExpression(VnameExpression ast, Void arg) { + return ast.type = ast.V.visit(this); + } + + // Declarations + + // Always returns null. Does not use the given object. + @Override + public Void visitBinaryOperatorDeclaration(BinaryOperatorDeclaration ast, Void arg) { + return null; + } + + @Override + public Void visitConstDeclaration(ConstDeclaration ast, Void arg) { + ast.E.visit(this); + idTable.enter(ast.I.spelling, ast); + checkAndReportError(!ast.duplicated, "identifier \"%\" already declared", ast.I, ast); + return null; + } + + @Override + public Void visitFuncDeclaration(FuncDeclaration ast, Void arg) { + ast.T = ast.T.visit(this); + // permits recursion + idTable.enter(ast.I.spelling, ast); + checkAndReportError(!ast.duplicated, "identifier \"%\" already declared", ast.I, ast); + + idTable.openScope(); + ast.FPS.visit(this); + var eType = ast.E.visit(this); + idTable.closeScope(); + + checkAndReportError(ast.T.equals(eType), "body of function \"%\" has wrong type", ast.I, ast.E); + return null; + } + + @Override + public Void visitProcDeclaration(ProcDeclaration ast, Void arg) { + // permits recursion + idTable.enter(ast.I.spelling, ast); + checkAndReportError(!ast.duplicated, "identifier \"%\" already declared", ast.I, ast); + + idTable.openScope(); + ast.FPS.visit(this); + ast.C.visit(this); + idTable.closeScope(); + + return null; + } + + @Override + public Void visitSequentialDeclaration(SequentialDeclaration ast, Void arg) { + ast.D1.visit(this); + ast.D2.visit(this); + return null; + } + + @Override + public Void visitTypeDeclaration(TypeDeclaration ast, Void arg) { + ast.T = ast.T.visit(this); + idTable.enter(ast.I.spelling, ast); + checkAndReportError(!ast.duplicated, "identifier \"%\" already declared", ast.I, ast); + return null; + } + + @Override + public Void visitUnaryOperatorDeclaration(UnaryOperatorDeclaration ast, Void arg) { + return null; + } + + @Override + public Void visitVarDeclaration(VarDeclaration ast, Void arg) { + ast.T = ast.T.visit(this); + idTable.enter(ast.I.spelling, ast); + checkAndReportError(!ast.duplicated, "identifier \"%\" already declared", ast.I, ast); + return null; + } + + // Array Aggregates + + // Returns the TypeDenoter for the Array Aggregate. Does not use the + // given object. + + @Override + public TypeDenoter visitMultipleArrayAggregate(MultipleArrayAggregate ast, Void arg) { + var eType = ast.E.visit(this); + var elemType = ast.AA.visit(this); + ast.elemCount = ast.AA.elemCount + 1; + checkAndReportError(eType.equals(elemType), "incompatible array-aggregate element", ast.E); + return elemType; + } + + @Override + public TypeDenoter visitSingleArrayAggregate(SingleArrayAggregate ast, Void arg) { + var elemType = ast.E.visit(this); + ast.elemCount = 1; + return elemType; + } + + // Record Aggregates + + // Returns the TypeDenoter for the Record Aggregate. Does not use the + // given object. + + @Override + public FieldTypeDenoter visitMultipleRecordAggregate(MultipleRecordAggregate ast, Void arg) { + var eType = ast.E.visit(this); + var rType = ast.RA.visit(this); + var fType = checkFieldIdentifier(rType, ast.I); + checkAndReportError(fType.equals(StdEnvironment.errorType), "duplicate field \"%\" in record", ast.I); + return ast.type = new MultipleFieldTypeDenoter(ast.I, eType, rType, ast.getPosition()); + } + + @Override + public FieldTypeDenoter visitSingleRecordAggregate(SingleRecordAggregate ast, Void arg) { + var eType = ast.E.visit(this); + return ast.type = new SingleFieldTypeDenoter(ast.I, eType, ast.getPosition()); + } + + // Formal Parameters + + // Always returns null. Does not use the given object. + + @Override + public Void visitConstFormalParameter(ConstFormalParameter ast, Void arg) { + ast.T = ast.T.visit(this); + idTable.enter(ast.I.spelling, ast); + checkAndReportError(!ast.duplicated, "duplicated formal parameter \"%\"", ast.I, ast); + return null; + } + + @Override + public Void visitFuncFormalParameter(FuncFormalParameter ast, Void arg) { + idTable.openScope(); + ast.FPS.visit(this); + idTable.closeScope(); + ast.T = ast.T.visit(this); + idTable.enter(ast.I.spelling, ast); + checkAndReportError(!ast.duplicated, "duplicated formal parameter \"%\"", ast.I, ast); + return null; + } + + @Override + public Void visitProcFormalParameter(ProcFormalParameter ast, Void arg) { + idTable.openScope(); + ast.FPS.visit(this); + idTable.closeScope(); + idTable.enter(ast.I.spelling, ast); + checkAndReportError(!ast.duplicated, "duplicated formal parameter \"%\"", ast.I, ast); + return null; + } + + @Override + public Void visitVarFormalParameter(VarFormalParameter ast, Void arg) { + ast.T = ast.T.visit(this); + idTable.enter(ast.I.spelling, ast); + checkAndReportError(!ast.duplicated, "duplicated formal parameter \"%\"", ast.I, ast); + return null; + } + + @Override + public Void visitEmptyFormalParameterSequence(EmptyFormalParameterSequence ast, Void arg) { + return null; + } + + @Override + public Void visitMultipleFormalParameterSequence(MultipleFormalParameterSequence ast, Void arg) { + ast.FP.visit(this); + ast.FPS.visit(this); + return null; + } + + @Override + public Void visitSingleFormalParameterSequence(SingleFormalParameterSequence ast, Void arg) { + ast.FP.visit(this); + return null; + } + + // Actual Parameters + + // Always returns null. Uses the given FormalParameter. + + @Override + public Void visitConstActualParameter(ConstActualParameter ast, FormalParameter arg) { + var eType = ast.E.visit(this); + if (arg instanceof ConstFormalParameter) { + ConstFormalParameter param = (ConstFormalParameter)arg; + checkAndReportError(eType.equals(((ConstFormalParameter)arg).T), "wrong type for const actual parameter", ast.E); + } else { + reportError("const actual parameter not expected here", ast); + } + return null; + } + + @Override + public Void visitFuncActualParameter(FuncActualParameter ast, FormalParameter arg) { + var binding = ast.I.visit(this); + if (binding instanceof FunctionDeclaration) { + FunctionDeclaration function = (FunctionDeclaration)binding; + var formals = function.getFormals(); + var functionType = function.getType(); + if (arg instanceof FuncFormalParameter) { + FuncFormalParameter param = (FuncFormalParameter)arg; + if (!formals.equals(param.getFormals())) { + reportError("wrong signature for function \"%\"", ast.I); + } else if (!functionType.equals(param.T)) { + reportError("wrong type for function \"%\"", ast.I); + } + } else { + reportError("func actual parameter not expected here", ast); + } + } else { + reportUndeclaredOrError(binding, ast.I, "\"%\" is not a function identifier"); + } + return null; + } + + @Override + public Void visitProcActualParameter(ProcActualParameter ast, FormalParameter arg) { + var binding = ast.I.visit(this); + if (binding instanceof ProcedureDeclaration) { + ProcedureDeclaration procedure = (ProcedureDeclaration)binding; + var formals = procedure.getFormals(); + if (arg instanceof ProcFormalParameter) { + ProcFormalParameter param = (ProcFormalParameter)arg; + checkAndReportError(formals.equals(param.getFormals()), "wrong signature for procedure \"%\"", ast.I); + } else { + reportError("proc actual parameter not expected here", ast); + } + } else { + reportUndeclaredOrError(binding, ast.I, "\"%\" is not a procedure identifier"); + } + return null; + } + + @Override + public Void visitVarActualParameter(VarActualParameter ast, FormalParameter arg) { + var vType = ast.V.visit(this); + if (!ast.V.variable) { + reportError("actual parameter is not a variable", ast.V); + } else if (arg instanceof VarFormalParameter) { + VarFormalParameter parameter = (VarFormalParameter)arg; + checkAndReportError(vType.equals(parameter.T), "wrong type for var actual parameter", ast.V); + } else { + reportError("var actual parameter not expected here", ast.V); + } + return null; + } + + @Override + public Void visitEmptyActualParameterSequence(EmptyActualParameterSequence ast, FormalParameterSequence arg) { + checkAndReportError(arg instanceof EmptyFormalParameterSequence, "too few actual parameters", ast); + return null; + } + + @Override + public Void visitMultipleActualParameterSequence(MultipleActualParameterSequence ast, FormalParameterSequence arg) { + if (arg instanceof MultipleFormalParameterSequence) { + MultipleFormalParameterSequence formals = (MultipleFormalParameterSequence)arg; + ast.AP.visit(this, formals.FP); + ast.APS.visit(this, formals.FPS); + } else { + reportError("too many actual parameters", ast); + } + return null; + } + + @Override + public Void visitSingleActualParameterSequence(SingleActualParameterSequence ast, FormalParameterSequence arg) { + if (arg instanceof SingleFormalParameterSequence) { + SingleFormalParameterSequence formal = (SingleFormalParameterSequence)arg; + ast.AP.visit(this, formal.FP); + } else { + reportError("incorrect number of actual parameters", ast); + } + return null; + } + + // Type Denoters + + // Returns the expanded version of the TypeDenoter. Does not + // use the given object. + + @Override + public TypeDenoter visitAnyTypeDenoter(AnyTypeDenoter ast, Void arg) { + return StdEnvironment.anyType; + } + + @Override + public TypeDenoter visitArrayTypeDenoter(ArrayTypeDenoter ast, Void arg) { + ast.T = ast.T.visit(this); + checkAndReportError(ast.IL.getValue() != 0, "arrays must not be empty", ast.IL); + return ast; + } + + @Override + public TypeDenoter visitBoolTypeDenoter(BoolTypeDenoter ast, Void arg) { + return StdEnvironment.booleanType; + } + + @Override + public TypeDenoter visitCharTypeDenoter(CharTypeDenoter ast, Void arg) { + return StdEnvironment.charType; + } + + @Override + public TypeDenoter visitErrorTypeDenoter(ErrorTypeDenoter ast, Void arg) { + return StdEnvironment.errorType; + } + + @Override + public TypeDenoter visitSimpleTypeDenoter(SimpleTypeDenoter ast, Void arg) { + var binding = ast.I.visit(this); + if (binding instanceof TypeDeclaration) { + TypeDeclaration decl = (TypeDeclaration)binding; + return decl.T; + } + + reportUndeclaredOrError(binding, ast.I, "\"%\" is not a type identifier"); + return StdEnvironment.errorType; + } + + @Override + public TypeDenoter visitIntTypeDenoter(IntTypeDenoter ast, Void arg) { + return StdEnvironment.integerType; + } + + @Override + public TypeDenoter visitRecordTypeDenoter(RecordTypeDenoter ast, Void arg) { + ast.FT = (FieldTypeDenoter) ast.FT.visit(this); + return ast; + } + + @Override + public TypeDenoter visitMultipleFieldTypeDenoter(MultipleFieldTypeDenoter ast, Void arg) { + ast.T = ast.T.visit(this); + ast.FT.visit(this); + return ast; + } + + @Override + public TypeDenoter visitSingleFieldTypeDenoter(SingleFieldTypeDenoter ast, Void arg) { + ast.T = ast.T.visit(this); + return ast; + } + + // Literals, Identifiers and Operators + @Override + public TypeDenoter visitCharacterLiteral(CharacterLiteral CL, Void arg) { + return StdEnvironment.charType; + } + + @Override + public Declaration visitIdentifier(Identifier I, Void arg) { + var binding = idTable.retrieve(I.spelling); + if (binding != null) { + I.decl = binding; + } + return binding; + } + + @Override + public TypeDenoter visitIntegerLiteral(IntegerLiteral IL, Void arg) { + return StdEnvironment.integerType; + } + + @Override + public Declaration visitOperator(Operator O, Void arg) { + var binding = idTable.retrieve(O.spelling); + if (binding != null) { + O.decl = binding; + } + return binding; + } + + // Value-or-variable names + + // Determines the address of a named object (constant or variable). + // This consists of a base object, to which 0 or more field-selection + // or array-indexing operations may be applied (if it is a record or + // array). As much as possible of the address computation is done at + // compile-time. Code is generated only when necessary to evaluate + // index expressions at run-time. + // currentLevel is the routine level where the v-name occurs. + // frameSize is the anticipated size of the local stack frame when + // the object is addressed at run-time. + // It returns the description of the base object. + // offset is set to the total of any field offsets (plus any offsets + // due to index expressions that happen to be literals). + // indexed is set to true iff there are any index expressions (other + // than literals). In that case code is generated to compute the + // offset due to these indexing operations at run-time. + + // Returns the TypeDenoter of the Vname. Does not use the + // given object. + + @Override + public TypeDenoter visitDotVname(DotVname ast, Void arg) { + ast.type = null; + var vType = ast.V.visit(this); + ast.variable = ast.V.variable; + if (vType instanceof RecordTypeDenoter) { + RecordTypeDenoter record = (RecordTypeDenoter)vType; + ast.type = checkFieldIdentifier(record.FT, ast.I); + checkAndReportError(ast.type != StdEnvironment.errorType, "no field \"%\" in this record type", + ast.I); + } else { + reportError("record expected here", ast.V); + } + return ast.type; + } + + @Override + public TypeDenoter visitSimpleVname(SimpleVname ast, Void arg) { + ast.variable = false; + ast.type = StdEnvironment.errorType; + + var binding = ast.I.visit(this); + if (binding instanceof ConstantDeclaration) { + ConstantDeclaration constant = (ConstantDeclaration)binding; + ast.variable = false; + return ast.type = constant.getType(); + } else if (binding instanceof VariableDeclaration) { + VariableDeclaration variable = (VariableDeclaration)binding; + ast.variable = true; + return ast.type = variable.getType(); + } + + reportUndeclaredOrError(binding, ast.I, "\"%\" is not a const or var identifier"); + return ast.type = StdEnvironment.errorType; + } + + @Override + public TypeDenoter visitSubscriptVname(SubscriptVname ast, Void arg) { + var vType = ast.V.visit(this); + ast.variable = ast.V.variable; + + var eType = ast.E.visit(this); + if (vType != StdEnvironment.errorType) { + if (vType instanceof ArrayTypeDenoter) { + ArrayTypeDenoter arrayType = (ArrayTypeDenoter)vType; + checkAndReportError(eType.equals(StdEnvironment.integerType), "Integer expression expected here", + ast.E); + ast.type = arrayType.T; + } else { + reportError("array expected here", ast.V); + } + } + + return ast.type; + } + + // Programs + + @Override + public Void visitProgram(Program ast, Void arg) { + ast.C.visit(this); + return null; + } + + // Checks whether the source program, represented by its AST, satisfies the + // language's scope rules and type rules. + // Also decorates the AST as follows: + // (a) Each applied occurrence of an identifier or operator is linked to + // the corresponding declaration of that identifier or operator. + // (b) Each expression and value-or-variable-name is decorated by its type. + // (c) Each type identifier is replaced by the type it denotes. + // Types are represented by small ASTs. + + public void check(Program ast) { + ast.visit(this); + } + + ///////////////////////////////////////////////////////////////////////////// + + public Checker(ErrorReporter reporter) { + this.reporter = reporter; + this.idTable = new IdentificationTable(); + establishStdEnvironment(); + } + + private IdentificationTable idTable; + private static SourcePosition dummyPos = new SourcePosition(); + private ErrorReporter reporter; + + private void reportUndeclaredOrError(Declaration binding, Terminal leaf, String message) { + if (binding == null) { + reportError("\"%\" is not declared", leaf); + } else { + reportError(message, leaf); + } + } + + private void reportError(String message, Terminal ast) { + reportError(message, ast, ast); + } + + private void reportError(String message, Terminal spellingNode, AbstractSyntaxTree positionNode) { + reporter.reportError(message, spellingNode.spelling, positionNode.getPosition()); + } + + private void reportError(String message, AbstractSyntaxTree positionNode) { + reporter.reportError(message, "", positionNode.getPosition()); + } + + private void checkAndReportError(boolean condition, String message, String token, SourcePosition position) { + if (!condition) { + reporter.reportError(message, token, position); + } + } + + private void checkAndReportError(boolean condition, String message, Terminal ast) { + checkAndReportError(condition, message, ast, ast); + } + + private void checkAndReportError(boolean condition, String message, Terminal spellingNode, + AbstractSyntaxTree positionNode) { + checkAndReportError(condition, message, spellingNode.spelling, positionNode.getPosition()); + } + + private void checkAndReportError(boolean condition, String message, AbstractSyntaxTree positionNode) { + checkAndReportError(condition, message, "", positionNode.getPosition()); + } + + private static TypeDenoter checkFieldIdentifier(FieldTypeDenoter ast, Identifier I) { + if (ast instanceof MultipleFieldTypeDenoter) { + MultipleFieldTypeDenoter ft = (MultipleFieldTypeDenoter)ast; + if (ft.I.spelling.compareTo(I.spelling) == 0) { + I.decl = ast; + return ft.T; + } else { + return checkFieldIdentifier(ft.FT, I); + } + } else if (ast instanceof SingleFieldTypeDenoter) { + SingleFieldTypeDenoter ft = (SingleFieldTypeDenoter)ast; + if (ft.I.spelling.compareTo(I.spelling) == 0) { + I.decl = ast; + return ft.T; + } + } + return StdEnvironment.errorType; + } + + // Creates a small AST to represent the "declaration" of a standard + // type, and enters it in the identification table. + + private TypeDeclaration declareStdType(String id, TypeDenoter typedenoter) { + + var binding = new TypeDeclaration(new Identifier(id, dummyPos), typedenoter, dummyPos); + idTable.enter(id, binding); + return binding; + } + + // Creates a small AST to represent the "declaration" of a standard + // type, and enters it in the identification table. + + private ConstDeclaration declareStdConst(String id, TypeDenoter constType) { + + // constExpr used only as a placeholder for constType + var constExpr = new IntegerExpression(null, dummyPos); + constExpr.type = constType; + var binding = new ConstDeclaration(new Identifier(id, dummyPos), constExpr, dummyPos); + idTable.enter(id, binding); + return binding; + } + + // Creates a small AST to represent the "declaration" of a standard + // type, and enters it in the identification table. + + private ProcDeclaration declareStdProc(String id, FormalParameterSequence fps) { + + var binding = new ProcDeclaration(new Identifier(id, dummyPos), fps, new EmptyCommand(dummyPos), dummyPos); + idTable.enter(id, binding); + return binding; + } + + // Creates a small AST to represent the "declaration" of a standard + // type, and enters it in the identification table. + + private FuncDeclaration declareStdFunc(String id, FormalParameterSequence fps, TypeDenoter resultType) { + + var binding = new FuncDeclaration(new Identifier(id, dummyPos), fps, resultType, new EmptyExpression(dummyPos), + dummyPos); + idTable.enter(id, binding); + return binding; + } + + // Creates a small AST to represent the "declaration" of a + // unary operator, and enters it in the identification table. + // This "declaration" summarises the operator's type info. + + private UnaryOperatorDeclaration declareStdUnaryOp(String op, TypeDenoter argType, TypeDenoter resultType) { + + var binding = new UnaryOperatorDeclaration(new Operator(op, dummyPos), argType, resultType, dummyPos); + idTable.enter(op, binding); + return binding; + } + + // Creates a small AST to represent the "declaration" of a + // binary operator, and enters it in the identification table. + // This "declaration" summarises the operator's type info. + + private BinaryOperatorDeclaration declareStdBinaryOp(String op, TypeDenoter arg1Type, TypeDenoter arg2type, + TypeDenoter resultType) { + + var binding = new BinaryOperatorDeclaration(new Operator(op, dummyPos), arg1Type, arg2type, resultType, + dummyPos); + idTable.enter(op, binding); + return binding; + } + + // Creates small ASTs to represent the standard types. + // Creates small ASTs to represent "declarations" of standard types, + // constants, procedures, functions, and operators. + // Enters these "declarations" in the identification table. + + private final static Identifier dummyI = new Identifier("", dummyPos); + + private void establishStdEnvironment() { + + // idTable.startIdentification(); + StdEnvironment.booleanType = new BoolTypeDenoter(dummyPos); + StdEnvironment.integerType = new IntTypeDenoter(dummyPos); + StdEnvironment.charType = new CharTypeDenoter(dummyPos); + StdEnvironment.anyType = new AnyTypeDenoter(dummyPos); + StdEnvironment.errorType = new ErrorTypeDenoter(dummyPos); + + StdEnvironment.booleanDecl = declareStdType("Boolean", StdEnvironment.booleanType); + StdEnvironment.falseDecl = declareStdConst("false", StdEnvironment.booleanType); + StdEnvironment.trueDecl = declareStdConst("true", StdEnvironment.booleanType); + StdEnvironment.notDecl = declareStdUnaryOp("\\", StdEnvironment.booleanType, StdEnvironment.booleanType); + StdEnvironment.andDecl = declareStdBinaryOp("/\\", StdEnvironment.booleanType, StdEnvironment.booleanType, + StdEnvironment.booleanType); + StdEnvironment.orDecl = declareStdBinaryOp("\\/", StdEnvironment.booleanType, StdEnvironment.booleanType, + StdEnvironment.booleanType); + + StdEnvironment.integerDecl = declareStdType("Integer", StdEnvironment.integerType); + StdEnvironment.maxintDecl = declareStdConst("maxint", StdEnvironment.integerType); + StdEnvironment.addDecl = declareStdBinaryOp("+", StdEnvironment.integerType, StdEnvironment.integerType, + StdEnvironment.integerType); + StdEnvironment.subtractDecl = declareStdBinaryOp("-", StdEnvironment.integerType, StdEnvironment.integerType, + StdEnvironment.integerType); + StdEnvironment.multiplyDecl = declareStdBinaryOp("*", StdEnvironment.integerType, StdEnvironment.integerType, + StdEnvironment.integerType); + StdEnvironment.divideDecl = declareStdBinaryOp("/", StdEnvironment.integerType, StdEnvironment.integerType, + StdEnvironment.integerType); + StdEnvironment.moduloDecl = declareStdBinaryOp("//", StdEnvironment.integerType, StdEnvironment.integerType, + StdEnvironment.integerType); + StdEnvironment.lessDecl = declareStdBinaryOp("<", StdEnvironment.integerType, StdEnvironment.integerType, + StdEnvironment.booleanType); + StdEnvironment.notgreaterDecl = declareStdBinaryOp("<=", StdEnvironment.integerType, StdEnvironment.integerType, + StdEnvironment.booleanType); + StdEnvironment.greaterDecl = declareStdBinaryOp(">", StdEnvironment.integerType, StdEnvironment.integerType, + StdEnvironment.booleanType); + StdEnvironment.notlessDecl = declareStdBinaryOp(">=", StdEnvironment.integerType, StdEnvironment.integerType, + StdEnvironment.booleanType); + + StdEnvironment.charDecl = declareStdType("Char", StdEnvironment.charType); + StdEnvironment.chrDecl = declareStdFunc("chr", + new SingleFormalParameterSequence( + new ConstFormalParameter(dummyI, StdEnvironment.integerType, dummyPos), dummyPos), + StdEnvironment.charType); + StdEnvironment.ordDecl = declareStdFunc("ord", + new SingleFormalParameterSequence(new ConstFormalParameter(dummyI, StdEnvironment.charType, dummyPos), + dummyPos), + StdEnvironment.integerType); + StdEnvironment.eofDecl = declareStdFunc("eof", new EmptyFormalParameterSequence(dummyPos), + StdEnvironment.booleanType); + StdEnvironment.eolDecl = declareStdFunc("eol", new EmptyFormalParameterSequence(dummyPos), + StdEnvironment.booleanType); + StdEnvironment.getDecl = declareStdProc("get", new SingleFormalParameterSequence( + new VarFormalParameter(dummyI, StdEnvironment.charType, dummyPos), dummyPos)); + StdEnvironment.putDecl = declareStdProc("put", new SingleFormalParameterSequence( + new ConstFormalParameter(dummyI, StdEnvironment.charType, dummyPos), dummyPos)); + StdEnvironment.getintDecl = declareStdProc("getint", new SingleFormalParameterSequence( + new VarFormalParameter(dummyI, StdEnvironment.integerType, dummyPos), dummyPos)); + StdEnvironment.putintDecl = declareStdProc("putint", new SingleFormalParameterSequence( + new ConstFormalParameter(dummyI, StdEnvironment.integerType, dummyPos), dummyPos)); + StdEnvironment.geteolDecl = declareStdProc("geteol", new EmptyFormalParameterSequence(dummyPos)); + StdEnvironment.puteolDecl = declareStdProc("puteol", new EmptyFormalParameterSequence(dummyPos)); + StdEnvironment.equalDecl = declareStdBinaryOp("=", StdEnvironment.anyType, StdEnvironment.anyType, + StdEnvironment.booleanType); + StdEnvironment.unequalDecl = declareStdBinaryOp("\\=", StdEnvironment.anyType, StdEnvironment.anyType, + StdEnvironment.booleanType); + + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/IdEntry.java b/Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/IdEntry.java new file mode 100644 index 0000000..7b79de0 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/IdEntry.java @@ -0,0 +1,37 @@ +/* + * @(#)IdEntry.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.contextualAnalyzer; + +import triangle.abstractSyntaxTrees.declarations.Declaration; + +public class IdEntry { + + protected String id; + protected Declaration attr; + protected int level; + protected IdEntry previous; + + IdEntry(String id, Declaration attr, int level, IdEntry previous) { + this.id = id; + this.attr = attr; + this.level = level; + this.previous = previous; + } + +} diff --git a/Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/IdentificationTable.java b/Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/IdentificationTable.java new file mode 100644 index 0000000..8807a01 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/IdentificationTable.java @@ -0,0 +1,91 @@ +/* + * @(#)IdentificationTable.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.contextualAnalyzer; + +import triangle.abstractSyntaxTrees.declarations.Declaration; + +public final class IdentificationTable { + + private int level; + private IdEntry latest; + + public IdentificationTable() { + level = 0; + latest = null; + } + + // Opens a new level in the identification table, 1 higher than the + // current topmost level. + + public void openScope() { + level++; + } + + // Closes the topmost level in the identification table, discarding + // all entries belonging to that level. + + public void closeScope() { + // Presumably, idTable.level > 0. + var entry = this.latest; + while (entry.level == this.level) { + entry = entry.previous; + } + + this.level--; + this.latest = entry; + } + + // Makes a new entry in the identification table for the given identifier + // and attribute. The new entry belongs to the current level. + // duplicated is set to to true iff there is already an entry for the + // same identifier at the current level. + + public void enter(String id, Declaration attr) { + attr.duplicated = retrieve(id, true) != null; + this.latest = new IdEntry(id, attr, this.level, this.latest); + } + + // Finds an entry for the given identifier in the identification table, + // if any. If there are several entries for that identifier, finds the + // entry at the highest level, in accordance with the scope rules. + // Returns null iff no entry is found. + // otherwise returns the attribute field of the entry found. + + public Declaration retrieve(String id) { + return retrieve(id, false); + } + + // thisLevelOnly limits the search to only the current level + + public Declaration retrieve(String id, boolean thisLevelOnly) { + var entry = this.latest; + while (true) { + if (entry == null || (thisLevelOnly && entry.level < this.level)) { + break; + } else if (entry.id.equals(id)) { + return entry.attr; + } else { + entry = entry.previous; + } + } + + return null; + } + +} diff --git a/Triangle.Compiler/src/main/java/triangle/optimiser/ConstantFolder.java b/Triangle.Compiler/src/main/java/triangle/optimiser/ConstantFolder.java new file mode 100644 index 0000000..1ba56ea --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/optimiser/ConstantFolder.java @@ -0,0 +1,599 @@ +package triangle.optimiser; + +import triangle.StdEnvironment; +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.Program; +import triangle.abstractSyntaxTrees.actuals.ConstActualParameter; +import triangle.abstractSyntaxTrees.actuals.EmptyActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.FuncActualParameter; +import triangle.abstractSyntaxTrees.actuals.MultipleActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.ProcActualParameter; +import triangle.abstractSyntaxTrees.actuals.SingleActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.VarActualParameter; +import triangle.abstractSyntaxTrees.aggregates.MultipleArrayAggregate; +import triangle.abstractSyntaxTrees.aggregates.MultipleRecordAggregate; +import triangle.abstractSyntaxTrees.aggregates.SingleArrayAggregate; +import triangle.abstractSyntaxTrees.aggregates.SingleRecordAggregate; +import triangle.abstractSyntaxTrees.commands.AssignCommand; +import triangle.abstractSyntaxTrees.commands.CallCommand; +import triangle.abstractSyntaxTrees.commands.EmptyCommand; +import triangle.abstractSyntaxTrees.commands.IfCommand; +import triangle.abstractSyntaxTrees.commands.LetCommand; +import triangle.abstractSyntaxTrees.commands.SequentialCommand; +import triangle.abstractSyntaxTrees.commands.WhileCommand; +import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration; +import triangle.abstractSyntaxTrees.declarations.ConstDeclaration; +import triangle.abstractSyntaxTrees.declarations.FuncDeclaration; +import triangle.abstractSyntaxTrees.declarations.ProcDeclaration; +import triangle.abstractSyntaxTrees.declarations.SequentialDeclaration; +import triangle.abstractSyntaxTrees.declarations.UnaryOperatorDeclaration; +import triangle.abstractSyntaxTrees.declarations.VarDeclaration; +import triangle.abstractSyntaxTrees.expressions.ArrayExpression; +import triangle.abstractSyntaxTrees.expressions.BinaryExpression; +import triangle.abstractSyntaxTrees.expressions.CallExpression; +import triangle.abstractSyntaxTrees.expressions.CharacterExpression; +import triangle.abstractSyntaxTrees.expressions.EmptyExpression; +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.expressions.IfExpression; +import triangle.abstractSyntaxTrees.expressions.IntegerExpression; +import triangle.abstractSyntaxTrees.expressions.LetExpression; +import triangle.abstractSyntaxTrees.expressions.RecordExpression; +import triangle.abstractSyntaxTrees.expressions.UnaryExpression; +import triangle.abstractSyntaxTrees.expressions.VnameExpression; +import triangle.abstractSyntaxTrees.formals.ConstFormalParameter; +import triangle.abstractSyntaxTrees.formals.EmptyFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.FuncFormalParameter; +import triangle.abstractSyntaxTrees.formals.MultipleFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.ProcFormalParameter; +import triangle.abstractSyntaxTrees.formals.SingleFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.VarFormalParameter; +import triangle.abstractSyntaxTrees.terminals.CharacterLiteral; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.terminals.IntegerLiteral; +import triangle.abstractSyntaxTrees.terminals.Operator; +import triangle.abstractSyntaxTrees.types.AnyTypeDenoter; +import triangle.abstractSyntaxTrees.types.ArrayTypeDenoter; +import triangle.abstractSyntaxTrees.types.BoolTypeDenoter; +import triangle.abstractSyntaxTrees.types.CharTypeDenoter; +import triangle.abstractSyntaxTrees.types.ErrorTypeDenoter; +import triangle.abstractSyntaxTrees.types.IntTypeDenoter; +import triangle.abstractSyntaxTrees.types.MultipleFieldTypeDenoter; +import triangle.abstractSyntaxTrees.types.RecordTypeDenoter; +import triangle.abstractSyntaxTrees.types.SimpleTypeDenoter; +import triangle.abstractSyntaxTrees.types.SingleFieldTypeDenoter; +import triangle.abstractSyntaxTrees.types.TypeDeclaration; +import triangle.abstractSyntaxTrees.visitors.ActualParameterSequenceVisitor; +import triangle.abstractSyntaxTrees.visitors.ActualParameterVisitor; +import triangle.abstractSyntaxTrees.visitors.ArrayAggregateVisitor; +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.abstractSyntaxTrees.visitors.FormalParameterSequenceVisitor; +import triangle.abstractSyntaxTrees.visitors.IdentifierVisitor; +import triangle.abstractSyntaxTrees.visitors.LiteralVisitor; +import triangle.abstractSyntaxTrees.visitors.OperatorVisitor; +import triangle.abstractSyntaxTrees.visitors.ProgramVisitor; +import triangle.abstractSyntaxTrees.visitors.RecordAggregateVisitor; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.abstractSyntaxTrees.visitors.VnameVisitor; +import triangle.abstractSyntaxTrees.vnames.DotVname; +import triangle.abstractSyntaxTrees.vnames.SimpleVname; +import triangle.abstractSyntaxTrees.vnames.SubscriptVname; + +public class ConstantFolder implements ActualParameterVisitor, + ActualParameterSequenceVisitor, ArrayAggregateVisitor, + CommandVisitor, DeclarationVisitor, + ExpressionVisitor, FormalParameterSequenceVisitor, + IdentifierVisitor, LiteralVisitor, + OperatorVisitor, ProgramVisitor, + RecordAggregateVisitor, TypeDenoterVisitor, + VnameVisitor { + { + + } + + @Override + public AbstractSyntaxTree visitConstFormalParameter(ConstFormalParameter ast, Void arg) { + ast.I.visit(this); + ast.T.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitFuncFormalParameter(FuncFormalParameter ast, Void arg) { + ast.I.visit(this); + ast.T.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitProcFormalParameter(ProcFormalParameter ast, Void arg) { + ast.I.visit(this); + ast.FPS.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitVarFormalParameter(VarFormalParameter ast, Void arg) { + ast.I.visit(this); + ast.T.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitMultipleFieldTypeDenoter(MultipleFieldTypeDenoter ast, Void arg) { + ast.FT.visit(this); + ast.I.visit(this); + ast.T.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitSingleFieldTypeDenoter(SingleFieldTypeDenoter ast, Void arg) { + ast.I.visit(this); + ast.T.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitDotVname(DotVname ast, Void arg) { + ast.I.visit(this); + ast.V.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitSimpleVname(SimpleVname ast, Void arg) { + ast.I.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitSubscriptVname(SubscriptVname ast, Void arg) { + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + ast.V.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitAnyTypeDenoter(AnyTypeDenoter ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitArrayTypeDenoter(ArrayTypeDenoter ast, Void arg) { + ast.IL.visit(this); + ast.T.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitBoolTypeDenoter(BoolTypeDenoter ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitCharTypeDenoter(CharTypeDenoter ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitErrorTypeDenoter(ErrorTypeDenoter ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitSimpleTypeDenoter(SimpleTypeDenoter ast, Void arg) { + ast.I.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitIntTypeDenoter(IntTypeDenoter ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitRecordTypeDenoter(RecordTypeDenoter ast, Void arg) { + ast.FT.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitMultipleRecordAggregate(MultipleRecordAggregate ast, Void arg) { + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + ast.I.visit(this); + ast.RA.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitSingleRecordAggregate(SingleRecordAggregate ast, Void arg) { + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + ast.I.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitProgram(Program ast, Void arg) { + ast.C.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitOperator(Operator ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitCharacterLiteral(CharacterLiteral ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitIntegerLiteral(IntegerLiteral ast, Void arg) { + return ast; + } + + @Override + public AbstractSyntaxTree visitIdentifier(Identifier ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitEmptyFormalParameterSequence(EmptyFormalParameterSequence ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitMultipleFormalParameterSequence(MultipleFormalParameterSequence ast, Void arg) { + ast.FP.visit(this); + ast.FPS.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitSingleFormalParameterSequence(SingleFormalParameterSequence ast, Void arg) { + ast.FP.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitArrayExpression(ArrayExpression ast, Void arg) { + ast.AA.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitBinaryExpression(BinaryExpression ast, Void arg) { + AbstractSyntaxTree replacement1 = ast.E1.visit(this); + AbstractSyntaxTree replacement2 = ast.E2.visit(this); + ast.O.visit(this); + + // if visiting a child node returns something, it's either the original constant + // (IntegerLiteral) or a folded version replacing the expression at that child + // node + // If both child nodes are not null; return a folded version of this + // BinaryExpression + // Otherwise, at least one child node isn't constant (foldable) so just replace + // the + // foldable child nodes with their folded equivalent and return null + if (replacement1 != null && replacement2 != null) { + return foldBinaryExpression(replacement1, replacement2, ast.O); + } else if (replacement1 != null) { + ast.E1 = (Expression) replacement1; + } else if (replacement2 != null) { + ast.E2 = (Expression) replacement2; + } + + // if we get here, we can't fold any higher than this level + return null; + } + + @Override + public AbstractSyntaxTree visitCallExpression(CallExpression ast, Void arg) { + ast.APS.visit(this); + ast.I.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitCharacterExpression(CharacterExpression ast, Void arg) { + ast.CL.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitEmptyExpression(EmptyExpression ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitIfExpression(IfExpression ast, Void arg) { + AbstractSyntaxTree replacement1 = ast.E1.visit(this); + if (replacement1 != null) { + ast.E1 = (Expression) replacement1; + } + AbstractSyntaxTree replacement2 = ast.E2.visit(this); + if (replacement2 != null) { + ast.E2 = (Expression) replacement2; + } + AbstractSyntaxTree replacement3 = ast.E3.visit(this); + if (replacement3 != null) { + ast.E3 = (Expression) replacement3; + } + + return null; + } + + @Override + public AbstractSyntaxTree visitIntegerExpression(IntegerExpression ast, Void arg) { + return ast; + } + + @Override + public AbstractSyntaxTree visitLetExpression(LetExpression ast, Void arg) { + ast.D.visit(this); + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + return null; + } + + @Override + public AbstractSyntaxTree visitRecordExpression(RecordExpression ast, Void arg) { + ast.RA.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitUnaryExpression(UnaryExpression ast, Void arg) { + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + + ast.O.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitVnameExpression(VnameExpression ast, Void arg) { + ast.V.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitBinaryOperatorDeclaration(BinaryOperatorDeclaration ast, Void arg) { + ast.ARG1.visit(this); + ast.ARG2.visit(this); + ast.O.visit(this); + ast.RES.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitConstDeclaration(ConstDeclaration ast, Void arg) { + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + ast.I.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitFuncDeclaration(FuncDeclaration ast, Void arg) { + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + ast.FPS.visit(this); + ast.I.visit(this); + ast.T.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitProcDeclaration(ProcDeclaration ast, Void arg) { + ast.C.visit(this); + ast.FPS.visit(this); + ast.I.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitSequentialDeclaration(SequentialDeclaration ast, Void arg) { + ast.D1.visit(this); + ast.D2.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitTypeDeclaration(TypeDeclaration ast, Void arg) { + ast.I.visit(this); + ast.T.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitUnaryOperatorDeclaration(UnaryOperatorDeclaration ast, Void arg) { + ast.ARG.visit(this); + ast.O.visit(this); + ast.RES.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitVarDeclaration(VarDeclaration ast, Void arg) { + ast.I.visit(this); + ast.T.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitAssignCommand(AssignCommand ast, Void arg) { + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + ast.V.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitCallCommand(CallCommand ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitEmptyCommand(EmptyCommand ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitIfCommand(IfCommand ast, Void arg) { + ast.C1.visit(this); + ast.C2.visit(this); + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + return null; + } + + @Override + public AbstractSyntaxTree visitLetCommand(LetCommand ast, Void arg) { + ast.C.visit(this); + ast.D.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitSequentialCommand(SequentialCommand ast, Void arg) { + ast.C1.visit(this); + ast.C2.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitWhileCommand(WhileCommand ast, Void arg) { + ast.C.visit(this); + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + return null; + } + + // TODO uncomment if you've implemented the repeat command +// @Override +// public AbstractSyntaxTree visitRepeatCommand(RepeatCommand ast, Void arg) { +// ast.C.visit(this); +// AbstractSyntaxTree replacement = ast.E.visit(this); +// if (replacement != null) { +// ast.E = (Expression) replacement; +// } +// return null; +// } + + @Override + public AbstractSyntaxTree visitMultipleArrayAggregate(MultipleArrayAggregate ast, Void arg) { + ast.AA.visit(this); + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + return null; + } + + @Override + public AbstractSyntaxTree visitSingleArrayAggregate(SingleArrayAggregate ast, Void arg) { + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + return null; + } + + @Override + public AbstractSyntaxTree visitEmptyActualParameterSequence(EmptyActualParameterSequence ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitMultipleActualParameterSequence(MultipleActualParameterSequence ast, Void arg) { + ast.AP.visit(this); + ast.APS.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitSingleActualParameterSequence(SingleActualParameterSequence ast, Void arg) { + ast.AP.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitConstActualParameter(ConstActualParameter ast, Void arg) { + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + return null; + } + + @Override + public AbstractSyntaxTree visitFuncActualParameter(FuncActualParameter ast, Void arg) { + ast.I.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitProcActualParameter(ProcActualParameter ast, Void arg) { + ast.I.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitVarActualParameter(VarActualParameter ast, Void arg) { + ast.V.visit(this); + return null; + } + + public AbstractSyntaxTree foldBinaryExpression(AbstractSyntaxTree node1, AbstractSyntaxTree node2, Operator o) { + // the only case we know how to deal with for now is two IntegerExpressions + if ((node1 instanceof IntegerExpression) && (node2 instanceof IntegerExpression)) { + int int1 = (Integer.parseInt(((IntegerExpression) node1).IL.spelling)); + int int2 = (Integer.parseInt(((IntegerExpression) node2).IL.spelling)); + Object foldedValue = null; + + if (o.decl == StdEnvironment.addDecl) { + foldedValue = int1 + int2; + } + + if (foldedValue instanceof Integer) { + IntegerLiteral il = new IntegerLiteral(foldedValue.toString(), node1.getPosition()); + IntegerExpression ie = new IntegerExpression(il, node1.getPosition()); + ie.type = StdEnvironment.integerType; + return ie; + } else if (foldedValue instanceof Boolean) { + /* currently not handled! */ + } + } + + // any unhandled situation (i.e., not foldable) is ignored + return null; + } + +} diff --git a/Triangle.Compiler/src/main/java/triangle/optimiser/SummaryStats.java b/Triangle.Compiler/src/main/java/triangle/optimiser/SummaryStats.java new file mode 100644 index 0000000..973b5b5 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/optimiser/SummaryStats.java @@ -0,0 +1,614 @@ +package triangle.optimiser; + +import triangle.StdEnvironment; +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.Program; +import triangle.abstractSyntaxTrees.actuals.ConstActualParameter; +import triangle.abstractSyntaxTrees.actuals.EmptyActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.FuncActualParameter; +import triangle.abstractSyntaxTrees.actuals.MultipleActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.ProcActualParameter; +import triangle.abstractSyntaxTrees.actuals.SingleActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.VarActualParameter; +import triangle.abstractSyntaxTrees.aggregates.MultipleArrayAggregate; +import triangle.abstractSyntaxTrees.aggregates.MultipleRecordAggregate; +import triangle.abstractSyntaxTrees.aggregates.SingleArrayAggregate; +import triangle.abstractSyntaxTrees.aggregates.SingleRecordAggregate; +import triangle.abstractSyntaxTrees.commands.AssignCommand; +import triangle.abstractSyntaxTrees.commands.CallCommand; +import triangle.abstractSyntaxTrees.commands.EmptyCommand; +import triangle.abstractSyntaxTrees.commands.IfCommand; +import triangle.abstractSyntaxTrees.commands.LetCommand; +import triangle.abstractSyntaxTrees.commands.SequentialCommand; +import triangle.abstractSyntaxTrees.commands.WhileCommand; +import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration; +import triangle.abstractSyntaxTrees.declarations.ConstDeclaration; +import triangle.abstractSyntaxTrees.declarations.FuncDeclaration; +import triangle.abstractSyntaxTrees.declarations.ProcDeclaration; +import triangle.abstractSyntaxTrees.declarations.SequentialDeclaration; +import triangle.abstractSyntaxTrees.declarations.UnaryOperatorDeclaration; +import triangle.abstractSyntaxTrees.declarations.VarDeclaration; +import triangle.abstractSyntaxTrees.expressions.ArrayExpression; +import triangle.abstractSyntaxTrees.expressions.BinaryExpression; +import triangle.abstractSyntaxTrees.expressions.CallExpression; +import triangle.abstractSyntaxTrees.expressions.CharacterExpression; +import triangle.abstractSyntaxTrees.expressions.EmptyExpression; +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.expressions.IfExpression; +import triangle.abstractSyntaxTrees.expressions.IntegerExpression; +import triangle.abstractSyntaxTrees.expressions.LetExpression; +import triangle.abstractSyntaxTrees.expressions.RecordExpression; +import triangle.abstractSyntaxTrees.expressions.UnaryExpression; +import triangle.abstractSyntaxTrees.expressions.VnameExpression; +import triangle.abstractSyntaxTrees.formals.ConstFormalParameter; +import triangle.abstractSyntaxTrees.formals.EmptyFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.FuncFormalParameter; +import triangle.abstractSyntaxTrees.formals.MultipleFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.ProcFormalParameter; +import triangle.abstractSyntaxTrees.formals.SingleFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.VarFormalParameter; +import triangle.abstractSyntaxTrees.terminals.CharacterLiteral; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.terminals.IntegerLiteral; +import triangle.abstractSyntaxTrees.terminals.Operator; +import triangle.abstractSyntaxTrees.types.AnyTypeDenoter; +import triangle.abstractSyntaxTrees.types.ArrayTypeDenoter; +import triangle.abstractSyntaxTrees.types.BoolTypeDenoter; +import triangle.abstractSyntaxTrees.types.CharTypeDenoter; +import triangle.abstractSyntaxTrees.types.ErrorTypeDenoter; +import triangle.abstractSyntaxTrees.types.IntTypeDenoter; +import triangle.abstractSyntaxTrees.types.MultipleFieldTypeDenoter; +import triangle.abstractSyntaxTrees.types.RecordTypeDenoter; +import triangle.abstractSyntaxTrees.types.SimpleTypeDenoter; +import triangle.abstractSyntaxTrees.types.SingleFieldTypeDenoter; +import triangle.abstractSyntaxTrees.types.TypeDeclaration; +import triangle.abstractSyntaxTrees.visitors.ActualParameterSequenceVisitor; +import triangle.abstractSyntaxTrees.visitors.ActualParameterVisitor; +import triangle.abstractSyntaxTrees.visitors.ArrayAggregateVisitor; +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.abstractSyntaxTrees.visitors.FormalParameterSequenceVisitor; +import triangle.abstractSyntaxTrees.visitors.IdentifierVisitor; +import triangle.abstractSyntaxTrees.visitors.LiteralVisitor; +import triangle.abstractSyntaxTrees.visitors.OperatorVisitor; +import triangle.abstractSyntaxTrees.visitors.ProgramVisitor; +import triangle.abstractSyntaxTrees.visitors.RecordAggregateVisitor; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.abstractSyntaxTrees.visitors.VnameVisitor; +import triangle.abstractSyntaxTrees.vnames.DotVname; +import triangle.abstractSyntaxTrees.vnames.SimpleVname; +import triangle.abstractSyntaxTrees.vnames.SubscriptVname; + +public class SummaryStats implements ActualParameterVisitor, + ActualParameterSequenceVisitor, ArrayAggregateVisitor, + CommandVisitor, DeclarationVisitor, + ExpressionVisitor, FormalParameterSequenceVisitor, + IdentifierVisitor, LiteralVisitor, + OperatorVisitor, ProgramVisitor, + RecordAggregateVisitor, TypeDenoterVisitor, + VnameVisitor { + { + + } + + //Task 5 + public int countCharExpr; + public int countIntExpr; + + public int getCharExprCount() { + return countCharExpr; + } + + public int getIntExprCount() { + return countIntExpr; + } + + + @Override + public AbstractSyntaxTree visitConstFormalParameter(ConstFormalParameter ast, Void arg) { + ast.I.visit(this); + ast.T.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitFuncFormalParameter(FuncFormalParameter ast, Void arg) { + ast.I.visit(this); + ast.T.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitProcFormalParameter(ProcFormalParameter ast, Void arg) { + ast.I.visit(this); + ast.FPS.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitVarFormalParameter(VarFormalParameter ast, Void arg) { + ast.I.visit(this); + ast.T.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitMultipleFieldTypeDenoter(MultipleFieldTypeDenoter ast, Void arg) { + ast.FT.visit(this); + ast.I.visit(this); + ast.T.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitSingleFieldTypeDenoter(SingleFieldTypeDenoter ast, Void arg) { + ast.I.visit(this); + ast.T.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitDotVname(DotVname ast, Void arg) { + ast.I.visit(this); + ast.V.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitSimpleVname(SimpleVname ast, Void arg) { + ast.I.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitSubscriptVname(SubscriptVname ast, Void arg) { + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + ast.V.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitAnyTypeDenoter(AnyTypeDenoter ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitArrayTypeDenoter(ArrayTypeDenoter ast, Void arg) { + ast.IL.visit(this); + ast.T.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitBoolTypeDenoter(BoolTypeDenoter ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitCharTypeDenoter(CharTypeDenoter ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitErrorTypeDenoter(ErrorTypeDenoter ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitSimpleTypeDenoter(SimpleTypeDenoter ast, Void arg) { + ast.I.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitIntTypeDenoter(IntTypeDenoter ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitRecordTypeDenoter(RecordTypeDenoter ast, Void arg) { + ast.FT.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitMultipleRecordAggregate(MultipleRecordAggregate ast, Void arg) { + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + ast.I.visit(this); + ast.RA.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitSingleRecordAggregate(SingleRecordAggregate ast, Void arg) { + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + ast.I.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitProgram(Program ast, Void arg) { + ast.C.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitOperator(Operator ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitCharacterLiteral(CharacterLiteral ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitIntegerLiteral(IntegerLiteral ast, Void arg) { + return ast; + } + + @Override + public AbstractSyntaxTree visitIdentifier(Identifier ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitEmptyFormalParameterSequence(EmptyFormalParameterSequence ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitMultipleFormalParameterSequence(MultipleFormalParameterSequence ast, Void arg) { + ast.FP.visit(this); + ast.FPS.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitSingleFormalParameterSequence(SingleFormalParameterSequence ast, Void arg) { + ast.FP.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitArrayExpression(ArrayExpression ast, Void arg) { + ast.AA.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitBinaryExpression(BinaryExpression ast, Void arg) { + AbstractSyntaxTree replacement1 = ast.E1.visit(this); + AbstractSyntaxTree replacement2 = ast.E2.visit(this); + ast.O.visit(this); + + // if visiting a child node returns something, it's either the original constant + // (IntegerLiteral) or a folded version replacing the expression at that child + // node + // If both child nodes are not null; return a folded version of this + // BinaryExpression + // Otherwise, at least one child node isn't constant (foldable) so just replace + // the + // foldable child nodes with their folded equivalent and return null + if (replacement1 != null && replacement2 != null) { + return foldBinaryExpression(replacement1, replacement2, ast.O); + } else if (replacement1 != null) { + ast.E1 = (Expression) replacement1; + } else if (replacement2 != null) { + ast.E2 = (Expression) replacement2; + } + + // if we get here, we can't fold any higher than this level + return null; + } + + @Override + public AbstractSyntaxTree visitCallExpression(CallExpression ast, Void arg) { + ast.APS.visit(this); + ast.I.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitCharacterExpression(CharacterExpression ast, Void arg) { + countCharExpr++; //Increment the count for stats + ast.CL.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitEmptyExpression(EmptyExpression ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitIfExpression(IfExpression ast, Void arg) { + AbstractSyntaxTree replacement1 = ast.E1.visit(this); + if (replacement1 != null) { + ast.E1 = (Expression) replacement1; + } + AbstractSyntaxTree replacement2 = ast.E2.visit(this); + if (replacement2 != null) { + ast.E2 = (Expression) replacement2; + } + AbstractSyntaxTree replacement3 = ast.E3.visit(this); + if (replacement3 != null) { + ast.E3 = (Expression) replacement3; + } + + return null; + } + + @Override + public AbstractSyntaxTree visitIntegerExpression(IntegerExpression ast, Void arg) { + countIntExpr++; //Increment the count for stats + return ast; + } + + @Override + public AbstractSyntaxTree visitLetExpression(LetExpression ast, Void arg) { + ast.D.visit(this); + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + return null; + } + + @Override + public AbstractSyntaxTree visitRecordExpression(RecordExpression ast, Void arg) { + ast.RA.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitUnaryExpression(UnaryExpression ast, Void arg) { + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + + ast.O.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitVnameExpression(VnameExpression ast, Void arg) { + ast.V.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitBinaryOperatorDeclaration(BinaryOperatorDeclaration ast, Void arg) { + ast.ARG1.visit(this); + ast.ARG2.visit(this); + ast.O.visit(this); + ast.RES.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitConstDeclaration(ConstDeclaration ast, Void arg) { + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + ast.I.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitFuncDeclaration(FuncDeclaration ast, Void arg) { + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + ast.FPS.visit(this); + ast.I.visit(this); + ast.T.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitProcDeclaration(ProcDeclaration ast, Void arg) { + ast.C.visit(this); + ast.FPS.visit(this); + ast.I.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitSequentialDeclaration(SequentialDeclaration ast, Void arg) { + ast.D1.visit(this); + ast.D2.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitTypeDeclaration(TypeDeclaration ast, Void arg) { + ast.I.visit(this); + ast.T.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitUnaryOperatorDeclaration(UnaryOperatorDeclaration ast, Void arg) { + ast.ARG.visit(this); + ast.O.visit(this); + ast.RES.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitVarDeclaration(VarDeclaration ast, Void arg) { + ast.I.visit(this); + ast.T.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitAssignCommand(AssignCommand ast, Void arg) { + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + ast.V.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitCallCommand(CallCommand ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitEmptyCommand(EmptyCommand ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitIfCommand(IfCommand ast, Void arg) { + ast.C1.visit(this); + ast.C2.visit(this); + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + return null; + } + + @Override + public AbstractSyntaxTree visitLetCommand(LetCommand ast, Void arg) { + ast.C.visit(this); + ast.D.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitSequentialCommand(SequentialCommand ast, Void arg) { + ast.C1.visit(this); + ast.C2.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitWhileCommand(WhileCommand ast, Void arg) { + ast.C.visit(this); + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + return null; + } + + // TODO uncomment if you've implemented the repeat command +// @Override +// public AbstractSyntaxTree visitRepeatCommand(RepeatCommand ast, Void arg) { +// ast.C.visit(this); +// AbstractSyntaxTree replacement = ast.E.visit(this); +// if (replacement != null) { +// ast.E = (Expression) replacement; +// } +// return null; +// } + + @Override + public AbstractSyntaxTree visitMultipleArrayAggregate(MultipleArrayAggregate ast, Void arg) { + ast.AA.visit(this); + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + return null; + } + + @Override + public AbstractSyntaxTree visitSingleArrayAggregate(SingleArrayAggregate ast, Void arg) { + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + return null; + } + + @Override + public AbstractSyntaxTree visitEmptyActualParameterSequence(EmptyActualParameterSequence ast, Void arg) { + return null; + } + + @Override + public AbstractSyntaxTree visitMultipleActualParameterSequence(MultipleActualParameterSequence ast, Void arg) { + ast.AP.visit(this); + ast.APS.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitSingleActualParameterSequence(SingleActualParameterSequence ast, Void arg) { + ast.AP.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitConstActualParameter(ConstActualParameter ast, Void arg) { + AbstractSyntaxTree replacement = ast.E.visit(this); + if (replacement != null) { + ast.E = (Expression) replacement; + } + return null; + } + + @Override + public AbstractSyntaxTree visitFuncActualParameter(FuncActualParameter ast, Void arg) { + ast.I.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitProcActualParameter(ProcActualParameter ast, Void arg) { + ast.I.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitVarActualParameter(VarActualParameter ast, Void arg) { + ast.V.visit(this); + return null; + } + + public AbstractSyntaxTree foldBinaryExpression(AbstractSyntaxTree node1, AbstractSyntaxTree node2, Operator o) { + // the only case we know how to deal with for now is two IntegerExpressions + if ((node1 instanceof IntegerExpression) && (node2 instanceof IntegerExpression)) { + int int1 = (Integer.parseInt(((IntegerExpression) node1).IL.spelling)); + int int2 = (Integer.parseInt(((IntegerExpression) node2).IL.spelling)); + Object foldedValue = null; + + if (o.decl == StdEnvironment.addDecl) { + foldedValue = int1 + int2; + } + + if (foldedValue instanceof Integer) { + IntegerLiteral il = new IntegerLiteral(foldedValue.toString(), node1.getPosition()); + IntegerExpression ie = new IntegerExpression(il, node1.getPosition()); + ie.type = StdEnvironment.integerType; + return ie; + } else if (foldedValue instanceof Boolean) { + /* currently not handled! */ + } + } + + // any unhandled situation (i.e., not foldable) is ignored + return null; + } + +} diff --git a/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Parser.java b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Parser.java new file mode 100644 index 0000000..e00e268 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Parser.java @@ -0,0 +1,948 @@ +/* + * @(#)Parser.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.syntacticAnalyzer; + +import triangle.ErrorReporter; +import triangle.abstractSyntaxTrees.Program; +import triangle.abstractSyntaxTrees.actuals.ActualParameter; +import triangle.abstractSyntaxTrees.actuals.ActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.ConstActualParameter; +import triangle.abstractSyntaxTrees.actuals.EmptyActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.FuncActualParameter; +import triangle.abstractSyntaxTrees.actuals.MultipleActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.ProcActualParameter; +import triangle.abstractSyntaxTrees.actuals.SingleActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.VarActualParameter; +import triangle.abstractSyntaxTrees.aggregates.ArrayAggregate; +import triangle.abstractSyntaxTrees.aggregates.MultipleArrayAggregate; +import triangle.abstractSyntaxTrees.aggregates.MultipleRecordAggregate; +import triangle.abstractSyntaxTrees.aggregates.RecordAggregate; +import triangle.abstractSyntaxTrees.aggregates.SingleArrayAggregate; +import triangle.abstractSyntaxTrees.aggregates.SingleRecordAggregate; +import triangle.abstractSyntaxTrees.commands.AssignCommand; +import triangle.abstractSyntaxTrees.commands.CallCommand; +import triangle.abstractSyntaxTrees.commands.Command; +import triangle.abstractSyntaxTrees.commands.EmptyCommand; +import triangle.abstractSyntaxTrees.commands.IfCommand; +import triangle.abstractSyntaxTrees.commands.LetCommand; +import triangle.abstractSyntaxTrees.commands.SequentialCommand; +import triangle.abstractSyntaxTrees.commands.WhileCommand; +import triangle.abstractSyntaxTrees.declarations.ConstDeclaration; +import triangle.abstractSyntaxTrees.declarations.Declaration; +import triangle.abstractSyntaxTrees.declarations.FuncDeclaration; +import triangle.abstractSyntaxTrees.declarations.ProcDeclaration; +import triangle.abstractSyntaxTrees.declarations.SequentialDeclaration; +import triangle.abstractSyntaxTrees.declarations.VarDeclaration; +import triangle.abstractSyntaxTrees.expressions.ArrayExpression; +import triangle.abstractSyntaxTrees.expressions.BinaryExpression; +import triangle.abstractSyntaxTrees.expressions.CallExpression; +import triangle.abstractSyntaxTrees.expressions.CharacterExpression; +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.expressions.IfExpression; +import triangle.abstractSyntaxTrees.expressions.IntegerExpression; +import triangle.abstractSyntaxTrees.expressions.LetExpression; +import triangle.abstractSyntaxTrees.expressions.RecordExpression; +import triangle.abstractSyntaxTrees.expressions.UnaryExpression; +import triangle.abstractSyntaxTrees.expressions.VnameExpression; +import triangle.abstractSyntaxTrees.formals.ConstFormalParameter; +import triangle.abstractSyntaxTrees.formals.EmptyFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.FormalParameter; +import triangle.abstractSyntaxTrees.formals.FormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.FuncFormalParameter; +import triangle.abstractSyntaxTrees.formals.MultipleFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.ProcFormalParameter; +import triangle.abstractSyntaxTrees.formals.SingleFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.VarFormalParameter; +import triangle.abstractSyntaxTrees.terminals.CharacterLiteral; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.terminals.IntegerLiteral; +import triangle.abstractSyntaxTrees.terminals.Operator; +import triangle.abstractSyntaxTrees.types.ArrayTypeDenoter; +import triangle.abstractSyntaxTrees.types.FieldTypeDenoter; +import triangle.abstractSyntaxTrees.types.MultipleFieldTypeDenoter; +import triangle.abstractSyntaxTrees.types.RecordTypeDenoter; +import triangle.abstractSyntaxTrees.types.SimpleTypeDenoter; +import triangle.abstractSyntaxTrees.types.SingleFieldTypeDenoter; +import triangle.abstractSyntaxTrees.types.TypeDeclaration; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.vnames.DotVname; +import triangle.abstractSyntaxTrees.vnames.SimpleVname; +import triangle.abstractSyntaxTrees.vnames.SubscriptVname; +import triangle.abstractSyntaxTrees.vnames.Vname; + +public class Parser { + + private Scanner lexicalAnalyser; + private ErrorReporter errorReporter; + private Token currentToken; + private SourcePosition previousTokenPosition; + + public Parser(Scanner lexer, ErrorReporter reporter) { + lexicalAnalyser = lexer; + errorReporter = reporter; + previousTokenPosition = new SourcePosition(); + } + + // accept checks whether the current token matches tokenExpected. + // If so, fetches the next token. + // If not, reports a syntactic error. + + void accept(int tokenExpected) throws SyntaxError { + if (currentToken.kind == tokenExpected) { + previousTokenPosition = currentToken.position; + currentToken = lexicalAnalyser.scan(); + } else { + syntacticError("\"%\" expected here", Token.spell(tokenExpected)); + } + } + + void acceptIt() { + previousTokenPosition = currentToken.position; + currentToken = lexicalAnalyser.scan(); + } + + // start records the position of the start of a phrase. + // This is defined to be the position of the first + // character of the first token of the phrase. + + void start(SourcePosition position) { + position.start = currentToken.position.start; + } + + // finish records the position of the end of a phrase. + // This is defined to be the position of the last + // character of the last token of the phrase. + + void finish(SourcePosition position) { + position.finish = previousTokenPosition.finish; + } + + void syntacticError(String messageTemplate, String tokenQuoted) throws SyntaxError { + SourcePosition pos = currentToken.position; + errorReporter.reportError(messageTemplate, tokenQuoted, pos); + throw (new SyntaxError()); + } + + /////////////////////////////////////////////////////////////////////////////// + // + // PROGRAMS + // + /////////////////////////////////////////////////////////////////////////////// + + public Program parseProgram() { + + Program programAST = null; + + previousTokenPosition.start = 0; + previousTokenPosition.finish = 0; + currentToken = lexicalAnalyser.scan(); + + try { + Command cAST = parseCommand(); + programAST = new Program(cAST, previousTokenPosition); + if (currentToken.kind != Token.EOT) { + syntacticError("\"%\" not expected after end of program", currentToken.spelling); + } + } catch (SyntaxError s) { + return null; + } + return programAST; + } + + /////////////////////////////////////////////////////////////////////////////// + // + // LITERALS + // + /////////////////////////////////////////////////////////////////////////////// + + // parseIntegerLiteral parses an integer-literal, and constructs + // a leaf AST to represent it. + + IntegerLiteral parseIntegerLiteral() throws SyntaxError { + IntegerLiteral IL = null; + + if (currentToken.kind == Token.INTLITERAL) { + previousTokenPosition = currentToken.position; + String spelling = currentToken.spelling; + IL = new IntegerLiteral(spelling, previousTokenPosition); + currentToken = lexicalAnalyser.scan(); + } else { + IL = null; + syntacticError("integer literal expected here", ""); + } + return IL; + } + + // parseCharacterLiteral parses a character-literal, and constructs a leaf + // AST to represent it. + + CharacterLiteral parseCharacterLiteral() throws SyntaxError { + CharacterLiteral CL = null; + + if (currentToken.kind == Token.CHARLITERAL) { + previousTokenPosition = currentToken.position; + String spelling = currentToken.spelling; + CL = new CharacterLiteral(spelling, previousTokenPosition); + currentToken = lexicalAnalyser.scan(); + } else { + CL = null; + syntacticError("character literal expected here", ""); + } + return CL; + } + + // parseIdentifier parses an identifier, and constructs a leaf AST to + // represent it. + + Identifier parseIdentifier() throws SyntaxError { + Identifier I = null; + + if (currentToken.kind == Token.IDENTIFIER) { + previousTokenPosition = currentToken.position; + String spelling = currentToken.spelling; + I = new Identifier(spelling, previousTokenPosition); + currentToken = lexicalAnalyser.scan(); + } else { + I = null; + syntacticError("identifier expected here", ""); + } + return I; + } + + // parseOperator parses an operator, and constructs a leaf AST to + // represent it. + + Operator parseOperator() throws SyntaxError { + Operator O = null; + + if (currentToken.kind == Token.OPERATOR) { + previousTokenPosition = currentToken.position; + String spelling = currentToken.spelling; + O = new Operator(spelling, previousTokenPosition); + currentToken = lexicalAnalyser.scan(); + } else { + O = null; + syntacticError("operator expected here", ""); + } + return O; + } + + /////////////////////////////////////////////////////////////////////////////// + // + // COMMANDS + // + /////////////////////////////////////////////////////////////////////////////// + + // parseCommand parses the command, and constructs an AST + // to represent its phrase structure. + + Command parseCommand() throws SyntaxError { + Command commandAST = null; // in case there's a syntactic error + + SourcePosition commandPos = new SourcePosition(); + + start(commandPos); + commandAST = parseSingleCommand(); + while (currentToken.kind == Token.SEMICOLON) { + acceptIt(); + Command c2AST = parseSingleCommand(); + finish(commandPos); + commandAST = new SequentialCommand(commandAST, c2AST, commandPos); + } + return commandAST; + } + + Command parseSingleCommand() throws SyntaxError { + Command commandAST = null; // in case there's a syntactic error + + SourcePosition commandPos = new SourcePosition(); + start(commandPos); + + switch (currentToken.kind) { + + case Token.IDENTIFIER: { + Identifier iAST = parseIdentifier(); + if (currentToken.kind == Token.LPAREN) { + acceptIt(); + ActualParameterSequence apsAST = parseActualParameterSequence(); + accept(Token.RPAREN); + finish(commandPos); + commandAST = new CallCommand(iAST, apsAST, commandPos); + + } else { + Vname vAST = parseRestOfVname(iAST); + //Task 3 a** + if (currentToken.kind == Token.OPERATOR && currentToken.spelling.equals("**")) { + acceptIt(); + + IntegerLiteral intLit = new IntegerLiteral("2", commandPos); + IntegerExpression intExp = new IntegerExpression(intLit, commandPos); + + VnameExpression vNameExp = new VnameExpression(vAST, commandPos); + Operator oper = new Operator("*", commandPos); + + Expression eAST = new BinaryExpression(vNameExp, oper, intExp, commandPos ); + + finish(commandPos); + + commandAST = new AssignCommand(vAST, eAST, commandPos); + } else { + accept(Token.BECOMES); + Expression eAST = parseExpression(); + finish(commandPos); + commandAST = new AssignCommand(vAST, eAST, commandPos); + } + } + } + break; + + case Token.BEGIN: + acceptIt(); + commandAST = parseCommand(); + accept(Token.END); + break; + + case Token.LET: { + acceptIt(); + Declaration dAST = parseDeclaration(); + accept(Token.IN); + Command cAST = parseSingleCommand(); + finish(commandPos); + commandAST = new LetCommand(dAST, cAST, commandPos); + } + break; + + case Token.IF: { + acceptIt(); + Expression eAST = parseExpression(); + accept(Token.THEN); + Command c1AST = parseSingleCommand(); + accept(Token.ELSE); + Command c2AST = parseSingleCommand(); + finish(commandPos); + commandAST = new IfCommand(eAST, c1AST, c2AST, commandPos); + } + break; + + case Token.WHILE: { + acceptIt(); + Expression eAST = parseExpression(); + accept(Token.DO); + Command cAST = parseSingleCommand(); + finish(commandPos); + commandAST = new WhileCommand(eAST, cAST, commandPos); + } + break; + + //Task 4 + case Token.LCURLY: + acceptIt(); + commandAST = parseCommand(); + accept(Token.RCURLY); + break; + + case Token.SEMICOLON: + case Token.END: + case Token.ELSE: + case Token.IN: + case Token.EOT: + case Token.RCURLY: + + finish(commandPos); + commandAST = new EmptyCommand(commandPos); + break; + + default: + syntacticError("\"%\" cannot start a command", currentToken.spelling); + break; + + } + + return commandAST; + } + + /////////////////////////////////////////////////////////////////////////////// + // + // EXPRESSIONS + // + /////////////////////////////////////////////////////////////////////////////// + + Expression parseExpression() throws SyntaxError { + Expression expressionAST = null; // in case there's a syntactic error + + SourcePosition expressionPos = new SourcePosition(); + + start(expressionPos); + + switch (currentToken.kind) { + + case Token.LET: { + acceptIt(); + Declaration dAST = parseDeclaration(); + accept(Token.IN); + Expression eAST = parseExpression(); + finish(expressionPos); + expressionAST = new LetExpression(dAST, eAST, expressionPos); + } + break; + + case Token.IF: { + acceptIt(); + Expression e1AST = parseExpression(); + accept(Token.THEN); + Expression e2AST = parseExpression(); + accept(Token.ELSE); + Expression e3AST = parseExpression(); + finish(expressionPos); + expressionAST = new IfExpression(e1AST, e2AST, e3AST, expressionPos); + } + break; + + default: + expressionAST = parseSecondaryExpression(); + break; + } + return expressionAST; + } + + Expression parseSecondaryExpression() throws SyntaxError { + Expression expressionAST = null; // in case there's a syntactic error + + SourcePosition expressionPos = new SourcePosition(); + start(expressionPos); + + expressionAST = parsePrimaryExpression(); + while (currentToken.kind == Token.OPERATOR) { + Operator opAST = parseOperator(); + Expression e2AST = parsePrimaryExpression(); + expressionAST = new BinaryExpression(expressionAST, opAST, e2AST, expressionPos); + } + return expressionAST; + } + + Expression parsePrimaryExpression() throws SyntaxError { + Expression expressionAST = null; // in case there's a syntactic error + + SourcePosition expressionPos = new SourcePosition(); + start(expressionPos); + + switch (currentToken.kind) { + + case Token.INTLITERAL: { + IntegerLiteral ilAST = parseIntegerLiteral(); + finish(expressionPos); + expressionAST = new IntegerExpression(ilAST, expressionPos); + } + break; + + case Token.CHARLITERAL: { + CharacterLiteral clAST = parseCharacterLiteral(); + finish(expressionPos); + expressionAST = new CharacterExpression(clAST, expressionPos); + } + break; + + case Token.LBRACKET: { + acceptIt(); + ArrayAggregate aaAST = parseArrayAggregate(); + accept(Token.RBRACKET); + finish(expressionPos); + expressionAST = new ArrayExpression(aaAST, expressionPos); + } + break; + + case Token.LCURLY: { + acceptIt(); + RecordAggregate raAST = parseRecordAggregate(); + accept(Token.RCURLY); + finish(expressionPos); + expressionAST = new RecordExpression(raAST, expressionPos); + } + break; + + case Token.IDENTIFIER: { + Identifier iAST = parseIdentifier(); + if (currentToken.kind == Token.LPAREN) { + acceptIt(); + ActualParameterSequence apsAST = parseActualParameterSequence(); + accept(Token.RPAREN); + finish(expressionPos); + expressionAST = new CallExpression(iAST, apsAST, expressionPos); + + } else { + Vname vAST = parseRestOfVname(iAST); + finish(expressionPos); + expressionAST = new VnameExpression(vAST, expressionPos); + } + } + break; + + case Token.OPERATOR: { + Operator opAST = parseOperator(); + Expression eAST = parsePrimaryExpression(); + finish(expressionPos); + expressionAST = new UnaryExpression(opAST, eAST, expressionPos); + } + break; + + case Token.LPAREN: + acceptIt(); + expressionAST = parseExpression(); + accept(Token.RPAREN); + break; + + default: + syntacticError("\"%\" cannot start an expression", currentToken.spelling); + break; + + } + return expressionAST; + } + + RecordAggregate parseRecordAggregate() throws SyntaxError { + RecordAggregate aggregateAST = null; // in case there's a syntactic error + + SourcePosition aggregatePos = new SourcePosition(); + start(aggregatePos); + + Identifier iAST = parseIdentifier(); + accept(Token.IS); + Expression eAST = parseExpression(); + + if (currentToken.kind == Token.COMMA) { + acceptIt(); + RecordAggregate aAST = parseRecordAggregate(); + finish(aggregatePos); + aggregateAST = new MultipleRecordAggregate(iAST, eAST, aAST, aggregatePos); + } else { + finish(aggregatePos); + aggregateAST = new SingleRecordAggregate(iAST, eAST, aggregatePos); + } + return aggregateAST; + } + + ArrayAggregate parseArrayAggregate() throws SyntaxError { + ArrayAggregate aggregateAST = null; // in case there's a syntactic error + + SourcePosition aggregatePos = new SourcePosition(); + start(aggregatePos); + + Expression eAST = parseExpression(); + if (currentToken.kind == Token.COMMA) { + acceptIt(); + ArrayAggregate aAST = parseArrayAggregate(); + finish(aggregatePos); + aggregateAST = new MultipleArrayAggregate(eAST, aAST, aggregatePos); + } else { + finish(aggregatePos); + aggregateAST = new SingleArrayAggregate(eAST, aggregatePos); + } + return aggregateAST; + } + + /////////////////////////////////////////////////////////////////////////////// + // + // VALUE-OR-VARIABLE NAMES + // + /////////////////////////////////////////////////////////////////////////////// + + Vname parseVname() throws SyntaxError { + Vname vnameAST = null; // in case there's a syntactic error + Identifier iAST = parseIdentifier(); + vnameAST = parseRestOfVname(iAST); + return vnameAST; + } + + Vname parseRestOfVname(Identifier identifierAST) throws SyntaxError { + SourcePosition vnamePos = new SourcePosition(); + vnamePos = identifierAST.getPosition(); + Vname vAST = new SimpleVname(identifierAST, vnamePos); + + while (currentToken.kind == Token.DOT || currentToken.kind == Token.LBRACKET) { + + if (currentToken.kind == Token.DOT) { + acceptIt(); + Identifier iAST = parseIdentifier(); + vAST = new DotVname(vAST, iAST, vnamePos); + } else { + acceptIt(); + Expression eAST = parseExpression(); + accept(Token.RBRACKET); + finish(vnamePos); + vAST = new SubscriptVname(vAST, eAST, vnamePos); + } + } + return vAST; + } + + /////////////////////////////////////////////////////////////////////////////// + // + // DECLARATIONS + // + /////////////////////////////////////////////////////////////////////////////// + + Declaration parseDeclaration() throws SyntaxError { + Declaration declarationAST = null; // in case there's a syntactic error + + SourcePosition declarationPos = new SourcePosition(); + start(declarationPos); + declarationAST = parseSingleDeclaration(); + while (currentToken.kind == Token.SEMICOLON) { + acceptIt(); + Declaration d2AST = parseSingleDeclaration(); + finish(declarationPos); + declarationAST = new SequentialDeclaration(declarationAST, d2AST, declarationPos); + } + return declarationAST; + } + + Declaration parseSingleDeclaration() throws SyntaxError { + Declaration declarationAST = null; // in case there's a syntactic error + + SourcePosition declarationPos = new SourcePosition(); + start(declarationPos); + + switch (currentToken.kind) { + + case Token.CONST: { + acceptIt(); + Identifier iAST = parseIdentifier(); + accept(Token.IS); + Expression eAST = parseExpression(); + finish(declarationPos); + declarationAST = new ConstDeclaration(iAST, eAST, declarationPos); + } + break; + + case Token.VAR: { + acceptIt(); + Identifier iAST = parseIdentifier(); + accept(Token.COLON); + TypeDenoter tAST = parseTypeDenoter(); + finish(declarationPos); + declarationAST = new VarDeclaration(iAST, tAST, declarationPos); + } + break; + + case Token.PROC: { + acceptIt(); + Identifier iAST = parseIdentifier(); + accept(Token.LPAREN); + FormalParameterSequence fpsAST = parseFormalParameterSequence(); + accept(Token.RPAREN); + accept(Token.IS); + Command cAST = parseSingleCommand(); + finish(declarationPos); + declarationAST = new ProcDeclaration(iAST, fpsAST, cAST, declarationPos); + } + break; + + case Token.FUNC: { + acceptIt(); + Identifier iAST = parseIdentifier(); + accept(Token.LPAREN); + FormalParameterSequence fpsAST = parseFormalParameterSequence(); + accept(Token.RPAREN); + accept(Token.COLON); + TypeDenoter tAST = parseTypeDenoter(); + accept(Token.IS); + Expression eAST = parseExpression(); + finish(declarationPos); + declarationAST = new FuncDeclaration(iAST, fpsAST, tAST, eAST, declarationPos); + } + break; + + case Token.TYPE: { + acceptIt(); + Identifier iAST = parseIdentifier(); + accept(Token.IS); + TypeDenoter tAST = parseTypeDenoter(); + finish(declarationPos); + declarationAST = new TypeDeclaration(iAST, tAST, declarationPos); + } + break; + + default: + syntacticError("\"%\" cannot start a declaration", currentToken.spelling); + break; + + } + return declarationAST; + } + + /////////////////////////////////////////////////////////////////////////////// + // + // PARAMETERS + // + /////////////////////////////////////////////////////////////////////////////// + + FormalParameterSequence parseFormalParameterSequence() throws SyntaxError { + FormalParameterSequence formalsAST; + + SourcePosition formalsPos = new SourcePosition(); + + start(formalsPos); + if (currentToken.kind == Token.RPAREN) { + finish(formalsPos); + formalsAST = new EmptyFormalParameterSequence(formalsPos); + + } else { + formalsAST = parseProperFormalParameterSequence(); + } + return formalsAST; + } + + FormalParameterSequence parseProperFormalParameterSequence() throws SyntaxError { + FormalParameterSequence formalsAST = null; // in case there's a syntactic error; + + SourcePosition formalsPos = new SourcePosition(); + start(formalsPos); + FormalParameter fpAST = parseFormalParameter(); + if (currentToken.kind == Token.COMMA) { + acceptIt(); + FormalParameterSequence fpsAST = parseProperFormalParameterSequence(); + finish(formalsPos); + formalsAST = new MultipleFormalParameterSequence(fpAST, fpsAST, formalsPos); + + } else { + finish(formalsPos); + formalsAST = new SingleFormalParameterSequence(fpAST, formalsPos); + } + return formalsAST; + } + + FormalParameter parseFormalParameter() throws SyntaxError { + FormalParameter formalAST = null; // in case there's a syntactic error; + + SourcePosition formalPos = new SourcePosition(); + start(formalPos); + + switch (currentToken.kind) { + + case Token.IDENTIFIER: { + Identifier iAST = parseIdentifier(); + accept(Token.COLON); + TypeDenoter tAST = parseTypeDenoter(); + finish(formalPos); + formalAST = new ConstFormalParameter(iAST, tAST, formalPos); + } + break; + + case Token.VAR: { + acceptIt(); + Identifier iAST = parseIdentifier(); + accept(Token.COLON); + TypeDenoter tAST = parseTypeDenoter(); + finish(formalPos); + formalAST = new VarFormalParameter(iAST, tAST, formalPos); + } + break; + + case Token.PROC: { + acceptIt(); + Identifier iAST = parseIdentifier(); + accept(Token.LPAREN); + FormalParameterSequence fpsAST = parseFormalParameterSequence(); + accept(Token.RPAREN); + finish(formalPos); + formalAST = new ProcFormalParameter(iAST, fpsAST, formalPos); + } + break; + + case Token.FUNC: { + acceptIt(); + Identifier iAST = parseIdentifier(); + accept(Token.LPAREN); + FormalParameterSequence fpsAST = parseFormalParameterSequence(); + accept(Token.RPAREN); + accept(Token.COLON); + TypeDenoter tAST = parseTypeDenoter(); + finish(formalPos); + formalAST = new FuncFormalParameter(iAST, fpsAST, tAST, formalPos); + } + break; + + default: + syntacticError("\"%\" cannot start a formal parameter", currentToken.spelling); + break; + + } + return formalAST; + } + + ActualParameterSequence parseActualParameterSequence() throws SyntaxError { + ActualParameterSequence actualsAST; + + SourcePosition actualsPos = new SourcePosition(); + + start(actualsPos); + if (currentToken.kind == Token.RPAREN) { + finish(actualsPos); + actualsAST = new EmptyActualParameterSequence(actualsPos); + + } else { + actualsAST = parseProperActualParameterSequence(); + } + return actualsAST; + } + + ActualParameterSequence parseProperActualParameterSequence() throws SyntaxError { + ActualParameterSequence actualsAST = null; // in case there's a syntactic error + + SourcePosition actualsPos = new SourcePosition(); + + start(actualsPos); + ActualParameter apAST = parseActualParameter(); + if (currentToken.kind == Token.COMMA) { + acceptIt(); + ActualParameterSequence apsAST = parseProperActualParameterSequence(); + finish(actualsPos); + actualsAST = new MultipleActualParameterSequence(apAST, apsAST, actualsPos); + } else { + finish(actualsPos); + actualsAST = new SingleActualParameterSequence(apAST, actualsPos); + } + return actualsAST; + } + + ActualParameter parseActualParameter() throws SyntaxError { + ActualParameter actualAST = null; // in case there's a syntactic error + + SourcePosition actualPos = new SourcePosition(); + + start(actualPos); + + switch (currentToken.kind) { + + case Token.IDENTIFIER: + case Token.INTLITERAL: + case Token.CHARLITERAL: + case Token.OPERATOR: + case Token.LET: + case Token.IF: + case Token.LPAREN: + case Token.LBRACKET: + case Token.LCURLY: { + Expression eAST = parseExpression(); + finish(actualPos); + actualAST = new ConstActualParameter(eAST, actualPos); + } + break; + + case Token.VAR: { + acceptIt(); + Vname vAST = parseVname(); + finish(actualPos); + actualAST = new VarActualParameter(vAST, actualPos); + } + break; + + case Token.PROC: { + acceptIt(); + Identifier iAST = parseIdentifier(); + finish(actualPos); + actualAST = new ProcActualParameter(iAST, actualPos); + } + break; + + case Token.FUNC: { + acceptIt(); + Identifier iAST = parseIdentifier(); + finish(actualPos); + actualAST = new FuncActualParameter(iAST, actualPos); + } + break; + + default: + syntacticError("\"%\" cannot start an actual parameter", currentToken.spelling); + break; + + } + return actualAST; + } + + /////////////////////////////////////////////////////////////////////////////// + // + // TYPE-DENOTERS + // + /////////////////////////////////////////////////////////////////////////////// + + TypeDenoter parseTypeDenoter() throws SyntaxError { + TypeDenoter typeAST = null; // in case there's a syntactic error + SourcePosition typePos = new SourcePosition(); + + start(typePos); + + switch (currentToken.kind) { + + case Token.IDENTIFIER: { + Identifier iAST = parseIdentifier(); + finish(typePos); + typeAST = new SimpleTypeDenoter(iAST, typePos); + } + break; + + case Token.ARRAY: { + acceptIt(); + IntegerLiteral ilAST = parseIntegerLiteral(); + accept(Token.OF); + TypeDenoter tAST = parseTypeDenoter(); + finish(typePos); + typeAST = new ArrayTypeDenoter(ilAST, tAST, typePos); + } + break; + + case Token.RECORD: { + acceptIt(); + FieldTypeDenoter fAST = parseFieldTypeDenoter(); + accept(Token.END); + finish(typePos); + typeAST = new RecordTypeDenoter(fAST, typePos); + } + break; + + default: + syntacticError("\"%\" cannot start a type denoter", currentToken.spelling); + break; + + } + return typeAST; + } + + FieldTypeDenoter parseFieldTypeDenoter() throws SyntaxError { + FieldTypeDenoter fieldAST = null; // in case there's a syntactic error + + SourcePosition fieldPos = new SourcePosition(); + + start(fieldPos); + Identifier iAST = parseIdentifier(); + accept(Token.COLON); + TypeDenoter tAST = parseTypeDenoter(); + if (currentToken.kind == Token.COMMA) { + acceptIt(); + FieldTypeDenoter fAST = parseFieldTypeDenoter(); + finish(fieldPos); + fieldAST = new MultipleFieldTypeDenoter(iAST, tAST, fAST, fieldPos); + } else { + finish(fieldPos); + fieldAST = new SingleFieldTypeDenoter(iAST, tAST, fieldPos); + } + return fieldAST; + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Scanner.java b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Scanner.java new file mode 100644 index 0000000..a6f0f42 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Scanner.java @@ -0,0 +1,276 @@ +/* + * @(#)Scanner.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.syntacticAnalyzer; + +public final class Scanner { + + private SourceFile sourceFile; + private boolean debug; + + private char currentChar; + private StringBuffer currentSpelling; + private boolean currentlyScanningToken; + + private boolean isLetter(char c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + } + + private boolean isDigit(char c) { + return (c >= '0' && c <= '9'); + } + + // isOperator returns true iff the given character is an operator character. + + private boolean isOperator(char c) { + return (c == '+' || c == '-' || c == '*' || c == '/' || c == '=' || c == '<' || c == '>' || c == '\\' + || c == '&' || c == '@' || c == '%' || c == '^' || c == '?'); + } + + /////////////////////////////////////////////////////////////////////////////// + + public Scanner(SourceFile source) { + sourceFile = source; + currentChar = sourceFile.getSource(); + debug = false; + } + + public void enableDebugging() { + debug = true; + } + + // takeIt appends the current character to the current token, and gets + // the next character from the source program. + + private void takeIt() { + if (currentlyScanningToken) + currentSpelling.append(currentChar); + currentChar = sourceFile.getSource(); + } + + // scanSeparator skips a single separator. + + private void scanSeparator() { + switch (currentChar) { + + // comment + case '!': { + takeIt(); + while ((currentChar != SourceFile.EOL) && (currentChar != SourceFile.EOT)) + takeIt(); + if (currentChar == SourceFile.EOL) + takeIt(); + } + break; + + // whitespace + case ' ': + case '\n': + case '\r': + case '\t': + takeIt(); + break; + } + } + + private int scanToken() { + + switch (currentChar) { + + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + takeIt(); + while (isLetter(currentChar) || isDigit(currentChar)) + takeIt(); + return Token.IDENTIFIER; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + takeIt(); + while (isDigit(currentChar)) + takeIt(); + return Token.INTLITERAL; + + case '+': + case '-': + case '*': + case '/': + case '=': + case '<': + case '>': + case '\\': + case '&': + case '@': + case '%': + case '^': + case '?': + takeIt(); + while (isOperator(currentChar)) + takeIt(); + return Token.OPERATOR; + + case '\'': + takeIt(); + takeIt(); // the quoted character + if (currentChar == '\'') { + takeIt(); + return Token.CHARLITERAL; + } else + return Token.ERROR; + + case '.': + takeIt(); + return Token.DOT; + + case ':': + takeIt(); + if (currentChar == '=') { + takeIt(); + return Token.BECOMES; + } else + return Token.COLON; + + case ';': + takeIt(); + return Token.SEMICOLON; + + case ',': + takeIt(); + return Token.COMMA; + + case '~': + takeIt(); + return Token.IS; + + case '(': + takeIt(); + return Token.LPAREN; + + case ')': + takeIt(); + return Token.RPAREN; + + case '[': + takeIt(); + return Token.LBRACKET; + + case ']': + takeIt(); + return Token.RBRACKET; + + case '{': + takeIt(); + return Token.LCURLY; + + case '}': + takeIt(); + return Token.RCURLY; + + case SourceFile.EOT: + return Token.EOT; + + default: + takeIt(); + return Token.ERROR; + } + } + + public Token scan() { + Token tok; + SourcePosition pos; + int kind; + + currentlyScanningToken = false; + // skip any whitespace or comments + while (currentChar == '!' || currentChar == ' ' || currentChar == '\n' || currentChar == '\r' + || currentChar == '\t') + scanSeparator(); + + currentlyScanningToken = true; + currentSpelling = new StringBuffer(""); + pos = new SourcePosition(); + pos.start = sourceFile.getCurrentLine(); + + kind = scanToken(); + + pos.finish = sourceFile.getCurrentLine(); + tok = new Token(kind, currentSpelling.toString(), pos); + if (debug) + System.out.println(tok); + return tok; + } + +} diff --git a/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SourceFile.java b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SourceFile.java new file mode 100644 index 0000000..2741f44 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SourceFile.java @@ -0,0 +1,72 @@ +/* + * @(#)SourceFile.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.syntacticAnalyzer; + +import java.net.URL; + +public class SourceFile { + + public static final char EOL = '\n'; + public static final char EOT = '\u0000'; + + java.io.File sourceFile; + java.io.InputStream source; + int currentLine; + + public static SourceFile ofPath(String pathname) { + try { + SourceFile sf = new SourceFile(); + sf.sourceFile = new java.io.File(pathname); + sf.source = new java.io.FileInputStream(sf.sourceFile); + return sf; + } catch (java.io.IOException s) { + return null; + } + } + + public static SourceFile fromResource(String handle) { + SourceFile sf = new SourceFile(); + //sf.sourceFile = new java.io.File(pathname); + sf.source = sf.getClass().getResourceAsStream(handle); + return sf; + } + + private SourceFile() { + currentLine = 1; + } + + char getSource() { + try { + int c = source.read(); + + if (c == -1) { + c = EOT; + } else if (c == EOL) { + currentLine++; + } + return (char) c; + } catch (java.io.IOException s) { + return EOT; + } + } + + int getCurrentLine() { + return currentLine; + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SourcePosition.java b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SourcePosition.java new file mode 100644 index 0000000..f3a7e0f --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SourcePosition.java @@ -0,0 +1,39 @@ +/* + * @(#)SourcePosition.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.syntacticAnalyzer; + +public class SourcePosition { + + public int start, finish; + + public SourcePosition() { + start = 0; + finish = 0; + } + + public SourcePosition(int s, int f) { + start = s; + finish = f; + } + + @Override + public String toString() { + return "(" + start + ", " + finish + ")"; + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SyntaxError.java b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SyntaxError.java new file mode 100644 index 0000000..639a2ba --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SyntaxError.java @@ -0,0 +1,33 @@ +/* + * @(#)SyntaxError.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.syntacticAnalyzer; + +class SyntaxError extends Exception { + + private static final long serialVersionUID = -5280306336102766860L; + + SyntaxError() { + super(); + } + + SyntaxError(String s) { + super(s); + } + +} diff --git a/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Token.java b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Token.java new file mode 100644 index 0000000..614c344 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Token.java @@ -0,0 +1,88 @@ +/* + * @(#)Token.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.syntacticAnalyzer; + +final class Token extends Object { + + protected int kind; + protected String spelling; + protected SourcePosition position; + + public Token(int kind, String spelling, SourcePosition position) { + + if (kind == Token.IDENTIFIER) { + int currentKind = firstReservedWord; + boolean searching = true; + + while (searching) { + int comparison = tokenTable[currentKind].compareTo(spelling); + if (comparison == 0) { + this.kind = currentKind; + searching = false; + } else if (comparison > 0 || currentKind == lastReservedWord) { + this.kind = Token.IDENTIFIER; + searching = false; + } else { + currentKind++; + } + } + } else + this.kind = kind; + + this.spelling = spelling; + this.position = position; + + } + + public static String spell(int kind) { + return tokenTable[kind]; + } + + @Override + public String toString() { + return "Kind=" + kind + ", spelling=" + spelling + ", position=" + position; + } + + // Token classes... + + public static final int + + // literals, identifiers, operators... + INTLITERAL = 0, CHARLITERAL = 1, IDENTIFIER = 2, OPERATOR = 3, + + // reserved words - must be in alphabetical order... + ARRAY = 4, BEGIN = 5, CONST = 6, DO = 7, ELSE = 8, END = 9, FUNC = 10, IF = 11, IN = 12, LET = 13, OF = 14, + PROC = 15, RECORD = 16, THEN = 17, TYPE = 18, VAR = 19, WHILE = 20, + + // punctuation... + DOT = 21, COLON = 22, SEMICOLON = 23, COMMA = 24, BECOMES = 25, IS = 26, + + // brackets... + LPAREN = 27, RPAREN = 28, LBRACKET = 29, RBRACKET = 30, LCURLY = 31, RCURLY = 32, + + // special tokens... + EOT = 33, ERROR = 34; + + private static String[] tokenTable = new String[] { "", "", "", "", "array", + "begin", "const", "do", "else", "end", "func", "if", "in", "let", "of", "proc", "record", "then", "type", + "var", "while", ".", ":", ";", ",", ":=", "~", "(", ")", "[", "]", "{", "}", "", "" }; + + private final static int firstReservedWord = Token.ARRAY, lastReservedWord = Token.WHILE; + +} diff --git a/Triangle.Compiler/src/main/java/triangle/treeDrawer/Drawer.java b/Triangle.Compiler/src/main/java/triangle/treeDrawer/Drawer.java new file mode 100644 index 0000000..1d7ab2d --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/treeDrawer/Drawer.java @@ -0,0 +1,72 @@ +/* + * @(#)Drawer.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.treeDrawer; + +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Point; + +import triangle.abstractSyntaxTrees.Program; + +public class Drawer { + + private DrawerFrame frame; + private DrawerPanel panel; + + private Program theAST; + private DrawingTree theDrawing; + + // Draw the AST representing a complete program. + + public void draw(Program ast) { + theAST = ast; + panel = new DrawerPanel(this); + frame = new DrawerFrame(panel); + + Font font = new Font("SansSerif", Font.PLAIN, 12); + frame.setFont(font); + + FontMetrics fontMetrics = frame.getFontMetrics(font); + + // another class of visitor is used for drawing the tree: LayoutVisitor + // LayoutVisitor is passed to the AST which, in turn, calls visitProgram + // and then each AST node is visited. This ultimately constructs a + // DrawingTree, which is structurally the same as the AST but is decorated + // with coordinates (and has only DrawingTree objects as nodes) + // Each DrawingTree object knows how to paint itself, so it's passed to a + // DrawerPanel and DrawerFrame for display + LayoutVisitor layout = new LayoutVisitor(fontMetrics); + theDrawing = (DrawingTree) theAST.visit(layout, null); + theDrawing.position(new Point(2048, 10)); + + frame.setVisible(true); + } + + public void paintAST(Graphics g) { + g.setColor(panel.getBackground()); + Dimension d = panel.getSize(); + g.fillRect(0, 0, d.width, d.height); + + if (theDrawing != null) { + theDrawing.paint(g); + } + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawerFrame.java b/Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawerFrame.java new file mode 100644 index 0000000..81b6894 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawerFrame.java @@ -0,0 +1,78 @@ +/* + * @(#)DrawerFrame.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.treeDrawer; + +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.event.AdjustmentEvent; +import java.awt.event.AdjustmentListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollBar; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; + +class DrawerFrame extends JFrame { + /** + * + */ + private static final long serialVersionUID = -3650404598416929282L; + + public DrawerFrame(JPanel panel) { + setSize(300, 200); + Toolkit tk = Toolkit.getDefaultToolkit(); + Dimension d = tk.getScreenSize(); + int screenHeight = d.height; + int screenWidth = d.width; + setTitle("Triangle Compiler Abstract Syntax Tree"); + setSize(screenWidth / 2, screenHeight / 2); + setLocation(screenWidth / 4, screenHeight / 4); + // Image img = tk.getImage("icon.gif"); + // setIconImage(img); + + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + System.exit(0); + } + }); + Container contentPane = getContentPane(); + final JScrollPane jScrollPane = new JScrollPane(panel); + + contentPane.addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + super.componentResized(e); + jScrollPane.getHorizontalScrollBar().setValue(jScrollPane.getHorizontalScrollBar().getMaximum()); + jScrollPane.getHorizontalScrollBar().setValue(jScrollPane.getHorizontalScrollBar().getValue() / 2); + } + }); + + contentPane.add(jScrollPane); + + } + +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawerPanel.java b/Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawerPanel.java new file mode 100644 index 0000000..d11eac9 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawerPanel.java @@ -0,0 +1,43 @@ +/* + * @(#)DrawerPanel.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.treeDrawer; + +import java.awt.Dimension; +import java.awt.Graphics; + +import javax.swing.JPanel; + +class DrawerPanel extends JPanel { + /** + * + */ + private static final long serialVersionUID = 565914745506889669L; + private Drawer drawer; + + public DrawerPanel(Drawer drawer) { + setPreferredSize(new Dimension(4096, 4096)); + this.drawer = drawer; + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + drawer.paintAST(g); + } +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawingTree.java b/Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawingTree.java new file mode 100644 index 0000000..85a7947 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawingTree.java @@ -0,0 +1,88 @@ +/* + * @(#)DrawingTree.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.treeDrawer; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Point; + +public class DrawingTree { + + String caption; + int width, height; + Point pos, offset; + Polygon contour; + DrawingTree parent; + DrawingTree[] children; + + public DrawingTree(String caption, int width, int height) { + this.caption = caption; + this.width = width; + this.height = height; + this.parent = null; + this.children = null; + this.pos = new Point(0, 0); + this.offset = new Point(0, 0); + this.contour = new Polygon(); + } + + public void setChildren(DrawingTree[] children) { + this.children = children; + for (int i = 0; i < children.length; i++) + children[i].parent = this; + } + + private final int FIXED_FONT_HEIGHT = 10; + private final Color nodeColor = new Color(250, 220, 100); + + public void paint(Graphics graphics) { + graphics.setColor(nodeColor); + graphics.fillRect(pos.x, pos.y, width, height); + graphics.setColor(Color.black); + graphics.drawRect(pos.x, pos.y, width - 1, height - 1); + graphics.drawString(caption, pos.x + 2, pos.y + (height + FIXED_FONT_HEIGHT) / 2); + + if (children != null) { + for (DrawingTree child : children) { + child.paint(graphics); + } + } + + if (parent != null) { + graphics.drawLine(pos.x + width / 2, pos.y, parent.pos.x + parent.width / 2, parent.pos.y + parent.height); + } + } + + public void position(Point pos) { + + this.pos.x = pos.x + this.offset.x; + this.pos.y = pos.y + this.offset.y; + + Point temp = new Point(this.pos.x, this.pos.y); + + if (children != null) { + for (DrawingTree child : children) { + child.position(temp); + temp.x += child.offset.x; + temp.y = this.pos.y + children[0].offset.y; + } + } + } + +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/treeDrawer/LayoutVisitor.java b/Triangle.Compiler/src/main/java/triangle/treeDrawer/LayoutVisitor.java new file mode 100644 index 0000000..b5ffec0 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/treeDrawer/LayoutVisitor.java @@ -0,0 +1,684 @@ +/* + * @(#)LayoutVisitor.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.treeDrawer; + +import java.awt.FontMetrics; + +import triangle.abstractSyntaxTrees.Program; +import triangle.abstractSyntaxTrees.actuals.ConstActualParameter; +import triangle.abstractSyntaxTrees.actuals.EmptyActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.FuncActualParameter; +import triangle.abstractSyntaxTrees.actuals.MultipleActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.ProcActualParameter; +import triangle.abstractSyntaxTrees.actuals.SingleActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.VarActualParameter; +import triangle.abstractSyntaxTrees.aggregates.MultipleArrayAggregate; +import triangle.abstractSyntaxTrees.aggregates.MultipleRecordAggregate; +import triangle.abstractSyntaxTrees.aggregates.SingleArrayAggregate; +import triangle.abstractSyntaxTrees.aggregates.SingleRecordAggregate; +import triangle.abstractSyntaxTrees.commands.AssignCommand; +import triangle.abstractSyntaxTrees.commands.CallCommand; +import triangle.abstractSyntaxTrees.commands.EmptyCommand; +import triangle.abstractSyntaxTrees.commands.IfCommand; +import triangle.abstractSyntaxTrees.commands.LetCommand; +import triangle.abstractSyntaxTrees.commands.SequentialCommand; +import triangle.abstractSyntaxTrees.commands.WhileCommand; +import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration; +import triangle.abstractSyntaxTrees.declarations.ConstDeclaration; +import triangle.abstractSyntaxTrees.declarations.FuncDeclaration; +import triangle.abstractSyntaxTrees.declarations.ProcDeclaration; +import triangle.abstractSyntaxTrees.declarations.SequentialDeclaration; +import triangle.abstractSyntaxTrees.declarations.UnaryOperatorDeclaration; +import triangle.abstractSyntaxTrees.declarations.VarDeclaration; +import triangle.abstractSyntaxTrees.expressions.ArrayExpression; +import triangle.abstractSyntaxTrees.expressions.BinaryExpression; +import triangle.abstractSyntaxTrees.expressions.CallExpression; +import triangle.abstractSyntaxTrees.expressions.CharacterExpression; +import triangle.abstractSyntaxTrees.expressions.EmptyExpression; +import triangle.abstractSyntaxTrees.expressions.IfExpression; +import triangle.abstractSyntaxTrees.expressions.IntegerExpression; +import triangle.abstractSyntaxTrees.expressions.LetExpression; +import triangle.abstractSyntaxTrees.expressions.RecordExpression; +import triangle.abstractSyntaxTrees.expressions.UnaryExpression; +import triangle.abstractSyntaxTrees.expressions.VnameExpression; +import triangle.abstractSyntaxTrees.formals.ConstFormalParameter; +import triangle.abstractSyntaxTrees.formals.EmptyFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.FuncFormalParameter; +import triangle.abstractSyntaxTrees.formals.MultipleFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.ProcFormalParameter; +import triangle.abstractSyntaxTrees.formals.SingleFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.VarFormalParameter; +import triangle.abstractSyntaxTrees.terminals.CharacterLiteral; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.terminals.IntegerLiteral; +import triangle.abstractSyntaxTrees.terminals.Operator; +import triangle.abstractSyntaxTrees.types.AnyTypeDenoter; +import triangle.abstractSyntaxTrees.types.ArrayTypeDenoter; +import triangle.abstractSyntaxTrees.types.BoolTypeDenoter; +import triangle.abstractSyntaxTrees.types.CharTypeDenoter; +import triangle.abstractSyntaxTrees.types.ErrorTypeDenoter; +import triangle.abstractSyntaxTrees.types.IntTypeDenoter; +import triangle.abstractSyntaxTrees.types.MultipleFieldTypeDenoter; +import triangle.abstractSyntaxTrees.types.RecordTypeDenoter; +import triangle.abstractSyntaxTrees.types.SimpleTypeDenoter; +import triangle.abstractSyntaxTrees.types.SingleFieldTypeDenoter; +import triangle.abstractSyntaxTrees.types.TypeDeclaration; +import triangle.abstractSyntaxTrees.visitors.ActualParameterSequenceVisitor; +import triangle.abstractSyntaxTrees.visitors.ActualParameterVisitor; +import triangle.abstractSyntaxTrees.visitors.ArrayAggregateVisitor; +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.abstractSyntaxTrees.visitors.FormalParameterSequenceVisitor; +import triangle.abstractSyntaxTrees.visitors.IdentifierVisitor; +import triangle.abstractSyntaxTrees.visitors.LiteralVisitor; +import triangle.abstractSyntaxTrees.visitors.OperatorVisitor; +import triangle.abstractSyntaxTrees.visitors.ProgramVisitor; +import triangle.abstractSyntaxTrees.visitors.RecordAggregateVisitor; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.abstractSyntaxTrees.visitors.VnameVisitor; +import triangle.abstractSyntaxTrees.vnames.DotVname; +import triangle.abstractSyntaxTrees.vnames.SimpleVname; +import triangle.abstractSyntaxTrees.vnames.SubscriptVname; + +public class LayoutVisitor implements ActualParameterVisitor, + ActualParameterSequenceVisitor, ArrayAggregateVisitor, + CommandVisitor, DeclarationVisitor, ExpressionVisitor, + FormalParameterSequenceVisitor, IdentifierVisitor, + LiteralVisitor, OperatorVisitor, ProgramVisitor, + RecordAggregateVisitor, TypeDenoterVisitor, + VnameVisitor { + + private final int BORDER = 5; + private final int PARENT_SEP = 30; + + private FontMetrics fontMetrics; + + public LayoutVisitor(FontMetrics fontMetrics) { + this.fontMetrics = fontMetrics; + } + + // Commands + @Override + public DrawingTree visitAssignCommand(AssignCommand ast, Void obj) { + var d1 = ast.V.visit(this); + var d2 = ast.E.visit(this); + return layoutBinary("AssignCom.", d1, d2); + } + + @Override + public DrawingTree visitCallCommand(CallCommand ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.APS.visit(this); + return layoutBinary("CallCom.", d1, d2); + } + + @Override + public DrawingTree visitEmptyCommand(EmptyCommand ast, Void obj) { + return layoutNullary("EmptyCom."); + } + + @Override + public DrawingTree visitIfCommand(IfCommand ast, Void obj) { + var d1 = ast.E.visit(this); + var d2 = ast.C1.visit(this); + var d3 = ast.C2.visit(this); + return layoutTernary("IfCom.", d1, d2, d3); + } + + @Override + public DrawingTree visitLetCommand(LetCommand ast, Void obj) { + var d1 = ast.D.visit(this); + var d2 = ast.C.visit(this); + return layoutBinary("LetCom.", d1, d2); + } + + @Override + public DrawingTree visitSequentialCommand(SequentialCommand ast, Void obj) { + var d1 = ast.C1.visit(this); + var d2 = ast.C2.visit(this); + return layoutBinary("Seq.Com.", d1, d2); + } + + @Override + public DrawingTree visitWhileCommand(WhileCommand ast, Void obj) { + var d1 = ast.E.visit(this); + var d2 = ast.C.visit(this); + return layoutBinary("WhileCom.", d1, d2); + } + + // Expressions + @Override + public DrawingTree visitArrayExpression(ArrayExpression ast, Void obj) { + var d1 = ast.AA.visit(this); + return layoutUnary("ArrayExpr.", d1); + } + + @Override + public DrawingTree visitBinaryExpression(BinaryExpression ast, Void obj) { + var d1 = ast.E1.visit(this); + var d2 = ast.O.visit(this); + var d3 = ast.E2.visit(this); + return layoutTernary("Bin.Expr.", d1, d2, d3); + } + + @Override + public DrawingTree visitCallExpression(CallExpression ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.APS.visit(this); + return layoutBinary("CallExpr.", d1, d2); + } + + @Override + public DrawingTree visitCharacterExpression(CharacterExpression ast, Void obj) { + var d1 = ast.CL.visit(this); + return layoutUnary("Char.Expr.", d1); + } + + @Override + public DrawingTree visitEmptyExpression(EmptyExpression ast, Void obj) { + return layoutNullary("EmptyExpr."); + } + + @Override + public DrawingTree visitIfExpression(IfExpression ast, Void obj) { + var d1 = ast.E1.visit(this); + var d2 = ast.E2.visit(this); + var d3 = ast.E3.visit(this); + return layoutTernary("IfExpr.", d1, d2, d3); + } + + @Override + public DrawingTree visitIntegerExpression(IntegerExpression ast, Void obj) { + var d1 = ast.IL.visit(this); + return layoutUnary("Int.Expr.", d1); + } + + @Override + public DrawingTree visitLetExpression(LetExpression ast, Void obj) { + var d1 = ast.D.visit(this); + var d2 = ast.E.visit(this); + return layoutBinary("LetExpr.", d1, d2); + } + + @Override + public DrawingTree visitRecordExpression(RecordExpression ast, Void obj) { + var d1 = ast.RA.visit(this); + return layoutUnary("Rec.Expr.", d1); + } + + @Override + public DrawingTree visitUnaryExpression(UnaryExpression ast, Void obj) { + var d1 = ast.O.visit(this); + var d2 = ast.E.visit(this); + return layoutBinary("UnaryExpr.", d1, d2); + } + + @Override + public DrawingTree visitVnameExpression(VnameExpression ast, Void obj) { + var d1 = ast.V.visit(this); + return layoutUnary("VnameExpr.", d1); + } + + // Declarations + @Override + public DrawingTree visitBinaryOperatorDeclaration(BinaryOperatorDeclaration ast, Void obj) { + var d1 = ast.O.visit(this); + var d2 = ast.ARG1.visit(this); + var d3 = ast.ARG2.visit(this); + var d4 = ast.RES.visit(this); + return layoutQuaternary("Bin.Op.Decl.", d1, d2, d3, d4); + } + + @Override + public DrawingTree visitConstDeclaration(ConstDeclaration ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.E.visit(this); + return layoutBinary("ConstDecl.", d1, d2); + } + + @Override + public DrawingTree visitFuncDeclaration(FuncDeclaration ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.FPS.visit(this); + var d3 = ast.T.visit(this); + var d4 = ast.E.visit(this); + return layoutQuaternary("FuncDecl.", d1, d2, d3, d4); + } + + @Override + public DrawingTree visitProcDeclaration(ProcDeclaration ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.FPS.visit(this); + var d3 = ast.C.visit(this); + return layoutTernary("ProcDecl.", d1, d2, d3); + } + + @Override + public DrawingTree visitSequentialDeclaration(SequentialDeclaration ast, Void obj) { + var d1 = ast.D1.visit(this); + var d2 = ast.D2.visit(this); + return layoutBinary("Seq.Decl.", d1, d2); + } + + @Override + public DrawingTree visitTypeDeclaration(TypeDeclaration ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.T.visit(this); + return layoutBinary("TypeDecl.", d1, d2); + } + + @Override + public DrawingTree visitUnaryOperatorDeclaration(UnaryOperatorDeclaration ast, Void obj) { + var d1 = ast.O.visit(this); + var d2 = ast.ARG.visit(this); + var d3 = ast.RES.visit(this); + return layoutTernary("UnaryOp.Decl.", d1, d2, d3); + } + + @Override + public DrawingTree visitVarDeclaration(VarDeclaration ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.T.visit(this); + return layoutBinary("VarDecl.", d1, d2); + } + + // Array Aggregates + @Override + public DrawingTree visitMultipleArrayAggregate(MultipleArrayAggregate ast, Void obj) { + var d1 = ast.E.visit(this); + var d2 = ast.AA.visit(this); + return layoutBinary("Mult.ArrayAgg.", d1, d2); + } + + @Override + public DrawingTree visitSingleArrayAggregate(SingleArrayAggregate ast, Void obj) { + var d1 = ast.E.visit(this); + return layoutUnary("Sing.ArrayAgg.", d1); + } + + // Record Aggregates + @Override + public DrawingTree visitMultipleRecordAggregate(MultipleRecordAggregate ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.E.visit(this); + var d3 = ast.RA.visit(this); + return layoutTernary("Mult.Rec.Agg.", d1, d2, d3); + } + + @Override + public DrawingTree visitSingleRecordAggregate(SingleRecordAggregate ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.E.visit(this); + return layoutBinary("Sing.Rec.Agg.", d1, d2); + } + + // Formal Parameters + @Override + public DrawingTree visitConstFormalParameter(ConstFormalParameter ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.T.visit(this); + return layoutBinary("ConstF.P.", d1, d2); + } + + @Override + public DrawingTree visitFuncFormalParameter(FuncFormalParameter ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.FPS.visit(this); + var d3 = ast.T.visit(this); + return layoutTernary("FuncF.P.", d1, d2, d3); + } + + @Override + public DrawingTree visitProcFormalParameter(ProcFormalParameter ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.FPS.visit(this); + return layoutBinary("ProcF.P.", d1, d2); + } + + @Override + public DrawingTree visitVarFormalParameter(VarFormalParameter ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.T.visit(this); + return layoutBinary("VarF.P.", d1, d2); + } + + @Override + public DrawingTree visitEmptyFormalParameterSequence(EmptyFormalParameterSequence ast, Void obj) { + return layoutNullary("EmptyF.P.S."); + } + + @Override + public DrawingTree visitMultipleFormalParameterSequence(MultipleFormalParameterSequence ast, Void obj) { + var d1 = ast.FP.visit(this); + var d2 = ast.FPS.visit(this); + return layoutBinary("Mult.F.P.S.", d1, d2); + } + + @Override + public DrawingTree visitSingleFormalParameterSequence(SingleFormalParameterSequence ast, Void obj) { + var d1 = ast.FP.visit(this); + return layoutUnary("Sing.F.P.S.", d1); + } + + // Actual Parameters + @Override + public DrawingTree visitConstActualParameter(ConstActualParameter ast, Void obj) { + var d1 = ast.E.visit(this); + return layoutUnary("ConstA.P.", d1); + } + + @Override + public DrawingTree visitFuncActualParameter(FuncActualParameter ast, Void obj) { + var d1 = ast.I.visit(this); + return layoutUnary("FuncA.P.", d1); + } + + @Override + public DrawingTree visitProcActualParameter(ProcActualParameter ast, Void obj) { + var d1 = ast.I.visit(this); + return layoutUnary("ProcA.P.", d1); + } + + @Override + public DrawingTree visitVarActualParameter(VarActualParameter ast, Void obj) { + var d1 = ast.V.visit(this); + return layoutUnary("VarA.P.", d1); + } + + @Override + public DrawingTree visitEmptyActualParameterSequence(EmptyActualParameterSequence ast, Void obj) { + return layoutNullary("EmptyA.P.S."); + } + + @Override + public DrawingTree visitMultipleActualParameterSequence(MultipleActualParameterSequence ast, Void obj) { + var d1 = ast.AP.visit(this); + var d2 = ast.APS.visit(this); + return layoutBinary("Mult.A.P.S.", d1, d2); + } + + @Override + public DrawingTree visitSingleActualParameterSequence(SingleActualParameterSequence ast, Void obj) { + var d1 = ast.AP.visit(this); + return layoutUnary("Sing.A.P.S.", d1); + } + + // Type Denoters + @Override + public DrawingTree visitAnyTypeDenoter(AnyTypeDenoter ast, Void obj) { + return layoutNullary("any"); + } + + @Override + public DrawingTree visitArrayTypeDenoter(ArrayTypeDenoter ast, Void obj) { + var d1 = ast.IL.visit(this); + var d2 = ast.T.visit(this); + return layoutBinary("ArrayTypeD.", d1, d2); + } + + @Override + public DrawingTree visitBoolTypeDenoter(BoolTypeDenoter ast, Void obj) { + return layoutNullary("bool"); + } + + @Override + public DrawingTree visitCharTypeDenoter(CharTypeDenoter ast, Void obj) { + return layoutNullary("char"); + } + + @Override + public DrawingTree visitErrorTypeDenoter(ErrorTypeDenoter ast, Void obj) { + return layoutNullary("error"); + } + + @Override + public DrawingTree visitSimpleTypeDenoter(SimpleTypeDenoter ast, Void obj) { + var d1 = ast.I.visit(this); + return layoutUnary("Sim.TypeD.", d1); + } + + @Override + public DrawingTree visitIntTypeDenoter(IntTypeDenoter ast, Void obj) { + return layoutNullary("int"); + } + + @Override + public DrawingTree visitRecordTypeDenoter(RecordTypeDenoter ast, Void obj) { + var d1 = ast.FT.visit(this); + return layoutUnary("Rec.TypeD.", d1); + } + + @Override + public DrawingTree visitMultipleFieldTypeDenoter(MultipleFieldTypeDenoter ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.T.visit(this); + var d3 = ast.FT.visit(this); + return layoutTernary("Mult.F.TypeD.", d1, d2, d3); + } + + @Override + public DrawingTree visitSingleFieldTypeDenoter(SingleFieldTypeDenoter ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.T.visit(this); + return layoutBinary("Sing.F.TypeD.", d1, d2); + } + + // Literals, Identifiers and Operators + @Override + public DrawingTree visitCharacterLiteral(CharacterLiteral ast, Void obj) { + return layoutNullary(ast.spelling); + } + + @Override + public DrawingTree visitIdentifier(Identifier ast, Void obj) { + return layoutNullary(ast.spelling); + } + + @Override + public DrawingTree visitIntegerLiteral(IntegerLiteral ast, Void obj) { + return layoutNullary(ast.spelling); + } + + @Override + public DrawingTree visitOperator(Operator ast, Void obj) { + return layoutNullary(ast.spelling); + } + + // Value-or-variable names + @Override + public DrawingTree visitDotVname(DotVname ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.V.visit(this); + return layoutBinary("DotVname", d1, d2); + } + + @Override + public DrawingTree visitSimpleVname(SimpleVname ast, Void obj) { + var d1 = ast.I.visit(this); + return layoutUnary("Sim.Vname", d1); + } + + @Override + public DrawingTree visitSubscriptVname(SubscriptVname ast, Void obj) { + var d1 = ast.V.visit(this); + var d2 = ast.E.visit(this); + return layoutBinary("Sub.Vname", d1, d2); + } + + // Programs + @Override + public DrawingTree visitProgram(Program ast, Void obj) { + var d1 = ast.C.visit(this); + return layoutUnary("Program", d1); + } + + private DrawingTree layoutCaption(String name) { + var w = fontMetrics.stringWidth(name) + 4; + var h = fontMetrics.getHeight() + 4; + return new DrawingTree(name, w, h); + } + + private DrawingTree layoutNullary(String name) { + var dt = layoutCaption(name); + dt.contour.upper_tail = new Polyline(0, dt.height + 2 * BORDER, null); + dt.contour.upper_head = dt.contour.upper_tail; + dt.contour.lower_tail = new Polyline(-dt.width - 2 * BORDER, 0, null); + dt.contour.lower_head = new Polyline(0, dt.height + 2 * BORDER, dt.contour.lower_tail); + return dt; + } + + private DrawingTree layoutUnary(String name, DrawingTree d1) { + var dt = layoutCaption(name); + dt.setChildren(new DrawingTree[] { d1 }); + attachParent(dt, join(dt)); + return dt; + } + + private DrawingTree layoutBinary(String name, DrawingTree d1, DrawingTree d2) { + var dt = layoutCaption(name); + dt.setChildren(new DrawingTree[] { d1, d2 }); + attachParent(dt, join(dt)); + return dt; + } + + private DrawingTree layoutTernary(String name, DrawingTree d1, DrawingTree d2, DrawingTree d3) { + var dt = layoutCaption(name); + dt.setChildren(new DrawingTree[] { d1, d2, d3 }); + attachParent(dt, join(dt)); + return dt; + } + + private DrawingTree layoutQuaternary(String name, DrawingTree d1, DrawingTree d2, DrawingTree d3, DrawingTree d4) { + var dt = layoutCaption(name); + dt.setChildren(new DrawingTree[] { d1, d2, d3, d4 }); + attachParent(dt, join(dt)); + return dt; + } + + private void attachParent(DrawingTree dt, int w) { + var y = PARENT_SEP; + var x2 = (w - dt.width) / 2 - BORDER; + var x1 = x2 + dt.width + 2 * BORDER - w; + + dt.children[0].offset.y = y + dt.height; + dt.children[0].offset.x = x1; + dt.contour.upper_head = new Polyline(0, dt.height, new Polyline(x1, y, dt.contour.upper_head)); + dt.contour.lower_head = new Polyline(0, dt.height, new Polyline(x2, y, dt.contour.lower_head)); + } + + private int join(DrawingTree dt) { + + dt.contour = dt.children[0].contour; + var sum = dt.children[0].width + 2 * BORDER; + var w = sum; + + for (var i = 1; i < dt.children.length; i++) { + var d = merge(dt.contour, dt.children[i].contour); + dt.children[i].offset.x = d + w; + dt.children[i].offset.y = 0; + w = dt.children[i].width + 2 * BORDER; + sum += d + w; + } + return sum; + } + + private int merge(Polygon c1, Polygon c2) { + int x = 0, y = 0, total = 0; + var upper = c1.lower_head; + var lower = c2.upper_head; + + while (lower != null && upper != null) { + var d = offset(x, y, lower.dx, lower.dy, upper.dx, upper.dy); + x += d; + total += d; + + if (y + lower.dy <= upper.dy) { + x += lower.dx; + y += lower.dy; + lower = lower.link; + } else { + x -= upper.dx; + y -= upper.dy; + upper = upper.link; + } + } + + if (lower != null) { + var b = bridge(c1.upper_tail, 0, 0, lower, x, y); + c1.upper_tail = (b.link != null) ? c2.upper_tail : b; + c1.lower_tail = c2.lower_tail; + } else { + var b = bridge(c2.lower_tail, x, y, upper, 0, 0); + if (b.link == null) { + c1.lower_tail = b; + } + } + + c1.lower_head = c2.lower_head; + + return total; + } + + private int offset(int p1, int p2, int a1, int a2, int b1, int b2) { + + if (b2 <= p2 || p2 + a2 <= 0) { + return 0; + } + + var t = b2 * a1 - a2 * b1; + if (t > 0) { + if (p2 < 0) { + var s = p2 * a1; + return Math.max(0, s / a2 - p1); + } else if (p2 > 0) { + var s = p2 * b1; + return Math.max(0, s / b2 - p1); + } else { + return Math.max(0, -p1); + } + } else if (b2 < p2 + a2) { + var s = (b2 - p2) * a1; + return Math.max(0, b1 - (p1 + s / a2)); + } else if (b2 > p2 + a2) { + var s = (a2 + p2) * b1; + return Math.max(0, s / b2 - (p1 + a1)); + } else { + return Math.max(0, b1 - (p1 + a1)); + } + } + + private Polyline bridge(Polyline line1, int x1, int y1, Polyline line2, int x2, int y2) { + + int dx; + var dy = y2 + line2.dy - y1; + if (line2.dy == 0) { + dx = line2.dx; + } else { + var s = dy * line2.dx; + dx = s / line2.dy; + } + + var r = new Polyline(dx, dy, line2.link); + line1.link = new Polyline(x2 + line2.dx - dx - x1, 0, r); + + return r; + } + +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/treeDrawer/Polygon.java b/Triangle.Compiler/src/main/java/triangle/treeDrawer/Polygon.java new file mode 100644 index 0000000..848c81d --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/treeDrawer/Polygon.java @@ -0,0 +1,24 @@ +/* + * @(#)Polygon.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.treeDrawer; + +class Polygon { + Polyline lower_head, lower_tail; + Polyline upper_head, upper_tail; +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/treeDrawer/Polyline.java b/Triangle.Compiler/src/main/java/triangle/treeDrawer/Polyline.java new file mode 100644 index 0000000..3885bef --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/treeDrawer/Polyline.java @@ -0,0 +1,33 @@ +/* + * @(#)Polyline.java + * + * Revisions and updates (c) 2022-2023 Sandy Brownlee. alexander.brownlee@stir.ac.uk + * + * Original release: + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.treeDrawer; + +/** + * used to keep track of the position for components in the tree to be drawn + */ +class Polyline { + int dx, dy; + Polyline link; + + Polyline(int dx, int dy, Polyline link) { + this.dx = dx; + this.dy = dy; + this.link = link; + } +} diff --git a/Triangle.Compiler/src/test/java/triangle/syntacticAnalyser/TestScanner.java b/Triangle.Compiler/src/test/java/triangle/syntacticAnalyser/TestScanner.java new file mode 100644 index 0000000..5113b97 --- /dev/null +++ b/Triangle.Compiler/src/test/java/triangle/syntacticAnalyser/TestScanner.java @@ -0,0 +1,92 @@ +package triangle.syntacticAnalyser; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertThrows; + +import org.junit.Test; +import org.junit.function.ThrowingRunnable; + +import triangle.ErrorReporter; +import triangle.syntacticAnalyzer.Parser; +import triangle.syntacticAnalyzer.Scanner; +import triangle.syntacticAnalyzer.SourceFile; + +public class TestScanner { + + @Test + public void testHi() { + compileExpectSuccess("/hi.tri"); + } + + + @Test + public void testHiNewComment() { + compileExpectFailure("/hi-newcomment.tri"); + } + + + @Test + public void testHiNewComment2() { + compileExpectFailure("/hi-newcomment2.tri"); + } + + + @Test + public void testBarDemo() { + compileExpectFailure("/bardemo.tri"); + } + + + @Test + public void testRepeatUntil() { + compileExpectFailure("/repeatuntil.tri"); + } + + @Test + public void testDouble() { + compileExpectSuccess("/double.tri"); + } + + @Test + public void testCurly() { + compileExpectSuccess("/while-curly.tri"); + } + + private void compileExpectSuccess(String filename) { + // build.gradle has a line sourceSets.test.resources.srcDir file("$rootDir/programs") + // which adds the programs directory to the list of places Java can easily find files + // getResource() below searches for a file, which is in /programs + //SourceFile source = SourceFile.ofPath(this.getClass().getResource(filename).getFile().toString()); + SourceFile source = SourceFile.fromResource(filename); + + Scanner scanner = new Scanner(source); + ErrorReporter reporter = new ErrorReporter(true); + Parser parser = new Parser(scanner, reporter); + + parser.parseProgram(); + + // we should get to here with no exceptions + + assertEquals("Problem compiling " + filename, 0, reporter.getNumErrors()); + } + + private void compileExpectFailure(String filename) { + //SourceFile source = SourceFile.ofPath(this.getClass().getResource(filename).getFile().toString()); + SourceFile source = SourceFile.fromResource(filename); + Scanner scanner = new Scanner(source); + ErrorReporter reporter = new ErrorReporter(true); + Parser parser = new Parser(scanner, reporter); + + // we expect an exception here as the program has invalid syntax + assertThrows(RuntimeException.class, new ThrowingRunnable() { + public void run(){ + parser.parseProgram(); + } + }); + + // currently this program will fail + assertNotEquals("Problem compiling " + filename, 0, reporter.getNumErrors()); + } + +} diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..a0aaa2c --- /dev/null +++ b/build.gradle @@ -0,0 +1,26 @@ +apply plugin: 'java' + +sourceCompatibility = 11 + +repositories { + mavenCentral() +} + +subprojects.each { subproject -> + evaluationDependsOn(subproject.path) +} + +dependencies { + implementation group: 'com.github.spullara.cli-parser', name: 'cli-parser', version: '1.1.5' +} + +jar { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } + + + from subprojects.sourceSets.main.output +} diff --git a/build/libs/Triangle-Tools.jar b/build/libs/Triangle-Tools.jar new file mode 100644 index 0000000000000000000000000000000000000000..6fba01e8836b2b07f21152f417c37aab2a48ddca GIT binary patch literal 197392 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
-U{F!~J6X^L9J310b;~**~a_rMcQH*K9W< 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

lbm_^SBMeChbUEig1ic@p;?rX^fqEJ(FlR_!; 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

~2O=#GZFNLC$QO_4(6* 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 S1~*XPpKji;uTy~1|NjA#ojYy- literal 0 HcmV?d00001 diff --git a/curl.tam b/curl.tam new file mode 100644 index 0000000000000000000000000000000000000000..e4c12dfa52c932e90f2d652e0ec1c8d38d85bed5 GIT binary patch literal 256 zcmZ{eT@HXS2!rc?qDG%Qp!dIo{cvVviA|t%P?)4u6`jkW%BV(Xf*#mkii|hU-`2CE lkFInT&i*{l&OE*T3?8dht3V1s|0Y98#0UrPW literal 0 HcmV?d00001 diff --git a/double.tam b/double.tam new file mode 100644 index 0000000000000000000000000000000000000000..5a998e0fe4c8a54db05034120bf1c65ac8511402 GIT binary patch literal 304 zcmZQzVBlgv07f8_8Nmh1u>koX43dKZWInQbCZGZ~AO_JOzzM{J^dqa61gb~oi-QaS T0(#oV4Y3kTg8a;n#Ag5ij5Yxe literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7f93135c49b765f8051ef9d0a6055ff8e46073d8 GIT binary patch literal 63721 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鯊%1Et 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⁢ zv5o9#E7!G0XmdzfsS{efPNi`1b44~SZ4Z8fuX!I}#8g+(wxzQwUT#Xb2(tbY1+EUhGKoT@KEU9Ktl>_0 z%bjDJg;#*gtJZv!-Zs`?^}v5eKmnbjqlvnSzE@_SP|LG_PJ6CYU+6zY6>92%E+ z=j@TZf-iW4(%U{lnYxQA;7Q!b;^brF8n0D>)`q5>|WDDXLrqYU_tKN2>=#@~OE7grMnNh?UOz-O~6 z6%rHy{#h9K0AT+lDC7q4{hw^|q6*Ry;;L%Q@)Ga}$60_q%D)rv(CtS$CQbpq9|y1e zRSrN4;$Jyl{m5bZw`$8TGvb}(LpY{-cQ)fcyJv7l3S52TLXVDsphtv&aPuDk1OzCA z4A^QtC(!11`IsNx_HnSy?>EKpHJWT^wmS~hc^p^zIIh@9f6U@I2 zC=Mve{j2^)mS#U$e{@Q?SO6%LDsXz@SY+=cK_QMmXBIU)j!$ajc-zLx3V60EXJ!qC zi<%2x8Q24YN+&8U@CIlN zrZkcT9yh%LrlGS9`G)KdP(@9Eo-AQz@8GEFWcb7U=a0H^ZVbLmz{+&M7W(nXJ4sN8 zJLR7eeK(K8`2-}j(T7JsO`L!+CvbueT%izanm-^A1Dn{`1Nw`9P?cq;7no+XfC`K(GO9?O^5zNIt4M+M8LM0=7Gz8UA@Z0N+lg+cX)NfazRu z5D)~HA^(u%w^cz+@2@_#S|u>GpB+j4KzQ^&Wcl9f z&hG#bCA(Yk0D&t&aJE^xME^&E-&xGHhXn%}psEIj641H+Nl-}boj;)Zt*t(4wZ5DN z@GXF$bL=&pBq-#vkTkh>7hl%K5|3 z{`Vn9b$iR-SoGENp}bn4;fR3>9sA%X2@1L3aE9yTra;Wb#_`xWwLSLdfu+PAu+o3| zGVnpzPr=ch{uuoHjtw7+_!L_2;knQ!DuDl0R`|%jr+}jFzXtrHIKc323?JO{l&;VF z*L1+}JU7%QJOg|5|Tc|D8fN zJORAg=_vsy{ak|o);@)Yh8Lkcg@$FG3k@ep36BRa^>~UmnRPziS>Z=`Jb2x*Q#`%A zU*i3&Vg?TluO@X0O;r2Jl6LKLUOVhSqg1*qOt^|8*c7 zo(298@+r$k_wQNGHv{|$tW(T8L+4_`FQ{kEW5Jgg{yf7ey4ss_(SNKfz(N9lx&a;< je(UuV8hP?p&}TPdm1I$XmG#(RzlD&B2izSj9sl%y5~4qc literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..ac72c34 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..0adc8e1 --- /dev/null +++ b/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..93e3f59 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/hi.tam b/hi.tam new file mode 100644 index 0000000000000000000000000000000000000000..11b8a308c9f8e4c28ab308d4f93e993bf205f303 GIT binary patch literal 192 zcmZQzVBlgv07f8_8Np>>0kUBjBnJZ^F&H0NJrhuz4TwQB2yg;1A^pheC4uUZ`Qku6 PHxR=B$WDG32Sft^Fh2mG literal 0 HcmV?d00001 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..596a93b --- /dev/null +++ b/pom.xml @@ -0,0 +1,19 @@ + + 4.0.0 + triangle.tools + triangle-tools + 2.1 + pom + + 17 + 17 + UTF-8 + + + Triangle.AbstractMachine + Triangle.Compiler + Triangle.AbstractMachine.Disassembler + Triangle.AbstractMachine.Interpreter + + \ No newline at end of file diff --git a/programs/adddeep.tri b/programs/adddeep.tri new file mode 100644 index 0000000..5f33bc1 --- /dev/null +++ b/programs/adddeep.tri @@ -0,0 +1,12 @@ +let + var a: Integer +in +begin + a := 10 + 20 * 2 / 3; + putint(a); + + puteol(); + + a := 5 + 8; + putint(a) +end diff --git a/programs/arrays.tri b/programs/arrays.tri new file mode 100644 index 0000000..1cfbd28 --- /dev/null +++ b/programs/arrays.tri @@ -0,0 +1,47 @@ +let + type Vector ~ array 3 of Integer; + type Matrix ~ array 3 of Vector; + + proc putvector (v: Vector) ~ + let var i: Integer + in + begin + put ('['); putint (v[0]); + i := 1; + while i < 3 do + begin + put (' '); putint (v[i]); + i := i+1 + end; + put (']') + end; + + proc putmatrix (m: Matrix) ~ + let var i: Integer + in + begin + i := 0; + while i < 3 do + begin + putvector (m[i]); + puteol (); + i := i+1 + end + end; + + func diagonal + (m: Matrix): Vector ~ + [m[0][0], m[1][1], m[2][2]]; + + var me: Matrix + +in + begin + me := [[1,2,3], [4,5,6], [7,8,9]]; + putmatrix (me); puteol (); + putvector (diagonal (me)); + puteol (); puteol (); + me[1] := [10,11,12]; + me[1][1] := 22; + putmatrix (me); puteol () + end diff --git a/programs/assignments.tri b/programs/assignments.tri new file mode 100644 index 0000000..102bb78 --- /dev/null +++ b/programs/assignments.tri @@ -0,0 +1,9 @@ +let + var n : Integer; + var c : Char +in + + begin + c := '&'; + n := n + 1 + end diff --git a/programs/bank.tri b/programs/bank.tri new file mode 100644 index 0000000..e7f3c0f --- /dev/null +++ b/programs/bank.tri @@ -0,0 +1,86 @@ +let + const max ~ 9999; + const invalid ~ 0-1; + type Money ~ Integer; ! 0 .. max + type Trans ~ Char; ! 'd' | 'w' | 'q' + + func sum (m: Money, n: Money): Money ~ + let const s ~ m + n + in + if s <= max then s else invalid; + + func diff (m: Money, n: Money): Money ~ + let const d ~ m - n + in + if 0 <= d then d else invalid; + + proc gettrans (var code: Trans, + var amount: Money) ~ + begin + get(var code); + if code = 'q' then + ! skip + else + begin + getint(var amount); + if (0 > amount) \/ (amount > max) then + begin + amount := invalid; code := '?' + end + else if (code \= 'd') /\ (code \= 'w') then + code := '?' + else + ! ok + end; + geteol() + end; + + proc processtrans (code: Trans, + amount: Money, + var balance: Money) ~ + let + var newbalance: Money + in + begin + if code = 'd' then + begin + put('D'); put('e'); put('p'); put('o'); put('s'); + put('i'); put('t'); put(' '); + putint(amount); puteol(); + newbalance := sum(balance, amount) + end + else if code = 'w' then + begin + put('W'); put('i'); put('t'); put('h'); put('d'); + put('r'); put('a'); put('w'); put(' '); + putint(amount); puteol(); + newbalance := diff(balance, amount) + end + else + ; !skip + if (code = '?') \/ (newbalance = invalid) then + begin + put('I'); put('n'); put('v'); put('a'); put('l'); + put('i'); put('d'); puteol() + end + else + balance := newbalance; + put('B'); put('a'); put('l'); put('a'); put('n'); + put('c'); put('e'); put(' '); + putint(balance); puteol(); + end; + + var balance: Money; + var amount: Money; + var trans: Trans + +in + begin + balance := 0; + gettrans(var trans, var amount); + while trans \= 'q' do + begin + processtrans(trans, amount, var balance); + gettrans(var trans, var amount) + end + end diff --git a/programs/bardemo.tri b/programs/bardemo.tri new file mode 100644 index 0000000..f730f74 --- /dev/null +++ b/programs/bardemo.tri @@ -0,0 +1,19 @@ +! this won't work until after some work in the practicals +let + var a : Integer; + var b : Integer + +in + begin + a := 1; + b := 2; + + putint(a); + puteol(); + putint(b); + puteol(); + putint(|a); + puteol(); + putint(|b); + puteol() + end diff --git a/programs/control.tri b/programs/control.tri new file mode 100644 index 0000000..9d76146 --- /dev/null +++ b/programs/control.tri @@ -0,0 +1,26 @@ +! Plot a histogram from a stream of nonzero integers. + +let + const mark ~ '+'; + var n : Integer +in + begin + getint (var n); geteol (); + while n \= 0 do + let + var i : Integer; + var gap : Integer + in + begin + gap := if n > 0 then 20 else 20 + n; + if n < 0 then n := 0 - n else ; + i := 0; + while i < gap do + begin put (' '); i := i + 1 end; + i := 0; + while i < n do + begin put (mark); i := i + 1 end; + puteol (); + getint (var n); geteol () + end + end diff --git a/programs/deepnest.tri b/programs/deepnest.tri new file mode 100644 index 0000000..315b123 --- /dev/null +++ b/programs/deepnest.tri @@ -0,0 +1,16 @@ +let proc p1 () ~ + let var c1: Char; + proc p2 () ~ + let proc p3 () ~ + let proc p4 () ~ + let proc p5 () ~ + let proc p6 () ~ + let proc p7 () ~ + put (c1) + in p7 () + in p6 () + in p5 () + in p4 () + in p3 () + in begin c1 := '+'; p2 () end +in p1 () diff --git a/programs/directories.tri b/programs/directories.tri new file mode 100644 index 0000000..49e6794 --- /dev/null +++ b/programs/directories.tri @@ -0,0 +1,117 @@ +let + type Name ~ array 6 of Char; + type Number ~ Integer; + + proc prompt () ~ + begin + put('N'); put('a'); put('m'); put('e'); + put('?'); put(' ') + end; + + proc getname (var newname: Name) ~ + let var i: Integer + in + begin + i := 0; + while i < 6 do + begin + if eol () then + newname[i] := ' ' + else + get (var newname[i]); + i := i+1 + end + end; + + proc putname (newname: Name) ~ + let var i: Integer + in + begin + i := 0; + while i < 6 do + begin + put (newname[i]); + i := i+1 + end + end; + + type Entry ~ record + number: Number, + name: Name + end; + type Directory ~ record + size: Integer, + entry: array 100 of Entry + end; + + proc initialize (var dir: Directory) ~ + dir.size := 0; + + proc add (var dir: Directory, + newname: Name, + newnumber: Number) ~ + begin + dir.entry[dir.size] := + {number ~ newnumber, name ~ newname}; + dir.size := dir.size + 1 + end; + + proc lookup (var dir: Directory, + oldname: Name, + var oldnumber: Number, + var found: Boolean) ~ + let + var i: Integer; + var searching: Boolean + in + begin + i := 0; searching := true; + while (i < dir.size) /\ searching do + if dir.entry[i].name = oldname then + searching := false + else + i := i+1; + found := \searching; + if found then + oldnumber := dir.entry[i].number + else !skip + end; + + var mydir: Directory + +in + + begin + initialize (var mydir); + add (var mydir, + ['D','a','v','i','d',' '], 6041); + add (var mydir, + ['M','u','f','f','y',' '], 4969); + add (var mydir, + ['K','i','e','r','a','n'], 6042); + add (var mydir, + ['A','l','e','x','a',' '], 5322); + + let + const blank ~ [' ', ' ', ' ', ' ', ' ', ' ']; + var name: Name; + var num: Number; + var ok: Boolean + in + begin + prompt (); + getname (var name); geteol (); + while name \= blank do + begin + putname (name); put (' '); + lookup (var mydir, name, var num, var ok); + if ok then + putint (num) + else + put ('?'); + puteol (); + prompt (); + getname (var name); geteol () + end + end + end diff --git a/programs/double.tri b/programs/double.tri new file mode 100644 index 0000000..f5f287b --- /dev/null +++ b/programs/double.tri @@ -0,0 +1,16 @@ +! for a given input integer a, should print a*2 and a*4 + +let + var a: Integer +in +begin + ! getint(var a); + a := 10; + + a**; + putint(a); + puteol(); + a**; + putint(a); + puteol(); +end diff --git a/programs/errors.tri b/programs/errors.tri new file mode 100644 index 0000000..ed0e097 --- /dev/null +++ b/programs/errors.tri @@ -0,0 +1,30 @@ +! Program with a variety of contextual errors. + +let + type String ~ array 4 of Char; + type Name ~ array 3 of String; + type Rec ~ record x: Integer, x: Integer end; + + var me: Name; + var silly : maxint; + var silly: Rec; + + proc putstr (s: String) ~ + let var i: Integer + in + begin + s[4] := ' '; + i := 0; + while i do + begin i := i+true; + put (s[\i]) + end + end + +in + begin + me[true] := ['T','i','n','y']; + me[2][2] := 0; + put (me[1]); put (4); put (); + putstr (initials (me)); puteol () + end diff --git a/programs/every.tri b/programs/every.tri new file mode 100644 index 0000000..011fd1c --- /dev/null +++ b/programs/every.tri @@ -0,0 +1,148 @@ +! Marry a woman and man. +! Input following data for each person (woman then man): +! surname, forename (each up to 10 non-blank chars), +! sex ('M'|'F'), marital status ('m'|'u'), +! day, month, year of birth. + +let + type Month ~ Integer; + const Jan ~ 1; const Feb ~ 2; const Mar ~ 3; + const Apr ~ 4; const May ~ 5; const Jun ~ 6; + const Jul ~ 7; const Aug ~ 8; const Sep ~ 9; + const Oct ~ 10; const Nov ~ 11; const Dec ~ 12; + + type Date ~ record + y : Integer, + m : Month, + d : Integer + end; + const today ~ {y ~ 1993, m ~ Apr, d ~ 1}; + + proc getdate (var date : Date) ~ + begin + getint (var date.d); getint (var date.m); getint (var date.y) + end; + + proc putdate (date : Date) ~ + begin + putint (date.d); put ('/'); + putint (date.m); put ('/'); + putint (date.y // 100) + end; + + func yearsbefore (yrs : Integer, date : Date) : Date ~ + {y ~ date.y - yrs, m ~ date.m, d ~ date.d}; + + func earlier (date1 : Date, date2 : Date) : Boolean ~ + if date1.y < date2.y then true + else if date1.y > date2.y then false + else if date1.m < date2.m then true + else if date1.m > date2.m then false + else date1.d < date2.d; + + const maxname ~ 10; + type Name ~ array 10 of Char; + + proc getname (var name : Name) ~ + let + var ch : Char; + var length : Integer + in + begin + get (var ch); while ch = ' ' do get (var ch); + length := 0; + while length < maxname do + begin + length := length + 1; name[length] := ch; + if ch \= ' ' then get (var ch) else ! skip + end + end; + + proc putname (name : Name) ~ + let + var pad : Boolean; + var length : Integer + in + begin + pad := false; length := 0; + while (\ pad) /\ (length < maxname) do + begin + length := length + 1; + if name[length] = ' ' then + pad := true + else + put (name[length]) + end + end; + + type Person ~ record + surname : Name, + forename : Name, + male : Boolean, + married : Boolean, + dob : Date + end; + + proc getperson (var person : Person) ~ + let + var fore : Name; + var sur : Name; + var s : Char; + var m : Char; + var birth : Date + in + begin + getname (var sur); getname (var fore); + get (var s); while s = ' ' do get (var s); + get (var m); while m = ' ' do get (var m); + getdate (var birth); + person := {surname ~ sur, forename ~ fore, + male ~ (s = 'M'), married ~ (m = 'm'), + dob ~ birth} + end; + + proc putperson (person : Person) ~ + begin + putname (person.surname); put (' '); + putname (person.forename); put (' '); + put (if person.male then 'M' else 'F'); put (' '); + put (if person.married then 'm' else 'u'); put (' '); + putdate (person.dob) + end; + + func age (person : Person) : Integer ~ + let + const dob ~ person.dob + in + if (today.m > dob.m) \/ + ((today.m = dob.m) /\ (today.d >= dob.d)) + then today.y - dob.y + else today.y - dob.y - 1; + + const latestdob ~ yearsbefore (16, today); + + var bride : Person; + var groom : Person + +in + begin + getperson (var bride); + getperson (var groom); + puteol (); + if \ bride.male /\ groom.male /\ + \ (bride.married \/ groom.married) /\ + \ earlier (latestdob, bride.dob) /\ + \ earlier (latestdob, groom.dob) then + begin + put ('O'); put ('K'); puteol (); + bride.married := true; groom.married := true; + bride.surname := groom.surname + end + else + begin + put ('N'); put ('o'); put ('!'); puteol () + end; + putperson (bride); put (' '); putint (age (bride)); puteol (); + putperson (groom); put (' '); putint (age (groom)); puteol (); + putdate (today); puteol () + end diff --git a/programs/factorials.tri b/programs/factorials.tri new file mode 100644 index 0000000..c1db33c --- /dev/null +++ b/programs/factorials.tri @@ -0,0 +1,15 @@ +let + func factorial (n: Integer): Integer ~ + if n <= 1 + then 1 + else n * factorial (n-1); + + var i: Integer + +in + begin + getint (var i); + putint (i); put ('!'); + put (' '); put ('='); put (' '); + putint (factorial (i)) + end diff --git a/programs/functions.tri b/programs/functions.tri new file mode 100644 index 0000000..d343874 --- /dev/null +++ b/programs/functions.tri @@ -0,0 +1,28 @@ +! Print powers of integers. + +let + func even (n : Integer) : Boolean ~ + (n // 2) = 0; + + func sqr (n : Integer) : Integer ~ + n * n; + + func power (b : Integer, n : Integer) : Integer ~ + ! assume n >= 0 + if n = 0 + then 1 + else + if even (n) + then sqr (power (b, n/2)) + else sqr (power (b, n/2)) * b; + + var x : Integer; + var m : Integer +in + begin + getint (var x); getint (var m); + putint (x); put ('^'); putint (m); + put (' '); put ('='); put (' '); + putint (power (x, m)); + puteol () + end diff --git a/programs/hi-newcomment.tri b/programs/hi-newcomment.tri new file mode 100644 index 0000000..0929f38 --- /dev/null +++ b/programs/hi-newcomment.tri @@ -0,0 +1,7 @@ +! this won't work until after some work in the practicals + +# new comment + +begin + put('H'); put('i'); put('!') +end diff --git a/programs/hi-newcomment2.tri b/programs/hi-newcomment2.tri new file mode 100644 index 0000000..4e764fc --- /dev/null +++ b/programs/hi-newcomment2.tri @@ -0,0 +1,11 @@ +! this won't work until after some work in the practicals + +# new comment + +$ +another new comment +$ + +begin + put('H'); put('i'); put('!') +end diff --git a/programs/hi.tam b/programs/hi.tam new file mode 100644 index 0000000000000000000000000000000000000000..26e8273394ea0093e3527aa8f5342c8302a0768d GIT binary patch literal 112 lcmZQzU|?oI01qIO4TzbbLZUz#Sw541ydoBPeyCYs3II>Z0YU%( literal 0 HcmV?d00001 diff --git a/programs/hi.tri b/programs/hi.tri new file mode 100644 index 0000000..aac4ec1 --- /dev/null +++ b/programs/hi.tri @@ -0,0 +1,3 @@ +begin + put('H'); put('i'); put('!') +end diff --git a/programs/hullo.tri b/programs/hullo.tri new file mode 100644 index 0000000..a7a40a0 --- /dev/null +++ b/programs/hullo.tri @@ -0,0 +1,53 @@ +let + const maxlength ~ 15; + type String ~ array 16 of Char; + const null ~ chr(0); +!Strings will be padded with nulls. + + proc getstring (var s: String) ~ + let var l: Integer + in + begin + l := 0; + while l < maxlength do + begin + if eol () then + s[l] := null + else + get (var s[l]); + l := l+1; + end; + s[maxlength] := null + end; + + proc putstring (s: String) ~ + let var i: Integer + in + begin + i := 0; + while s[i] \= null do + begin + put (s[i]); + i := i+1 + end + end; + + var you: String + +in + begin + putstring ( + ['W','h','o',' ', + 'a','r','e',' ', + 'y','o','u','?', + null,null,null,null]); + puteol (); + getstring (var you); geteol (); + putstring ( + ['H','u','l','l', + 'o',',',' ',null, + null,null,null,null, + null,null,null,null]); + putstring (you); put ('!'); + puteol () +end diff --git a/programs/ifdemo.tri b/programs/ifdemo.tri new file mode 100644 index 0000000..ddc4df3 --- /dev/null +++ b/programs/ifdemo.tri @@ -0,0 +1,9 @@ +let + var a : Integer; + var n : Integer +in + begin + if a < 0 + then n := 0 + else n := 1 + end diff --git a/programs/increment.tri b/programs/increment.tri new file mode 100644 index 0000000..11358a5 --- /dev/null +++ b/programs/increment.tri @@ -0,0 +1,14 @@ +! this won't compile without implementing the bonus material in Practical 3 + +let + var a: Integer +in +begin + getint(var a); + a++; + putint(a); + puteol(); + a++; + putint(a); + puteol(); +end diff --git a/programs/names.tri b/programs/names.tri new file mode 100644 index 0000000..741167a --- /dev/null +++ b/programs/names.tri @@ -0,0 +1,52 @@ +let + type Name ~ array 6 of Char; + type Number ~ Integer; + + proc getname (var newname: Name) ~ + let var i: Integer + in + begin + i := 0; + while i < 6 do + begin + if eol () then + newname[i] := ' ' + else + get (var newname[i]); + i := i+1 + end + end; + + proc putname (newname: Name) ~ + let var i: Integer + in + begin + i := 0; + while i < 6 do + begin + put (newname[i]); + i := i+1 + end + end; + + func samename (name1: Name, name2: Name) : Boolean ~ + let + func same (n: Integer) : Boolean ~ + (name1[n] = name2[n]) /\ + (if n = 0 then true else same (n-1)) + in + same (5); + + var nam: Name + +in + + begin + getname (var nam); geteol (); + putname (nam); put (' '); + if samename (nam, ['D','a','v','i','d',' ']) then + put ('Y') + else + put ('N'); + puteol () + end diff --git a/programs/nesting.tri b/programs/nesting.tri new file mode 100644 index 0000000..90838ca --- /dev/null +++ b/programs/nesting.tri @@ -0,0 +1,31 @@ +let + var g: Integer; + + proc P() ~ + let + var p: Integer; + + proc Q() ~ + let + var q: Integer; + proc R() ~ + let + var r: Integer + in + r := (g+p+q) * 1000 ! should cause overflow + in + begin q := g+p; R() end; + + proc S() ~ + let + var s: Integer + in + begin s := g+p+1; Q() end + + in + begin p := g+1; S() end + +in + begin g := 1000; P() end + + diff --git a/programs/procedural.tri b/programs/procedural.tri new file mode 100644 index 0000000..65263d0 --- /dev/null +++ b/programs/procedural.tri @@ -0,0 +1,56 @@ +! test program proc.Æ +let + const size ~ 6; + type String ~ array 6 of Char; + + proc putstr (s: String) ~ + let var i: Integer + in + begin + i := 0; + while i < size do + begin put (s[i]); i := i+1 end + end; + + proc apply (proc p (var c : Char), var s : String) ~ + let + var i : Integer + in + begin + i := 0; + while i < size do + begin + p (var s[i]); + i := i+1 + end + end; !apply + + proc shift (var l : Char) ~ + let const ordl ~ ord (l) + in + if (ord('a') <= ordl) + /\ (ordl <= ord('z')) then + l := chr (ordl - ord('a') + ord('A')) + else + ; !skip + + proc replaceall (old: Char, new: Char, + var s: String) ~ + let + proc zap (var c: Char) ~ + if c = old then c := new else !skip + in + apply (proc zap, var s); + + var name : String + +in + begin + apply (proc get, var name); + geteol (); + putstr (name); puteol (); + apply (proc shift, var name); + putstr (name); puteol (); + replaceall ('I', 'i', var name); + putstr (name); puteol () + end diff --git a/programs/procedures.tri b/programs/procedures.tri new file mode 100644 index 0000000..a72f68c --- /dev/null +++ b/programs/procedures.tri @@ -0,0 +1,31 @@ +! Plot a histogram from a stream of nonzero integers. + +let + const mid ~ 40; + var n : Integer; + + proc putmany (c : Char, n : Integer) ~ + let + var i : Integer + in + begin + i := 0; + while i < n do + begin put (c); i := i + 1 end + end; + + proc makenonnegative (var n : Integer) ~ + if n < 0 then n := 0 - n else + +in + begin + getint (var n); geteol (); + while n \= 0 do + begin + putmany (' ', if n > 0 then mid else mid + n); + makenonnegative (var n); + putmany ('+', n); + puteol (); + getint (var n); geteol () + end + end diff --git a/programs/records.tri b/programs/records.tri new file mode 100644 index 0000000..5d8f63e --- /dev/null +++ b/programs/records.tri @@ -0,0 +1,24 @@ +! test program record.Æ +let + type Month ~ array 3 of Char; + type Date ~ record d: Integer, m: Month end; + const xmas ~ {d ~ 25, + m ~ ['D','e','c']}; + var eve: Date; + + proc putmonth (mth: Month) ~ + begin + put (mth[0]); put (mth[1]); put (mth[2]) + end; + + proc putdate (date: Date) ~ + begin + putint (date.d); put ('/'); putmonth (date.m) + end + +in + begin + putdate (xmas); puteol (); + eve := {d ~ xmas.d-1, m ~ xmas.m}; + putdate (eve); puteol () + end \ No newline at end of file diff --git a/programs/repeatuntil.tri b/programs/repeatuntil.tri new file mode 100644 index 0000000..c2518de --- /dev/null +++ b/programs/repeatuntil.tri @@ -0,0 +1,14 @@ +! this won't work until after some lab work + +let + var a : Integer +in +begin + a := 0; + repeat + begin + put('a'); + a := a + 1; + end + until a >= 5 +end diff --git a/programs/repl.tri b/programs/repl.tri new file mode 100644 index 0000000..f6cf367 --- /dev/null +++ b/programs/repl.tri @@ -0,0 +1,13 @@ +let + type Str ~ array 10 of Char; + + func replicate (c: Char): Str ~ + [c,c,c,c,c,c,c,c,c,c]; + + var s: Str +in + + begin + s := replicate('*'); + put (s[0]); put(s[9]); puteol() + end diff --git a/programs/simpleadding.tri b/programs/simpleadding.tri new file mode 100644 index 0000000..139847a --- /dev/null +++ b/programs/simpleadding.tri @@ -0,0 +1,10 @@ +let + var a : Integer; + var b : Integer; + var c : Integer + +in + begin + a := 1; b := 2; c := a / b; + end + diff --git a/programs/starstart.tri b/programs/starstart.tri new file mode 100644 index 0000000..94e6ca4 --- /dev/null +++ b/programs/starstart.tri @@ -0,0 +1,10 @@ +let + var a: Integer +in +begin + a := 4; + a**; + + putint(a); + puteol(); +end diff --git a/programs/triangle.tri b/programs/triangle.tri new file mode 100644 index 0000000..555ea81 --- /dev/null +++ b/programs/triangle.tri @@ -0,0 +1,32 @@ +let + + proc putmany (n: Integer, c: Char) ~ + let + var i: Integer + in + begin + i := 0; + while i < n do + begin i := i+1; put (c) end + end; + + var n: Integer; var r: Integer; + const mark ~ '@' + +in + begin + getint (var n); geteol (); + r := 0; + while r < (n-1) do + begin + r := r + 1; + putmany (n-r, ' '); put (mark); + if r >= 2 then + begin + putmany (2*r - 3, ' '); put (mark) + end + else; !skip + puteol () + end; + putmany (2*n - 1, mark) + end diff --git a/programs/while-curly.tri b/programs/while-curly.tri new file mode 100644 index 0000000..052fc01 --- /dev/null +++ b/programs/while-curly.tri @@ -0,0 +1,13 @@ +! print out aaaaa + +let + var a : Integer +in +{ + a := 0; + while a < 5 do + { + put('a'); + a := a + 1; + } +} diff --git a/programs/while-longloop.tri b/programs/while-longloop.tri new file mode 100644 index 0000000..75b1088 --- /dev/null +++ b/programs/while-longloop.tri @@ -0,0 +1,22 @@ +let + var a : Integer; + var b : Integer; + var c : Integer +in +begin + put('1'); + puteol(); + a := 0; + while a < 5000 do + begin + b := 0; + while b < 3000 do + begin + c := c + a; + c := c / (1 + b); + b := b + 1; + end; + a := a + 1; + end; + putint(c); +end diff --git a/programs/while.tri b/programs/while.tri new file mode 100644 index 0000000..9bbb664 --- /dev/null +++ b/programs/while.tri @@ -0,0 +1,11 @@ +let + var a : Integer +in +begin + a := 0; + while a < 5 do + begin + put('a'); + a := a + 1; + end +end diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..5e273cd --- /dev/null +++ b/settings.gradle @@ -0,0 +1,7 @@ +rootProject.name = 'Triangle-Tools' + +include 'Triangle.Compiler' +include 'Triangle.AbstractMachine' +include 'Triangle.AbstractMachine.Disassembler' +include 'Triangle.AbstractMachine.Interpreter' + diff --git a/star.tam b/star.tam new file mode 100644 index 0000000000000000000000000000000000000000..11b8a308c9f8e4c28ab308d4f93e993bf205f303 GIT binary patch literal 192 zcmZQzVBlgv07f8_8Np>>0kUBjBnJZ^F&H0NJrhuz4TwQB2yg;1A^pheC4uUZ`Qku6 PHxR=B$WDG32Sft^Fh2mG literal 0 HcmV?d00001 diff --git a/while.tam b/while.tam new file mode 100644 index 0000000000000000000000000000000000000000..e4c12dfa52c932e90f2d652e0ec1c8d38d85bed5 GIT binary patch literal 256 zcmZ{eT@HXS2!rc?qDG%Qp!dIo{cvVviA|t%P?)4u6`jkW%BV(Xf*#mkii|hU-`2CE lkFInT&i*{l&OE*T3?8dht3V1s|0Y98#0UrPW literal 0 HcmV?d00001