2024-08-12 21:00:52 +02:00
|
|
|
module Language.Elna.Intermediate
|
|
|
|
( Label(..)
|
|
|
|
, Operand(..)
|
|
|
|
, Quadruple(..)
|
|
|
|
, Variable(..)
|
2024-08-15 20:13:56 +02:00
|
|
|
, intermediate
|
2024-08-12 21:00:52 +02:00
|
|
|
) where
|
|
|
|
|
|
|
|
import Data.Int (Int32)
|
2024-08-15 20:13:56 +02:00
|
|
|
import Data.HashMap.Strict (HashMap)
|
|
|
|
import qualified Data.HashMap.Strict as HashMap
|
2024-08-12 21:00:52 +02:00
|
|
|
import Data.Text (Text)
|
2024-08-15 20:13:56 +02:00
|
|
|
import Data.Word (Word32)
|
|
|
|
import Data.Vector (Vector)
|
|
|
|
import qualified Data.Vector as Vector
|
|
|
|
import qualified Language.Elna.AST as AST
|
|
|
|
import Language.Elna.Types (Type(..))
|
|
|
|
import Language.Elna.SymbolTable (SymbolTable, Info(..))
|
|
|
|
import qualified Language.Elna.SymbolTable as SymbolTable
|
2024-08-12 21:00:52 +02:00
|
|
|
|
|
|
|
data Operand
|
2024-08-15 20:13:56 +02:00
|
|
|
= VariableOperand Variable
|
2024-08-12 21:00:52 +02:00
|
|
|
| IntOperand Int32
|
|
|
|
deriving (Eq, Show)
|
|
|
|
|
|
|
|
newtype Label = Label Text
|
|
|
|
deriving (Eq, Show)
|
|
|
|
|
2024-08-15 20:13:56 +02:00
|
|
|
data Variable = Variable Text | TempVariable
|
2024-08-12 21:00:52 +02:00
|
|
|
deriving (Eq, Show)
|
|
|
|
|
|
|
|
data Quadruple
|
|
|
|
= StartQuadruple
|
|
|
|
| GoToQuadruple Label
|
|
|
|
| AssignQuadruple Operand Variable
|
2024-08-15 20:13:56 +02:00
|
|
|
| ArrayQuadruple Variable Operand Variable
|
2024-08-12 21:00:52 +02:00
|
|
|
| ArrayAssignQuadruple Operand Word32 Variable
|
|
|
|
| AddQuadruple Operand Operand Variable
|
|
|
|
| SubtractionQuadruple Operand Operand Variable
|
|
|
|
| ProductQuadruple Operand Operand Variable
|
|
|
|
| DivisionQuadruple Operand Operand Variable
|
|
|
|
| NegationQuadruple Operand Variable
|
|
|
|
| EqualQuadruple Operand Operand Label
|
|
|
|
| NonEqualQuadruple Operand Operand Label
|
|
|
|
| LessQuadruple Operand Operand Label
|
|
|
|
| GreaterQuadruple Operand Operand Label
|
|
|
|
| LessOrEqualQuadruple Operand Operand Label
|
|
|
|
| GreaterOrEqualQuadruple Operand Operand Label
|
|
|
|
| LabelQuadruple Label
|
|
|
|
| ParameterQuadruple Operand
|
|
|
|
| CallQuadruple Variable Word32
|
|
|
|
| StopQuadruple
|
|
|
|
deriving (Eq, Show)
|
2024-08-15 20:13:56 +02:00
|
|
|
|
|
|
|
intermediate :: SymbolTable -> AST.Program -> HashMap AST.Identifier (Vector Quadruple)
|
|
|
|
intermediate globalTable (AST.Program declarations) =
|
|
|
|
foldr go HashMap.empty declarations
|
|
|
|
where
|
|
|
|
go (AST.TypeDefinition _ _) accumulator = accumulator
|
|
|
|
go (AST.ProcedureDefinition procedureName _ _ statements) accumulator =
|
|
|
|
let translatedStatements
|
|
|
|
= Vector.cons StartQuadruple
|
|
|
|
$ flip Vector.snoc StopQuadruple
|
|
|
|
$ foldMap (statement globalTable) statements
|
|
|
|
in HashMap.insert procedureName translatedStatements accumulator
|
|
|
|
|
|
|
|
statement :: SymbolTable -> AST.Statement -> Vector Quadruple
|
|
|
|
statement _ AST.EmptyStatement = mempty
|
|
|
|
statement globalTable (AST.CompoundStatement statements) =
|
|
|
|
foldMap (statement globalTable) statements
|
|
|
|
|
|
|
|
variableAccess
|
|
|
|
:: SymbolTable
|
|
|
|
-> AST.VariableAccess
|
|
|
|
-> Maybe Operand
|
|
|
|
-> Type
|
|
|
|
-> Vector Quadruple
|
|
|
|
-> (AST.Identifier, Maybe Operand, Vector Quadruple)
|
|
|
|
variableAccess _ (AST.VariableAccess identifier) accumulatedIndex _ accumulatedStatements =
|
|
|
|
(identifier, accumulatedIndex, accumulatedStatements)
|
|
|
|
variableAccess localTable (AST.ArrayAccess access1 index1) Nothing (ArrayType _ baseType) _ =
|
|
|
|
let (indexPlace, statements) = expression localTable index1
|
|
|
|
in variableAccess localTable access1 (Just indexPlace) baseType statements
|
|
|
|
variableAccess localTable (AST.ArrayAccess arrayAccess' arrayIndex) (Just baseIndex) (ArrayType arraySize baseType) statements =
|
|
|
|
let (indexPlace, statements') = expression localTable arrayIndex
|
|
|
|
resultVariable = TempVariable
|
|
|
|
resultOperand = VariableOperand resultVariable
|
|
|
|
indexCalculation = Vector.fromList
|
|
|
|
[ ProductQuadruple (IntOperand $ fromIntegral arraySize) baseIndex resultVariable
|
|
|
|
, AddQuadruple indexPlace resultOperand resultVariable
|
|
|
|
]
|
|
|
|
in variableAccess localTable arrayAccess' (Just resultOperand) baseType
|
|
|
|
$ statements <> indexCalculation <> statements'
|
|
|
|
variableAccess _ _ _ _ _ = error "Array access operator doesn't match the type."
|
|
|
|
|
|
|
|
variableType :: AST.VariableAccess -> SymbolTable -> Type
|
|
|
|
variableType (AST.VariableAccess identifier) symbolTable
|
|
|
|
| Just (TypeInfo type') <- SymbolTable.lookup identifier symbolTable = type'
|
|
|
|
| otherwise = error "Undefined type."
|
|
|
|
variableType (AST.ArrayAccess arrayAccess' _) symbolTable =
|
|
|
|
variableType arrayAccess' symbolTable
|
|
|
|
|
|
|
|
expression :: SymbolTable -> AST.Expression -> (Operand, Vector Quadruple)
|
|
|
|
expression localTable = \case
|
|
|
|
(AST.VariableExpression variableExpression) ->
|
|
|
|
let variableType' = variableType variableExpression localTable
|
|
|
|
in case variableAccess localTable variableExpression Nothing variableType' mempty of
|
|
|
|
(AST.Identifier identifier, Nothing, statements) ->
|
|
|
|
(VariableOperand (Variable identifier), statements)
|
|
|
|
(AST.Identifier identifier, Just operand, statements) ->
|
|
|
|
let arrayAddress = TempVariable
|
|
|
|
arrayStatement = ArrayQuadruple (Variable identifier) operand arrayAddress
|
|
|
|
in (VariableOperand arrayAddress, Vector.snoc statements arrayStatement)
|
|
|
|
(AST.LiteralExpression literal') -> (literal literal', mempty)
|
|
|
|
(AST.NegationExpression negation) ->
|
|
|
|
let (operand, statements) = expression localTable negation
|
|
|
|
tempVariable = TempVariable
|
|
|
|
negationQuadruple = NegationQuadruple operand tempVariable
|
|
|
|
in (VariableOperand tempVariable, Vector.snoc statements negationQuadruple)
|
|
|
|
(AST.SumExpression lhs rhs) -> binaryExpression AddQuadruple lhs rhs
|
|
|
|
(AST.SubtractionExpression lhs rhs) ->
|
|
|
|
binaryExpression SubtractionQuadruple lhs rhs
|
|
|
|
(AST.ProductExpression lhs rhs) ->
|
|
|
|
binaryExpression ProductQuadruple lhs rhs
|
|
|
|
(AST.DivisionExpression lhs rhs) ->
|
|
|
|
binaryExpression DivisionQuadruple lhs rhs
|
|
|
|
where
|
|
|
|
binaryExpression f lhs rhs =
|
|
|
|
let (lhsOperand, lhsStatements) = expression localTable lhs
|
|
|
|
(rhsOperand, rhsStatements) = expression localTable rhs
|
|
|
|
tempVariable = TempVariable
|
|
|
|
newQuadruple = f lhsOperand rhsOperand tempVariable
|
|
|
|
in (VariableOperand tempVariable, Vector.snoc (lhsStatements <> rhsStatements) newQuadruple)
|
|
|
|
|
|
|
|
literal :: AST.Literal -> Operand
|
|
|
|
literal (AST.IntegerLiteral integer) = IntOperand integer
|
|
|
|
literal (AST.HexadecimalLiteral integer) = IntOperand integer
|
|
|
|
literal (AST.CharacterLiteral character) = IntOperand $ fromIntegral character
|
|
|
|
literal (AST.BooleanLiteral boolean)
|
|
|
|
| boolean = IntOperand 1
|
|
|
|
| otherwise = IntOperand 0
|