Python Lark transformer在解析多个语句时返回树

Python Lark transformer在解析多个语句时返回树,python,lark-parser,Python,Lark Parser,我正在使用Lark制作一种编程语言,并试图从一个文件中解析多个语句。当我解析 print("HI"); print("HI"); print("Hi"); 它回来了 Tree('start', ['HI', HI']) Hi 但是当我解析 print("HI"); print("HI"); print("Hi"); 它回来了 Tree('start', ['HI',

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

print("HI");
print("HI");
print("Hi");
它回来了

Tree('start', ['HI', HI'])
Hi
但是当我解析

print("HI");
print("HI");
print("Hi");
它回来了

Tree('start', ['HI', 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

下面是我的变压器文件的工作原理

来自lark进口变压器,v_参数
主变压器(变压器)等级:
string=str
def print_语句(自身、值):
value=str(value).strip(“”)
返回值
这是我的压头代码的工作原理

class主压头(压头):
NL_类型=“_NL”
OPEN\u PAREN\u types=['LPAR','LBRACE']
关闭参数类型=['RPAR','RBRACE']
缩进类型=“\u缩进”
DEDENT\u type='\u DEDENT'
tab_len=8
这是我的
main.py
文件

来自lark import lark
从变压器进口主变压器
从压头导入主压头
parser=Lark.open(“main_parser.Lark”,parser=“lalr”,transformer=MainTransformer(),postlex=maindindenter())
main_parser=parser.parse
输入_str=''
打印(“HI”);
打印(“HI”);
'''
打印(主语法分析器(输入语法))

非常感谢您的帮助,谢谢!

我玩过这个游戏,如果您使用一个完整的最小可重复性示例(mre),我会更轻松、更快15分钟在您的问题中-请下次这样做,因为我不打算在将来花15分钟重新创建您的问题中应该包含的内容。特别是将其作为一个代码块,并完成所有需要的导入,如果您觉得迫切需要将其拆分为文本块,请抵制并使用Python注释代替该文本

这是一个免费的mre

一件事是,我没有得到一个打印语句“HI”的相同结果-我得到了一个字符串值为“HI”的标记

首先,我添加了
->语句

然后我删除了
string=str
,因为这样做不对:它将值(始终是列表)转换为字符串形式的列表文本

然后我添加了一个
string()
transformer和
语句()
transformer。让他们打印输入和返回值可以更容易地看到发生了什么。在我使用Lark on的项目中,我保留了这些用于识别transformer函数和输入/输出的打印,直到我将其全部稳定并工作为止-因此我可以检查标识符是否正确地转换为URI,或者正在为加法添加两个值,并返回一个值

transformer函数take
value
始终是一个列表,对于像print或string这样的一元运算符,返回其中的第一个(唯一)项。一个接受两个输入的运算符将两个要添加的内容作为
value
中的两个条目,添加它们,然后返回结果;这就是转换

令牌是带有元数据的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"')]

如果您可能想更改字符串返回的内容,请首先进行更改,因为更改会波及转换器中的项目。

正在取得进展。这可能是Lark的一个优化,即如果只有一个结果,则将其展开。尝试在
语句*
上放置一个转换器,将多个值转换为您想要的值想要成为thr结果。这确实可以追溯到我在你之前的一个问题上提到的事情:你需要决定你希望你的解析器/转换器得到什么结果。第二件事是,请你能将你的代码片段组合成一个可复制/粘贴的代码段,这样任何人都可以很容易地粘贴到一个文件中并运行-make I帮助不容易。好的,我会这样做,谢谢!所以我为我的
statemet*
制作了一个转换器?如果我打印
的话,我希望它返回
HI
在文件中两次可能有很多方法,但至少如果你在
语句*
上这样做,那么这些都会被处理。你真的是说你只希望两个打印语句有一个HI-不确定如何做,听起来不太对/明显。谢谢你!我感谢你的帮助,我会确保把mi放得更好。”尼马尔在我的问题复制的例子,谢谢!