При написании синтаксического анализатора языка, подобного Оберону, у меня возникли проблемы с компиляцией синтаксического анализатора после того, как я обновил его, чтобы иметь возможность определять больше процедур на одном уровне, а не только вкладывать одну в другую.
Это мой лексер:
{
module Lexer where
}
%wrapper "basic"
$alpha = [a-zA-Z]
$digit = [0-9]
$validChar = [^\"]
tokens :-
$white+ ;
"PROCEDURE" { \s -> KW_TokenProcedure }
"END" { \s -> KW_TokenEnd }
";" { \s -> KW_TokenSemiColon }
$alpha [$alpha $digit \_]* { \s -> TokenVariableIdentifier s }
{
-- The token type:
data Token =
KW_TokenProcedure |
KW_TokenEnd |
KW_TokenSemiColon |
TokenVariableIdentifier String |
deriving (Eq,Show)
}
Это мой парсер:
{
module Main where
import Lexer
import Tools
}
%name myParse
%tokentype { Token }
%error { parseError }
%token
KW_PROCEDURE { KW_TokenProcedure }
KW_END { KW_TokenEnd }
';' { KW_TokenSemiColon }
identifier { TokenVariableIdentifier $$ }
%%
ProcedureDeclarationList : ProcedureDeclaration { $1 }
| ProcedureDeclaration ';' ProcedureDeclarationList { $3 : $1 }
ProcedureDeclaration : ProcedureHeading ';' ProcedureBody identifier {
do
let newProc = $1 -- Crea la nuova procedura
let procBody = $3
addProcedureToProcedure newProc procBody
}
ProcedureHeading : KW_PROCEDURE identifier { defaultProcedure { procedureName = $2 } }
ProcedureBody : KW_END { Nothing }
| DeclarationSequence KW_END { Just $1 }
DeclarationSequence : ProcedureDeclarationList { $1 }
{
parseError :: [Token] -> a
parseError _ = error "Parse error"
main = do
inStr <- getContents
let result = oLikeParse (alexScanTokens inStr)
putStrLn ("result: " ++ show(result))
}
А это модуль, в котором определяются типы и некоторые служебные функции:
module Tools where
data Procedure = Procedure { procedureName :: String,
procedureProcedures :: [Procedure] } deriving (Show)
defaultProcedure = Procedure { procedureName = "",
procedureProcedures = [] }
addProcedureToProcedure :: Procedure -> Maybe Procedure -> Procedure
addProcedureToProcedure procDest Nothing = Procedure { procedureName = (procedureName procDest),
procedureProcedures = (procedureProcedures procDest) }
addProcedureToProcedure procDest (Just procToAdd) = Procedure { procedureName = (procedureName procDest),
procedureProcedures = (procedureProcedures procDest) ++ [procToAdd] }
Ошибки, которые компилятор дает мне, следующие:
Couldn't match type ‘[Procedure]’ with ‘Procedure’
Occurs check: cannot construct the infinite type: t4 ~ [t4]
Я изолировал проблему и точно знаю, что если я удалю второй случай моего ProcedureDeclarationList
, все будет нормально компилироваться, но я не могу распознать больше процедур на том же уровне.
ОБНОВИТЬ
Я изменил свою структуру данных, так что я больше не использую Maybe Procedure
, и мне не нужен список из двух типов, но у меня все еще есть проблема с несоответствием типов.
Это мой обновленный парсер:
{
module Main where
import Lexer
import Tools
}
%name myParse
%tokentype { Token }
%error { parseError }
%token
KW_INTEGER { KW_TokenInteger }
KW_REAL { KW_TokenReal }
KW_BOOLEAN { KW_TokenBoolean }
KW_CHAR { KW_TokenChar }
KW_PROCEDURE { KW_TokenProcedure }
KW_END { KW_TokenEnd }
KW_VAR { KW_TokenVar }
';' { KW_TokenSemiColon }
',' { KW_TokenComa }
':' { KW_TokenColon }
identifier { TokenVariableIdentifier $$ }
%%
ProcedureDeclarationList : ProcedureDeclaration { [$1] }
| ProcedureDeclaration ';' ProcedureDeclarationList { $1:$3 }
ProcedureDeclaration : ProcedureHeading ';' ProcedureBody identifier { defaultDeclaration { declarationType = DT_Procedure, procedureDeclared = (addBodyToProcedure $1 $3)} }
IdentifiersList : identifier { [$1] }
| identifier ',' IdentifiersList { $1:$3 }
VariableDeclaration : IdentifiersList ':' type { createVariablesDefinitionsOfType $1 $3 }
ProcedureHeading : KW_PROCEDURE identifier { defaultProcedure { procedureName = $2 } }
ProcedureBody : KW_END { [] }
| DeclarationSequence KW_END { $1 }
DeclarationSequence : KW_VAR VariableDeclarationList ';' { $2 }
| ProcedureDeclarationList { $1 }
VariableDeclarationList : VariableDeclaration { [$1] }
| VariableDeclaration ';' VariableDeclarationList { $1:$3 }
type : KW_INTEGER { Integer }
| KW_REAL { Float }
| KW_BOOLEAN { Boolean }
| KW_CHAR { Char }
{
parseError :: [Token] -> a
parseError _ = error "Parse error"
main = do
inStr <- getContents
let result = oLikeParse (alexScanTokens inStr)
putStrLn ("result: " ++ show(result))
}
Это мой обновленный лексер:
{
module Lexer where
}
%wrapper "basic"
$alpha = [a-zA-Z]
$digit = [0-9]
$validChar = [^\"]
tokens :-
$white+ ;
"INTEGER" { \s -> KW_TokenInteger }
"REAL" { \s -> KW_TokenReal }
"BOOLEAN" { \s -> KW_TokenBoolean }
"CHAR" { \s -> KW_TokenChar }
"PROCEDURE" { \s -> KW_TokenProcedure }
"END" { \s -> KW_TokenEnd }
"VAR" { \s -> KW_TokenVar }
";" { \s -> KW_TokenSemiColon }
"," { \s -> KW_TokenComa }
":" { \s -> KW_TokenColon }
$alpha [$alpha $digit \_]* { \s -> TokenVariableIdentifier s }
{
-- The token type:
data Token =
KW_TokenInteger |
KW_TokenReal |
KW_TokenBoolean |
KW_TokenChar |
KW_TokenVar |
KW_TokenProcedure |
KW_TokenEnd |
KW_TokenSemiColon |
KW_TokenComa |
KW_TokenColon |
TokenVariableIdentifier String |
deriving (Eq,Show)
}
А это мой обновленный модуль инструментов:
module Tools where
data AttributeType = String
| Float
| Char
| Integer
| Boolean
deriving (Show, Eq)
data Attribute = Attribute { attributeName :: String,
attributeType :: AttributeType,
stringValue :: String,
floatValue :: Float,
integerValue :: Integer,
charValue :: Char,
booleanValue :: Bool } deriving (Show)
data Procedure = Procedure { procedureName :: String,
attributes :: [Attribute],
procedureProcedures :: [Procedure] } deriving (Show)
data DeclarationType = DT_Variable
| DT_Constant
| DT_Procedure
deriving (Show, Eq)
data Declaration = Declaration { declarationType :: DeclarationType,
attributeDeclared :: Attribute,
procedureDeclared :: Procedure } deriving (Show)
defaultAttribute = Attribute { attributeName = "",
attributeType = Integer,
stringValue = "",
floatValue = 0.0,
integerValue = 0,
charValue = ' ',
booleanValue = False }
defaultProcedure = Procedure { procedureName = "",
attributes = [],
procedureProcedures = [] }
defaultDeclaration = Declaration { declarationType = DT_Variable,
attributeDeclared = defaultAttribute,
procedureDeclared = defaultProcedure }
addAttributeToProcedure :: Procedure -> Attribute -> Procedure
addAttributeToProcedure proc att = Procedure { procedureName = (procedureName proc),
attributes = (attributes proc) ++ [att],
procedureProcedures = (procedureProcedures proc) }
addProcedureToProcedure :: Procedure -> Procedure -> Procedure
addProcedureToProcedure procDest procToAdd = Procedure { procedureName = (procedureName procDest),
attributes = (attributes procDest),
procedureProcedures = (procedureProcedures procDest) ++ [procToAdd] }
addBodyToProcedure :: Procedure -> [Declaration] -> Procedure
addBodyToProcedure procDest [] = procDest
addBodyToProcedure procDest declList = do
let decl = head declList
let declType = declarationType decl
if declType == DT_Variable || declType == DT_Constant then
addBodyToProcedure (addAttributeToProcedure procDest (attributeDeclared decl)) (tail declList)
else
addBodyToProcedure (addProcedureToProcedure procDest (procedureDeclared decl)) (tail declList)
createVariablesDefinitionsOfType :: [String] -> AttributeType -> [Declaration]
createVariablesDefinitionsOfType namesList t = map (\x -> defaultDeclaration { declarationType = DT_Variable, attributeDeclared = (defaultAttribute {attributeName = x, attributeType = t})} ) namesList
Это схема типов производства:
PRODUCTION TYPE
--------------- ---------------
ProcedureDeclarationList [Declaration]
ProcedureDeclaration Declaration
IdentifiersList [String]
VariableDeclaration [Declaration]
ProcedureHeading Procedure
ProcedureBody [Declaration]
DeclarationSequence [Declaration]
VariableDeclarationList [Declaration]
type AttributeType
Это единственные 3 ошибки, которые я получаю сейчас:
Couldn't match type ‘[Declaration]’ with ‘Declaration’
x2Couldn't match type ‘Declaration’ with ‘[Declaration]’