2009-12-01 4 views
16

저는 C--라는 가상의 프로그래밍 언어에 대한 파서를 작성합니다 (실제 C-- 언어가 아님). 나는 언어의 문법을 Pyparsing이 받아 들일 수있는 것으로 변환해야하는 무대에 다다 랐다. 불행히도 필자가 필자의 입력 문자열 (Pyparsing 오류를 일으키지 않아야 함)을 구문 분석하러 왔을 때 올바르게 구문 분석하지 않습니다. 이것이 문법 오류로 인한 것이 아닌가하는 생각이 들지만 처음으로 Pyparsing을 시작할 때 어디서 잘못 될지 모르겠습니다.Parsarsing 문법 디버깅

내가 번역 한 문법을 ​​업로드하여 사람들이 읽을 수 있도록 here에서 업로드했습니다.

편집 : 바울의 조언으로 업데이트되었습니다.

이 내가 현재 가지고 한 문법이다 (구문 정의의 두 상단 라인은 내가 알고 나를 정말 나쁜) : 나는 '어떤 실수가 있다면 내가 좋아하는 것

# Lexical structure definition 
ifS = Keyword('if') 
elseS = Keyword('else') 
whileS = Keyword('while') 
returnS = Keyword('return') 
intVar = Keyword('int') 
voidKeyword = Keyword('void') 
sumdiff = Literal('+') | Literal('-') 
prodquot = Literal('*') | Literal('/') 
relation = Literal('<=') | Literal('<') | Literal('==') | \ 
      Literal('!=') | Literal('>') | Literal('=>') 
lbrace = Literal('{') 
rbrace = Literal('}') 
lparn = Literal('(') 
rparn = Literal(')') 
semi = Literal(';') 
comma = Literal(',') 
number = Word(nums) 
identifier = Word(alphas, alphanums) 

# Syntax definition 
term = '' 
statement = '' 
variable = intVar + identifier + semi 
locals  = ZeroOrMore(variable) 
expr  = term | OneOrMore(Group(sumdiff + term)) 
args  = ZeroOrMore(OneOrMore(Group(expr + comma)) | expr) 
funccall = Group(identifier + lparn + args + rparn) 
factor  = Group(lparn + expr + rparn) | identifier | funccall | number 
term  = factor | OneOrMore(prodquot + factor) 
cond  = Group(lparn + expr + relation + expr + rparn) 
returnState = Group(returnS + semi) | Combine(returnS + expr + semi) 
assignment = Group(identifier + '=' + expr + semi) 
proccall = Group(identifier + lparn + args + rparn + semi) 
block  = Group(lbrace + locals + statement + rbrace) 
iteration = Group(whileS + cond + block) 
selection = Group(ifS + cond + block) | Group(ifS + cond + block + elseS + block) 
statement = OneOrMore(proccall | assignment | selection | iteration | returnState) 
param  = Group(intVar + identifier) 
paramlist = OneOrMore(Combine(param + comma)) | param 
params  = paramlist | voidKeyword 
procedure = Group(voidKeyword + identifier + lparn + params + rparn + block) 
function = Group(intVar + identifier + lparn + params + rparn + block) 
declaration = variable | function | procedure 
program  = OneOrMore(declaration) 

알고 문법을 가로 질러 번역했는데, 내가 준 문법을 고수하면서 간소화하기 위해 할 수있는 개선점은 무엇인가.

EDIT 2 : 새 오류가 포함되도록 업데이트되었습니다. 여기

내가 구문 분석하고 입력 문자열입니다

int larger (int first , int second) { 
if (first > second) { 
return first ; 
} else { 
return second ; 
} 
} 

void main (void) { 
int count ; 
int sum ; 
int max ; 
int x ; 

x = input () ; 
max = x ; 
sum = 0 ; 
count = 0 ; 

while (x != 0) { 
count = count + 1 ; 
sum = sum + x ; 
max = larger (max , x) ; 
x = input () ; 
} 

output (count) ; 
output (sum) ; 
output (max) ; 
} 

그리고 이것은 터미널에서 내 프로그램을 실행할 때 내가 오류 메시지입니다 :

