Implement addition and subtraction

This commit is contained in:
Eugen Wissner 2024-09-29 19:50:55 +02:00
parent ed144309fa
commit c2c923276f
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
11 changed files with 131 additions and 89 deletions

8
TODO
View File

@ -17,6 +17,12 @@
# Built-in # Built-in
Printi should print a sign for negative numbers. - Implement printc (with int argument).
- Implement exit() as standalone function.
# Register allocation
- Temporary variables always use the same register, t0. Allocate registers for
temporaries.
# Type analysis # Type analysis

View File

@ -115,12 +115,12 @@ instance Show VariableDeclaration
show (VariableDeclaration identifier typeExpression) = show (VariableDeclaration identifier typeExpression) =
concat ["var ", show identifier, ": " <> show typeExpression, ";"] concat ["var ", show identifier, ": " <> show typeExpression, ";"]
newtype Expression data Expression
= LiteralExpression Literal = LiteralExpression Literal
{- | VariableExpression VariableAccess
| NegationExpression Expression
| SumExpression Expression Expression | SumExpression Expression Expression
| SubtractionExpression Expression Expression | SubtractionExpression Expression Expression
{- | VariableExpression VariableAccess
| NegationExpression Expression
| ProductExpression Expression Expression | ProductExpression Expression Expression
| DivisionExpression Expression Expression -} | DivisionExpression Expression Expression -}
deriving Eq deriving Eq
@ -128,10 +128,10 @@ newtype Expression
instance Show Expression instance Show Expression
where where
show (LiteralExpression literal) = show literal show (LiteralExpression literal) = show literal
{- show (VariableExpression variable) = show variable
show (NegationExpression negation) = '-' : show negation
show (SumExpression lhs rhs) = concat [show lhs, " + ", show rhs] show (SumExpression lhs rhs) = concat [show lhs, " + ", show rhs]
show (SubtractionExpression lhs rhs) = concat [show lhs, " - ", show rhs] show (SubtractionExpression lhs rhs) = concat [show lhs, " - ", show rhs]
{- show (VariableExpression variable) = show variable
show (NegationExpression negation) = '-' : show negation
show (ProductExpression lhs rhs) = concat [show lhs, " * ", show rhs] show (ProductExpression lhs rhs) = concat [show lhs, " * ", show rhs]
show (DivisionExpression lhs rhs) = concat [show lhs, " / ", show rhs] -} show (DivisionExpression lhs rhs) = concat [show lhs, " / ", show rhs] -}
{- {-

View File

@ -6,11 +6,12 @@ module Language.Elna.CodeGenerator
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
import Data.HashMap.Strict (HashMap) import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap import qualified Data.HashMap.Strict as HashMap
import Data.Int (Int32)
import Data.Vector (Vector) import Data.Vector (Vector)
import qualified Data.Vector as Vector import qualified Data.Vector as Vector
import qualified Data.Text.Encoding as Text.Encoding import qualified Data.Text.Encoding as Text.Encoding
import Language.Elna.Location (Identifier(..)) import Language.Elna.Location (Identifier(..))
import Language.Elna.Intermediate (Operand(..), Quadruple(..)) import Language.Elna.Intermediate (Operand(..), Quadruple(..), Variable(..))
import qualified Language.Elna.Architecture.RiscV as RiscV import qualified Language.Elna.Architecture.RiscV as RiscV
import Language.Elna.SymbolTable (SymbolTable) import Language.Elna.SymbolTable (SymbolTable)
import Data.Bits (Bits(..)) import Data.Bits (Bits(..))
@ -40,26 +41,11 @@ quadruple StartQuadruple = Vector.fromList
, Instruction (RiscV.BaseInstruction RiscV.Store $ RiscV.S 4 RiscV.SW RiscV.SP RiscV.RA) , Instruction (RiscV.BaseInstruction RiscV.Store $ RiscV.S 4 RiscV.SW RiscV.SP RiscV.RA)
, Instruction (RiscV.BaseInstruction RiscV.OpImm $ RiscV.I RiscV.S0 RiscV.ADDI RiscV.SP 4) , Instruction (RiscV.BaseInstruction RiscV.OpImm $ RiscV.I RiscV.S0 RiscV.ADDI RiscV.SP 4)
] ]
quadruple (ParameterQuadruple (IntOperand intValue)) quadruple (ParameterQuadruple operand1) =
= mappend go let (operandRegister, statements) = loadImmediateOrRegister operand1 RiscV.A0
$ Vector.fromList in mappend statements $ Vector.fromList
[ Instruction (RiscV.BaseInstruction RiscV.OpImm $ RiscV.I RiscV.SP RiscV.ADDI RiscV.SP (negate 4)) [ Instruction (RiscV.BaseInstruction RiscV.OpImm $ RiscV.I RiscV.SP RiscV.ADDI RiscV.SP (negate 4))
, Instruction (RiscV.BaseInstruction RiscV.Store $ RiscV.S 0 RiscV.SW RiscV.SP RiscV.A0) , Instruction (RiscV.BaseInstruction RiscV.Store $ RiscV.S 0 RiscV.SW RiscV.SP operandRegister)
]
where
hi = intValue `shiftR` 12
lo = intValue
go
| intValue >= -2048
, intValue <= 2047 = Vector.singleton
$ Instruction (RiscV.BaseInstruction RiscV.OpImm $ RiscV.I RiscV.A0 RiscV.ADDI RiscV.A0 $ fromIntegral lo)
| intValue .&. 0x800 /= 0 = Vector.fromList
[ Instruction (RiscV.BaseInstruction RiscV.Lui $ RiscV.U RiscV.A0 $ fromIntegral $ succ hi)
, Instruction (RiscV.BaseInstruction RiscV.OpImm $ RiscV.I RiscV.A0 RiscV.ADDI RiscV.A0 $ fromIntegral lo)
]
| otherwise = Vector.fromList
[ Instruction (RiscV.BaseInstruction RiscV.Lui $ RiscV.U RiscV.A0 $ fromIntegral hi)
, Instruction (RiscV.BaseInstruction RiscV.OpImm $ RiscV.I RiscV.A0 RiscV.ADDI RiscV.A0 $ fromIntegral lo)
] ]
quadruple (CallQuadruple callName numberOfArguments) = Vector.fromList quadruple (CallQuadruple callName numberOfArguments) = Vector.fromList
[ Instruction (RiscV.CallInstruction callName) [ Instruction (RiscV.CallInstruction callName)
@ -71,3 +57,39 @@ quadruple StopQuadruple = Vector.fromList
, Instruction (RiscV.BaseInstruction RiscV.OpImm $ RiscV.I RiscV.SP RiscV.ADDI RiscV.SP 4) , Instruction (RiscV.BaseInstruction RiscV.OpImm $ RiscV.I RiscV.SP RiscV.ADDI RiscV.SP 4)
, Instruction (RiscV.BaseInstruction RiscV.Jalr $ RiscV.I RiscV.RA RiscV.JALR RiscV.Zero 0) , Instruction (RiscV.BaseInstruction RiscV.Jalr $ RiscV.I RiscV.RA RiscV.JALR RiscV.Zero 0)
] ]
quadruple (AddQuadruple operand1 operand2 (TempVariable _)) =
let (operandRegister1, statements1) = loadImmediateOrRegister operand1 RiscV.A0
(operandRegister2, statements2) = loadImmediateOrRegister operand2 RiscV.A1
in Vector.snoc (statements1 <> statements2)
$ Instruction
$ RiscV.BaseInstruction RiscV.Op
$ RiscV.R RiscV.T0 RiscV.ADD operandRegister1 operandRegister2 (RiscV.Funct7 0b0000000)
quadruple (SubtractionQuadruple operand1 operand2 (TempVariable _)) =
let (operandRegister1, statements1) = loadImmediateOrRegister operand1 RiscV.A0
(operandRegister2, statements2) = loadImmediateOrRegister operand2 RiscV.A1
in Vector.snoc (statements1 <> statements2)
$ Instruction
$ RiscV.BaseInstruction RiscV.Op
$ RiscV.R RiscV.T0 RiscV.SUB operandRegister1 operandRegister2 (RiscV.Funct7 0b0100000)
loadImmediateOrRegister :: Operand -> RiscV.XRegister -> (RiscV.XRegister, Vector Statement)
loadImmediateOrRegister (IntOperand intValue) targetRegister =
(targetRegister, lui intValue targetRegister)
loadImmediateOrRegister (VariableOperand _) _ = (RiscV.T0, Vector.empty)
lui :: Int32 -> RiscV.XRegister -> Vector Statement
lui intValue targetRegister
| intValue >= -2048
, intValue <= 2047 = Vector.singleton
$ Instruction (RiscV.BaseInstruction RiscV.OpImm $ RiscV.I targetRegister RiscV.ADDI RiscV.Zero lo)
| intValue .&. 0x800 /= 0 = Vector.fromList
[ Instruction (RiscV.BaseInstruction RiscV.Lui $ RiscV.U targetRegister $ fromIntegral $ succ hi)
, Instruction (RiscV.BaseInstruction RiscV.OpImm $ RiscV.I targetRegister RiscV.ADDI targetRegister lo)
]
| otherwise = Vector.fromList
[ Instruction (RiscV.BaseInstruction RiscV.Lui $ RiscV.U targetRegister $ fromIntegral hi)
, Instruction (RiscV.BaseInstruction RiscV.OpImm $ RiscV.I targetRegister RiscV.ADDI targetRegister lo)
]
where
hi = intValue `shiftR` 12
lo = fromIntegral intValue

