我在解析字符串并在Python中为其添加括号时遇到问题。我的一个问题是字符串可能以完全括号的方式输入(即(01U(1U0))
),也可能根本不输入(即01U1U0
)。我似乎无法分开的语法是:
A -> e* | (eUe)
e -> any combination of chars from the grammar
e*
的优先级高于U
。
希望这是有道理的。任何人都有任何想法我如何解析并检查括号?
答案 0 :(得分:0)
从LL语法编写解析器的最简单方法是每个非终端符号有一个函数。此函数应该使用输入字符串中的字符对应一个规则的减少。下面是与语法
对应的解析器A -> e+ | '(' A 'U' A ')'
e -> '0' | '1'
这不完全是你想要的语法,但它与你给出的例子更相关。语法是LL(1),你只需要读一个字就知道如何继续。以下解析器为这两个非终端符号定义了两个函数A()和e():
class MySyntaxError(Exception):
def __init__(self, text, index):
self.text = text
self.index = index
def __str__(self):
return "Syntax error at index " + repr(self.index) + ": " + self.text
def parse(input):
global index
index = 0
def eat_char(set):
global index
if index < len(input) and input[index] in set:
index += 1
else:
raise MySyntaxError("expected char in " + repr(set), index)
def e():
eat_char(['0', '1'])
def A():
global index
if index == len(input): # Successfully parsed
return
elif input[index] in ['0', '1']:
while (input[index] in ['0', '1']):
e()
elif input[index] is '(':
eat_char(['('])
A()
eat_char(['U'])
A()
eat_char([')'])
else:
raise MySyntaxError("expected char '0', '1' or '('", index)
A()
if index != len(input): # Parsing didn't reach the end of the string
raise MySyntaxError("parsing ended before the end of the input", index)
def test(string):
try:
parse(string)
print "The string " + string + " have been successfully parsed"
except MySyntaxError as e:
print "The string " + string + " can't be parsed:"
print e
test("(01U(1U0))")
test("(01U(1U0)") # Missing parenthesis, syntax error
test("(01U(1U0)))") # Too many parenthesis, syntax error
test("01U(1U0)") # No parenthesis, syntax error
注意使用e *而不是e +会将空缩减为A,这会使解析器复杂化。
下推自动机隐藏在解析器中。 o从语法中构建自动机并不是那么简单。这里,PDA只有一个状态。我们可以用这种方式描述自动机:
from state [1]
read a '0' or a '1' and loop into state [1]
read a '(', push the parenthesis and loop into state [1]
read a 'U', when there is an open parenthesis on the top of stack, push the 'U' and loop into state [1]
read a ')', when there is a 'U' on the top of the stack, pop the 'U', pop the opend parenthesis following, and loop into state[1]
在Python中编写这个自动机有一种简单的方法。通常,您需要一个goto来编写自动机。每个州都绑定一个标签,从一个州进入另一个州是用goto完成的。不幸的是,Python中没有goto。但是,由于你只有一个状态,所以没有必要和一个循环:
def parse(input):
index = 0
stack = [];
def top():
if len(stack) > 0:
return stack[len(stack)-1]
else:
return None
while index < len(input):
if input[index] in ['0', '1']:
pass
elif input[index] is '(':
stack.append('(')
elif input[index] is 'U' and top() == '(':
stack.append('U')
elif input[index] is ')' and top() == 'U':
stack.pop()
stack.pop()
else:
raise MySyntaxError("Unexpected char '" + input[index] + "'", index)
index += 1
if len(stack):
raise MySyntaxError("unterminated input", index)
这是一个具有显式堆栈的PDA。前一个解析器使用程序堆栈而不是隐式堆栈,并记住递归调用数中的括号读取次数。当您想要检查字符串的有效性时,第二个解析器很有用。但是当你想要生成输入的表示时,它是不方便的,比如抽象语法树:它们通常是从语法构建的,因此更容易从第一个解析器生成。第一个也更容易阅读,因为您不必计算自动机来理解它。