/Users/Joe/Documents/Eclipse Projects/Parser/src/pyparsing.py:1156: SyntaxWarning: null string passed to Literal; use Empty() instead 
other = Literal(other) 
/Users/Joe/Documents/Eclipse Projects/Parser/src/pyparsing.py:1258: SyntaxWarning: null string passed to Literal; use Empty() instead 
other = Literal(other) 
Expected ")" (at char 30), (line:6, col:26) 
None 
+0

어떤 오류 메시지가 표시되는지와 같은 단서가 있습니까? "올바르게 구문 분석하지 못한다"고 말하면서 어떻게 알 수 있습니까? 오류가 있습니까? 잘못된 AST가 발생합니까? 더 많은 정보가 필요합니다. –

+0

죄송합니다. 구문 분석하려고하는 입력 문자열과 터미널에있는 오류 메시지로 내 질문을 업데이트했습니다. – greenie

답변

31

1) Literal("if")Keyword("if")로 변경 (및 등등, Literal("void")까지), "ifactor"이라는 변수의 선행 "if"와 일치하지 않게합니다.

2) nums, alphasalphanums는 "같은"단어 "를 정의 할 때 숫자로 구성된 단어입니다 그들은 문자의 전형적인 세트를 정의하는 말씀 클래스를 사용할 수있는 문자열이다, 표현하지 않습니다 nums "또는"식별자는 알파로 시작하고 0 개 이상의 영숫자로 시작하는 단어입니다. " 그래서 대신 :

number = nums 
identifier = alphas + OneOrMore(alphanums) 

당신이

number = Word(nums) 
identifier = Word(alphas, alphanums) 

3

을 원하는) 대신 Combine, 난 당신이 Group을 원하는 생각합니다. 일치하는 토큰을 공백없이 삽입하고 싶다면 Combine을 사용하고 토큰을 연결하여 단일 문자열로 리턴하십시오. 문자열 ['3', '.', '14']의 목록을 반환 "3.14"를 분석,

realnum = Combine(Word(nums) + "." + Word(nums)) 

Combine하지 않고, 그래서 realnum에 대한 분석 결과가 '3.14' 수 있도록 우리는 당신이 다음에 전달할 수있는 (Combine을 추가 Combine은 종종 다음과 같은 경우에 사용된다 구문 분석 작업을 수행하여 실제 부동 값 3.14으로 변환합니다. Combine 중첩 공백을 사용하지 않으면 우연히 'The answer is 3. 10 is too much.'을 파싱하지 않고 "3. 10"을 실수로 나타내는 것을 방지합니다.

4) 오류가 발생해서는 안되지만 입력 문자열에 lots 공백이 있습니다. 문법이 작동하면 "int x ;"뿐만 아니라 "int x;"을 구문 분석 할 수 있어야합니다.

이러한 힌트 중 일부가 도움이되기를 바랍니다. 온라인 pyparsing 기사 또는 자습서를 읽었습니까? 그리고 온라인 예제를 살펴보십시오. Word, Literal, Combine 등이 각각의 구문 분석 작업을 어떻게 수행하는지 잘 이해해야합니다.

5) 용어 및 문에 대한 재귀 적 정의가 잘못 구현되었습니다. 실제로 << 연산자를 사용하여, 자신의 재귀 적 정의로 정의로 이동하면 다음

term = Forward() 
statement = Forward() 

을 (그리고 ()의에서 RHS를 동봉해야합니다) 대신 그들에게 ''를 할당하는, 물품.

term << (... term definition ...) 
statement << (... statement definition ...) 
당신은 재귀 파서 here, 기본 대한 파싱 사용 here에 프레젠테이션의 예를 찾을 수 있습니다

- 섹션을 참조 더 단계별 재귀 처리하는 방법에 대한 "목록을 구문 분석".

+0

폴 감사합니다. 나는 Combine과 Group의 모든 인스턴스를 Group으로 대체했으며 이제는 내가 사용한 구문보다는 내 규칙이 어떻게 작성되었는지와 관련된 몇 가지 오류가 발생합니다. 내가 제안한 변경 사항과 새로운 오류가 반영되도록 원래 게시물을 업데이트했습니다. – greenie

+0

우수 Paul, 대단히 감사합니다. 내가 너를 +1 할 수 있으면 좋겠다. :) – greenie