다음과 같이 줄일 수있는 성가신 섹션이있는 JavaCC 문법이 있습니다.
void Start(): {}
{
A()
<EOF>
}
void A(): {}
{
( "(" A() ")" | "biz" )
( B() | C() )*
}
void B(): {}
{ "foo" A() }
void C(): {}
{ "bar" A() }
위의 문법을 컴파일 할 때 JavaCC는 줄에서 선택 충돌에 대해 경고합니다 ( B() | C() )*
. 내가 이해하려는 두 가지가 있습니다. 첫 번째는이 경우 충돌이 있다고 생각하는 이유입니다. AFAICT는 각 지점에서 현재 토큰만을 기반으로 어떤 경로를 취할지 결정할 수 있어야합니다. 두 번째는 경고를 제거하는 방법입니다. 나는 LOOKAHEAD
진술 을 할 올바른 자리를 찾을 수없는 것 같다 . 어디에 두든 상관없이 선택 지점에 있지 않다는 경고를 받거나 동일한 경고를 계속받습니다. 다음과 같이 생각했습니다.
void Start(): {}
{
A()
<EOF>
}
void A(): {}
{
( "(" A() ")" | "biz" )
( LOOKAHEAD(1) B() | LOOKAHEAD(1) C() )*
}
void B(): {}
{ "foo" A() }
void C(): {}
{ "bar" A() }
그러나 이것은 여전히 경고를 생성합니다. 또한 운이없는 다양한 의미 론적 미리보기 문을 시도했습니다. 나는 분명히 뭔가를 놓치고 있지만 무엇을 잃어 버렸습니다. FWIW, 토큰을 넣어도 ( B() | C() )*
문제를 "수정"하므로 해당 루프를 종료하는 방법을 모르는 것과 관련이 있다고 생각하지만 "foo"또는 "바". 생성 된 코드는 올바른 것처럼 보이지만 여기에 모호한 부분이 있으면 분명히 문제가되지 않습니다.
Java 문법을 살펴보고 살펴본 후 이것이 일이 행복하다는 것을 알았습니다.
void Start(): {}
{
A()
<EOF>
}
void A(): {}
{
( "(" A() ")" | "biz" )
(
LOOKAHEAD(2)
(B() | C())
)*
}
void B(): {}
{ "foo" A() }
void C(): {}
{ "bar" A() }
루프에서 취할 옵션을 결정하기 위해 추가 토큰이 필요한 이유가 아직 명확하지 않습니다 (정말 그렇지 않을 수도 있음).
문법이 모호합니다. 입력 고려
biz foo biz foo biz EOF
다음 두 가지 가장 왼쪽 파생물이 있습니다.
Start
=> ^^^^^ Expand
A EOF
=> ^ Expand
( "(" A ")" | "biz") ( B | C)* EOF
=> ^^^^^ choose
"biz" ( B | C )* EOF
=> ^^^^^^^^^^ unroll and choose the B
"biz" B ( B | C )* EOF
=> ^ expand
"biz" "foo" A ( B | C )* EOF
=> ^ expand
"biz" "foo" ( "(" A ")" | "biz") ( B | C)* ( B | C )* EOF
=> ^^^^^ choose
"biz" "foo" "biz" ( B | C)* ( B | C )* EOF
=> ^^^^^^^^^^ unroll and choose the B
"biz" "foo" "biz" B ( B | C)* ( B | C )* EOF
=> ^ expand
"biz" "foo" "biz" "foo" A ( B | C)* ( B | C )* EOF
=> ^ expand
"biz" "foo" "biz" "foo" ( "(" A ")" | "biz") ( B | C)* ( B | C)* ( B | C )* EOF
=> ^^^^^ choose
"biz" "foo" "biz" "foo" "biz" ( B | C)* ( B | C)* ( B | C )* EOF
=> ^^^^^^^^^ Terminate
"biz" "foo" "biz" "foo" "biz" ( B | C)* ( B | C )* EOF
=> ^^^^^^^^^ Terminate
"biz" "foo" "biz" "foo" "biz"( B | C )* EOF
=> ^^^^^^^^^ Terminate
"biz" "foo" "biz" "foo" "biz" EOF
두 번째 파생의 경우 파서가 두 번째 루프에 들어갈 지 여부를 결정해야하는 지점까지 모든 것이 첫 번째 파생과 동일합니다.
Start
=>* As above
"biz" "foo" "biz" ( B | C)* ( B | C )* EOF
=> ^^^^^^^^^ Terminate!! (Previously it was expand)
"biz" "foo" "biz" ( B | C )*
=> ^^^^^^^^^^ Unroll and choose B
"biz" "foo" "biz" B ( B | C )* EOF
=> ^ Expand
"biz" "foo" "biz" "foo" A ( B | C )* EOF
=> ^ Expand
"biz" "foo" "biz" "foo" ( "(" A ")" | "biz") ( B | C)* ( B | C )* EOF
=> ^^^^^ Choose
"biz" "foo" "biz" "foo" "biz" ( B | C)* ( B | C )* EOF
=> ^^^^^^^^^ Terminate
"biz" "foo" "biz" "foo" "biz"( B | C )* EOF
=> ^^^^^^^^^ Terminate
"biz" "foo" "biz" "foo" "biz" EOF
구문 분석 트리와 관련하여 다음과 같은 두 가지 가능성이 있습니다.
Start --> A -+---------------------------> biz <--------------+- A <-- Start
| |
+-> B -+--------------------> foo <------+-- B <-+
| | |
+-> A -+-------------> biz <- A <-+ |
| |
+-> B -+------> foo <------+-- B <-+
| |
+-> A -> biz <- A <-+
종종 미리보기 문제를 처리하는 가장 좋은 방법은 문법을 모호하지 않고 LL (1)로 다시 작성하는 것입니다.
문법이 모호하면 미리 보기로도 충돌을 해결할 수 없습니다. 위의 예에서 어떤 수의 토큰을 미리 보는 것은 파서가 어떤 선택이 "올바른지"그리고 어떤 것이 "틀렸는 지"알아내는 데 도움이되지 않을 것입니다.
그렇다면 왜 JavaCC는 "LOOKAHEAD"지시문을 넣을 때 경고를 중지합니다. 미리보기 문제가 해결 되었기 때문이 아닙니다. 미리보기 지시문을 넣으면 JavaCC가 항상 경고를 표시하지 않기 때문입니다. 당신이 무엇을하고 있는지 알고 있다고 가정합니다.
그래서 어떻게해야합니까? 어떤 종류의 구문 분석 트리를 선호하는지 모르기 때문에 잘 모르겠습니다. 왼쪽에있는 경우 *를? 문제를 해결할 것입니다.
오른쪽의 구문 분석 트리가 마음에 들면 다음 문법으로 할 수 있다고 생각합니다.
void Start(): {}
{
A()
<EOF>
}
void A(): {}
{
SimpleA()
( B() | C() )*
}
void SimpleA() : {}
{
"(" A() ")" | "biz"
}
void B(): {}
{ "foo" SimpleA() }
void C(): {}
{ "bar" SimpleA() }
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다