View File

@ -1,8 +1,8 @@
module Language.Elna.Intermediate module Language.Elna.Intermediate
( Operand(..) ( Operand(..)
, Quadruple(..) , Quadruple(..)
{- , Label(..) {- , Label(..) -}
, Variable(..) -} , Variable(..)
, intermediate , intermediate
) where ) where
@ -17,12 +17,20 @@ import Data.Text (Text)
import qualified Language.Elna.AST as AST import qualified Language.Elna.AST as AST
import Language.Elna.SymbolTable (SymbolTable{-, Info(..) -}) import Language.Elna.SymbolTable (SymbolTable{-, Info(..) -})
import Data.Foldable (Foldable(..)) import Data.Foldable (Foldable(..))
import Control.Monad.Trans.State (State, runState) import Control.Monad.Trans.State (State, get, modify', runState)
import Data.Maybe (catMaybes) import Data.Maybe (catMaybes)
newtype Operand newtype Variable = TempVariable Word32 -- | Variable Text
deriving Eq
instance Show Variable
where
-- show (Variable variable) = '$' : Text.unpack variable
show (TempVariable variable) = '$' : show variable
data Operand
= IntOperand Int32 = IntOperand Int32
-- | VariableOperand Variable | VariableOperand Variable
deriving (Eq, Show) deriving (Eq, Show)
data Quadruple data Quadruple
@ -30,12 +38,12 @@ data Quadruple
| StopQuadruple | StopQuadruple
| ParameterQuadruple Operand | ParameterQuadruple Operand
| CallQuadruple Text Word32 | CallQuadruple Text Word32
| AddQuadruple Operand Operand Variable
| SubtractionQuadruple Operand Operand Variable
{-| GoToQuadruple Label {-| GoToQuadruple Label
| AssignQuadruple Operand Variable | AssignQuadruple Operand Variable
| ArrayQuadruple Variable Operand Variable | ArrayQuadruple Variable Operand Variable
| ArrayAssignQuadruple Operand Operand Variable | ArrayAssignQuadruple Operand Operand Variable
| AddQuadruple Operand Operand Variable
| SubtractionQuadruple Operand Operand Variable
| ProductQuadruple Operand Operand Variable | ProductQuadruple Operand Operand Variable
| DivisionQuadruple Operand Operand Variable | DivisionQuadruple Operand Operand Variable
| NegationQuadruple Operand Variable | NegationQuadruple Operand Variable
@ -142,6 +150,12 @@ statement localTable (AST.WhileStatement whileCondition whileStatement) = do
statement localTable (AST.CompoundStatement statements) = statement localTable (AST.CompoundStatement statements) =
fold <$> traverse (statement localTable) statements -} fold <$> traverse (statement localTable) statements -}
createTemporary :: Intermediate Variable
createTemporary = do
currentCounter <- Intermediate get
Intermediate $ modify' (+ 1)
pure $ TempVariable currentCounter
{- {-
import Language.Elna.Types (Type(..)) import Language.Elna.Types (Type(..))
import qualified Language.Elna.SymbolTable as SymbolTable import qualified Language.Elna.SymbolTable as SymbolTable
@ -171,16 +185,6 @@ createLabel = do
{ labelCounter = getField @"labelCounter" generator + 1 { labelCounter = getField @"labelCounter" generator + 1
} }
createTemporary :: Intermediate Variable
createTemporary = do
currentCounter <- Intermediate $ gets temporaryCounter
Intermediate $ modify' modifier
pure $ TempVariable currentCounter
where
modifier generator = generator
{ temporaryCounter = getField @"temporaryCounter" generator + 1
}
condition condition
:: SymbolTable :: SymbolTable
-> AST.Condition -> AST.Condition
@ -257,8 +261,11 @@ variableType (AST.ArrayAccess arrayAccess' _) symbolTable =
variableType arrayAccess' symbolTable variableType arrayAccess' symbolTable
-} -}
expression :: SymbolTable -> AST.Expression -> Intermediate (Operand, Vector Quadruple) expression :: SymbolTable -> AST.Expression -> Intermediate (Operand, Vector Quadruple)
expression _localTable = \case expression localTable = \case
(AST.LiteralExpression literal') -> pure (literal literal', mempty) (AST.LiteralExpression literal') -> pure (literal literal', mempty)
(AST.SumExpression lhs rhs) -> binaryExpression AddQuadruple lhs rhs
(AST.SubtractionExpression lhs rhs) ->
binaryExpression SubtractionQuadruple lhs rhs
{- (AST.VariableExpression variableExpression) -> do {- (AST.VariableExpression variableExpression) -> do
let variableType' = variableType variableExpression localTable let variableType' = variableType variableExpression localTable
variableAccess' <- variableAccess localTable variableExpression Nothing variableType' mempty variableAccess' <- variableAccess localTable variableExpression Nothing variableType' mempty
@ -280,13 +287,10 @@ expression _localTable = \case
( VariableOperand tempVariable ( VariableOperand tempVariable
, Vector.snoc statements negationQuadruple , Vector.snoc statements negationQuadruple
) )
(AST.SumExpression lhs rhs) -> binaryExpression AddQuadruple lhs rhs
(AST.SubtractionExpression lhs rhs) ->
binaryExpression SubtractionQuadruple lhs rhs
(AST.ProductExpression lhs rhs) -> (AST.ProductExpression lhs rhs) ->
binaryExpression ProductQuadruple lhs rhs binaryExpression ProductQuadruple lhs rhs
(AST.DivisionExpression lhs rhs) -> (AST.DivisionExpression lhs rhs) ->
binaryExpression DivisionQuadruple lhs rhs binaryExpression DivisionQuadruple lhs rhs -}
where where
binaryExpression f lhs rhs = do binaryExpression f lhs rhs = do
(lhsOperand, lhsStatements) <- expression localTable lhs (lhsOperand, lhsStatements) <- expression localTable lhs
@ -298,14 +302,6 @@ expression _localTable = \case
, Vector.snoc (lhsStatements <> rhsStatements) newQuadruple , Vector.snoc (lhsStatements <> rhsStatements) newQuadruple
) )
data Variable = Variable Text | TempVariable Int32
deriving Eq
instance Show Variable
where
show (Variable variable) = '$' : Text.unpack variable
show (TempVariable variable) = '$' : show variable
-}
literal :: AST.Literal -> Operand literal :: AST.Literal -> Operand
literal (AST.IntegerLiteral integer) = IntOperand integer literal (AST.IntegerLiteral integer) = IntOperand integer
{-literal (AST.HexadecimalLiteral integer) = IntOperand integer {-literal (AST.HexadecimalLiteral integer) = IntOperand integer

View File

@ -136,16 +136,16 @@ checkSymbol globalTable identifier
expression :: SymbolTable -> AST.Expression -> NameAnalysis () expression :: SymbolTable -> AST.Expression -> NameAnalysis ()
expression _ (AST.LiteralExpression _) = pure () expression _ (AST.LiteralExpression _) = pure ()
{- expression globalTable (AST.VariableExpression variableExpression) =
variableAccess globalTable variableExpression
expression globalTable (AST.NegationExpression negation) =
expression globalTable negation
expression globalTable (AST.SumExpression lhs rhs) expression globalTable (AST.SumExpression lhs rhs)
= expression globalTable lhs = expression globalTable lhs
>> expression globalTable rhs >> expression globalTable rhs
expression globalTable (AST.SubtractionExpression lhs rhs) expression globalTable (AST.SubtractionExpression lhs rhs)
= expression globalTable lhs = expression globalTable lhs
>> expression globalTable rhs >> expression globalTable rhs
{- expression globalTable (AST.VariableExpression variableExpression) =
variableAccess globalTable variableExpression
expression globalTable (AST.NegationExpression negation) =
expression globalTable negation
expression globalTable (AST.ProductExpression lhs rhs) expression globalTable (AST.ProductExpression lhs rhs)
= expression globalTable lhs = expression globalTable lhs
>> expression globalTable rhs >> expression globalTable rhs

View File

@ -4,7 +4,7 @@ module Language.Elna.Parser
) where ) where
import Control.Monad (void) import Control.Monad (void)
import Control.Monad.Combinators.Expr ({-Operator(..), -} makeExprParser) import Control.Monad.Combinators.Expr (Operator(..), makeExprParser)
import Data.Text (Text) import Data.Text (Text)
import qualified Data.Text as Text import qualified Data.Text as Text
import Data.Void (Void) import Data.Void (Void)
@ -69,6 +69,31 @@ termP = choice
, LiteralExpression <$> literalP , LiteralExpression <$> literalP
-- , VariableExpression <$> variableAccessP -- , VariableExpression <$> variableAccessP
] ]
operatorTable :: [[Operator Parser Expression]]
operatorTable =
[{- unaryOperator
, factorOperator
,-} termOperator
]
where
{- unaryOperator =
[ prefix "-" NegationExpression
, prefix "+" id
]
factorOperator =
[ binary "*" ProductExpression
, binary "/" DivisionExpression
] -}
termOperator =
[ binary "+" SumExpression
, binary "-" SubtractionExpression
]
-- prefix name f = Prefix (f <$ symbol name)
binary name f = InfixL (f <$ symbol name)
expressionP :: Parser Expression
expressionP = makeExprParser termP operatorTable
{- {-
variableAccessP :: Parser VariableAccess variableAccessP :: Parser VariableAccess
variableAccessP = do variableAccessP = do
@ -76,31 +101,6 @@ variableAccessP = do
indices <- many $ bracketsP expressionP indices <- many $ bracketsP expressionP
pure $ foldr (flip ArrayAccess) (VariableAccess identifier) indices pure $ foldr (flip ArrayAccess) (VariableAccess identifier) indices
operatorTable :: [[Operator Parser Expression]]
operatorTable =
[ unaryOperator
, factorOperator
, termOperator
]
where
unaryOperator =
[ prefix "-" NegationExpression
, prefix "+" id
]
factorOperator =
[ binary "*" ProductExpression
, binary "/" DivisionExpression
]
termOperator =
[ binary "+" SumExpression
, binary "-" SubtractionExpression
]
prefix name f = Prefix (f <$ symbol name)
binary name f = InfixL (f <$ symbol name)
-}
expressionP :: Parser Expression
expressionP = makeExprParser termP [] -- operatorTable
{-
conditionP :: Parser Condition conditionP :: Parser Condition
conditionP = do conditionP = do
lhs <- expressionP lhs <- expressionP
@ -204,8 +204,8 @@ statementP
<$> variableAccessP <$> variableAccessP
<* symbol ":=" <* symbol ":="
<*> expressionP <*> expressionP
<* semicolonP <* semicolonP -}
-}
variableDeclarationP :: Parser VariableDeclaration variableDeclarationP :: Parser VariableDeclaration
variableDeclarationP = VariableDeclaration variableDeclarationP = VariableDeclaration
<$> (symbol "var" *> identifierP) <$> (symbol "var" *> identifierP)

