繁体   English   中英

求和型无限递归中的左递归语法解析

[英]Parsing left-recursive grammar in sum-type inifinite recursion

我正在尝试从ML中的现代编译器实现中为Tiger语言编写一个解析器,并且停留在一种递归类型上。

我有以下类型

data LValue =                                                                                                                       
    Id Atom                                                                                                                         
    | RecordAccess LValue Atom                                                                                                      
    | ArraySubscript LValue Expression  

具有以下语法:

lvalue -> id
       -> lvalue.id
       -> lvalue[exp]
id -> atom
exp -> (the big, overarching, everything-is-an-expression type)

我正在尝试使用Parsec解析它,但是我陷入了无限递归循环中。 这是我当前的基本解析器:

lvalueParser :: Parsec String () LValue                                                                                             
lvalueParser =                                                                                                                      
    try (Id <$> (atomParser <* (notFollowedBy (char '.'))))                                                                         
    <|> try recordAccessParser                                                                                                      
    where recordAccessParser = (uncurry RecordAccess) <$> do {                                                                      
      record <- lvalueParser;                                                                                                         
      char '.';                                                                                                                     
      atom <- atomParser;                                                                                                           
      return (record, atom)                                                                                                      
      }

(注意:我尚未尝试实现任何方法来处理ArrayAccess部分)

显然,当recordAccessParser回调给lvalueParser时,就会发生无限lvalueParser

我可以这样更改recordAccessParser

recordAccessParser = (uncurry RecordAccess) <$> do {                                                                      
          record <- atomParser;                                                                                                         
          char '.';                                                                                                                     
          atom <- atomParser;                                                                                                           
          return (Id record, atom)                                                                                                      
          }

它终止了。 但是,它不会解析记录访问权限超过单个级别:

Parsec.parse lvalueParser "" "record_1.field_1.field_2"
#=> RecordAccess (Id record_1) (Id field_1)

我希望

#=> RecordAccess (RecordAccess (Id record_1) (Id field_1)) (Id field_2)

我看了chainl1 ,但是链接解析器的类型是a -> a -> a LValue a -> a -> a ,并且与反映语法的LValue类型不匹配。 我也看了many ; 但是我没有为每个术语提供固定的前缀-左递归术语是我要解析为结果类型一部分的内容。

我想我错过了Parsec / parsing的特定概念,很想指出正确的方向。 我正在为其编写解析器的语言中有更多类型,它们将具有类似的构造。

使用不支持左递归的工具来解析左递归语法的通常方法,确实是用重复(即many )代替左递归。 对于记录访问,这意味着要替换诸如

lvalue ::= lvalue '.' ID
         | primaryLValue

lvalue ::= primaryLValue ('.' ID)*

就Parsec而言,这意味着:

record <- atomParser                                                                                                       
fields <- many (char '.' >> idParser)

现在,您有了一个LValue和一个0或多个字段名称的列表,该列表不适合您的AST类型,但是您可以通过将RecordAccess构造函数折叠在列表RecordAccess解决此问题。

尽管您不能在此处使用chainl1 ,但是您可以像这样定义chainl1的组合器:

leftRec :: (Stream s m t)
        => ParsecT s u m a -> ParsecT s u m (a -> a) -> ParsecT s u m a
leftRec p op = rest =<< p
  where
    rest x = do f <- op
                rest (f x)
          <|> return x

在这里咨询以实现此目的。 通过使用此组合器,可以如下定义lvalueParser

lvalueParser :: Parser LValue
lvalueParser = leftRec idParser (recordAccessModifier <|> arraySubscriptModifier)
  where
    idParser = Id <$> atomParser
    recordAccessModifier = do
      a <- char '.' *> atomParser
      return (\l -> RecordAccess l a)
    arraySubscriptModifier = do
      e <- between (char '[') (char ']') expParser
      return (\l -> ArraySubscript l e)

例:

main = parseTest lvalueParser "x.y[2].z"
-- => RecordAccess (ArraySubscript (RecordAccess (Id 'x') 'y') (ENat 2)) 'z'

其中AtomExpression及其解析器的定义如下:

type Atom = Char
atomParser :: Parser Atom
atomParser = letter <?> "atom"

data Expression = ENat Int
  deriving Show
expParser :: Parser Expression
expParser = (ENat . read) <$> many digit

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM