我正在编写基本的编译器,因此很早就陷入了困境。当我尝试运行我的野牛文件时,它会引发错误(如下所示),我不知道为什么会这样做,并且已经花了很长时间了。
错误:
compiler/parser.y: warning: 9 nonterminals useless in grammar [-Wother]
compiler/parser.y: warning: 32 rules useless in grammar [-Wother]
compiler/parser.y:34.1-7: fatal error: start symbol program does not derive any sentence
program : DECLARE declaration IN commands END
FLEX:
%option noyywrap
%{
#include <stdio.h>
#include "parser.tab.h"
%}
NUMBER [0-9]+
PID [_a-z]+
WHITESPACE [ \t\r]+
%x COMMENT
%%
<INITIAL>{
"[" BEGIN(COMMENT);
\n yylineno++;
{WHITESPACE}
{NUMBER} {
printf("Number: %s\n", yytext);
yylval.ival = (char*) strdup(yytext);
return NUM;
}
{PID} {
printf("PID: %s\n", yytext);
yylval.sval = (char*) strdup(yytext);
return PID;
}
":=" return ASSIGN;
"+" return ADD;
"-" return SUB;
"*" return MUL;
"/" return DIV;
"%" return MOD;
"=" return EQ;
"!=" return NEQ;
"<" return LT;
">" return GT;
"<=" return LE;
">=" return GE;
")" return R_BRACKET;
"(" return L_BRACKET;
";" return SEMICOLON;
":" return COLON;
"DECLARE" return DECLARE;
"IN" return IN;
"END" return END;
"IF" return IF;
"ELSE" return ELSE;
"ENDIF" return ENDIF;
"WHILE" return WHILE;
"DO" return DO;
"ENDWHILE" return ENDWHILE;
"ENDDO" return ENDDO;
"FOR" return FOR;
"FROM" return FROM;
"TO" return TO;
"DOWNTO" return DOWNTO;
"ENDFOR" return ENDFOR;
"READ" return READ;
"WRITE" return WRITE;
}
<COMMENT>{
"]" BEGIN(INITIAL);
[^\n]+\n yylineno++;
}
%%
野牛:
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern int yylineno;
int yylex(void);
void yyerror(const char *);
int error = 0;
%}
%union{
char* sval;
char* ival;
}
%token <sval> DECLARE /* Declarations block */
%token <sval> IN END /* Code block */
%token <sval> IF THEN ELSE ENDIF /* Conditional block */
%token <sval> WHILE DO ENDWHILE ENDDO /* While-do and Do-while loop block */
%token <sval> FOR FROM TO DOWNTO ENDFOR /* For loop block */
%token <sval> READ WRITE
%token <sval> ASSIGN
%token <sval> ADD SUB MUL DIV MOD /* Arithmetic operators */
%token <sval> EQ NEQ LT GT LE GE /* Boolean operators */
%token <sval> L_BRACKET R_BRACKET SEMICOLON COLON /* Symbols */
%token <ival> NUM
%token <sval> PID
%%
program : DECLARE declaration IN commands END
;
declaration : declaration PID SEMICOLON
| declaration PID L_BRACKET NUM COLON NUM R_BRACKET SEMICOLON
;
commands : commands command
| command
;
command : id ASSIGN expression SEMICOLON
| IF condition THEN commands ELSE commands ENDIF
| IF condition THEN commands ENDIF
| WHILE condition DO commands ENDWHILE
| DO commands WHILE condition ENDDO
| FOR PID FROM value TO value DO commands ENDFOR
| FOR PID FROM value DOWNTO value DO commands ENDFOR
| READ id SEMICOLON
| WRITE value SEMICOLON
;
expression : value
| value ADD value
| value SUB value
| value MUL value
| value DIV value
| value MOD value
;
condition : value EQ value
| value NEQ value
| value LT value
| value GT value
| value LE value
| value GE value
;
value : NUM
| id
;
id : PID
| PID L_BRACKET PID R_BRACKET
| PID L_BRACKET NUM R_BRACKET
;
%%
void yyerror(const char *msg) {
fprintf(stderr, "Compiling error: %s\n", msg);
}
如果您想知道,我可以从另一个文件运行main函数,但是我认为这不是问题。
答案 0 :(得分:3)
您的语法说有一个program
,您必须有一个declaration
:
program : DECLARE declaration ...
获取声明的唯一方法是这两个规则
declaration : declaration ...
| declaration ...
但这两个都要求您已经拥有declaration
。由于您从一无所有开始,并且如果已经拥有declaration
,那么您只能得到program
,因此您永远不会有任何声明。
因此,您永远无法解析~$ virtualenv --python-python3 firstdjango
。
答案 1 :(得分:0)
通常,当野牛说那句话的时候,它抱怨的是您使用它的语法。该错误消息意味着使用该语法不可能构建仅由终端符号组成的有效句子。您必须对语法进行修补,以便能够构建仅包含终端符号的语法树。如果您进行检查,您会发现实际上不可能构建仅在叶子中具有终端符号的解析树。尝试自己照顾自己。发生这种简单的语法。
sentence: '*' sentence
| '(' sentence ')' ;
您会看到,为sentence
构建的所有分析树的叶子之一始终是sentence
,因此不可能用只有终端符号的语言来构建有效的句子。 / p>
具体问题的技术细节在其他答案中进行了讨论,因此在此不再赘述(在您的情况下,Bison默认使用您在语法中编写的第一条规则用作语法树的根)是declaration
,而不是程序)
无论如何,如果遇到该错误,可能这不是您遇到的唯一问题。如果您尝试将bison
与选项--report
和--report-file
(请参见联机帮助页)一起使用,您将获得有关使该规则失败的规则的更详细信息。
查看代码后,将declaration
扩展为declaration
,并在为declaration
提供的所有替代方案中添加更多内容仅包含终端符号,因为随着您的展开,总会有一个declaration
展开。