Haskell快乐的解析器错误不匹配类型和无限类型 [英] Haskell Happy parser error mismatching types and infinite type

查看:163
本文介绍了Haskell快乐的解析器错误不匹配类型和无限类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编写一个类似Oberon的语言解析器,我在编译解析器后遇到了麻烦,因为我已经更新了解析器,以便能够在同一级别定义更多的过程,并且不仅嵌套在另一个过程中。



这是我的词法分析器:

  {
模块Lexer其中


%wrapperbasic

$ alpha = [a-zA-Z]
$ digit = [0-9]
$ validChar = [^ \]

标记: -

$白色+;
PROCEDURE{\s - > KW_TokenProcedure}
END{\ s - > KW_TokenEnd}
;{\s - > KW_TokenSemiColon}
$ alpha [$ alpha $ digit \ _] * {\s - > TokenVariableIdentifier s}

{

- 令牌类型:
数据令牌=
KW_TokenProcedure |
KW_TokenEnd |
KW_TokenSemiColon |
TokenVariableIdentifier St ring |
deriving(Eq,Show)
}

这是我的解析器:

  {
模块Main其中
导入Lexer
导入工具
}

%名称myParse
%tokentype {令牌}
%错误{parseError}

令牌
KW_PROCEDURE {KW_TokenProcedure}
KW_END {KW_TokenEnd}
';'{KW_TokenSemiColon}
标识符{TokenVariableIdentifier $$}

%%

ProcedureDeclarationList:ProcedureDeclaration {$ 1}
| ProcedureDeclaration';'ProcedureDeclarationList {$ 3:$ 1}

ProcedureDeclaration:ProcedureHeading';'ProcedureBody标识符{
do
let newProc = $ 1 - Crea la nuova procedura
让procBody = $ 3
addProcedureToProcedure newProc procBody
}

ProcedureHeading:KW_PROCEDURE identifier {defaultProcedure {procedureName = $ 2}}

ProcedureBody:KW_END {Nothing}
| DeclareSequence KW_END {只需$ 1}

DeclarationSequence:ProcedureDeclarationList {$ 1}

{
parseError :: [Token] - > a
parseError _ =错误解析错误

main = do
inStr< - getContents
let result = oLikeParse(alexScanTokens inStr)
putStrLn (result:++ show(result))
}

这就是模块,其中定义了类型和一些实用函数:

 模块工具其中

data过程=过程{procedureName :: String,
procedureProcedures :: [Procedure]}派生(显示)

defaultProcedure =过程{procedureName =,
procedureProcedures = []}

addProcedureToProcedure :: Procedure - >也许程序 - >过程
addProcedureToProcedure procDest Nothing = Procedure {procedureName =(procedureName procDest),
procedureProcedures =(procedureProcedures procDest)}
addProcedureToProcedure procDest(Just procToAdd)= Procedure {procedureName =(procedureName procDest),
procedureProcedures =(procedureProcedures procDest)++ [procToAdd]}

编译器给出的错误我是这两个:


  • 无法将类型'[Procedure]'与'Procedure'匹配
  • 发生检查:无法构造无限类型:t4〜[t4]



我已经隔离了这个问题,并且我确定如果删除第二个我的 ProcedureDeclarationList 编译好,但我不认识更多的亲




更新



I'我改变了我的数据结构,以至于我不再使用 Maybe Procedure ,而且我不需要两种类型的列表,但我仍然遇到不匹配类型的问题。



这是我更新的解析器:

  {
模块Main其中
导入Lexer
导入工具
}

%名称myParse
%tokentype {令牌}
%错误{parseError}

令牌
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)}}

标识符列表:标识符{[$ 1]}
|标识符','标识符列表{$ 1:$ 3}

VariableDeclaration:IdentifiersList':'type {createVariablesDefinitionsOfType $ 1 $ 3}

ProcedureHeading:KW_PROCEDURE标识符{defaultProcedure {procedureName = $ 2}}

ProcedureBody:KW_END {[]}
| DeclarationSequence KW_END {$ 1}

DeclarationSequence:KW_VAR VariableDeclarationList';'{$ 2}
| ProcedureDeclarationList {$ 1}

