我正在尝试构建一个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
这里的错误是什么?
编辑:错误发生在词法分析器中。
答案 0 :(得分:11)
Lisp语法不能表示为无上下文语法,yacc无法解析所有lisp代码。 这是因为lisp功能,如读取评估和可编程读取器。因此,为了只读取任意lisp代码,您需要运行完整的lisp。这不是一些模糊的,未使用的功能,但它实际上是使用的。例如,CL-INTERPOL,CL-SQL。
如果目标是解析lisp的子集,那么程序文本就是一系列的性别。
答案 1 :(得分:11)
错误实际上是词法分析器。你的括号最后成为最后一个“。”在词法分析器中,并且不会在解析器中显示为括号。
添加
等规则\) { return RPAREN; }
\( { return LPAREN; }
到词法分析器并在解析器中分别将'(',')'的所有出现更改为LPAREN和RPAREN。 (另外,您需要#define LPAREN和RPAREN来定义您的令牌列表)
注意:我不确定语法,可能是反斜杠错误。
答案 2 :(得分:4)
你是正确的,你需要定义一个非终端。那将被定义为一组sexpr。我不确定YACC的语法。对于解析器生成器,我偏爱ANTLR,语法为:
program: sexpr*
表示0或更多sexpr。
使用YACC语法更新:
program : /* empty */
| program sexpr
;
不在YACC中,但无论如何都可能有用,这里是ANTLR v3中的完整语法,适用于您描述的情况(排除词法分析器中的字符串,因为它对于此示例并不重要,也使用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完全不同,因为YACC生成和LALR解析器,而ANTLR是修改后的递归下降。如果你想这样,那么ANTLR有一个C / C ++输出目标。
答案 3 :(得分:2)
您是否需要yacc / bison解析器? “读取lisp语法的子集”读取器并不难以在C中实现(从read_sexpr函数开始,当您看到'(',然后构建包含的sexprs列表直到a'时,调度到read_list) )''被看到;否则,调用一个收集原子的read_atom,当它不再能读取原子组成的字符时返回它。)
但是,如果你想能够阅读arbritary Common Lisp,你需要(最坏的情况下)实现一个Common Lisp,因为CL可以修改阅读器的运行时间(甚至可以在不同的read-table之间切换)程序控制下的运行时;当你想要加载用另一种语言或lisp方言编写的代码时非常方便。
答案 4 :(得分:1)
我和YACC合作已经很久了,但你需要一个顶级的非终端。你可以更具体地说“尝试过它”和“它似乎没有用”吗?或者,就此而言,错误是什么?
我还怀疑YACC对于这种语法轻量级语言可能有点过分。更简单的东西(如递归下降)可能会更好。
答案 5 :(得分:1)
您可以尝试this grammar here。
答案 6 :(得分:1)
我刚尝试过,我的“yacc lisp语法”工作正常:
%start exprs
exprs:
| exprs expr
/// if you prefer right recursion :
/// | expr exprs
;
list:
'(' exprs ')'
;
expr:
atom
| list
;
atom:
IDENTIFIER
| CONSTANT
| NIL
| '+'
| '-'
| '*'
| '^'
| '/'
;