Generate a call to _divide_by_zero_error on RiscV

This commit is contained in:
Eugen Wissner 2024-10-30 14:12:51 +01:00
parent 6b92e5059c
commit 43882a3a06
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
11 changed files with 89 additions and 29 deletions

5
TODO
View File

@ -21,11 +21,6 @@
there more variables the allocation will fail with out of bounds runtime there more variables the allocation will fail with out of bounds runtime
error. Implement spill over. error. Implement spill over.
# Prarsing and abstract syntax tree
- Parse signed hexadecimal numbers.
# Other # Other
- Type analysis. - Type analysis.
- Generate a call to _divide_by_zero_error on RiscV.

View File

@ -15,9 +15,10 @@ module Language.Elna.Frontend.AST
import Data.Char (chr) import Data.Char (chr)
import Data.Int (Int32) import Data.Int (Int32)
import Data.List (intercalate) import Data.List (intercalate)
import Data.Word (Word8, Word32) import Data.Word (Word8)
import Language.Elna.Location (Identifier(..), showArrayType) import Language.Elna.Location (Identifier(..), showArrayType)
import Numeric (showHex) import Numeric (showHex)
import Data.Bifunctor (Bifunctor(bimap))
newtype Program = Program [Declaration] newtype Program = Program [Declaration]
deriving Eq deriving Eq
@ -57,13 +58,14 @@ showParameters parameters =
data TypeExpression data TypeExpression
= NamedType Identifier = NamedType Identifier
| ArrayType Word32 TypeExpression | ArrayType Literal TypeExpression
deriving Eq deriving Eq
instance Show TypeExpression instance Show TypeExpression
where where
show (NamedType typeName) = show typeName show (NamedType typeName) = show typeName
show (ArrayType elementCount typeName) = showArrayType elementCount typeName show (ArrayType elementCount typeName) =
showArrayType elementCount typeName
data Statement data Statement
= EmptyStatement = EmptyStatement
@ -96,18 +98,59 @@ data VariableDeclaration =
deriving Eq deriving Eq
data Literal data Literal
= IntegerLiteral Int32 = DecimalLiteral Int32
| HexadecimalLiteral Int32 | HexadecimalLiteral Int32
| CharacterLiteral Word8 | CharacterLiteral Word8
deriving Eq deriving Eq
instance Show Literal instance Show Literal
where where
show (IntegerLiteral integer) = show integer show (DecimalLiteral integer) = show integer
show (HexadecimalLiteral integer) = '0' : 'x' : showHex integer "" show (HexadecimalLiteral integer) = '0' : 'x' : showHex integer ""
show (CharacterLiteral character) = show (CharacterLiteral character) =
'\'' : chr (fromEnum character) : ['\''] '\'' : chr (fromEnum character) : ['\'']
instance Ord Literal
where
compare x y = compare (int32Literal x) (int32Literal y)
instance Num Literal
where
x + y = DecimalLiteral $ int32Literal x + int32Literal y
x * y = DecimalLiteral $ int32Literal x * int32Literal y
abs (DecimalLiteral x) = DecimalLiteral $ abs x
abs (HexadecimalLiteral x) = HexadecimalLiteral $ abs x
abs (CharacterLiteral x) = CharacterLiteral $ abs x
negate (DecimalLiteral x) = DecimalLiteral $ negate x
negate (HexadecimalLiteral x) = HexadecimalLiteral $ negate x
negate (CharacterLiteral x) = CharacterLiteral $ negate x
signum (DecimalLiteral x) = DecimalLiteral $ signum x
signum (HexadecimalLiteral x) = HexadecimalLiteral $ signum x
signum (CharacterLiteral x) = CharacterLiteral $ signum x
fromInteger = DecimalLiteral . fromInteger
instance Real Literal
where
toRational (DecimalLiteral integer) = toRational integer
toRational (HexadecimalLiteral integer) = toRational integer
toRational (CharacterLiteral integer) = toRational integer
instance Enum Literal
where
toEnum = DecimalLiteral . fromIntegral
fromEnum = fromEnum . int32Literal
instance Integral Literal
where
toInteger = toInteger . int32Literal
quotRem x y = bimap DecimalLiteral DecimalLiteral
$ quotRem (int32Literal x) (int32Literal y)
int32Literal :: Literal -> Int32
int32Literal (DecimalLiteral integer) = integer
int32Literal (HexadecimalLiteral integer) = integer
int32Literal (CharacterLiteral integer) = fromIntegral integer
instance Show VariableDeclaration instance Show VariableDeclaration
where where
show (VariableDeclaration identifier typeExpression) = show (VariableDeclaration identifier typeExpression) =

View File

@ -134,7 +134,7 @@ dataType environmentSymbolTable (AST.NamedType baseType) = do
| otherwise -> NameAnalysis $ throwE $ UnexpectedTypeInfoError baseInfo | otherwise -> NameAnalysis $ throwE $ UnexpectedTypeInfoError baseInfo
_ -> NameAnalysis $ throwE $ UndefinedTypeError baseType _ -> NameAnalysis $ throwE $ UndefinedTypeError baseType
dataType environmentSymbolTable (AST.ArrayType arraySize baseType) = dataType environmentSymbolTable (AST.ArrayType arraySize baseType) =
dataType environmentSymbolTable baseType <&> ArrayType arraySize dataType environmentSymbolTable baseType <&> ArrayType (fromIntegral arraySize)
checkSymbol :: SymbolTable -> Identifier -> NameAnalysis () checkSymbol :: SymbolTable -> Identifier -> NameAnalysis ()
checkSymbol globalTable identifier checkSymbol globalTable identifier

View File