VariableDeclarationList:VariableDeclaration {[$ 1]}
| VariableDeclaration';'VariableDeclarationList {$ 1:$ 3}

类型:KW_INTEGER {整数}
| KW_REAL {Float}
| KW_BOOLEAN {布尔}
| KW_CHAR {Char}

{
parseError :: [Token] - > a
parseError _ =错误解析错误

main = do
inStr< - getContents
let result = oLikeParse(alexScanTokens inStr)
putStrLn (result:++ show(result))
}

这是我的更新lexer:

  {
模块Lexer其中
}

%wrapper基本

$ alpha = [a-zA-Z]
$ digit = [0-9]
$ validChar = [^ \]

令牌: -

$白色+;
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}

{

- 令牌类型:
数据令牌=
KW_TokenInteger |
KW_TokenReal |
KW_TokenBoolean |
KW_TokenChar |
KW_TokenVar |
KW_TokenProcedure |
KW_TokenEnd |
KW_TokenSemiColon |
KW_TokenComa |
KW_TokenColon |
TokenVariableIdentifier字符串|
deriving(Eq,Show)
}

这是我更新的工具模块:

 模块工具其中

data AttributeType = String
|浮动
| Char
|整数
| Boolean
deriving(Show,Eq)

data属性=属性{attributeName :: String,
attributeType :: AttributeType,
stringValue :: String,
floatValue :: Float,
integerValue :: Integer,
charValue :: Char,
booleanValue :: Bool}派生(显示)

数据过程=过程{ procedureName :: String,
attributes :: [Attribute],
procedureProcedures :: [Procedure]}派生(显示)

数据DeclarationType = DT_Variable
| DT_Constant
| DT_Procedure
derived(Show,Eq)

data Declaration = Declaration {declarationType :: DeclarationType,
attributeDeclared :: Attribute,
procedureDeclared :: Procedure} deriving(Show )
$ b defaultAttribute =属性{attributeName =,
attributeType = Integer,
stringValue =,
floatValue = 0.0,
integerValue = 0 ,
charValue ='',
booleanValue = False}

defaultProcedure =过程{procedureName =,
attributes = [],
procedureProcedures = []}

defaultDeclaration =声明{declarationType = DT_Variable,
attributeDeclared = defaultAttribute,
procedureDeclared = defaultProcedure}

addAttributeToProcedure :: Procedure - >属性 - >过程
addAttributeToProcedure proc att =过程{procedureName =(procedureName proc),
attributes =(attributes proc)++ [att],
procedureProcedures =(procedureProcedures proc)}

addProcedureToProcedure :: Procedure - >程序 - >过程
addProcedureToProcedure procDest procToAdd = Procedure {procedureName =(procedureName procDest),
attributes =(attributes procDest),
procedureProcedures =(procedureProcedures procDest)++ [procToAdd]}

addBodyToProcedure :: 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 - > [声明]
createVariablesDefinitionsOfType namesList t = map(\ x - > defaultDeclaration {declarationType = DT_Variable,attributeDeclared =(defaultAttribute {attributeName = x,attributeType = t})})namesList


$ b

这是生产类型的模式:

 生产类型
--------------- ---------------
ProcedureDeclarationList [声明]
ProcedureDeclaration声明
IdentifiersList [String]
VariableDeclaration [声明]
ProcedureHeading过程
ProcedureBody [声明]
DeclarationSequence [声明]
VariableDeclarationList [声明]
type AttributeType

这是我现在得到的唯一3个错误:




  • 无法将'[Declaration]'与'Declaration' code> x2

  • 无法将类型'声明'与'[声明]'匹配


解决方案

使用注释跟踪每个制作的类型将帮助您追踪类型错误。 b
$ b

每种产品应具有的类型:

 生产类型
- ------------ ---------
ProcedureHeading Procedure
ProcedureDeclaration Procedure
ProcedureDeclarationList [Procedure]
DeclarationSequence [Procedure]
ProcedureBody可能过程现在检查每个生产规则以查看它们是否具有正确的类型(例如,b






$ b) 。
$ b


  1. ProcedureHeading 返回 defaultProcedure 改名,所以没关系。

  2. $ c> ProcedureDeclaration
    将调用的结果返回给 addProcedureToProcedure ,以便检出。请注意, addProcedureToProcedure 调用的第二个参数是 $ 3 ,它引用 ProcedureBody production,这意味着该生产的返回类型必须是 Maybe Procedure
  3. ProcedureDeclarationList 有问题。生产规则应为:

      ProcedureDeclarationList 
    :ProcedureDeclaration {[$ 1]}
    | ProcedureDeclaration';'ProcedureDeclarationList {$ 1:$ 3}


