문제
나는 LISP 문법을 만들려고 노력하고 있습니다. 쉽지? 분명히.
이 입력을 제시하고 오류를받습니다 ...
( 1 1)
23 23 23
ui ui
이것은 문법입니다 ...
%%
sexpr: atom {printf("matched sexpr\n");}
| list
;
list: '(' members ')' {printf("matched list\n");}
| '('')' {printf("matched empty list\n");}
;
members: sexpr {printf("members 1\n");}
| sexpr members {printf("members 2\n");}
;
atom: ID {printf("ID\n");}
| NUM {printf("NUM\n");}
| STR {printf("STR\n");}
;
%%
내가 알 수있는 한, 나는 전체 구문 분석 트리가 매달릴 수있는 프로그램으로 정의 된 단일 비 터미널이 필요합니다. 그러나 나는 그것을 시도했지만 작동하지 않는 것 같습니다.
편집 - 이것은 나의 "최상단 터미널"접근법이었습니다.
program: slist;
slist: slist sexpr | sexpr;
그러나 다음과 같은 문제를 허용합니다.
( 1 1
edit2 : Flex 코드는 ...
%{
#include <stdio.h>
#include "a.yacc.tab.h"
int linenumber;
extern int yylval;
%}
%%
\n { linenumber++; }
[0-9]+ { yylval = atoi(yytext); return NUM; }
\"[^\"\n]*\" { return STR; }
[a-zA-Z][a-zA-Z0-9]* { return ID; }
.
%%
과잉 매칭의 예 ...
(1 1 1)
NUM
matched sexpr
NUM
matched sexpr
NUM
matched sexpr
(1 1
NUM
matched sexpr
NUM
matched sexpr
여기 오류는 무엇입니까?
편집 : 오류는 Lexer에있었습니다.
해결책
오류는 실제로 Lexer에 있습니다. 당신의 괄호는 마지막으로 끝납니다. Lexer에서, 파서에서 괄호로 나타나지 마십시오.
같은 규칙을 추가하십시오
\) { return RPAREN; }
\( { return LPAREN; }
Lexer에게 '(', ')의 모든 발생을 각각 파서에서 lparen과 rparen으로 변경합니다. (또한 토큰 목록을 정의하는 #define lparen 및 rparen이 필요합니다).
참고 : 구문에 대해 잘 모르겠습니다. 백 슬래시가 잘못되었을 수 있습니다.
다른 팁
LISP 문법은 컨텍스트가없는 문법으로 표시 될 수 없으며 YACC는 모든 LISP 코드를 구문 분석 할 수 없습니다. Read-Evaluation 및 Programmable Reader와 같은 LISP 기능 때문입니다. 따라서 임의의 LISP 코드를 읽으려면 전체 LISP를 실행해야합니다. 이것은 모호하고 사용되지 않는 기능이 아니지만 실제로 사용됩니다. EG, CL-interpol, CL-SQL.
목표가 LISP의 하위 집합을 구문 분석하는 것이라면 프로그램 텍스트는 SexPR의 시퀀스입니다.
당신은 비 터미널을 정의해야한다는 점에서 맞습니다. 그것은 sexpr 세트로 정의됩니다. YACC 구문이 확실하지 않습니다. 나는 부분적이다 antlr 파서 생성기와 구문은 다음과 같습니다.
program: sexpr*
0 이상의 sexpr을 나타냅니다.
YACC 구문으로 업데이트 :
program : /* empty */
| program sexpr
;
YACC는 아니지만 어쨌든 도움이 될 수 있습니다. 여기에 antlr v3의 전체 문법이 설명되어 있습니다 (이 예제에는 중요하지 않기 때문에 Lexer의 문자열을 제외하고 C# 콘솔 출력도 사용하기 때문에 C# 콘솔 출력을 사용합니다. ) : :
program: (sexpr)*;
sexpr: list
| atom {Console.WriteLine("matched sexpr");}
;
list:
'('')' {Console.WriteLine("matched empty list");}
| '(' members ')' {Console.WriteLine("matched list");}
;
members: (sexpr)+ {Console.WriteLine("members 1");};
atom: Id {Console.WriteLine("ID");}
| Num {Console.WriteLine("NUM");}
;
Num: ( '0' .. '9')+;
Id: ('a' .. 'z' | 'A' .. 'Z')+;
Whitespace : ( ' ' | '\r' '\n' | '\n' | '\t' ) {Skip();};
YACC는 LALR 파서를 생성하고 LALR 파서를 생성하고 ANTLR은 수정 된 재귀 하강이기 때문에 YACC와 정확히 작동하지 않습니다. 그런 식으로 가고 싶다면 Antlr에 대한 C/C ++ 출력 대상이 있습니다.
YACC/Bison Parser가 필요합니까? "LISP 구문의 하위 집합"리더는 C에서 구현하기가 어렵지 않습니다 (read_sexpr 함수로 시작하고 a '('( ')를 볼 때 read_list로 발송합니다. ) '보인다; 그렇지 않으면, 원자를 수집하는 read_atom을 호출하고 더 이상 원자-대응 문자를 읽을 수 없을 때 반환한다).
그러나 Arbritary Common LISP를 읽을 수 있으려면 CL이 독자 런타임을 수정하고 다른 읽기 테이블 런타임 사이에서 전환 할 수 있으므로 공통 LISP를 구현해야합니다. 프로그램 제어하에; LISP의 다른 언어 나 방언으로 작성된 코드를로드하려고 할 때 매우 편리합니다).
내가 YACC와 함께 일한 지 오래되었지만 최상위 비 터미널이 필요합니다. "시도한 시도"와 "작동하지 않는 것"에 대해 더 구체적으로 할 수 있습니까? 또는 그 문제에 대해 오류는 무엇입니까?
또한 YACC가 그러한 구문 라이트 언어에 대해 과잉 일 수 있다고 생각합니다. 재귀 적 출신과 같은 단순한 것이 더 잘 작동 할 수 있습니다.
당신은 시도 할 수 있습니다 이 문법은 여기에 있습니다.
방금 시도했습니다. "YACC LISP 문법"이 잘 작동합니다.
%start exprs
exprs:
| exprs expr
/// if you prefer right recursion :
/// | expr exprs
;
list:
'(' exprs ')'
;
expr:
atom
| list
;
atom:
IDENTIFIER
| CONSTANT
| NIL
| '+'
| '-'
| '*'
| '^'
| '/'
;