Add call pseudo instruction
This commit is contained in:
		
							
								
								
									
										1
									
								
								TODO
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								TODO
									
									
									
									
									
								
							@@ -8,3 +8,4 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
- Don't ignore relocations where the symbol is not defined in the symbol table.
 | 
					- Don't ignore relocations where the symbol is not defined in the symbol table.
 | 
				
			||||||
  Report an error about an undefined symbol.
 | 
					  Report an error about an undefined symbol.
 | 
				
			||||||
 | 
					- Don't hardcode symbols in symbolEntry.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,25 +1,56 @@
 | 
				
			|||||||
module Language.Elna.AST
 | 
					module Language.Elna.AST
 | 
				
			||||||
    ( Program(..)
 | 
					    ( Declaration(..)
 | 
				
			||||||
 | 
					    , Identifier(..)
 | 
				
			||||||
 | 
					    , Parameter(..)
 | 
				
			||||||
 | 
					    , Program(..)
 | 
				
			||||||
 | 
					    , Statement(..)
 | 
				
			||||||
 | 
					    , TypeExpression(..)
 | 
				
			||||||
 | 
					    , VariableDeclaration(..)
 | 
				
			||||||
    {-, VariableAccess(..)
 | 
					    {-, VariableAccess(..)
 | 
				
			||||||
    , Condition(..)
 | 
					    , Condition(..)
 | 
				
			||||||
    , Declaration(..)
 | 
					 | 
				
			||||||
    , Expression(..)
 | 
					    , Expression(..)
 | 
				
			||||||
    , Identifier(..)
 | 
					    , Literal(..)-}
 | 
				
			||||||
    , Literal(..)
 | 
					 | 
				
			||||||
    , Parameter(..)
 | 
					 | 
				
			||||||
    , Statement(..)
 | 
					 | 
				
			||||||
    , VariableDeclaration(..)
 | 
					 | 
				
			||||||
    , TypeExpression(..)-}
 | 
					 | 
				
			||||||
    ) where
 | 
					    ) where
 | 
				
			||||||
 | 
					
 | 
				
			||||||
