0

我正在使用 Lark 制作一种编程语言,并且我正在尝试从一个文件中解析多个语句。当我解析

print("HI");
print("HI");

它返回

Tree('start', ['HI', HI'])

但是当我解析

print("Hi");

它返回

Hi

这是我的语法有点像

?start: expr
      | statement*
?expr: STRING -> string
?statement: "print" "(" expr ")" ";" -> print_statement

%import common.ESCAPED_STRING -> STRING 
%declare _INDENT _DEDENT
%import common.WS_INLINE
%ignore WS_INLINE
%import common.NEWLINE -> _NL
%ignore _NL

这就是我的转换器文件的工作原理

from lark import Transformer, v_args
class MainTransformer(Transformer):
  string = str
  def print_statement(self, value):
    value = str(value).strip('"')
    return value

这就是我的压头代码的工作原理

class MainIndenter(Indenter):
    NL_type = '_NL'
    OPEN_PAREN_types = ['LPAR', 'LBRACE']
    CLOSE_PAREN_types = ['RPAR', 'RBRACE']
    INDENT_TYPE = '_INDENT'
    DEDENT_type = '_DEDENT'
    tab_len = 8

这是我的main.py文件

from lark import Lark
from transformer import MainTransformer
from indenter import MainIndenter
parser = Lark.open("main_parser.lark", parser="lalr", transformer=MainTransformer(), postlex=MainIndenter())
main_parser = parser.parse

input_str = '''
print("HI");
print("HI");
'''
print(main_parser(input_str))

帮助将不胜感激,谢谢!

4

1 回答 1

0

我玩了这个,如果你在你的问题中放一个完整的最小可重现示例(mre),这对我来说会容易得多,快 15 分钟 - 请下次这样做,因为我不打算在未来花 15 分钟重新创建应该在您的问题中的东西。特别是让它成为一个完整的代码块,包含所有需要的导入,如果你想用文本块分割它,请抵制并使用 Python 注释代替该文本

所以这是一个免费的mre。

有一件事是,对于单个打印语句“HI”,我没有得到相同的结果——我得到了一个带有 STRING 值“HI”的令牌。

首先我添加了-> statements

然后我删除了,string = str因为那是不对的:它将值(始终是列表)转换为列表的文字作为字符串。

然后我添加了一个string()变压器和statements()变压器。让他们打印他们的输入和返回值可以更容易地看到发生了什么。在我使用 Lark 的项目中,我保留了这些标识转换器功能和输入/输出的打印件,直到我得到它所有的稳定+工作 - 所以我可以检查一个标识符是否正确地被转换为一个 URI,或者两个正在添加添加的值并返回单个值。

转换器函数 takevalue它始终是一个列表,对于像 print 或 string 这样的一元运算符返回其中的第一个(唯一)项目。接受两个输入的运算符将把这两个东西作为两个条目添加到 中value,将它们相加并返回结果;这就是转变。

Token 是带有元数据的 str,运行此代码时可以看到结果。

from lark import Lark
from lark.indenter import Indenter
from lark import Transformer, v_args

grammar = """
?start: expr
      | statement* -> statements // ADDED
?expr: STRING -> string
?statement: "print" "(" expr ")" ";" -> print_statement

%import common.ESCAPED_STRING -> STRING 
%declare _INDENT _DEDENT
%import common.WS_INLINE
%ignore WS_INLINE
%import common.NEWLINE -> _NL
%ignore _NL
"""

class MainIndenter(Indenter):
    NL_type = '_NL'
    OPEN_PAREN_types = ['LPAR', 'LBRACE']
    CLOSE_PAREN_types = ['RPAR', 'RBRACE']
    INDENT_TYPE = '_INDENT'
    DEDENT_type = '_DEDENT'
    tab_len = 8


class MainTransformer(Transformer):
#    string = str # REMOVED
    def string(self,value): # ADDED
        print( f"string {value=}" )
        res = value[0]  # this seems like quite a common thing to do for a unary thing like string - return value[0]
        print( f"string returning {res}" )
        return res
    
    def print_statement(self, value):
        print( f"print_statement {value=}" )
#        value = str(value).strip('"')
        res = value[0]  # this seems like quite a common thing to do for a unary thing like print - return value[0]
        print( f"print_statement returning {res}" )
        return res
        
    def statements(self,value): # ADDED
        print( f"statements {value=}" )
        for i,v in enumerate(value):
            print( f"  {i=} {v=}" )
        return value

parser = Lark(grammar, parser="lalr", transformer=MainTransformer(), postlex=MainIndenter())

main_parser = parser.parse

hiho_input_str = '''
print("HI");
print("HO");
print("HI");
print("HO");
'''

hihoresult = main_parser(hiho_input_str)
print( "hiho result=")
for i,hiho in enumerate(hihoresult):
    print(f"  {i} {hiho}")
print()

hi_input_str = '''
print("HI");
'''

print("Hi result=",main_parser(hi_input_str))

结果:

string value=[Token('STRING', '"HI"')]
string returning "HI"
print_statement value=[Token('STRING', '"HI"')]
print_statement returning "HI"
string value=[Token('STRING', '"HO"')]
string returning "HO"
print_statement value=[Token('STRING', '"HO"')]
print_statement returning "HO"
string value=[Token('STRING', '"HI"')]
string returning "HI"
print_statement value=[Token('STRING', '"HI"')]
print_statement returning "HI"
string value=[Token('STRING', '"HO"')]
string returning "HO"
print_statement value=[Token('STRING', '"HO"')]
print_statement returning "HO"
statements value=[Token('STRING', '"HI"'), Token('STRING', '"HO"'), Token('STRING', '"HI"'), Token('STRING', '"HO"')]
  i=0 v=Token('STRING', '"HI"')
  i=1 v=Token('STRING', '"HO"')
  i=2 v=Token('STRING', '"HI"')
  i=3 v=Token('STRING', '"HO"')
hiho result=
  0 "HI"
  1 "HO"
  2 "HI"
  3 "HO"

string value=[Token('STRING', '"HI"')]
string returning "HI"
print_statement value=[Token('STRING', '"HI"')]
print_statement returning "HI"
statements value=[Token('STRING', '"HI"')]
  i=0 v=Token('STRING', '"HI"')
Hi result= [Token('STRING', '"HI"')]

如果您可能想要更改字符串返回的内容,请先执行此操作,因为该更改会通过转换器中的项目向上传播。

于 2020-11-04T17:39:58.223 回答