代码之家  ›  专栏  ›  技术社区  ›  greenie

调试pyparsing语法

  •  17
  • greenie  · 技术社区  · 16 年前

    我正在为一种虚构的编程语言C(而不是实际的C语言)构建一个解析器。我已经到了需要将语言语法翻译成Pyparsing可以接受的语言的阶段。不幸的是,当我开始分析输入字符串(这是正确的,不应该导致pyparsing出错)时,它没有正确地分析。我担心这是因为我的语法错误,但是当我第一次开始分析pyparsing时,我似乎看不出哪里出错了。

    我上传了我翻译的语法 here 供人们通读。

    编辑: 更新了保罗的建议。

    这是我目前掌握的语法(语法定义的两个最上面的行对我来说非常糟糕,我知道):

    # Lexical structure definition
    ifS = Keyword('if')
    elseS = Keyword('else')
    whileS = Keyword('while')
    returnS = Keyword('return')
    intVar = Keyword('int')
    voidKeyword = Keyword('void')
    sumdiff = Literal('+') | Literal('-')
    prodquot = Literal('*') | Literal('/')
    relation = Literal('<=') | Literal('<') | Literal('==') | \
               Literal('!=') | Literal('>') | Literal('=>')
    lbrace = Literal('{')
    rbrace = Literal('}')
    lparn = Literal('(')
    rparn = Literal(')')
    semi = Literal(';')
    comma = Literal(',')
    number = Word(nums)
    identifier = Word(alphas, alphanums)
    
    # Syntax definition
    term = ''
    statement = ''
    variable    =   intVar + identifier + semi
    locals      =   ZeroOrMore(variable)
    expr        =   term | OneOrMore(Group(sumdiff + term))
    args        =   ZeroOrMore(OneOrMore(Group(expr + comma)) | expr)
    funccall    =   Group(identifier + lparn + args + rparn)
    factor      =   Group(lparn + expr + rparn) | identifier | funccall | number
    term        =   factor | OneOrMore(prodquot + factor)
    cond        =   Group(lparn + expr + relation + expr + rparn)
    returnState =   Group(returnS + semi) | Combine(returnS + expr + semi)
    assignment  =   Group(identifier + '=' + expr + semi)
    proccall    =   Group(identifier + lparn + args + rparn + semi)
    block       =   Group(lbrace + locals + statement + rbrace)
    iteration   =   Group(whileS + cond + block)
    selection   =   Group(ifS + cond + block) | Group(ifS + cond + block + elseS + block)
    statement   =   OneOrMore(proccall | assignment | selection | iteration | returnState)
    param       =   Group(intVar + identifier)
    paramlist   =   OneOrMore(Combine(param + comma)) | param
    params      =   paramlist | voidKeyword
    procedure   =   Group(voidKeyword + identifier + lparn + params + rparn + block)
    function    =   Group(intVar + identifier + lparn + params + rparn + block)
    declaration =   variable | function | procedure
    program     =   OneOrMore(declaration)
    

    我想知道我在翻译语法时是否犯过任何错误,以及在坚持所给语法的同时,我可以做些什么改进来简化它。

    编辑2: 已更新以包含新错误。

    下面是我要分析的输入字符串:

    int larger ( int first , int second ) { 
    if ( first > second ) { 
    return first ; 
    } else { 
    return second ; 
    } 
    } 
    
    void main ( void ) { 
    int count ; 
    int sum ; 
    int max ; 
    int x ; 
    
    x = input ( ) ; 
    max = x ; 
    sum = 0 ; 
    count = 0 ; 
    
    while ( x != 0 ) { 
    count = count + 1 ; 
    sum = sum + x ; 
    max = larger ( max , x ) ; 
    x = input ( ) ; 
    } 
    
    output ( count ) ; 
    output ( sum ) ; 
    output ( max ) ; 
    } 
    

    这是我从终端运行程序时收到的错误消息:

    /Users/Joe/Documents/Eclipse Projects/Parser/src/pyparsing.py:1156: SyntaxWarning: null string passed to Literal; use Empty() instead
    other = Literal( other )
    /Users/Joe/Documents/Eclipse Projects/Parser/src/pyparsing.py:1258: SyntaxWarning: null string passed to Literal; use Empty() instead
    other = Literal( other )
    Expected ")" (at char 30), (line:6, col:26)
    None
    
    1 回复  |  直到 13 年前
        1
  •  31
  •   Zearin lifeisstillgood    13 年前

    1)变化 Literal("if") Keyword("if") (等等,一直到 Literal("void") )以防止匹配名为 "ifactor" .

    2) nums , alphas ,和 alphanums 不是表达式,它们是字符串,可以与Word类一起使用,在定义“单词”时定义一些典型的字符集,例如“数字是由nums组成的单词”,或者“标识符是以字母开头,后跟零个或多个字母。”因此,而不是:

    number = nums
    identifier = alphas + OneOrMore(alphanums)
    

    你想要

    number = Word(nums)
    identifier = Word(alphas, alphanums)
    

    3)而不是 Combine ,我想你想要 Group . 使用 联合 当您希望匹配的令牌是连续的,并且没有中间的空格时,将连接这些令牌并将它们作为单个字符串返回。 联合 通常用于以下情况:

    realnum = Combine(Word(nums) + "." + Word(nums))
    

    没有 联合 解析 "3.14" 将返回字符串列表 ['3', '.', '14'] 所以我们添加 联合 所以realnum的解析结果是 '3.14' (然后可以传递给parse操作以转换为实际的浮点值 3.14 ) 联合 对不干涉空白的强制执行也可以防止我们意外地解析 'The answer is 3. 10 is too much.' 和思考 "3. 10" 表示实数。

    4)这不会导致错误,但输入字符串 太多了 额外的空间。如果你的语法工作正常,你应该能够分析 "int x;" 一样好 "int x ;" .

    希望这些提示能让你走。你读过任何在线的PyParsing文章或教程吗?请看一下网上的例子。你需要很好地掌握 Word , Literal , 联合 等等。执行各自的解析任务。

    5)您错误地实现了术语和语句的递归定义。而不是分配 '' 对他们来说,写:

    term = Forward()
    statement = Forward()
    

    然后,当您使用它们的递归定义实际定义它们时,使用 << 操作员(并确保将右侧封闭在 () s)。

    term << (... term definition ...)
    statement << (... statement definition ...)
    

    您可以找到一个递归解析器的例子 here 以及关于基本PyParsing用法的演示 here -请参阅标题为“解析列表”的部分,了解有关如何处理递归的更多步骤。