data Program = Program
 | 
					 | 
				
			||||||
{-
 | 
					 | 
				
			||||||
import Data.Int (Int32)
 | 
					 | 
				
			||||||
import Data.List (intercalate)
 | 
					import Data.List (intercalate)
 | 
				
			||||||
import Data.Word (Word16, Word32)
 | 
					import Data.Word ({-Word16, -}Word32)
 | 
				
			||||||
import Data.Char (chr)
 | 
					 | 
				
			||||||
import Language.Elna.Location (Identifier(..), showArrayType)
 | 
					import Language.Elna.Location (Identifier(..), showArrayType)
 | 
				
			||||||
import Numeric (showHex)
 | 
					
 | 
				
			||||||
 | 
					newtype Program = Program [Declaration]
 | 
				
			||||||
 | 
					    deriving Eq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					instance Show Program
 | 
				
			||||||
 | 
					  where
 | 
				
			||||||
 | 
					    show (Program declarations) = unlines (show <$> declarations)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					data Declaration
 | 
				
			||||||
 | 
					    = ProcedureDeclaration Identifier [Parameter] [VariableDeclaration] [Statement]
 | 
				
			||||||
 | 
					    -- | TypeDefinition Identifier TypeExpression
 | 
				
			||||||
 | 
					    deriving Eq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					instance Show Declaration
 | 
				
			||||||
 | 
					  where
 | 
				
			||||||
 | 
					    {- show (TypeDefinition identifier typeExpression) =
 | 
				
			||||||
 | 
					        concat ["type ", show identifier, " = ", show typeExpression, ";"] -}
 | 
				
			||||||
 | 
					    show (ProcedureDeclaration procedureName parameters variables body)
 | 
				
			||||||
 | 
					        = "proc " <> show procedureName <> showParameters parameters <> " {\n"
 | 
				
			||||||
 | 
					        <> unlines (("  " <>) . show <$> variables)
 | 
				
			||||||
 | 
					        <> unlines (("  " <>) . show <$> body)
 | 
				
			||||||
 | 
					        <> "}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					data Parameter = Parameter Identifier TypeExpression Bool
 | 
				
			||||||
 | 
					    deriving Eq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					instance Show Parameter
 | 
				
			||||||
 | 
					  where
 | 
				
			||||||
 | 
					    show (Parameter identifier typeName ref) = concat
 | 
				
			||||||
 | 
					        [ if ref then "ref " else ""
 | 
				
			||||||
 | 
					        , show identifier, ": ", show typeName
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					showParameters :: [Parameter] -> String
 | 
				
			||||||
 | 
					showParameters parameters =
 | 
				
			||||||
 | 
					    "(" <> intercalate ", " (show <$> parameters) <> ")"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
data TypeExpression
 | 
					data TypeExpression
 | 
				
			||||||
    = NamedType Identifier
 | 
					    = NamedType Identifier
 | 
				
			||||||
@@ -31,6 +62,45 @@ instance Show TypeExpression
 | 
				
			|||||||
    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
 | 
				
			||||||
 | 
					    = EmptyStatement
 | 
				
			||||||
 | 
					    {-| AssignmentStatement VariableAccess Expression
 | 
				
			||||||
 | 
					    | IfStatement Condition Statement (Maybe Statement)
 | 
				
			||||||
 | 
					    | WhileStatement Condition Statement
 | 
				
			||||||
 | 
					    | CompoundStatement [Statement]
 | 
				
			||||||
 | 
					    | CallStatement Identifier [Expression]-}
 | 
				
			||||||
 | 
					    deriving Eq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					instance Show Statement
 | 
				
			||||||
 | 
					  where
 | 
				
			||||||
 | 
					    show EmptyStatement = ";"
 | 
				
			||||||
 | 
					    {-show (AssignmentStatement lhs rhs) =
 | 
				
			||||||
 | 
					        concat [show lhs, " := ", show rhs, ";"]
 | 
				
			||||||
 | 
					    show (IfStatement condition if' else') = concat
 | 
				
			||||||
 | 
					        [ "if (", show condition, ") "
 | 
				
			||||||
 | 
					        , show if'
 | 
				
			||||||
 | 
					        , maybe "" ((<> " else ") . show) else'
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					    show (WhileStatement expression statement) =
 | 
				
			||||||
 | 
					        concat ["while (", show expression, ") ", show statement, ";"]
 | 
				
			||||||
 | 
					    show (CompoundStatement statements) =
 | 
				
			||||||
 | 
					        concat ["{\n", unlines (show <$> statements), " }"]
 | 
				
			||||||
 | 
					    show (CallStatement name parameters) = show name <> "("
 | 
				
			||||||
 | 
					        <> intercalate ", " (show <$> parameters) <> ")"-}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					data VariableDeclaration =
 | 
				
			||||||
 | 
					    VariableDeclaration Identifier TypeExpression
 | 
				
			||||||
 | 
					    deriving Eq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					instance Show VariableDeclaration
 | 
				
			||||||
 | 
					  where
 | 
				
			||||||
 | 
					    show (VariableDeclaration identifier typeExpression) =
 | 
				
			||||||
 | 
					        concat ["var ", show identifier, ": " <> show typeExpression, ";"]
 | 
				
			||||||
 | 
					{-
 | 
				
			||||||
 | 
					import Data.Int (Int32)
 | 
				
			||||||
 | 
					import Data.Char (chr)
 | 
				
			||||||
 | 
					import Numeric (showHex)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
data Literal
 | 
					data Literal
 | 
				
			||||||
    = IntegerLiteral Int32
 | 
					    = IntegerLiteral Int32
 | 
				
			||||||
    | HexadecimalLiteral Int32
 | 
					    | HexadecimalLiteral Int32
 | 
				
			||||||
@@ -96,75 +166,4 @@ instance Show Condition
 | 
				
			|||||||
    show (GreaterCondition lhs rhs) = concat [show lhs, " > ", show rhs]
 | 
					    show (GreaterCondition lhs rhs) = concat [show lhs, " > ", show rhs]
 | 
				
			||||||
    show (LessOrEqualCondition lhs rhs) = concat [show lhs, " <= ", show rhs]
 | 
					    show (LessOrEqualCondition lhs rhs) = concat [show lhs, " <= ", show rhs]
 | 
				
			||||||
    show (GreaterOrEqualCondition lhs rhs) = concat [show lhs, " >= ", show rhs]
 | 
					    show (GreaterOrEqualCondition lhs rhs) = concat [show lhs, " >= ", show rhs]
 | 
				
			||||||
 | 
					 | 
				
			||||||
data Statement
 | 
					 | 
				
			||||||
    = EmptyStatement
 | 
					 | 
				
			||||||
    | AssignmentStatement VariableAccess Expression
 | 
					 | 
				
			||||||
    | IfStatement Condition Statement (Maybe Statement)
 | 
					 | 
				
			||||||
    | WhileStatement Condition Statement
 | 
					 | 
				
			||||||
    | CompoundStatement [Statement]
 | 
					 | 
				
			||||||
    | CallStatement Identifier [Expression]
 | 
					 | 
				
			||||||
    deriving Eq
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
instance Show Statement
 | 
					 | 
				
			||||||
  where
 | 
					 | 
				
			||||||
    show EmptyStatement = ";"
 | 
					 | 
				
			||||||
    show (AssignmentStatement lhs rhs) =
 | 
					 | 
				
			||||||
        concat [show lhs, " := ", show rhs, ";"]
 | 
					 | 
				
			||||||
    show (IfStatement condition if' else') = concat
 | 
					 | 
				
			||||||
        [ "if (", show condition, ") "
 | 
					 | 
				
			||||||
        , show if'
 | 
					 | 
				
			||||||
        , maybe "" ((<> " else ") . show) else'
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
    show (WhileStatement expression statement) =
 | 
					 | 
				
			||||||
        concat ["while (", show expression, ") ", show statement, ";"]
 | 
					 | 
				
			||||||
    show (CompoundStatement statements) =
 | 
					 | 
				
			||||||
        concat ["{\n", unlines (show <$> statements), " }"]
 | 
					 | 
				
			||||||
    show (CallStatement name parameters) = show name <> "("
 | 
					 | 
				
			||||||
        <> intercalate ", " (show <$> parameters) <> ")"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
data Parameter = Parameter Identifier TypeExpression Bool
 | 
					 | 
				
			||||||
    deriving Eq
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
instance Show Parameter
 | 
					 | 
				
			||||||
  where
 | 
					 | 
				
			||||||
    show (Parameter identifier typeName ref) = concat
 | 
					 | 
				
			||||||
        [ if ref then "ref " else ""
 | 
					 | 
				
			||||||
        , show identifier, ": ", show typeName
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
data VariableDeclaration =
 | 
					 | 
				
			||||||
    VariableDeclaration Identifier TypeExpression
 | 
					 | 
				
			||||||
    deriving Eq
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
instance Show VariableDeclaration
 | 
					 | 
				
			||||||
  where
 | 
					 | 
				
			||||||
    show (VariableDeclaration identifier typeExpression) =
 | 
					 | 
				
			||||||
        concat ["var ", show identifier, ": " <> show typeExpression, ";"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
data Declaration
 | 
					 | 
				
			||||||
    = TypeDefinition Identifier TypeExpression
 | 
					 | 
				
			||||||
    | ProcedureDefinition Identifier [Parameter] [VariableDeclaration] [Statement]
 | 
					 | 
				
			||||||
    deriving Eq
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
instance Show Declaration
 | 
					 | 
				
			||||||
  where
 | 
					 | 
				
			||||||
    show (TypeDefinition identifier typeExpression) =
 | 
					 | 
				
			||||||
        concat ["type ", show identifier, " = ", show typeExpression, ";"]
 | 
					 | 
				
			||||||
    show (ProcedureDefinition procedureName parameters variables body)
 | 
					 | 
				
			||||||
        = "proc " <> show procedureName <> showParameters parameters <> " {\n"
 | 
					 | 
				
			||||||
        <> unlines (("  " <>) . show <$> variables)
 | 
					 | 
				
			||||||
        <> unlines (("  " <>) . show <$> body)
 | 
					 | 
				
			||||||
        <> "}"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
newtype Program = Program [Declaration]
 | 
					 | 
				
			||||||
    deriving Eq
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
instance Show Program
 | 
					 | 
				
			||||||
  where
 | 
					 | 
				
			||||||
    show (Program declarations) = unlines (show <$> declarations)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
showParameters :: [Parameter] -> String
 | 
					 | 
				
			||||||
showParameters parameters =
 | 
					 | 
				
			||||||
    "(" <> intercalate ", " (show <$> parameters) <> ")"
 | 
					 | 
				
			||||||
-}
 | 
					-}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -150,6 +150,7 @@ data RelocationType
 | 
				
			|||||||
data Instruction
 | 
					data Instruction
 | 
				
			||||||
    = Instruction BaseOpcode Type
 | 
					    = Instruction BaseOpcode Type
 | 
				
			||||||
    | RelocatableInstruction BaseOpcode RelocationType
 | 
					    | RelocatableInstruction BaseOpcode RelocationType
 | 
				
			||||||
 | 
					    | CallInstruction Text
 | 
				
			||||||
    deriving Eq
 | 
					    deriving Eq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
xRegister :: XRegister -> Word8
 | 
					xRegister :: XRegister -> Word8
 | 
				
			||||||
@@ -306,6 +307,10 @@ instruction :: Instruction -> ByteString.Builder.Builder
 | 
				
			|||||||
instruction = \case
 | 
					instruction = \case
 | 
				
			||||||
    (Instruction base instructionType) -> go base $ type' instructionType
 | 
					    (Instruction base instructionType) -> go base $ type' instructionType
 | 
				
			||||||
    (RelocatableInstruction base instructionType) -> go base $ relocationType instructionType
 | 
					    (RelocatableInstruction base instructionType) -> go base $ relocationType instructionType
 | 
				
			||||||
 | 
					    (CallInstruction _) -> foldMap instruction
 | 
				
			||||||
 | 
					        [ Instruction Auipc $ U RA 0
 | 
				
			||||||
 | 
					        , Instruction Jalr $ I RA JALR RA 0
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
  where
 | 
					  where
 | 
				
			||||||
    go base instructionType
 | 
					    go base instructionType
 | 
				
			||||||
        = ByteString.Builder.word32LE
 | 
					        = ByteString.Builder.word32LE
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,8 @@ import Language.Elna.SymbolTable (SymbolTable)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
generateCode :: SymbolTable -> Vector Quadruple -> Vector RiscV.Instruction
 | 
					generateCode :: SymbolTable -> Vector Quadruple -> Vector RiscV.Instruction
 | 
				
			||||||
generateCode _ _ = Vector.fromList
 | 
					generateCode _ _ = Vector.fromList
 | 
				
			||||||
    [ RiscV.Instruction RiscV.OpImm $ RiscV.I RiscV.A0 RiscV.ADDI RiscV.Zero 0
 | 
					    [ RiscV.CallInstruction "printi"
 | 
				
			||||||
 | 
					    , RiscV.Instruction RiscV.OpImm $ RiscV.I RiscV.A0 RiscV.ADDI RiscV.Zero 0
 | 
				
			||||||
    , RiscV.Instruction RiscV.OpImm $ RiscV.I RiscV.A7 RiscV.ADDI RiscV.Zero 93
 | 
					    , RiscV.Instruction RiscV.OpImm $ RiscV.I RiscV.A7 RiscV.ADDI RiscV.Zero 93
 | 
				
			||||||
    , RiscV.Instruction RiscV.System $ RiscV.Type RiscV.Zero RiscV.PRIV RiscV.Zero RiscV.ECALL
 | 
					    , RiscV.Instruction RiscV.System $ RiscV.Type RiscV.Zero RiscV.PRIV RiscV.Zero RiscV.ECALL
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,89 +3,48 @@ module Language.Elna.Parser
 | 
				
			|||||||
    , programP
 | 
					    , programP
 | 
				
			||||||
    ) 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)
 | 
				
			||||||
import Language.Elna.AST
 | 
					import Language.Elna.AST
 | 
				
			||||||
    ( Program(..)
 | 
					    ( Declaration(..)
 | 
				
			||||||
    {-, VariableAccess(..)
 | 
					 | 
				
			||||||
    , Condition(..)
 | 
					 | 
				
			||||||
    , Declaration(..)
 | 
					 | 
				
			||||||
    , Expression(..)
 | 
					 | 
				
			||||||
    , Identifier(..)
 | 
					    , Identifier(..)
 | 
				
			||||||
    , Literal(..)
 | 
					 | 
				
			||||||
    , Parameter(..)
 | 
					    , Parameter(..)
 | 
				
			||||||
 | 
					    , Program(..)
 | 
				
			||||||
    , Statement(..)
 | 
					    , Statement(..)
 | 
				
			||||||
    , TypeExpression(..)
 | 
					    , TypeExpression(..)
 | 
				
			||||||
    , VariableDeclaration(..)-}
 | 
					    , VariableDeclaration(..)
 | 
				
			||||||
 | 
					    {-, VariableAccess(..)
 | 
				
			||||||
 | 
					    , Condition(..)
 | 
				
			||||||
 | 
					    , Expression(..)
 | 
				
			||||||
 | 
					    , Literal(..)-}
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
import Text.Megaparsec
 | 
					import Text.Megaparsec
 | 
				
			||||||
    ( Parsec
 | 
					    ( Parsec
 | 
				
			||||||
    {-, MonadParsec(..)
 | 
					 | 
				
			||||||
    , (<?>)
 | 
					    , (<?>)
 | 
				
			||||||
 | 
					    --, MonadParsec(..)
 | 
				
			||||||
 | 
					    , eof
 | 
				
			||||||
    , optional
 | 
					    , optional
 | 
				
			||||||
    , between
 | 
					    , between
 | 
				
			||||||
    , sepBy
 | 
					    , sepBy
 | 
				
			||||||
    , choice -}
 | 
					    --, choice
 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
{- import Text.Megaparsec.Char
 | 
					 | 
				
			||||||
    ( alphaNumChar
 | 
					 | 
				
			||||||
    , char
 | 
					 | 
				
			||||||
    , letterChar
 | 
					 | 
				
			||||||
    , space1
 | 
					 | 
				
			||||||
    , string
 | 
					 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
import qualified Text.Megaparsec.Char.Lexer as Lexer
 | 
					import qualified Text.Megaparsec.Char.Lexer as Lexer
 | 
				
			||||||
 | 
					import Text.Megaparsec.Char
 | 
				
			||||||
 | 
					    ( alphaNumChar
 | 
				
			||||||
 | 
					--    , char
 | 
				
			||||||
 | 
					    , letterChar
 | 
				
			||||||
 | 
					    , space1
 | 
				
			||||||
 | 
					--    , string
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
import Control.Applicative (Alternative(..))
 | 
					import Control.Applicative (Alternative(..))
 | 
				
			||||||
import Data.Maybe (isJust)
 | 
					import Data.Maybe (isJust)
 | 
				
			||||||
import Data.Functor (($>))
 | 
					-- import Data.Functor (($>))
 | 
				
			||||||
-}
 | 
					
 | 
				
			||||||
type Parser = Parsec Void Text
 | 
					type Parser = Parsec Void Text
 | 
				
			||||||
{-
 | 
					{-
 | 
				
			||||||
space :: Parser ()
 | 
					 | 
				
			||||||
space = Lexer.space space1 (Lexer.skipLineComment "//")
 | 
					 | 
				
			||||||
    $ Lexer.skipBlockComment "/*" "*/"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
lexeme :: forall a. Parser a -> Parser a
 | 
					 | 
				
			||||||
lexeme = Lexer.lexeme space
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
symbol :: Text -> Parser Text
 | 
					 | 
				
			||||||
symbol = Lexer.symbol space
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
blockP :: forall a. Parser a -> Parser a
 | 
					 | 
				
			||||||
blockP = between (symbol "{") (symbol "}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
procedureP :: Parser ()
 | 
					 | 
				
			||||||
procedureP = void $ symbol "proc"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
parensP :: forall a. Parser a -> Parser a
 | 
					 | 
				
			||||||
parensP = between (symbol "(")  (symbol ")")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bracketsP :: forall a. Parser a -> Parser a
 | 
					 | 
				
			||||||
bracketsP = between (symbol "[") (symbol "]")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
colonP :: Parser ()
 | 
					 | 
				
			||||||
colonP = void $ symbol ":"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
semicolonP :: Parser ()
 | 
					 | 
				
			||||||
semicolonP = void $ symbol ";"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
identifierP :: Parser Identifier
 | 
					 | 
				
			||||||
identifierP =
 | 
					 | 
				
			||||||
    let wordParser = (:) <$> letterChar <*> many alphaNumChar <?> "identifier"
 | 
					 | 
				
			||||||
     in fmap Identifier $ lexeme $ Text.pack <$> wordParser
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typeExpressionP :: Parser TypeExpression
 | 
					 | 
				
			||||||
typeExpressionP = arrayTypeExpression
 | 
					 | 
				
			||||||
    <|> NamedType <$> identifierP
 | 
					 | 
				
			||||||
    <?> "type expression"
 | 
					 | 
				
			||||||
  where
 | 
					 | 
				
			||||||
    arrayTypeExpression = ArrayType
 | 
					 | 
				
			||||||
        <$> (symbol "array" *> bracketsP (lexeme Lexer.decimal))
 | 
					 | 
				
			||||||
        <*> (symbol "of" *> typeExpressionP)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typeDefinitionP :: Parser Declaration
 | 
					typeDefinitionP :: Parser Declaration
 | 
				
			||||||
typeDefinitionP = TypeDefinition
 | 
					typeDefinitionP = TypeDefinition
 | 
				
			||||||
    <$> (symbol "type" *> identifierP)
 | 
					    <$> (symbol "type" *> identifierP)
 | 
				
			||||||
@@ -93,24 +52,6 @@ typeDefinitionP = TypeDefinition
 | 
				
			|||||||
    <* semicolonP
 | 
					    <* semicolonP
 | 
				
			||||||
    <?> "type definition"
 | 
					    <?> "type definition"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
variableDeclarationP :: Parser VariableDeclaration
 | 
					 | 
				
			||||||
variableDeclarationP = VariableDeclaration
 | 
					 | 
				
			||||||
    <$> (symbol "var" *> identifierP)
 | 
					 | 
				
			||||||
    <*> (colonP *> typeExpressionP)
 | 
					 | 
				
			||||||
    <* semicolonP
 | 
					 | 
				
			||||||
    <?> "variable declaration"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
parameterP :: Parser Parameter
 | 
					 | 
				
			||||||
parameterP = paramCons
 | 
					 | 
				
			||||||
    <$> optional (symbol "ref")
 | 
					 | 
				
			||||||
    <*> identifierP
 | 
					 | 
				
			||||||
    <*> (colonP *> typeExpressionP)
 | 
					 | 
				
			||||||
  where
 | 
					 | 
				
			||||||
    paramCons ref name typeName = Parameter name typeName (isJust ref)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
commaP :: Parser ()
 | 
					 | 
				
			||||||
commaP = void $ symbol ","
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
literalP :: Parser Literal
 | 
					literalP :: Parser Literal
 | 
				
			||||||
literalP
 | 
					literalP
 | 
				
			||||||
    = HexadecimalLiteral <$> (string "0x" *> lexeme Lexer.hexadecimal)
 | 
					    = HexadecimalLiteral <$> (string "0x" *> lexeme Lexer.hexadecimal)
 | 
				
			||||||
@@ -174,17 +115,80 @@ conditionP = do
 | 
				
			|||||||
        , symbol "=" >> pure EqualCondition
 | 
					        , symbol "=" >> pure EqualCondition
 | 
				
			||||||
        , symbol "#" >> pure NonEqualCondition
 | 
					        , symbol "#" >> pure NonEqualCondition
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					symbol :: Text -> Parser Text
 | 
				
			||||||
 | 
					symbol = Lexer.symbol space
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					space :: Parser ()
 | 
				
			||||||
 | 
					space = Lexer.space space1 (Lexer.skipLineComment "//")
 | 
				
			||||||
 | 
					    $ Lexer.skipBlockComment "/*" "*/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					lexeme :: forall a. Parser a -> Parser a
 | 
				
			||||||
 | 
					lexeme = Lexer.lexeme space
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					blockP :: forall a. Parser a -> Parser a
 | 
				
			||||||
 | 
					blockP = between (symbol "{") (symbol "}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					parensP :: forall a. Parser a -> Parser a
 | 
				
			||||||
 | 
					parensP = between (symbol "(")  (symbol ")")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bracketsP :: forall a. Parser a -> Parser a
 | 
				
			||||||
 | 
					bracketsP = between (symbol "[") (symbol "]")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					colonP :: Parser ()
 | 
				
			||||||
 | 
					colonP = void $ symbol ":"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					commaP :: Parser ()
 | 
				
			||||||
 | 
					commaP = void $ symbol ","
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					semicolonP :: Parser ()
 | 
				
			||||||
 | 
					semicolonP = void $ symbol ";"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					identifierP :: Parser Identifier
 | 
				
			||||||
 | 
					identifierP =
 | 
				
			||||||
 | 
					    let wordParser = (:) <$> letterChar <*> many alphaNumChar <?> "identifier"
 | 
				
			||||||
 | 
					     in fmap Identifier $ lexeme $ Text.pack <$> wordParser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					procedureP :: Parser ()
 | 
				
			||||||
 | 
					procedureP = void $ symbol "proc"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					parameterP :: Parser Parameter
 | 
				
			||||||
 | 
					parameterP = paramCons
 | 
				
			||||||
 | 
					    <$> optional (symbol "ref")
 | 
				
			||||||
 | 
					    <*> identifierP
 | 
				
			||||||
 | 
					    <*> (colonP *> typeExpressionP)
 | 
				
			||||||
 | 
					  where
 | 
				
			||||||
 | 
					    paramCons ref name typeName = Parameter name typeName (isJust ref)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typeExpressionP :: Parser TypeExpression
 | 
				
			||||||
 | 
					typeExpressionP = arrayTypeExpression
 | 
				
			||||||
 | 
					    <|> NamedType <$> identifierP
 | 
				
			||||||
 | 
					    <?> "type expression"
 | 
				
			||||||
 | 
					  where
 | 
				
			||||||
 | 
					    arrayTypeExpression = ArrayType
 | 
				
			||||||
 | 
					        <$> (symbol "array" *> bracketsP (lexeme Lexer.decimal))
 | 
				
			||||||
 | 
					        <*> (symbol "of" *> typeExpressionP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					procedureDeclarationP :: Parser Declaration
 | 
				
			||||||
 | 
					procedureDeclarationP = procedureCons
 | 
				
			||||||
 | 
					    <$> (procedureP *> identifierP)
 | 
				
			||||||
 | 
					    <*> parensP (sepBy parameterP commaP)
 | 
				
			||||||
 | 
					    <*> blockP ((,) <$> many variableDeclarationP <*> many statementP)
 | 
				
			||||||
 | 
					    <?> "procedure definition"
 | 
				
			||||||
 | 
					  where
 | 
				
			||||||
 | 
					    procedureCons procedureName parameters (variables, body) =
 | 
				
			||||||
 | 
					        ProcedureDeclaration procedureName parameters variables body
 | 
				
			||||||
 | 
					
 | 
				
			||||||
statementP :: Parser Statement
 | 
					statementP :: Parser Statement
 | 
				
			||||||
statementP
 | 
					statementP
 | 
				
			||||||
    = EmptyStatement <$ semicolonP
 | 
					    = EmptyStatement <$ semicolonP
 | 
				
			||||||
    <|> CompoundStatement <$> blockP (many statementP)
 | 
					    {-<|> CompoundStatement <$> blockP (many statementP)
 | 
				
			||||||
    <|> try assignmentP
 | 
					    <|> try assignmentP
 | 
				
			||||||
    <|> try ifElseP
 | 
					    <|> try ifElseP
 | 
				
			||||||
    <|> try whileP
 | 
					    <|> try whileP
 | 
				
			||||||
    <|> try callP
 | 
					    <|> try callP -}
 | 
				
			||||||
    <?> "statement"
 | 
					    <?> "statement"
 | 
				
			||||||
  where
 | 
					  {-where
 | 
				
			||||||
    ifElseP = IfStatement
 | 
					    ifElseP = IfStatement
 | 
				
			||||||
        <$> (symbol "if" *> parensP conditionP)
 | 
					        <$> (symbol "if" *> parensP conditionP)
 | 
				
			||||||
        <*> statementP
 | 
					        <*> statementP
 | 
				
			||||||
@@ -201,19 +205,16 @@ statementP
 | 
				
			|||||||
        <* symbol ":="
 | 
					        <* symbol ":="
 | 
				
			||||||
        <*> expressionP
 | 
					        <*> expressionP
 | 
				
			||||||
        <* semicolonP
 | 
					        <* semicolonP
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
procedureDefinitionP :: Parser Declaration
 | 
					variableDeclarationP :: Parser VariableDeclaration
 | 
				
			||||||
procedureDefinitionP = procedureCons
 | 
					variableDeclarationP = VariableDeclaration
 | 
				
			||||||
    <$> (procedureP *> identifierP)
 | 
					    <$> (symbol "var" *> identifierP)
 | 
				
			||||||
    <*> parensP (sepBy parameterP commaP)
 | 
					    <*> (colonP *> typeExpressionP)
 | 
				
			||||||
    <*> blockP ((,) <$> many variableDeclarationP <*> many statementP)
 | 
					    <* semicolonP
 | 
				
			||||||
    <?> "procedure definition"
 | 
					    <?> "variable declaration"
 | 
				
			||||||
  where
 | 
					 | 
				
			||||||
    procedureCons procedureName parameters (variables, body) =
 | 
					 | 
				
			||||||
        ProcedureDefinition procedureName parameters variables body
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
declarationP :: Parser Declaration
 | 
					declarationP :: Parser Declaration
 | 
				
			||||||
declarationP = typeDefinitionP <|> procedureDefinitionP
 | 
					declarationP = procedureDeclarationP -- <|> typeDefinitionP
 | 
				
			||||||
-}
 | 
					
 | 
				
			||||||
programP :: Parser Program
 | 
					programP :: Parser Program
 | 
				
			||||||
programP = pure Program -- <$> many declarationP
 | 
					programP = Program <$> many declarationP <* eof
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -211,9 +211,17 @@ riscv32Elf code objectHandle = text
 | 
				
			|||||||
                , st_name = fromIntegral $ ByteString.length names
 | 
					                , st_name = fromIntegral $ ByteString.length names
 | 
				
			||||||
                , st_info = stInfo STB_GLOBAL STT_FUNC
 | 
					                , st_info = stInfo STB_GLOBAL STT_FUNC
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					            printEntry = Elf32_Sym
 | 
				
			||||||
 | 
					                { st_value = 0
 | 
				
			||||||
 | 
					                , st_size = 0
 | 
				
			||||||
 | 
					                , st_shndx = 0
 | 
				
			||||||
 | 
					                , st_other = 0
 | 
				
			||||||
 | 
					                , st_name = fromIntegral (ByteString.length names) + 7
 | 
				
			||||||
 | 
					                , st_info = stInfo STB_GLOBAL STT_FUNC
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
        liftIO $ ByteString.hPut objectHandle $ LazyByteString.toStrict encoded
 | 
					        liftIO $ ByteString.hPut objectHandle $ LazyByteString.toStrict encoded
 | 
				
			||||||
        let newResult = ElfHeaderResult (names <> "_start\0")
 | 
					        let newResult = ElfHeaderResult (names <> "_start\0printi\0")
 | 
				
			||||||
                $ Vector.snoc entries newEntry
 | 
					                $ Vector.snoc (Vector.snoc entries newEntry) printEntry
 | 
				
			||||||
        pure (newResult, size, updatedRelocations)
 | 
					        pure (newResult, size, updatedRelocations)
 | 
				
			||||||
    encodeInstruction (instructions, offset, relocations) instruction =
 | 
					    encodeInstruction (instructions, offset, relocations) instruction =
 | 
				
			||||||
        let unresolvedRelocation = case instruction of
 | 
					        let unresolvedRelocation = case instruction of
 | 
				
			||||||
@@ -227,6 +235,9 @@ riscv32Elf code objectHandle = text
 | 
				
			|||||||
                    | RiscV.Lower12S symbolName _ _ _ <- instructionType
 | 
					                    | RiscV.Lower12S symbolName _ _ _ <- instructionType
 | 
				
			||||||
                        -> Just -- R_RISCV_LO12_S
 | 
					                        -> Just -- R_RISCV_LO12_S
 | 
				
			||||||
                        $ UnresolvedRelocation (Text.Encoding.encodeUtf8 symbolName) offset 28
 | 
					                        $ UnresolvedRelocation (Text.Encoding.encodeUtf8 symbolName) offset 28
 | 
				
			||||||
 | 
					                RiscV.CallInstruction symbolName
 | 
				
			||||||
 | 
					                    -> Just -- R_RISCV_CALL_PLT
 | 
				
			||||||
 | 
					                    $ UnresolvedRelocation (Text.Encoding.encodeUtf8 symbolName) offset 19
 | 
				
			||||||
                RiscV.Instruction _ _ -> Nothing
 | 
					                RiscV.Instruction _ _ -> Nothing
 | 
				
			||||||
            encoded = ByteString.Builder.toLazyByteString
 | 
					            encoded = ByteString.Builder.toLazyByteString
 | 
				
			||||||
                $ RiscV.instruction instruction
 | 
					                $ RiscV.instruction instruction
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,32 +5,47 @@ require_relative 'shared'
 | 
				
			|||||||
CLEAN.include(TMP + 'riscv')
 | 
					CLEAN.include(TMP + 'riscv')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LINKER = 'build/rootfs/riscv32-unknown-linux-gnu/bin/ld'
 | 
					LINKER = 'build/rootfs/riscv32-unknown-linux-gnu/bin/ld'
 | 
				
			||||||
 | 
					AS = 'build/rootfs/riscv32-unknown-linux-gnu/bin/as'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace :test do
 | 
					namespace :test do
 | 
				
			||||||
  test_sources = FileList['tests/vm/*.elna']
 | 
					  test_sources = FileList['tests/vm/*.elna', 'tests/vm/*.s']
 | 
				
			||||||
  compiler = `cabal list-bin elna`.strip
 | 
					  compiler = `cabal list-bin elna`.strip
 | 
				
			||||||
  object_directory = TMP + 'riscv/tests'
 | 
					  object_directory = TMP + 'riscv/tests'
 | 
				
			||||||
  root_directory = TMP + 'riscv/root'
 | 
					  root_directory = TMP + 'riscv/root'
 | 
				
			||||||
  executable_directory = root_directory + 'tests'
 | 
					  executable_directory = root_directory + 'tests'
 | 
				
			||||||
  expectation_directory = root_directory + 'expectations'
 | 
					  expectation_directory = root_directory + 'expectations'
 | 
				
			||||||
  init = TMP + 'riscv/root/init'
 | 
					  init = TMP + 'riscv/root/init'
 | 
				
			||||||
 | 
					  builtin = TMP + 'riscv/builtin.o'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  directory root_directory
 | 
					  directory root_directory
 | 
				
			||||||
  directory object_directory
 | 
					  directory object_directory
 | 
				
			||||||
  directory executable_directory
 | 
					  directory executable_directory
 | 
				
			||||||
  directory expectation_directory
 | 
					  directory expectation_directory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  file builtin => ['tools/builtin.s', object_directory] do |task|
 | 
				
			||||||
 | 
					    sh AS, '-o', task.name, task.prerequisites.first
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  test_files = test_sources.flat_map do |test_source|
 | 
					  test_files = test_sources.flat_map do |test_source|
 | 
				
			||||||
    test_basename = File.basename(test_source, '.elna')
 | 
					    test_basename = File.basename(test_source, '.*')
 | 
				
			||||||
    test_object = object_directory + test_basename.ext('.o')
 | 
					    test_object = object_directory + test_basename.ext('.o')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    file test_object => [test_source, object_directory] do
 | 
					    file test_object => [test_source, object_directory] do |task|
 | 
				
			||||||
      sh compiler, '--output', test_object.to_path, test_source
 | 
					      case File.extname(task.prerequisites.first)
 | 
				
			||||||
 | 
					      when '.s'
 | 
				
			||||||
 | 
					        sh AS, '-mno-relax', '-o', task.name, task.prerequisites.first
 | 
				
			||||||
 | 
					      when '.elna'
 | 
				
			||||||
 | 
					        sh compiler, '--output', task.name, task.prerequisites.first
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        raise "Unknown source file extension #{task.prerequisites.first}"
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
    test_executable = executable_directory + test_basename
 | 
					    test_executable = executable_directory + test_basename
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    file test_executable => [test_object, executable_directory] do
 | 
					    file test_executable => [test_object, executable_directory, builtin] do |task|
 | 
				
			||||||
      sh LINKER, '-o', test_executable.to_path, test_object.to_path
 | 
					      objects = task.prerequisites.filter { |prerequisite| File.file? prerequisite }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      sh LINKER, '-o', test_executable.to_path, *objects
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
    expectation_name = test_basename.ext '.txt'
 | 
					    expectation_name = test_basename.ext '.txt'
 | 
				
			||||||
    source_expectation = "tests/expectations/#{expectation_name}"
 | 
					    source_expectation = "tests/expectations/#{expectation_name}"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					0
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					proc main() {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										29
									
								
								tools/builtin.s
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								tools/builtin.s
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					.global printi
 | 
				
			||||||
 | 
					.type printi, @function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.text
 | 
				
			||||||
 | 
					printi:
 | 
				
			||||||
 | 
					    addi sp, sp, -8
 | 
				
			||||||
 | 
					    sw s0, 0(sp)
 | 
				
			||||||
 | 
					    sw ra, 4(sp)
 | 
				
			||||||
 | 
					    addi s0, sp, 8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    addi t0, a0, 0
 | 
				
			||||||
 | 
					    addi a0, a0, '0'
 | 
				
			||||||
 | 
					    sw a0, 0(s0)
 | 
				
			||||||
 | 
					    addi a0, x0, 1
 | 
				
			||||||
 | 
					    addi a1, s0, 0
 | 
				
			||||||
 | 
					    addi a2, x0, 1
 | 
				
			||||||
 | 
					    addi a7, x0, 64
 | 
				
			||||||
 | 
					    ecall
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    addi t1, x0, '\n'
 | 
				
			||||||
 | 
					    sw t1, 0(s0)
 | 
				
			||||||
 | 
					    ecall
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    addi a0, t0, 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lw s0, 0(sp)
 | 
				
			||||||
 | 
					    lw ra, 4(sp)
 | 
				
			||||||
 | 
					    addi sp, sp, 8
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
@@ -118,7 +118,6 @@ enum status run_test(const char *file_entry_name)
 | 
				
			|||||||
        close(pipe_ends[0]);
 | 
					        close(pipe_ends[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int wait_status = 0;
 | 
					        int wait_status = 0;
 | 
				
			||||||
        wait(&wait_status);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        make_path(filename, "./expectations/", file_entry_name, ".txt");
 | 
					        make_path(filename, "./expectations/", file_entry_name, ".txt");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user