[$ 1] 列出单个过程,并且 $ 1:$ 3 将单个过程前置到列表


  1. DeclarationSequence ProcedureDeclarationList ,以便签出。

  2. 正如步骤2中所述, ProcedureBody 必须是 Maybe Procedure KW_END 的规则没有问题,但第二条规则需要做一些工作:

      ProcedureBody 
    | KW_END {Nothing}
    |声明序列KW_END {??? }


DeclarationSequence (它是一个 [Procedure] ),我们必须产生一个 Maybe Procedure 。这是你的问题所在。 只要$ 1 的类型为 Maybe [Procedure] ,这样就不会在这里工作。


Writing a Oberon-like language parser, I'm having troubles compiling the parser after I've updated it to be able to define more procedures on the same level, and not only nested one inside the other.

This is my lexer:

{
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)
}

This is my parser:

{
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))
}

And this is the module where the types and some utility functions are defined:

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] }

The errors the compiler is giving me are these two:

  • Couldn't match type ‘[Procedure]’ with ‘Procedure’
  • Occurs check: cannot construct the infinite type: t4 ~ [t4]

I've isolated the problem and I know for sure that if I remove the second case of my ProcedureDeclarationList everything compiles fine, but I can't recognize more procedures on the same level.


UPDATE

I've changed the my data structure so that I'm not using Maybe Procedure anymore and I won't need a list of two types, but I still have a problem with mismatching types.

This is my updated parser:

{
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))
}

This is my updated lexer:

{
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)
}

And this is my updated tools module:

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

This is the schema of the production types:

PRODUCTION                  TYPE
---------------             ---------------
ProcedureDeclarationList    [Declaration]
ProcedureDeclaration        Declaration
IdentifiersList             [String]
VariableDeclaration         [Declaration]
ProcedureHeading            Procedure
ProcedureBody               [Declaration]
DeclarationSequence         [Declaration]
VariableDeclarationList     [Declaration]
type                        AttributeType

This are the only 3 errors I get now:

  • Couldn't match type ‘[Declaration]’ with ‘Declaration’ x2
  • Couldn't match type ‘Declaration’ with ‘[Declaration]’

解决方案

Keeping track of the types of each production with comments will help you track down type errors.

Here the types each production should have:

Production                            Type
--------------                        ---------
ProcedureHeading                      Procedure
ProcedureDeclaration                  Procedure
ProcedureDeclarationList              [ Procedure ]
DeclarationSequence                   [ Procedure ]
ProcedureBody                         Maybe Procedure

Now check each of your production rules to see if they have the correct type.

  1. ProcedureHeading returns defaultProcedure with a changed name, so that's ok.

  2. ProcedureDeclaration returns the result of a call to addProcedureToProcedure, so that checks out. Note that the second argument to the addProcedureToProcedure call is $3 which refers to the result of a ProcedureBody production, so that means the return type of that production must be a Maybe Procedure.

  3. ProcedureDeclarationList has problems. The production rules should read:

    ProcedureDeclarationList
      : ProcedureDeclaration                              { [ $1 ] }
      | ProcedureDeclaration ';' ProcedureDeclarationList { $1 : $3 }
    

[$1] makes a list out of a single Procedure, and $1:$3 prepends a single Procedure to a list of Procedures.

  1. DeclarationSequence is simply a ProcedureDeclarationList, so that checks out.

  2. As noted in step 2, ProcedureBody has to be a Maybe Procedure. The rule for KW_END is fine, but the second rule needs some work:

    ProcedureBody
        | KW_END                     { Nothing }
        | DeclarationSequence KW_END { ??? }
    

From a DeclarationSequence (which is a [Procedure]) we have to produce a Maybe Procedure. This is where your problem is. Just $1 has type Maybe [Procedure], so that isn't going to work here.

这篇关于Haskell快乐的解析器错误不匹配类型和无限类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