View File

@ -0,0 +1 @@
-8

View File

@ -0,0 +1 @@
18

View File

@ -0,0 +1,3 @@
proc main() {
printi(5 - 13);
}

3
tests/vm/print_sum.elna Normal file
View File

@ -0,0 +1,3 @@
proc main() {
printi(5 + 13);
}

View File

@ -18,10 +18,16 @@ printi:
# t1 - Constant 10. # t1 - Constant 10.
# a1 - Local buffer. # a1 - Local buffer.
# t2 - Current character. # t2 - Current character.
# t3 - Whether the number is negative.
lw t0, 0(s0) lw t0, 0(s0)
addi t1, zero, 10 addi t1, zero, 10
addi a1, s0, -2 addi a1, s0, -2
addi t3, zero, 0
bge t0, zero, .digit10
addi t3, zero, 1
sub t0, zero, t0
.digit10: .digit10:
rem t2, t0, t1 rem t2, t0, t1
addi t2, t2, '0' addi t2, t2, '0'
@ -30,8 +36,12 @@ printi:
addi a1, a1, -1 addi a1, a1, -1
bne zero, t0, .digit10 bne zero, t0, .digit10
ecall beq zero, t3, .write_call
addi t2, zero, '-'
sb t2, 0(a1)
addi a1, a1, -1
.write_call:
addi a0, zero, 1 addi a0, zero, 1
addi a1, a1, 1 addi a1, a1, 1
sub a2, s0, a1 sub a2, s0, a1