2016-05-04 10 views
0

Ich schreibe einen Oberon-like Sprachparser, ich habe Probleme beim Kompilieren des Parsers, nachdem ich es aktualisiert habe, um mehr Prozeduren auf der gleichen Ebene zu definieren, und nicht nur verschachtelt eins in dem anderen.Haskell Happy Parser Fehler nicht übereinstimmende Typen und unendliche Art

Das ist mein Lexer:

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

Und das ist das Modul, in dem die Typen und einige Utility-Funktionen definiert werden:

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

Das ist mein Parser ist

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

Die Fehler, die der Compiler mir gibt, sind diese zwei:

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

Ich habe das Problem isoliert und ich weiß sicher, dass, wenn ich den zweiten Fall meines ProcedureDeclarationList alles kompiliert fein zu entfernen, aber ich kann nicht mehr Verfahren auf dem erkennen das selbe Level.


UPDATE

Ich habe die Struktur meiner Daten geändert, so dass ich nicht bin Maybe Procedure mehr und ich werde Sie eine Liste von zwei Typen nicht brauchen, aber ich habe immer noch ein Problem mit unpassenden Typen .

Das ist mein aktualisiert 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)) 
} 

Das ist mein aktualisiert 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) 
} 

Und das ist meine aktualisierte Tools Modul:

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 

Dies ist das Schema die Produktionsarten:

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

Dies sind die einzigen drei Fehler, die ich bekommen:

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

Antwort

1

Die Verfolgung der Typen jeder Produktion mit Kommentaren Sie Typfehler aufzuspüren helfen .

Hier die Typen sollte jede Produktion haben:

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

Jetzt jede Ihrer Produktionsregeln überprüfen, um zu sehen, ob sie den richtigen Typ haben.

  1. ProcedureHeading kehrt defaultProcedure mit einem geänderten Namen, so dass ok ist.

  2. ProcedureDeclaration gibt das Ergebnis eines Aufrufs an addProcedureToProcedure zurück, so dass auscheckt. Beachten Sie, dass das zweite Argument des Aufrufs addProcedureToProcedure$3 ist, das sich auf das Ergebnis einer ProcedureBody Produktion bezieht, so dass der Rückgabetyp dieser Produktion ein Maybe Procedure sein muss.

  3. ProcedureDeclarationList hat Probleme. Die Produktionsregeln sollen lauten:

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

[$1] eine Liste aus einem einzigen Verfahren macht, und $1:$3 prepends ein einziges Verfahren zu einer Liste von Prozeduren.

  1. DeclarationSequence ist einfach ein ProcedureDeclarationList, so dass auscheckt.

  2. Wie in Schritt 2 erwähnt, muss ProcedureBody eine Maybe Procedure sein. Die Regel für KW_END ist in Ordnung, aber die zweite Regel braucht etwas Arbeit:

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

Aus DeclarationSequence (das ist ein [Procedure]) haben wir eine Maybe Procedure zu produzieren. Hier ist dein Problem. Just $1 hat den Typ Maybe [Procedure], damit das hier nicht funktioniert.

+0

Ich denke, ich habe verstanden, was Sie sagen. Vielleicht kann ich dieses Problem auf andere Weise überwinden, ich meine, ich habe 'Maybe Procedure' verwendet, weil ich testen wollte, ob die Prozedur etwas im Körper hatte oder nicht. Wenn man jedoch mit der Implementierung fortfährt, können innerhalb eines Prozedurhauptteils andere Variablen als nur andere Prozeduren deklariert werden, so dass ich denke, '{Nothing}' durch '{[]}' und '{Just $ 1}' durch '{$ 1 zu ersetzen } ', so dass innerhalb von' DeclarationSequence' eine Liste zurückgegeben werden kann, die Prozeduren oder Variablen enthalten kann. Das Problem könnte sein: Wie kann ich zwei Typen in derselben Liste speichern? – zeb

+0

Sie können nicht zwei verschiedene Typen in derselben Liste speichern. Während das nicht genau richtig ist, bedeutet es normalerweise, wenn man so denkt, dass man auf dem falschen Weg ist. Übrigens - wenn Sie etwas von dem gefunden haben, was ich hilfreich geschrieben habe, ist Upvoting angemessen und geschätzt. – ErikR

+0

Ich habe meine Datenstruktur geändert, um 'Maybe Procedure' nicht mehr zu verwenden und ich brauche keine Liste von zwei Typen mehr. Ich habe meine Frage aktualisiert, da ich aufgrund von Typenkonflikten einige Fehler erhalte. Ich habe die Produktionstypen verfolgt, aber es hat nicht viel geholfen. – zeb