내가 고안 한 Excel과 같은 수식을 구문 분석하는 문법을 만들려고하는데 문자열의 시작 부분에 특수 문자가 다른 소스를 나타냅니다. 예를 들어, $
문자열을 나타낼 수 있으므로 " $This is text
"는 프로그램에서 문자열 입력으로 처리되고 &
함수를 나타낼 &foo()
수 있으므로 내부 함수에 대한 호출로 처리 될 수 있습니다 foo
.
내가 겪고있는 문제는 문법을 올바르게 구성하는 방법입니다. 예를 들어, 이것은 MWE로 단순화 된 버전입니다.
grammar = r'''start: instruction
?instruction: simple
| func
STARTSYMBOL: "!"|"#"|"$"|"&"|"~"
SINGLESTR: (LETTER+|DIGIT+|"_"|" ")*
simple: STARTSYMBOL [SINGLESTR] (WORDSEP SINGLESTR)*
ARGSEP: ",," // argument separator
WORDSEP: "," // word separator
CONDSEP: ";;" // condition separator
STAR: "*"
func: STARTSYMBOL SINGLESTR "(" [simple|func] (ARGSEP simple|func)* ")"
%import common.LETTER
%import common.WORD
%import common.DIGIT
%ignore ARGSEP
%ignore WORDSEP
'''
parser = lark.Lark(grammar, parser='earley')
그래서,이 문법과 같은 일이 : $This is a string
, &foo()
, &foo(#arg1)
, &foo($arg1,,#arg2)
그리고 &foo(!w1,w2,w3,,!w4,w5,w6)
예상대로 모든 구문 분석됩니다. 그러나 simple
터미널 에 더 많은 유연성을 추가 하려면 SINGLESTR
편리하지 않은 토큰 정의를 다루어야 합니다.
내가 시도한 것
내가 지나칠 수없는 부분은 괄호 (리터럴 포함)를 포함하는 문자열을 원하면 func
현재 상황에서 처리 할 수 없다는 것입니다.
- 내가 괄호에 추가하면
SINGLESTR
, 그때 얻을Expected STARTSYMBOL
그것이 함께 혼합지고 있기 때문에,func
정의와는 함수의 인수가 의미가있는, 통과되어야한다고 생각한다. - 함수에 대해서만 앰퍼샌드 기호를 예약하고 괄호를 추가하도록 문법을 재정의하면 괄호로
SINGLESTR
문자열을 구문 분석 할 수 있지만 구문 분석하려는 모든 함수는을 제공합니다Expected LPAR
.
내 의도는 a로 시작하는 모든 것이 토큰 $
으로 구문 분석 된 SINGLESTR
다음과 같은 것을 구문 분석 할 수 있다는 것 &foo($first arg (has) parentheses,,$second arg)
입니다.
내 솔루션은 현재 문자열에 LEFTPAR 및 RIGHTPAR과 같은 '탈출'단어를 사용하고 트리를 처리 할 때 괄호로 변경하는 도우미 함수를 작성했다는 것입니다. 따라서 $This is a LEFTPARtestRIGHTPAR
올바른 트리를 생성하고 처리하면로 변환됩니다 This is a (test)
.
일반적인 질문을 공식화하려면 : 문법에 특수한 일부 문자가 어떤 상황에서는 일반 문자로 처리되고 다른 경우에는 특수 문자로 처리되도록 문법을 정의 할 수 있습니까?
편집 1
시작 주석을 jbndlr
기반으로 개별 모드를 만들기 위해 문법을 수정했습니다.
grammar = r'''start: instruction
?instruction: simple
| func
SINGLESTR: (LETTER+|DIGIT+|"_"|" ") (LETTER+|DIGIT+|"_"|" "|"("|")")*
FUNCNAME: (LETTER+) (LETTER+|DIGIT+|"_")* // no parentheses allowed in the func name
DB: "!" SINGLESTR (WORDSEP SINGLESTR)*
TEXT: "$" SINGLESTR
MD: "#" SINGLESTR
simple: TEXT|DB|MD
ARGSEP: ",," // argument separator
WORDSEP: "," // word separator
CONDSEP: ";;" // condition separator
STAR: "*"
func: "&" FUNCNAME "(" [simple|func] (ARGSEP simple|func)* ")"
%import common.LETTER
%import common.WORD
%import common.DIGIT
%ignore ARGSEP
%ignore WORDSEP
'''
이것은 두 번째 테스트 사례에 해당합니다. 모든 simple
유형의 문자열 (괄호를 포함 할 수있는 TEXT, MD 또는 DB 토큰)과 비어있는 함수를 구문 분석 할 수 있습니다. 예를 들어, &foo()
또는 &foo(&bar())
올바르게 구문 분석. 함수 내에서 인수를 넣는 순간 (어떤 유형에 관계없이)을 얻습니다 UnexpectedEOF Error: Expected ampersand, RPAR or ARGSEP
. 개념 증명으로, 위의 새 문법에서 SINGLESTR 정의에서 괄호를 제거하면 모든 것이 정상적으로 작동하지만 다시 정사각형으로 돌아갑니다.
STARTSYMBOL
있고 명확해야 할 경우 구분 기호와 괄호를 추가합니다. 나는 여기서 모호성을 보지 못한다. 여전히STARTSYMBOL
구별 할 수 있도록 목록을 개별 항목으로 분할해야 합니다.