Код: Выделить всё
?start: forstmt
forstmt: "for" ID "in" range FOO -> forstmt
?range: "[" atom DOTDOT atom "]" -> rangetuple
DOTDOT.2: ".."
?atom: NUM -> num
%import common.NUMBER -> NUM
%import common.WS
%ignore WS
< р>
Код: Выделить всё
[Но даже при назначении центральным точкам собственного именованного терминала и назначении что приоритет выше, чем у чисел, он все равно всегда анализируется как:
Код: Выделить всё
[Я пробовал изменить приоритет терминала, я пытался изменить приоритет правила в разделе анализатор Earley, и я попробовал запустить анализатор Earley с ambiguity='explicit', и все это без каких-либо изменений в текущем ошибочном выводе.
Вот ошибка, которую я получаю при работе с parser(grammar, parser='lalr'):
Код: Выделить всё
Unexpected token Token('NUM', '.10') at line 1, column 13.
Expected one of:
* DOTDOT
* MINUS
* STAR
* SLASH
* PLUS
Previous tokens: [Token('NUM', '1.')]
Код: Выделить всё
?start: stmtlist
?stmtlist: stmt (";" stmt?)* -> stmtlist
stmt: "var" ID "=" expr -> decl
| ID "=" expr -> assign
| "if" "(" expr ")" stmt ("else" stmt)? -> ifstmt
| "while" "(" expr ")" stmt -> whstmt
| "for" ID "in" range stmt -> forstmt
| "print" "(" expr ")" -> prstmt
| "{" stmtlist "}" -> block
?range: "[" expr DOTDOT expr "]" -> rangetuple
DOTDOT.2: ".."
?expr: expr "+" term -> add
| expr "-" term -> sub
| term
?term: term "*" atom -> mul
| term "/" atom -> div
| atom
?atom: "(" expr ")"
| ID -> var
| NUM -> num
%import common.CNAME -> ID
%import common.NUMBER -> NUM
%import common.WS
%ignore WS
Минимальный воспроизводимый пример:
Жаворонок: 1.1.9
Python: 3.12.3
Код: Выделить всё
import sys
from lark import Lark, v_args
from lark.visitors import Interpreter
from typing import Any
grammar = """
?start: stmtlist
?stmtlist: stmt? (";" stmt?)* -> stmtlist
stmt: "for" ID "in" range stmt -> forstmt
| "print" "(" expr ")" -> prstmt
| "{" stmtlist "}" -> block
?range: "[" expr ".." expr "]" -> rangetuple
?expr: ID -> var
| NUM -> num
%import common.CNAME -> ID
%import common.NUMBER -> NUM
%import common.WS
%ignore WS
"""
parser = Lark(grammar)
class Env():
'''Keeps track of variables and manages scopes for those variables.'''
def __init__(self) -> None:
# initializes with one scope open by default; global scope
self._scopes: list[dict] = [dict()]
def extend(self, x: str, val: Any | None = None) -> None:
'''Declares `x` as a variable in the
current scope, with `x = val`.'''
location = self._findScope(x)
# variable is undefined or has not been declared in current scope
if (location is None) or (location != (len(self._scopes) - 1)):
self._scopes[-1][x] = val
# variable is defined in current scope
else:
raise NameError(f'{x} was redeclared', name=x)
def update(self, x: str, val: Any) -> None:
'''Assigns `val` to current visible `x`.'''
location = self._findScope(x)
if location is not None:
self._scopes[location][x] = val # overwrite nearest x
else:
raise NameError(f'{x} is undefined', name=x)
def _findScope(self, x) -> int | None:
'''Return the scope index that `x` exists in, if any.
Returns index in order by environment recency.'''
for index in range(len(self._scopes)-1, -1, -1):
if x in self._scopes[index]:
return index
return None
def lookup(self, x: str) -> Any:
'''returns `x`'s value from the most recently assigned scope.'''
location = self._findScope(x)
if location is not None:
return self._scopes[location][x]
else:
raise NameError(f"{x} is undefined", name=x)
def openScope(self) -> None:
'''Increases variable stack height.'''
self._scopes.append(dict())
def closeScope(self) -> None:
'''Decreases variable stack height.'''
if len(self._scopes) >= 1:
del self._scopes[-1]
else:
raise IndexError("attempted to close scope when none were open")
@v_args(inline=True)
class Eval(Interpreter):
def __init__(self, env: Env | None = None):
super().__init__()
# if no environment is supplied, it will rely on its own
self.env = env if env is not None else Env()
def num(self, val) -> int | float:
for char in ".e": # signifiers for float
if char in val:
return float(val)
return int(val)
def var(self, var: str) -> int | float:
return self.env.lookup(var)
def block(self, statements) -> None:
self.env.openScope()
self.visit(statements)
self.env.closeScope()
def stmtlist(self, *statements) -> None:
for statement in statements:
self.visit(statement)
def forstmt(self, id, rangetuple, stmt) -> None:
self.env.openScope()
self.env.extend(id)
for i in range(*self.visit(rangetuple)):
self.env.update(id, i)
self.visit(stmt)
self.env.closeScope()
def rangetuple(self, expr1, expr2) -> tuple[int, int]:
return (self.visit(expr1), self.visit(expr2))
def main():
try:
prog = sys.stdin.read()
tree = parser.parse(prog)
Eval().visit(tree)
except Exception as e:
print(e)
if __name__ == "__main__":
main()
Код: Выделить всё
for i in [1..3] print(i)
Код: Выделить всё
No terminal matches '.' in the current parser context, at line 1 col 13
for i in [1..3] print(i)
^
Expected one of:
* __ANON_0
Подробнее здесь: https://stackoverflow.com/questions/791 ... g-priority
Мобильная версия