Parse local variables

This commit is contained in:
Eugen Wissner 2024-11-06 22:23:49 +01:00
parent e2d4b76c0b
commit 060496fc6e
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
11 changed files with 115 additions and 91 deletions

17
TODO
View File

@ -1,9 +1,12 @@
# Intermediate code generation
- To access named parameters and local variables inside a procedure, IR should
be able to reference them. During the generation the needed information (e.g.
offsets or registers) can be extracted from the symbol table and saved in the
operands.
- To access named parameters inside a procedure, IR should be able to reference
them. During the generation the needed information (e.g. offsets or registers)
can be extracted from the symbol table and saved in the operands.
- Glue always generates the same intermediate variable (LocalVariable 0) for
local variables. (LocalVariable 0) is handled the same as temporary variables
that are currently saved only in registers. There space on the stack allocated
for local variables.
# ELF generation
@ -15,3 +18,9 @@
- Each temporary variable gets a tn register where n is the variable index. If
there more variables the allocation will fail with out of bounds runtime
error. Implement spill over.
- The allocator puts temporary and local variables into the same registers,
causing conflicts.
# Language
- Array support.

View File

@ -30,26 +30,21 @@ allocate MachineConfiguration{..} = fmap function
quadruple (ParameterQuadruple operand1) =
ParameterQuadruple (operand operand1)
quadruple (CallQuadruple name count) = CallQuadruple name count
quadruple (AddQuadruple operand1 operand2 (TempVariable index))
quadruple (AddQuadruple operand1 operand2 variable)
= AddQuadruple (operand operand1) (operand operand2)
$ Store
$ temporaryRegisters !! fromIntegral index
quadruple (SubtractionQuadruple operand1 operand2 (TempVariable index))
$ storeVariable variable
quadruple (SubtractionQuadruple operand1 operand2 variable)
= SubtractionQuadruple (operand operand1) (operand operand2)
$ Store
$ temporaryRegisters !! fromIntegral index
quadruple (NegationQuadruple operand1 (TempVariable index))
$ storeVariable variable
quadruple (NegationQuadruple operand1 variable)
= NegationQuadruple (operand operand1)
$ Store
$ temporaryRegisters !! fromIntegral index
quadruple (ProductQuadruple operand1 operand2 (TempVariable index))
$ storeVariable variable
quadruple (ProductQuadruple operand1 operand2 variable)
= ProductQuadruple (operand operand1) (operand operand2)
$ Store
$ temporaryRegisters !! fromIntegral index
quadruple (DivisionQuadruple operand1 operand2 (TempVariable index))
$ storeVariable variable
quadruple (DivisionQuadruple operand1 operand2 variable)
= DivisionQuadruple (operand operand1) (operand operand2)
$ Store
$ temporaryRegisters !! fromIntegral index
$ storeVariable variable
quadruple (LabelQuadruple label) = LabelQuadruple label
quadruple (GoToQuadruple label) = GoToQuadruple label
quadruple (EqualQuadruple operand1 operand2 goToLabel) =
@ -64,9 +59,20 @@ allocate MachineConfiguration{..} = fmap function
LessOrEqualQuadruple (operand operand1) (operand operand2) goToLabel
quadruple (GreaterOrEqualQuadruple operand1 operand2 goToLabel) =
GreaterOrEqualQuadruple (operand operand1) (operand operand2) goToLabel
quadruple (AssignQuadruple operand1 variable)
= AssignQuadruple (operand operand1)
$ storeVariable variable
operand :: Operand Variable -> Operand (Store r)
operand (IntOperand x) = IntOperand x
operand (VariableOperand (TempVariable index))
= VariableOperand
$ Store
$ temporaryRegisters !! fromIntegral index
operand (VariableOperand (LocalVariable index))
= VariableOperand
$ Store
$ temporaryRegisters !! fromIntegral index
storeVariable (TempVariable index) =
Store $ temporaryRegisters !! fromIntegral index
storeVariable (LocalVariable index) =
Store $ temporaryRegisters !! fromIntegral index

View File