@ -46,8 +46,8 @@ type Parser = Parsec Void Text
literalP :: Parser Literal literalP :: Parser Literal
literalP literalP
= HexadecimalLiteral <$> (string "0x" *> lexeme Lexer.hexadecimal) = HexadecimalLiteral <$> Lexer.signed space hexadecimalP
<|> IntegerLiteral <$> Lexer.signed space integerP <|> DecimalLiteral <$> Lexer.signed space decimalP
<|> CharacterLiteral <$> lexeme charP <|> CharacterLiteral <$> lexeme charP
where where
charP = fromIntegral . fromEnum charP = fromIntegral . fromEnum
@ -141,8 +141,11 @@ commaP = void $ symbol ","
semicolonP :: Parser () semicolonP :: Parser ()
semicolonP = void $ symbol ";" semicolonP = void $ symbol ";"
integerP :: Integral a => Parser a decimalP :: Integral a => Parser a
integerP = lexeme Lexer.decimal decimalP = lexeme Lexer.decimal
hexadecimalP :: Integral a => Parser a
hexadecimalP = string "0x" *> lexeme Lexer.hexadecimal
identifierP :: Parser Identifier identifierP :: Parser Identifier
identifierP = identifierP =
@ -166,7 +169,7 @@ typeExpressionP = arrayTypeExpression
<?> "type expression" <?> "type expression"
where where
arrayTypeExpression = ArrayType arrayTypeExpression = ArrayType
<$> (symbol "array" *> bracketsP integerP) <$> (symbol "array" *> bracketsP literalP)
<*> (symbol "of" *> typeExpressionP) <*> (symbol "of" *> typeExpressionP)
procedureDeclarationP :: Parser Declaration procedureDeclarationP :: Parser Declaration

View File

@ -267,6 +267,6 @@ expression localTable = \case
) )
literal :: AST.Literal -> Operand Variable literal :: AST.Literal -> Operand Variable
literal (AST.IntegerLiteral integer) = IntOperand integer literal (AST.DecimalLiteral integer) = IntOperand integer
literal (AST.HexadecimalLiteral integer) = IntOperand integer literal (AST.HexadecimalLiteral integer) = IntOperand integer
literal (AST.CharacterLiteral character) = IntOperand $ fromIntegral character literal (AST.CharacterLiteral character) = IntOperand $ fromIntegral character

View File

@ -53,6 +53,6 @@ instance Hashable Identifier
where where
hashWithSalt salt (Identifier identifier) = hashWithSalt salt identifier hashWithSalt salt (Identifier identifier) = hashWithSalt salt identifier
showArrayType :: Show a => Word32 -> a -> String showArrayType :: (Show a, Show b) => a -> b -> String
showArrayType elementCount typeName = concat showArrayType elementCount typeName = concat
["array[", show elementCount, "] of ", show typeName] ["array[", show elementCount, "] of ", show typeName]

View File

@ -234,20 +234,31 @@ quadruple (DivisionQuadruple operand1 operand2 (Store register))
, IntOperand immediateOperand2 <- operand2 = , IntOperand immediateOperand2 <- operand2 =
let statements2 = lui immediateOperand2 register let statements2 = lui immediateOperand2 register
Store operandRegister1 = variableOperand1 Store operandRegister1 = variableOperand1
in pure $ Vector.snoc statements2 operationInstruction
$ Instruction | immediateOperand2 == 0 =
$ RiscV.BaseInstruction RiscV.Op RiscV.CallInstruction "_divide_by_zero_error"
$ RiscV.R register RiscV.DIV operandRegister1 register | otherwise = RiscV.BaseInstruction RiscV.Op
$ RiscV.Funct7 0b0000001 $ RiscV.R register RiscV.DIV operandRegister1 register
$ RiscV.Funct7 0b0000001
in pure $ Vector.snoc statements2
$ Instruction operationInstruction
| IntOperand immediateOperand1 <- operand1 | IntOperand immediateOperand1 <- operand1
, VariableOperand variableOperand2 <- operand2 = , VariableOperand variableOperand2 <- operand2 = do
let statements1 = lui immediateOperand1 register let statements1 = lui immediateOperand1 register
Store operandRegister2 = variableOperand2 Store operandRegister2 = variableOperand2
in pure $ Vector.snoc statements1 divisionInstruction = Instruction
$ Instruction $ RiscV.BaseInstruction RiscV.Op
$ RiscV.BaseInstruction RiscV.Op $ RiscV.R register RiscV.DIV register operandRegister2 (RiscV.Funct7 0b0000001)
$ RiscV.R register RiscV.DIV register operandRegister2 branchLabel <- createLabel
$ RiscV.Funct7 0b0000001 let branchInstruction = Instruction
$ RiscV.RelocatableInstruction RiscV.Branch
$ RiscV.RBranch branchLabel RiscV.BNE RiscV.Zero operandRegister2
pure $ mappend statements1 $ Vector.fromList
[ branchInstruction
, Instruction (RiscV.CallInstruction "_divide_by_zero_error")
, JumpLabel branchLabel []
, divisionInstruction
]
quadruple (LabelQuadruple (Label label)) = pure $ Vector.singleton $ JumpLabel label mempty quadruple (LabelQuadruple (Label label)) = pure $ Vector.singleton $ JumpLabel label mempty
quadruple (GoToQuadruple label) = pure $ Vector.singleton $ unconditionalJal label quadruple (GoToQuadruple label) = pure $ Vector.singleton $ unconditionalJal label
quadruple (EqualQuadruple operand1 operand2 goToLabel) quadruple (EqualQuadruple operand1 operand2 goToLabel)

View File

@ -0,0 +1 @@
-129

View File

@ -0,0 +1 @@
129

View File

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

View File

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