@ -17,12 +17,12 @@ instance Show Label
where
show (Label label) = '.' : Text.unpack label
newtype Variable = TempVariable Word32 -- | Variable Text
data Variable = TempVariable Word32 | LocalVariable Word32
deriving Eq
instance Show Variable
where
-- show (Variable variable) = '$' : Text.unpack variable
show (LocalVariable variable) = '@' : show variable
show (TempVariable variable) = '$' : show variable
data Operand v
@ -41,8 +41,8 @@ data Quadruple v
| ProductQuadruple (Operand v) (Operand v) v
| DivisionQuadruple (Operand v) (Operand v) v
| GoToQuadruple Label
{-| AssignQuadruple Operand Variable
| ArrayQuadruple Variable Operand Variable
| AssignQuadruple (Operand v) v
{-| ArrayQuadruple Variable Operand Variable
| ArrayAssignQuadruple Operand Operand Variable -}
| LessOrEqualQuadruple (Operand v) (Operand v) Label
| GreaterOrEqualQuadruple (Operand v) (Operand v) Label

View File

@ -6,7 +6,7 @@ module Language.Elna.Frontend.AST
, Statement(..)
, TypeExpression(..)
, VariableDeclaration(..)
--, VariableAccess(..)
, VariableAccess(..)
, Condition(..)
, Expression(..)
, Literal(..)
@ -70,8 +70,8 @@ instance Show TypeExpression
data Statement
= EmptyStatement
| IfStatement Condition Statement (Maybe Statement)
{-| AssignmentStatement VariableAccess Expression
| WhileStatement Condition Statement -}
| AssignmentStatement VariableAccess Expression
-- | WhileStatement Condition Statement
| CompoundStatement [Statement]
| CallStatement Identifier [Expression]
deriving Eq
@ -84,9 +84,9 @@ instance Show Statement
, show if'
, maybe "" ((<> " else ") . show) else'
]
{-show (AssignmentStatement lhs rhs) =
show (AssignmentStatement lhs rhs) =
concat [show lhs, " := ", show rhs, ";"]
show (WhileStatement expression statement) =
{-show (WhileStatement expression statement) =
concat ["while (", show expression, ") ", show statement, ";"]-}
show (CompoundStatement statements) =
concat ["{\n", unlines (show <$> statements), " }"]
@ -163,7 +163,7 @@ data Expression
| NegationExpression Expression
| ProductExpression Expression Expression
| DivisionExpression Expression Expression
-- | VariableExpression VariableAccess
| VariableExpression VariableAccess
deriving Eq
instance Show Expression
@ -174,19 +174,19 @@ instance Show Expression
show (NegationExpression negation) = '-' : show negation
show (ProductExpression lhs rhs) = concat [show lhs, " * ", show rhs]
show (DivisionExpression lhs rhs) = concat [show lhs, " / ", show rhs]
-- show (VariableExpression variable) = show variable
{-
data VariableAccess
show (VariableExpression variable) = show variable
newtype VariableAccess
= VariableAccess Identifier
| ArrayAccess VariableAccess Expression
-- | ArrayAccess VariableAccess Expression
deriving Eq
instance Show VariableAccess
where
show (VariableAccess variableName) = show variableName
show (ArrayAccess arrayAccess elementIndex) =
concat [show arrayAccess, "[", show elementIndex, "]"]
-}
{- show (ArrayAccess arrayAccess elementIndex) =
concat [show arrayAccess, "[", show elementIndex, "]"] -}
data Condition
= EqualCondition Expression Expression
| NonEqualCondition Expression Expression

View File

@ -158,9 +158,9 @@ expression globalTable (AST.ProductExpression lhs rhs)
expression globalTable (AST.DivisionExpression lhs rhs)
= expression globalTable lhs
>> expression globalTable rhs
{- expression globalTable (AST.VariableExpression variableExpression) =
expression globalTable (AST.VariableExpression variableExpression) =
variableAccess globalTable variableExpression
-}
statement :: SymbolTable -> AST.Statement -> NameAnalysis ()
statement _ AST.EmptyStatement = pure ()
statement globalTable (AST.CallStatement name arguments)
@ -172,9 +172,9 @@ statement globalTable (AST.IfStatement ifCondition ifStatement elseStatement)
= condition globalTable ifCondition
>> statement globalTable ifStatement
>> maybe (pure ()) (statement globalTable) elseStatement
-- statement globalTable (AST.AssignmentStatement lvalue rvalue)
-- = variableAccess globalTable lvalue
-- >> expression globalTable rvalue
statement globalTable (AST.AssignmentStatement lvalue rvalue)
= variableAccess globalTable lvalue
>> expression globalTable rvalue
--statement globalTable (AST.WhileStatement whileCondition loop)
-- = condition globalTable whileCondition
-- >> statement globalTable loop
@ -198,13 +198,13 @@ condition globalTable (AST.LessOrEqualCondition lhs rhs)
condition globalTable (AST.GreaterOrEqualCondition lhs rhs)
= expression globalTable lhs
>> expression globalTable rhs
{-
variableAccess :: SymbolTable -> AST.VariableAccess -> NameAnalysis ()
variableAccess globalTable (AST.ArrayAccess arrayExpression indexExpression)
= variableAccess globalTable arrayExpression
>> expression globalTable indexExpression
variableAccess globalTable (AST.VariableAccess identifier) =
checkSymbol globalTable identifier
{- variableAccess globalTable (AST.ArrayAccess arrayExpression indexExpression)
= variableAccess globalTable arrayExpression
>> expression globalTable indexExpression
enter :: Identifier -> Info -> SymbolTable -> NameAnalysis SymbolTable
enter identifier info table
@ -216,9 +216,4 @@ identifierAlreadyDefinedError = NameAnalysis
. lift
. throwE
. IdentifierAlreadyDefinedError
variableDeclaration :: AST.VariableDeclaration -> NameAnalysis (Identifier, Info)
variableDeclaration (AST.VariableDeclaration identifier typeExpression)
= (identifier,) . VariableInfo False
<$> dataType typeExpression
-}

View File

@ -16,7 +16,7 @@ import Language.Elna.Frontend.AST
, Statement(..)
, TypeExpression(..)
, VariableDeclaration(..)
--, VariableAccess(..)
, VariableAccess(..)
, Condition(..)
, Expression(..)
, Literal(..)
@ -64,7 +64,7 @@ termP :: Parser Expression
termP = choice
[ parensP expressionP
, LiteralExpression <$> literalP
-- , VariableExpression <$> variableAccessP
, VariableExpression <$> variableAccessP
]
operatorTable :: [[Operator Parser Expression]]
@ -91,13 +91,13 @@ operatorTable =
expressionP :: Parser Expression
expressionP = makeExprParser termP operatorTable
{-
variableAccessP :: Parser VariableAccess
variableAccessP = do
variableAccessP = VariableAccess <$> identifierP {- do
identifier <- identifierP
indices <- many $ bracketsP expressionP
pure $ foldr (flip ArrayAccess) (VariableAccess identifier) indices
-}
pure $ foldr (flip ArrayAccess) (VariableAccess identifier) indices -}
conditionP :: Parser Condition
conditionP = do
lhs <- expressionP
@ -187,8 +187,8 @@ statementP
= EmptyStatement <$ semicolonP
<|> ifElseP
<|> CompoundStatement <$> blockP (many statementP)
{-<|> try assignmentP
<|> try whileP -}
<|> try assignmentP
-- <|> try whileP
<|> callP
<?> "statement"
where
@ -202,12 +202,12 @@ statementP
<*> optional (symbol "else" *> statementP)
{-whileP = WhileStatement
<$> (symbol "while" *> parensP conditionP)
<*> statementP
<*> statementP -}
assignmentP = AssignmentStatement
<$> variableAccessP
<* symbol ":="
<*> expressionP
<* semicolonP -}
<* semicolonP
variableDeclarationP :: Parser VariableDeclaration
variableDeclarationP = VariableDeclaration

View File

@ -3,10 +3,11 @@ module Language.Elna.Frontend.TypeAnalysis
, -- Error(..)
) where
import Control.Applicative (Alternative(..))
import Control.Monad (unless)
import Control.Monad.Trans.Class (MonadTrans(..))
import Control.Monad.Trans.Except (Except, runExcept, throwE)
import Control.Monad.Trans.Reader (ReaderT, runReaderT, withReaderT, ask)
import Control.Monad.Trans.Reader (ReaderT, runReaderT, withReaderT, ask, asks)
import Data.Foldable (traverse_)
import qualified Data.Vector as Vector
import qualified Language.Elna.Frontend.AST as AST
@ -22,9 +23,6 @@ typeAnalysis globalTable = either Just (const Nothing)
. runTypeAnalysis
. program
{-
import Control.Applicative (Alternative(..))
-}
data Error
= UnexpectedProcedureInfoError Info
| UndefinedSymbolError Identifier
@ -96,14 +94,14 @@ declaration (AST.TypeDefinition _ _) = pure ()
statement :: SymbolTable -> AST.Statement -> TypeAnalysis ()
statement globalTable = \case
AST.EmptyStatement -> pure ()
{- AST.AssignmentStatement lhs rhs -> do
AST.AssignmentStatement lhs rhs -> do
lhsType <- variableAccess globalTable lhs
rhsType <- expression globalTable rhs
unless (lhsType == intType)
$ TypeAnalysis $ lift $ throwE $ InvalidConditionTypeError lhsType
unless (rhsType == intType)
$ TypeAnalysis $ lift $ throwE $ InvalidConditionTypeError rhsType
AST.WhileStatement whileCondition whileStatement -> do
{- AST.WhileStatement whileCondition whileStatement -> do
conditionType <- condition globalTable whileCondition
unless (conditionType == booleanType)
$ TypeAnalysis $ lift $ throwE $ InvalidConditionTypeError conditionType
@ -136,7 +134,7 @@ statement globalTable = \case
when (isReferenceParameter && not (isLvalue argument))
$ TypeAnalysis $ lift $ throwE $ ExpectedLvalueError argument
isLvalue (AST.VariableExpression _) = True
isLvalue _ = False
isLvalue _ = False -}
variableAccess :: SymbolTable -> AST.VariableAccess -> TypeAnalysis Type
variableAccess globalTable (AST.VariableAccess identifier) = do
@ -147,7 +145,7 @@ variableAccess globalTable (AST.VariableAccess identifier) = do
$ UnexpectedVariableInfoError anotherInfo
Nothing -> TypeAnalysis $ lift $ throwE
$ UndefinedSymbolError identifier
variableAccess globalTable (AST.ArrayAccess arrayExpression indexExpression) = do
{-variableAccess globalTable (AST.ArrayAccess arrayExpression indexExpression) = do
arrayType <- variableAccess globalTable arrayExpression
indexType <- expression globalTable indexExpression
unless (indexType == intType)
@ -159,8 +157,8 @@ variableAccess globalTable (AST.ArrayAccess arrayExpression indexExpression) = d
-}
expression :: SymbolTable -> AST.Expression -> TypeAnalysis Type
expression globalTable = \case
{- AST.VariableExpression variableExpression -> do
variableAccess globalTable variableExpression -}
AST.VariableExpression variableExpression ->
variableAccess globalTable variableExpression
AST.LiteralExpression literal' -> literal literal'
AST.NegationExpression negation -> do
operandType <- expression globalTable negation

View File

@ -15,13 +15,15 @@ import qualified Data.Text.Lazy as Text.Lazy
import qualified Data.Vector as Vector
import Data.Word (Word32)
import qualified Language.Elna.Frontend.AST as AST
import Language.Elna.Frontend.Types (Type(..))
import Language.Elna.Backend.Intermediate
( Label(..)
, Operand(..)
, Quadruple(..)
, Variable(..)
)
import Language.Elna.Frontend.SymbolTable (SymbolTable)
import Language.Elna.Frontend.SymbolTable (Info(..), SymbolTable)
import qualified Language.Elna.Frontend.SymbolTable as SymbolTable
import GHC.Records (HasField(..))
data Paste = Paste
@ -98,20 +100,20 @@ statement localTable (AST.IfStatement ifCondition ifStatement elseStatement) = d
<> Vector.snoc ifStatements (LabelQuadruple endLabel)
Nothing -> Vector.fromList [jumpConstructor ifLabel, GoToQuadruple endLabel, LabelQuadruple ifLabel]
<> Vector.snoc ifStatements (LabelQuadruple endLabel)
{- statement localTable (AST.AssignmentStatement variableAccess' assignee) = do
statement localTable (AST.AssignmentStatement variableAccess' assignee) = do
(rhsOperand, rhsStatements) <- expression localTable assignee
let variableType' = variableType variableAccess' localTable
accessResult <- variableAccess localTable variableAccess' Nothing variableType' mempty
pure $ rhsStatements <> case accessResult of
(AST.Identifier identifier, Just accumulatedIndex, accumulatedStatements) ->
{-(AST.Identifier identifier, Just accumulatedIndex, accumulatedStatements) ->
Vector.snoc accumulatedStatements
$ ArrayAssignQuadruple rhsOperand accumulatedIndex
$ Variable identifier
$ LocalVariable identifier -}
(AST.Identifier identifier, Nothing, accumulatedStatements) ->
Vector.snoc accumulatedStatements
$ AssignQuadruple rhsOperand
$ Variable identifier
statement localTable (AST.WhileStatement whileCondition whileStatement) = do
$ LocalVariable 0
{- statement localTable (AST.WhileStatement whileCondition whileStatement) = do
(conditionStatements, jumpConstructor) <- condition localTable whileCondition
startLabel <- createLabel
endLabel <- createLabel
@ -189,20 +191,17 @@ condition localTable (AST.GreaterOrEqualCondition lhs rhs) = do
( lhsStatements <> rhsStatements
, GreaterOrEqualQuadruple lhsOperand rhsOperand
)
{-
import Language.Elna.Types (Type(..))
import qualified Language.Elna.SymbolTable as SymbolTable
variableAccess
:: SymbolTable
-> AST.VariableAccess
-> Maybe Operand
-> Maybe (Operand Variable)
-> Type
-> Vector Quadruple
-> Glue (AST.Identifier, Maybe Operand, Vector Quadruple)
-> Vector (Quadruple Variable)
-> Glue (AST.Identifier, Maybe (Operand Variable), Vector (Quadruple Variable))
variableAccess _ (AST.VariableAccess identifier) accumulatedIndex _ accumulatedStatements =
pure (identifier, accumulatedIndex, accumulatedStatements)
variableAccess localTable (AST.ArrayAccess access1 index1) Nothing (ArrayType _ baseType) _ = do
{- variableAccess localTable (AST.ArrayAccess access1 index1) Nothing (ArrayType _ baseType) _ = do
(indexPlace, statements) <- expression localTable index1
variableAccess localTable access1 (Just indexPlace) baseType statements
variableAccess localTable (AST.ArrayAccess arrayAccess' arrayIndex) (Just baseIndex) (ArrayType arraySize baseType) statements = do
@ -216,14 +215,14 @@ variableAccess localTable (AST.ArrayAccess arrayAccess' arrayIndex) (Just baseIn
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
-}
{-variableType (AST.ArrayAccess arrayAccess' _) symbolTable =
variableType arrayAccess' symbolTable -}
expression :: SymbolTable -> AST.Expression -> Glue (Operand Variable, Vector (Quadruple Variable))
expression localTable = \case
(AST.LiteralExpression literal') -> pure (literal literal', mempty)
@ -242,8 +241,9 @@ expression localTable = \case
binaryExpression ProductQuadruple lhs rhs
(AST.DivisionExpression lhs rhs) ->
binaryExpression DivisionQuadruple lhs rhs
{- (AST.VariableExpression variableExpression) -> do
let variableType' = variableType variableExpression localTable
(AST.VariableExpression variableExpression) -> do
pure (VariableOperand (LocalVariable 0), mempty)
{- let variableType' = variableType variableExpression localTable
variableAccess' <- variableAccess localTable variableExpression Nothing variableType' mempty
case variableAccess' of
(AST.Identifier identifier, Nothing, statements) ->

View File

@ -427,11 +427,11 @@ quadruple (GreaterOrEqualQuadruple operand1 operand2 goToLabel)
then pure $ Vector.singleton $ unconditionalJal goToLabel
else pure Vector.empty
| VariableOperand variableOperand1 <- operand1
, VariableOperand variableOperand2 <- operand2 = do
, VariableOperand variableOperand2 <- operand2 =
let Store operandRegister1 = variableOperand1
Store operandRegister2 = variableOperand2
Label goToLabel' = goToLabel
pure $ Vector.singleton
in pure $ Vector.singleton
$ Instruction
$ RiscV.RelocatableInstruction RiscV.Branch
$ RiscV.RBranch goToLabel' RiscV.BGE operandRegister1 operandRegister2
@ -453,6 +453,15 @@ quadruple (GreaterOrEqualQuadruple operand1 operand2 goToLabel)
$ Instruction
$ RiscV.RelocatableInstruction RiscV.Branch
$ RiscV.RBranch goToLabel' RiscV.BGE immediateRegister operandRegister2
quadruple (AssignQuadruple operand1 (Store register))
| IntOperand immediateOperand1 <- operand1 = pure
$ lui immediateOperand1 register
| VariableOperand variableOperand1 <- operand1 =
let Store operandRegister1 = variableOperand1
in pure $ Vector.singleton
$ Instruction
$ RiscV.BaseInstruction RiscV.OpImm
$ RiscV.I register RiscV.ADDI operandRegister1 0
unconditionalJal :: Label -> Statement
unconditionalJal (Label goToLabel) = Instruction

View File

@ -0,0 +1 @@
58

View File

@ -0,0 +1,6 @@
proc main() {
var i: int;
i := 58;
printi(i);
}