构建野牛语法时,终端上出现了太多无用的规则
too many useless rules show up on terminal while building a bison grammar
代码:
%{
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include "gener.h"
#include "sym_tab.h"
#include "scope.h"
#include "defs.h"
extern char *yytext;
#define YYPRINT(file, type, value) yyprint (file, type, value)
%}
%union
{
char *name;
char idtype;
decl_list idlist;
/*decl_list is in gener.h,
you should #include "gener.h"
*/
}
%token PROGRAM
%token IDENTIFIER
%token DECIMAL_CONSTANT
%token DECLARE ENDDECLARE
%token AND CALL DEFAULT
%token FUNCTION PROCEDURE IN INOUT
%token IF ELSE DO WHILE FOR OR NOT SELECT
%token RETURN EXIT PRINT
%token EQ_LT EQ_GT NE EXACT
%left '+' '-'
%right '*' '/'
%start program
%%
program
: %empty
| PROGRAM IDENTIFIER block
;
block
: "{" declarations subprograms sequence "}"
;
declarations
: %empty
| DECLARE varlist ENDDECLARE
;
varlist
: %empty
| assignment_stat identifier2
;
identifier2 : ',' assignment_stat
| ',' assignment_stat
;
subprograms
: func
| subprograms ','
;
func
: PROCEDURE IDENTIFIER funcbody
| FUNCTION IDENTIFIER funcbody
;
funcbody
: formalpars block
;
formalpars
: '('')'
| '(' formalparlist ')'
;
formalparlist
: formalparitem
| formalparlist ','
;
formalparitem
: IN IDENTIFIER
| INOUT IDENTIFIER
;
sequence
: statement statement_sequence
;
statement_sequence
: ";"statement
| ';' statement statement_sequence
;
brackets_seq
: '{' sequence '}'
;
brack_or_stat
: brackets_seq
| statement
;
statement
: %empty
| assignment_stat
| if_stat
| do_while_stat
| while_stat
| select_stat
| exit_stat
| return_stat
| print_stat
| call_stat
;
assignment_stat
: IDENTIFIER EXACT IDENTIFIER
;
if_stat
: IF '(' condition')' brack_or_stat elsepart
;
elsepart
: %empty
| ELSE brack_or_stat
;
while_stat
: WHILE '(' condition')' brack_or_stat
;
select_stat
: SELECT'(' IDENTIFIER')'
dec
DEFAULT":" brack_or_stat
;
dec
: DECIMAL_CONSTANT ':' brack_or_stat
| dec ','
;
do_while_stat
: DO brack_or_stat WHILE '(' condition ')'
;
exit_stat
: EXIT
;
return_stat
: RETURN '(' expression ')'
;
print_stat
: PRINT '('expression ')'
;
call_stat
: CALL IDENTIFIER actualpars
;
actualpars
: '('')'
| '('actualparlist')'
;
actualparlist
: actualparitem
| actualparlist ','
;
actualparitem
: IN expression
| INOUT IDENTIFIER
;
condition
: boolterm or_boolterm
;
or_boolterm
: OR boolterm
| OR boolterm or_boolterm
;
boolterm
: boolfactor and_boolfactor
;
and_boolfactor
: AND boolfactor
| AND boolfactor and_boolfactor
;
boolfactor
: NOT '[' condition ']'
| '[' condition ']'
| expression relational_oper expression
;
expression
: optional_sign term add_oper_term
;
add_oper_term
: add_oper term
| add_oper term add_oper_term
;
term
: factor mul_oper_factor
;
mul_oper_factor
: mul_oper factor
| mul_oper factor mul_oper_factor
;
factor
: DECIMAL_CONSTANT
| expression
| IDENTIFIER idtail
;
idtail
: %empty
| actualpars
;
relational_oper
: '='
| '<'
| "<="
| "<>"
| ">="
| '>'
;
add_oper
: '+'
| '-'
;
mul_oper
: '*'
| '/'
;
optional_sign
: add_oper
| %empty
;
%%
这是我为 bison 创建的语法,但是当我在终端上尝试 bison gram.y 时,出现了一堆警告。试图改变它们的书写顺序,但我仍然得到同样的结果
这是终端输出
gram.y: warning: 44 nonterminals useless in grammar [-Wother]
gram.y: warning: 86 rules useless in grammar [-Wother]
gram.y:43.38-42: warning: nonterminal useless in grammar: block [-Wother]
| PROGRAM IDENTIFIER block
^^^^^
gram.y:47.23-34: warning: nonterminal useless in grammar: declarations [-Wother]
: "{" declarations subprograms sequence "}"
^^^^^^^^^^^^
gram.y:51.27-33: warning: nonterminal useless in grammar: varlist [-Wother]
| DECLARE varlist ENDDECLARE
^^^^^^^
gram.y:55.35-45: warning: nonterminal useless in grammar: identifier2 [-Wother]
| assignment_stat identifier2
^^^^^^^^^^^
gram.y:47.36-46: warning: nonterminal useless in grammar: subprograms [-Wother]
: "{" declarations subprograms sequence "}"
^^^^^^^^^^^
gram.y:63.19-22: warning: nonterminal useless in grammar: func [-Wother]
: func
^^^^
gram.y:67.40-47: warning: nonterminal useless in grammar: funcbody [-Wother]
: PROCEDURE IDENTIFIER funcbody
^^^^^^^^
gram.y:71.19-28: warning: nonterminal useless in grammar: formalpars [-Wother]
: formalpars block
^^^^^^^^^^
gram.y:75.23-35: warning: nonterminal useless in grammar: formalparlist [-Wother]
| '(' formalparlist ')'
^^^^^^^^^^^^^
gram.y:79.19-31: warning: nonterminal useless in grammar: formalparitem [-Wother]
: formalparitem
^^^^^^^^^^^^^
gram.y:47.48-55: warning: nonterminal useless in grammar: sequence [-Wother]
: "{" declarations subprograms sequence "}"
^^^^^^^^
gram.y:88.29-46: warning: nonterminal useless in grammar: statement_sequence [-Wother]
: statement statement_sequence
^^^^^^^^^^^^^^^^^^
gram.y:94.1-12: warning: nonterminal useless in grammar: brackets_seq [-Wother]
brackets_seq
^^^^^^^^^^^^
gram.y:97.1-13: warning: nonterminal useless in grammar: brack_or_stat [-Wother]
brack_or_stat
^^^^^^^^^^^^^
gram.y:88.19-27: warning: nonterminal useless in grammar: statement [-Wother]
: statement statement_sequence
^^^^^^^^^
gram.y:55.19-33: warning: nonterminal useless in grammar: assignment_stat [-Wother]
| assignment_stat identifier2
^^^^^^^^^^^^^^^
gram.y:106.19-25: warning: nonterminal useless in grammar: if_stat [-Wother]
| if_stat
^^^^^^^
gram.y:120.53-60: warning: nonterminal useless in grammar: elsepart [-Wother]
: IF '(' condition')' brack_or_stat elsepart
^^^^^^^^
gram.y:108.19-28: warning: nonterminal useless in grammar: while_stat [-Wother]
| while_stat
^^^^^^^^^^
gram.y:109.19-29: warning: nonterminal useless in grammar: select_stat [-Wother]
| select_stat
^^^^^^^^^^^
gram.y:131.19-21: warning: nonterminal useless in grammar: dec [-Wother]
dec
^^^
gram.y:107.19-31: warning: nonterminal useless in grammar: do_while_stat [-Wother]
| do_while_stat
^^^^^^^^^^^^^
gram.y:110.19-27: warning: nonterminal useless in grammar: exit_stat [-Wother]
| exit_stat
^^^^^^^^^
gram.y:111.19-29: warning: nonterminal useless in grammar: return_stat [-Wother]
| return_stat
^^^^^^^^^^^
gram.y:112.19-28: warning: nonterminal useless in grammar: print_stat [-Wother]
| print_stat
^^^^^^^^^^
gram.y:113.19-27: warning: nonterminal useless in grammar: call_stat [-Wother]
| call_stat
^^^^^^^^^
gram.y:151.35-44: warning: nonterminal useless in grammar: actualpars [-Wother]
: CALL IDENTIFIER actualpars
^^^^^^^^^^
gram.y:155.22-34: warning: nonterminal useless in grammar: actualparlist [-Wother]
| '('actualparlist')'
^^^^^^^^^^^^^
gram.y:158.19-31: warning: nonterminal useless in grammar: actualparitem [-Wother]
: actualparitem
^^^^^^^^^^^^^
gram.y:120.26-34: warning: nonterminal useless in grammar: condition [-Wother]
: IF '(' condition')' brack_or_stat elsepart
^^^^^^^^^
gram.y:166.28-38: warning: nonterminal useless in grammar: or_boolterm [-Wother]
: boolterm or_boolterm
^^^^^^^^^^^
gram.y:166.19-26: warning: nonterminal useless in grammar: boolterm [-Wother]
: boolterm or_boolterm
^^^^^^^^
gram.y:173.30-43: warning: nonterminal useless in grammar: and_boolfactor [-Wother]
: boolfactor and_boolfactor
^^^^^^^^^^^^^^
gram.y:173.19-28: warning: nonterminal useless in grammar: boolfactor [-Wother]
: boolfactor and_boolfactor
^^^^^^^^^^
gram.y:145.30-39: warning: nonterminal useless in grammar: expression [-Wother]
: RETURN '(' expression ')'
^^^^^^^^^^
gram.y:185.38-50: warning: nonterminal useless in grammar: add_oper_term [-Wother]
: optional_sign term add_oper_term
^^^^^^^^^^^^^
gram.y:185.33-36: warning: nonterminal useless in grammar: term [-Wother]
: optional_sign term add_oper_term
^^^^
gram.y:192.26-40: warning: nonterminal useless in grammar: mul_oper_factor [-Wother]
: factor mul_oper_factor
^^^^^^^^^^^^^^^
gram.y:192.19-24: warning: nonterminal useless in grammar: factor [-Wother]
: factor mul_oper_factor
^^^^^^
gram.y:201.30-35: warning: nonterminal useless in grammar: idtail [-Wother]
| IDENTIFIER idtail
^^^^^^
gram.y:182.30-44: warning: nonterminal useless in grammar: relational_oper [-Wother]
| expression relational_oper expression
^^^^^^^^^^^^^^^
gram.y:188.19-26: warning: nonterminal useless in grammar: add_oper [-Wother]
: add_oper term
^^^^^^^^
gram.y:195.19-26: warning: nonterminal useless in grammar: mul_oper [-Wother]
: mul_oper factor mul_oper_factor
^^^^^^^^
gram.y:185.19-31: warning: nonterminal useless in grammar: optional_sign [-Wother]
: optional_sign term add_oper_term
^^^^^^^^^^^^^
gram.y:43.19-42: warning: rule useless in grammar [-Wother]
| PROGRAM IDENTIFIER block
^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:47.19-59: warning: rule useless in grammar [-Wother]
: "{" declarations subprograms sequence "}"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:50.19-24: warning: rule useless in grammar [-Wother]
: %empty
^^^^^^
gram.y:51.19-44: warning: rule useless in grammar [-Wother]
| DECLARE varlist ENDDECLARE
^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:54.19-24: warning: rule useless in grammar [-Wother]
: %empty
^^^^^^
gram.y:55.19-45: warning: rule useless in grammar [-Wother]
| assignment_stat identifier2
^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:58.19-37: warning: rule useless in grammar [-Wother]
identifier2 : ',' assignment_stat
^^^^^^^^^^^^^^^^^^^
gram.y:59.19-37: warning: rule useless in grammar [-Wother]
| ',' assignment_stat
^^^^^^^^^^^^^^^^^^^
gram.y:63.19-22: warning: rule useless in grammar [-Wother]
: func
^^^^
gram.y:64.19-33: warning: rule useless in grammar [-Wother]
| subprograms ','
^^^^^^^^^^^^^^^
gram.y:67.19-47: warning: rule useless in grammar [-Wother]
: PROCEDURE IDENTIFIER funcbody
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:68.19-46: warning: rule useless in grammar [-Wother]
| FUNCTION IDENTIFIER funcbody
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:71.19-34: warning: rule useless in grammar [-Wother]
: formalpars block
^^^^^^^^^^^^^^^^
gram.y:74.19-24: warning: rule useless in grammar [-Wother]
: '('')'
^^^^^^
gram.y:75.19-39: warning: rule useless in grammar [-Wother]
| '(' formalparlist ')'
^^^^^^^^^^^^^^^^^^^^^
gram.y:79.19-31: warning: rule useless in grammar [-Wother]
: formalparitem
^^^^^^^^^^^^^
gram.y:80.19-35: warning: rule useless in grammar [-Wother]
| formalparlist ','
^^^^^^^^^^^^^^^^^
gram.y:84.19-31: warning: rule useless in grammar [-Wother]
: IN IDENTIFIER
^^^^^^^^^^^^^
gram.y:85.19-34: warning: rule useless in grammar [-Wother]
| INOUT IDENTIFIER
^^^^^^^^^^^^^^^^
gram.y:88.19-46: warning: rule useless in grammar [-Wother]
: statement statement_sequence
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:91.19-30: warning: rule useless in grammar [-Wother]
: ";"statement
^^^^^^^^^^^^
gram.y:92.19-50: warning: rule useless in grammar [-Wother]
| ';' statement statement_sequence
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:95.19-34: warning: rule useless in grammar [-Wother]
: '{' sequence '}'
^^^^^^^^^^^^^^^^
gram.y:98.19-30: warning: rule useless in grammar [-Wother]
: brackets_seq
^^^^^^^^^^^^
gram.y:99.19-27: warning: rule useless in grammar [-Wother]
| statement
^^^^^^^^^
gram.y:104.19-24: warning: rule useless in grammar [-Wother]
: %empty
^^^^^^
gram.y:105.19-33: warning: rule useless in grammar [-Wother]
| assignment_stat
^^^^^^^^^^^^^^^
gram.y:106.19-25: warning: rule useless in grammar [-Wother]
| if_stat
^^^^^^^
gram.y:107.19-31: warning: rule useless in grammar [-Wother]
| do_while_stat
^^^^^^^^^^^^^
gram.y:108.19-28: warning: rule useless in grammar [-Wother]
| while_stat
^^^^^^^^^^
gram.y:109.19-29: warning: rule useless in grammar [-Wother]
| select_stat
^^^^^^^^^^^
gram.y:110.19-27: warning: rule useless in grammar [-Wother]
| exit_stat
^^^^^^^^^
gram.y:111.19-29: warning: rule useless in grammar [-Wother]
| return_stat
^^^^^^^^^^^
gram.y:112.19-28: warning: rule useless in grammar [-Wother]
| print_stat
^^^^^^^^^^
gram.y:113.19-27: warning: rule useless in grammar [-Wother]
| call_stat
^^^^^^^^^
gram.y:116.19-45: warning: rule useless in grammar [-Wother]
: IDENTIFIER EXACT IDENTIFIER
^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:120.19-60: warning: rule useless in grammar [-Wother]
: IF '(' condition')' brack_or_stat elsepart
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:123.19-24: warning: rule useless in grammar [-Wother]
: %empty
^^^^^^
gram.y:124.19-36: warning: rule useless in grammar [-Wother]
| ELSE brack_or_stat
^^^^^^^^^^^^^^^^^^
gram.y:127.19-54: warning: rule useless in grammar [-Wother]
: WHILE '(' condition')' brack_or_stat
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:130.19-132.42: warning: rule useless in grammar [-Wother]
: SELECT'(' IDENTIFIER')'
^^^^^^^^^
gram.y:135.19-52: warning: rule useless in grammar [-Wother]
: DECIMAL_CONSTANT ':' brack_or_stat
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:136.19-25: warning: rule useless in grammar [-Wother]
| dec ','
^^^^^^^
gram.y:139.19-58: warning: rule useless in grammar [-Wother]
: DO brack_or_stat WHILE '(' condition ')'
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:142.19-22: warning: rule useless in grammar [-Wother]
: EXIT
^^^^
gram.y:145.19-43: warning: rule useless in grammar [-Wother]
: RETURN '(' expression ')'
^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:148.19-41: warning: rule useless in grammar [-Wother]
: PRINT '('expression ')'
^^^^^^^^^^^^^^^^^^^^^^^
gram.y:151.19-44: warning: rule useless in grammar [-Wother]
: CALL IDENTIFIER actualpars
^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:154.19-24: warning: rule useless in grammar [-Wother]
: '('')'
^^^^^^
gram.y:155.19-37: warning: rule useless in grammar [-Wother]
| '('actualparlist')'
^^^^^^^^^^^^^^^^^^^
gram.y:158.19-31: warning: rule useless in grammar [-Wother]
: actualparitem
^^^^^^^^^^^^^
gram.y:159.19-35: warning: rule useless in grammar [-Wother]
| actualparlist ','
^^^^^^^^^^^^^^^^^
gram.y:162.19-31: warning: rule useless in grammar [-Wother]
: IN expression
^^^^^^^^^^^^^
gram.y:163.19-34: warning: rule useless in grammar [-Wother]
| INOUT IDENTIFIER
^^^^^^^^^^^^^^^^
gram.y:166.19-38: warning: rule useless in grammar [-Wother]
: boolterm or_boolterm
^^^^^^^^^^^^^^^^^^^^
gram.y:169.19-29: warning: rule useless in grammar [-Wother]
: OR boolterm
^^^^^^^^^^^
gram.y:170.19-41: warning: rule useless in grammar [-Wother]
| OR boolterm or_boolterm
^^^^^^^^^^^^^^^^^^^^^^^
gram.y:173.19-43: warning: rule useless in grammar [-Wother]
: boolfactor and_boolfactor
^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:176.19-32: warning: rule useless in grammar [-Wother]
: AND boolfactor
^^^^^^^^^^^^^^
gram.y:177.19-47: warning: rule useless in grammar [-Wother]
| AND boolfactor and_boolfactor
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:180.19-39: warning: rule useless in grammar [-Wother]
: NOT '[' condition ']'
^^^^^^^^^^^^^^^^^^^^^
gram.y:181.19-35: warning: rule useless in grammar [-Wother]
| '[' condition ']'
^^^^^^^^^^^^^^^^^
gram.y:182.19-55: warning: rule useless in grammar [-Wother]
| expression relational_oper expression
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:185.19-50: warning: rule useless in grammar [-Wother]
: optional_sign term add_oper_term
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:188.19-31: warning: rule useless in grammar [-Wother]
: add_oper term
^^^^^^^^^^^^^
gram.y:189.19-45: warning: rule useless in grammar [-Wother]
| add_oper term add_oper_term
^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:192.19-40: warning: rule useless in grammar [-Wother]
: factor mul_oper_factor
^^^^^^^^^^^^^^^^^^^^^^
gram.y:195.19-49: warning: rule useless in grammar [-Wother]
: mul_oper factor mul_oper_factor
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:196.19-33: warning: rule useless in grammar [-Wother]
| mul_oper factor
^^^^^^^^^^^^^^^
gram.y:199.19-34: warning: rule useless in grammar [-Wother]
: DECIMAL_CONSTANT
^^^^^^^^^^^^^^^^
gram.y:200.19-28: warning: rule useless in grammar [-Wother]
| expression
^^^^^^^^^^
gram.y:201.19-35: warning: rule useless in grammar [-Wother]
| IDENTIFIER idtail
^^^^^^^^^^^^^^^^^
gram.y:204.19-24: warning: rule useless in grammar [-Wother]
: %empty
^^^^^^
gram.y:205.19-28: warning: rule useless in grammar [-Wother]
| actualpars
^^^^^^^^^^
gram.y:208.19-21: warning: rule useless in grammar [-Wother]
: '='
^^^
gram.y:209.19-21: warning: rule useless in grammar [-Wother]
| '<'
^^^
gram.y:210.19-22: warning: rule useless in grammar [-Wother]
| "<="
^^^^
gram.y:211.19-22: warning: rule useless in grammar [-Wother]
| "<>"
^^^^
gram.y:212.19-22: warning: rule useless in grammar [-Wother]
| ">="
^^^^
gram.y:213.19-21: warning: rule useless in grammar [-Wother]
| '>'
^^^
gram.y:216.19-21: warning: rule useless in grammar [-Wother]
: '+'
^^^
gram.y:217.19-21: warning: rule useless in grammar [-Wother]
| '-'
^^^
gram.y:220.19-21: warning: rule useless in grammar [-Wother]
: '*'
^^^
gram.y:221.19-21: warning: rule useless in grammar [-Wother]
| '/'
^^^
gram.y:224.19-26: warning: rule useless in grammar [-Wother]
: add_oper
^^^^^^^^
gram.y:225.19-24: warning: rule useless in grammar [-Wother]
| %empty
^^^^^^
任何人都可以帮助我吗?
问题是您为 subprograms
制作的作品。
但了解如何自行查找此类问题可能对您(以及您可能偶然发现此问题和答案的任何同学)更有用。
Whosebug 鼓励您提供 "Minimal, Complete and Verifiable Example" (MCVE),您应该花点时间阅读该帮助页面。提出要求并不是因为我们喜欢刁难有问题的人。这是因为将问题减少到最少的行为是调试的关键部分,你会发现当它成为一种习惯时,你会越来越善于发现问题。当然,它也可以帮助任何试图帮助您解决问题的人,因为它消除了所有不相关的噪音。
但是 MCVE 不仅仅是小。它也是 complete:也就是说,它是实际展示问题的摘录。仅仅说 "I think the problem is here, so I will just show this part." 是不够的,您必须实际上 证明 问题出在您认为的地方,方法是创建最小示例并证明它确实会产生同样的问题。
事实上,如果您牢记这一策略,您将以不同的方式编写程序。您无需编写一千行代码,然后将其全部输入编译器,而是编写一些独立的小片段,并在将它们组合成一个整体之前检查每个片段。这样,当您无法解决特定问题时,您已经拥有了 MCVE。
语法相互关联,令人恼火,而且不像人们希望的程序那样模块化。一个生产中的一个小变化可能会导致另一个看似完整的不相关生产的转移减少冲突。尽管如此,您通常可以将语法拆分为或多或少的独立组件。例如,您可以只从定义表达式的语法部分开始:
%token PROGRAM
%token IDENTIFIER
%token DECIMAL_CONSTANT
%token DECLARE ENDDECLARE
%token AND CALL DEFAULT
%token FUNCTION PROCEDURE IN INOUT
%token IF ELSE DO WHILE FOR OR NOT SELECT
%token RETURN EXIT PRINT
%token EQ_LT EQ_GT NE EXACT
%left '+' '-'
%right '*' '/'
%%
expression
: optional_sign term add_oper_term
;
add_oper_term
: add_oper term
| add_oper term add_oper_term
;
term
: factor mul_oper_factor
;
mul_oper_factor
: mul_oper factor
| mul_oper factor mul_oper_factor
;
factor
: DECIMAL_CONSTANT
| expression
| IDENTIFIER idtail
;
idtail
: %empty
| actualpars
;
add_oper
: '+'
| '-'
;
mul_oper
: '*'
| '/'
;
optional_sign
: add_oper
| %empty
;
actualpars
: '('')'
| '('actualparlist')'
;
actualparlist
: actualparitem
| actualparlist ','
;
actualparitem
: IN expression
| INOUT IDENTIFIER
;
这会产生许多 shift/reduce 冲突,您必须解决这些冲突,但它没有无用的产生式。 (请注意,我保留了所有 %token
声明,所以上面的内容不是 相当 最小值。Bison 不关心你是否声明了你从不使用的终端,所以为接下来的步骤保留声明会更容易。)
往上走一步,我们可以添加condition
,这涉及到添加:
condition
: boolterm or_boolterm
;
or_boolterm
: OR boolterm
| OR boolterm or_boolterm
;
boolterm
: boolfactor and_boolfactor
;
and_boolfactor
: AND boolfactor
| AND boolfactor and_boolfactor
;
boolfactor
: NOT '[' condition ']'
| '[' condition ']'
| expression relational_oper expression
;
relational_oper
: '='
| '<'
| "<="
| "<>"
| ">="
| '>'
;
现在有更多shift/reduce冲突,但仍然没有无用的非终端。
下一步是添加语句制作。在这里,我们会发现很多语句使用了非终结符brack_or_stat
,其定义为:
brack_or_stat
: brackets_seq
| statement
;
为了避免与brackets_seq
打交道,我们可以暂时将其添加到终端列表中。 (这是隐藏语法细节的标准技术。)稍后,当我们包含 brackets_seq
的产生式时,我们可以删除 %token
声明。)所以我们现在添加
%token brackets_seq
before the `%%`, and the statement productions after it:
brack_or_stat
: brackets_seq
| statement
;
statement
: %empty
| assignment_stat
| if_stat
| do_while_stat
| while_stat
| select_stat
| exit_stat
| return_stat
| print_stat
| call_stat
;
assignment_stat
: IDENTIFIER EXACT IDENTIFIER
;
if_stat
: IF '(' condition')' brack_or_stat elsepart
;
elsepart
: %empty
| ELSE brack_or_stat
;
while_stat
: WHILE '(' condition')' brack_or_stat
;
select_stat
: SELECT'(' IDENTIFIER')'
dec
DEFAULT":" brack_or_stat
;
dec
: DECIMAL_CONSTANT ':' brack_or_stat
| dec ','
;
do_while_stat
: DO brack_or_stat WHILE '(' condition ')'
;
exit_stat
: EXIT
;
return_stat
: RETURN '(' expression ')'
;
print_stat
: PRINT '('expression ')'
;
call_stat
: CALL IDENTIFIER actualpars
;
现在有更多 shift/reduce 冲突,但没有无用的非终端。
所以现在我们已经查看了一半以上的语法,并且有理由相信问题不在我们所查看的部分。 (虽然还有很多其他问题需要解决。)
所以如果我们假设 statement
没问题,让我们把它变成一个终端,并从测试中删除它和它引用的所有非终端。这给我们留下了一个更简单的程序:(当我通过 bison 复制并粘贴此摘录并 运行 时,它告诉我 assignment_stat
未定义。所以我只是将它添加到 %token
声明。)
%token PROGRAM
%token IDENTIFIER
%token DECIMAL_CONSTANT
%token DECLARE ENDDECLARE
%token AND CALL DEFAULT
%token FUNCTION PROCEDURE IN INOUT
%token IF ELSE DO WHILE FOR OR NOT SELECT
%token RETURN EXIT PRINT
%token EQ_LT EQ_GT NE EXACT
%token statement assignment_stat
%start program
%%
program
: %empty
| PROGRAM IDENTIFIER block
;
block
: "{" declarations subprograms sequence "}"
;
declarations
: %empty
| DECLARE varlist ENDDECLARE
;
varlist
: %empty
| assignment_stat identifier2
;
identifier2 : ',' assignment_stat
| ',' assignment_stat
;
subprograms
: func
| subprograms ','
;
func
: PROCEDURE IDENTIFIER funcbody
| FUNCTION IDENTIFIER funcbody
;
funcbody
: formalpars block
;
formalpars
: '('')'
| '(' formalparlist ')'
;
formalparlist
: formalparitem
| formalparlist ','
;
formalparitem
: IN IDENTIFIER
| INOUT IDENTIFIER
;
sequence
: statement statement_sequence
;
statement_sequence
: ";"statement
| ';' statement statement_sequence
;
brackets_seq
: '{' sequence '}'
;
brack_or_stat
: brackets_seq
| statement
;
现在我们有一个充满 "useless non-terminal" 警告的屏幕。
不过,语法现在简单多了。 (如果它看起来不够简单,您可以继续进行简化练习。例如,一种可能是将声明分开。)事实上,问题可能是可见的:
subprograms
: func
| subprograms ','
func : PROCEDURE IDENTIFIER funcbody
| FUNCTION IDENTIFIER funcbody
funcbody: formalpars block
block: "{" declarations subprograms sequence "}"
请注意这里发生的事情:subprograms
有两个作品。第二个显然是递归的。但是不费吹灰之力就可以看出另一个也是递归的:func
有两个产生式,但都使用funcbody
; funcbody
的唯一作品使用 block
,而 block
使用 subprograms
。
所以subprograms
没有非递归产生式,因此永远无法跳出递归。 func
、funcbody
或 block
.
也不能
但是如果block
不能生成任何句子,那么program
(PROGRAM IDENTIFIER block
)的第二次产生式也不能生成任何句子,留下program: %empty
作为唯一有效的生产开始符号。这使得空字符串成为唯一有效的 program
,因此 bison 将所有其他非终端标记为无用。
现在,让我们回到subprograms
(正如我在开头所说,这是紧迫的问题)。定义是:
subprograms
: func
| subprograms ','
现在,这是一个非常奇怪的定义(而且,我认为,这种奇怪现象在您的语法中反复出现)。这是什么意思? subprograms
是 func
或 subprograms
后跟一个逗号。所以它会产生:
func
func ,
func , ,
func , , ,
func , , , ,
等等。单个 func
,后跟零个或多个逗号。它必须有一个函数,不能有更多。
它不能为空的事实是无限递归的原因。一个 block
必须包含一个 subprograms
,一个 subprograms
必须包含一个 func
。但是 func
必须包含 block
。并且没有逃脱那个旋转木马。
所以这里有两个问题:subprograms
不能为空,也不能包含多个func
。您可能正在寻找的是:
function_list: func
| function_list ',' func
subprograms : %empty
| function_list
注意 function_list
使用左递归。那是故意的。 Bison 生产 LR 解析器,它喜欢左递归。
如果您以前研究过 LL 解析器并以某种方式在您的脑海中认识到左递归是邪恶的,忘记那个教训。 LL 解析器无法处理左递归,但 LR 解析器可以同时处理左递归和右递归,并且更好地处理左递归(因为它不会耗尽解析器堆栈)。
代码:
%{
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include "gener.h"
#include "sym_tab.h"
#include "scope.h"
#include "defs.h"
extern char *yytext;
#define YYPRINT(file, type, value) yyprint (file, type, value)
%}
%union
{
char *name;
char idtype;
decl_list idlist;
/*decl_list is in gener.h,
you should #include "gener.h"
*/
}
%token PROGRAM
%token IDENTIFIER
%token DECIMAL_CONSTANT
%token DECLARE ENDDECLARE
%token AND CALL DEFAULT
%token FUNCTION PROCEDURE IN INOUT
%token IF ELSE DO WHILE FOR OR NOT SELECT
%token RETURN EXIT PRINT
%token EQ_LT EQ_GT NE EXACT
%left '+' '-'
%right '*' '/'
%start program
%%
program
: %empty
| PROGRAM IDENTIFIER block
;
block
: "{" declarations subprograms sequence "}"
;
declarations
: %empty
| DECLARE varlist ENDDECLARE
;
varlist
: %empty
| assignment_stat identifier2
;
identifier2 : ',' assignment_stat
| ',' assignment_stat
;
subprograms
: func
| subprograms ','
;
func
: PROCEDURE IDENTIFIER funcbody
| FUNCTION IDENTIFIER funcbody
;
funcbody
: formalpars block
;
formalpars
: '('')'
| '(' formalparlist ')'
;
formalparlist
: formalparitem
| formalparlist ','
;
formalparitem
: IN IDENTIFIER
| INOUT IDENTIFIER
;
sequence
: statement statement_sequence
;
statement_sequence
: ";"statement
| ';' statement statement_sequence
;
brackets_seq
: '{' sequence '}'
;
brack_or_stat
: brackets_seq
| statement
;
statement
: %empty
| assignment_stat
| if_stat
| do_while_stat
| while_stat
| select_stat
| exit_stat
| return_stat
| print_stat
| call_stat
;
assignment_stat
: IDENTIFIER EXACT IDENTIFIER
;
if_stat
: IF '(' condition')' brack_or_stat elsepart
;
elsepart
: %empty
| ELSE brack_or_stat
;
while_stat
: WHILE '(' condition')' brack_or_stat
;
select_stat
: SELECT'(' IDENTIFIER')'
dec
DEFAULT":" brack_or_stat
;
dec
: DECIMAL_CONSTANT ':' brack_or_stat
| dec ','
;
do_while_stat
: DO brack_or_stat WHILE '(' condition ')'
;
exit_stat
: EXIT
;
return_stat
: RETURN '(' expression ')'
;
print_stat
: PRINT '('expression ')'
;
call_stat
: CALL IDENTIFIER actualpars
;
actualpars
: '('')'
| '('actualparlist')'
;
actualparlist
: actualparitem
| actualparlist ','
;
actualparitem
: IN expression
| INOUT IDENTIFIER
;
condition
: boolterm or_boolterm
;
or_boolterm
: OR boolterm
| OR boolterm or_boolterm
;
boolterm
: boolfactor and_boolfactor
;
and_boolfactor
: AND boolfactor
| AND boolfactor and_boolfactor
;
boolfactor
: NOT '[' condition ']'
| '[' condition ']'
| expression relational_oper expression
;
expression
: optional_sign term add_oper_term
;
add_oper_term
: add_oper term
| add_oper term add_oper_term
;
term
: factor mul_oper_factor
;
mul_oper_factor
: mul_oper factor
| mul_oper factor mul_oper_factor
;
factor
: DECIMAL_CONSTANT
| expression
| IDENTIFIER idtail
;
idtail
: %empty
| actualpars
;
relational_oper
: '='
| '<'
| "<="
| "<>"
| ">="
| '>'
;
add_oper
: '+'
| '-'
;
mul_oper
: '*'
| '/'
;
optional_sign
: add_oper
| %empty
;
%%
这是我为 bison 创建的语法,但是当我在终端上尝试 bison gram.y 时,出现了一堆警告。试图改变它们的书写顺序,但我仍然得到同样的结果 这是终端输出
gram.y: warning: 44 nonterminals useless in grammar [-Wother]
gram.y: warning: 86 rules useless in grammar [-Wother]
gram.y:43.38-42: warning: nonterminal useless in grammar: block [-Wother]
| PROGRAM IDENTIFIER block
^^^^^
gram.y:47.23-34: warning: nonterminal useless in grammar: declarations [-Wother]
: "{" declarations subprograms sequence "}"
^^^^^^^^^^^^
gram.y:51.27-33: warning: nonterminal useless in grammar: varlist [-Wother]
| DECLARE varlist ENDDECLARE
^^^^^^^
gram.y:55.35-45: warning: nonterminal useless in grammar: identifier2 [-Wother]
| assignment_stat identifier2
^^^^^^^^^^^
gram.y:47.36-46: warning: nonterminal useless in grammar: subprograms [-Wother]
: "{" declarations subprograms sequence "}"
^^^^^^^^^^^
gram.y:63.19-22: warning: nonterminal useless in grammar: func [-Wother]
: func
^^^^
gram.y:67.40-47: warning: nonterminal useless in grammar: funcbody [-Wother]
: PROCEDURE IDENTIFIER funcbody
^^^^^^^^
gram.y:71.19-28: warning: nonterminal useless in grammar: formalpars [-Wother]
: formalpars block
^^^^^^^^^^
gram.y:75.23-35: warning: nonterminal useless in grammar: formalparlist [-Wother]
| '(' formalparlist ')'
^^^^^^^^^^^^^
gram.y:79.19-31: warning: nonterminal useless in grammar: formalparitem [-Wother]
: formalparitem
^^^^^^^^^^^^^
gram.y:47.48-55: warning: nonterminal useless in grammar: sequence [-Wother]
: "{" declarations subprograms sequence "}"
^^^^^^^^
gram.y:88.29-46: warning: nonterminal useless in grammar: statement_sequence [-Wother]
: statement statement_sequence
^^^^^^^^^^^^^^^^^^
gram.y:94.1-12: warning: nonterminal useless in grammar: brackets_seq [-Wother]
brackets_seq
^^^^^^^^^^^^
gram.y:97.1-13: warning: nonterminal useless in grammar: brack_or_stat [-Wother]
brack_or_stat
^^^^^^^^^^^^^
gram.y:88.19-27: warning: nonterminal useless in grammar: statement [-Wother]
: statement statement_sequence
^^^^^^^^^
gram.y:55.19-33: warning: nonterminal useless in grammar: assignment_stat [-Wother]
| assignment_stat identifier2
^^^^^^^^^^^^^^^
gram.y:106.19-25: warning: nonterminal useless in grammar: if_stat [-Wother]
| if_stat
^^^^^^^
gram.y:120.53-60: warning: nonterminal useless in grammar: elsepart [-Wother]
: IF '(' condition')' brack_or_stat elsepart
^^^^^^^^
gram.y:108.19-28: warning: nonterminal useless in grammar: while_stat [-Wother]
| while_stat
^^^^^^^^^^
gram.y:109.19-29: warning: nonterminal useless in grammar: select_stat [-Wother]
| select_stat
^^^^^^^^^^^
gram.y:131.19-21: warning: nonterminal useless in grammar: dec [-Wother]
dec
^^^
gram.y:107.19-31: warning: nonterminal useless in grammar: do_while_stat [-Wother]
| do_while_stat
^^^^^^^^^^^^^
gram.y:110.19-27: warning: nonterminal useless in grammar: exit_stat [-Wother]
| exit_stat
^^^^^^^^^
gram.y:111.19-29: warning: nonterminal useless in grammar: return_stat [-Wother]
| return_stat
^^^^^^^^^^^
gram.y:112.19-28: warning: nonterminal useless in grammar: print_stat [-Wother]
| print_stat
^^^^^^^^^^
gram.y:113.19-27: warning: nonterminal useless in grammar: call_stat [-Wother]
| call_stat
^^^^^^^^^
gram.y:151.35-44: warning: nonterminal useless in grammar: actualpars [-Wother]
: CALL IDENTIFIER actualpars
^^^^^^^^^^
gram.y:155.22-34: warning: nonterminal useless in grammar: actualparlist [-Wother]
| '('actualparlist')'
^^^^^^^^^^^^^
gram.y:158.19-31: warning: nonterminal useless in grammar: actualparitem [-Wother]
: actualparitem
^^^^^^^^^^^^^
gram.y:120.26-34: warning: nonterminal useless in grammar: condition [-Wother]
: IF '(' condition')' brack_or_stat elsepart
^^^^^^^^^
gram.y:166.28-38: warning: nonterminal useless in grammar: or_boolterm [-Wother]
: boolterm or_boolterm
^^^^^^^^^^^
gram.y:166.19-26: warning: nonterminal useless in grammar: boolterm [-Wother]
: boolterm or_boolterm
^^^^^^^^
gram.y:173.30-43: warning: nonterminal useless in grammar: and_boolfactor [-Wother]
: boolfactor and_boolfactor
^^^^^^^^^^^^^^
gram.y:173.19-28: warning: nonterminal useless in grammar: boolfactor [-Wother]
: boolfactor and_boolfactor
^^^^^^^^^^
gram.y:145.30-39: warning: nonterminal useless in grammar: expression [-Wother]
: RETURN '(' expression ')'
^^^^^^^^^^
gram.y:185.38-50: warning: nonterminal useless in grammar: add_oper_term [-Wother]
: optional_sign term add_oper_term
^^^^^^^^^^^^^
gram.y:185.33-36: warning: nonterminal useless in grammar: term [-Wother]
: optional_sign term add_oper_term
^^^^
gram.y:192.26-40: warning: nonterminal useless in grammar: mul_oper_factor [-Wother]
: factor mul_oper_factor
^^^^^^^^^^^^^^^
gram.y:192.19-24: warning: nonterminal useless in grammar: factor [-Wother]
: factor mul_oper_factor
^^^^^^
gram.y:201.30-35: warning: nonterminal useless in grammar: idtail [-Wother]
| IDENTIFIER idtail
^^^^^^
gram.y:182.30-44: warning: nonterminal useless in grammar: relational_oper [-Wother]
| expression relational_oper expression
^^^^^^^^^^^^^^^
gram.y:188.19-26: warning: nonterminal useless in grammar: add_oper [-Wother]
: add_oper term
^^^^^^^^
gram.y:195.19-26: warning: nonterminal useless in grammar: mul_oper [-Wother]
: mul_oper factor mul_oper_factor
^^^^^^^^
gram.y:185.19-31: warning: nonterminal useless in grammar: optional_sign [-Wother]
: optional_sign term add_oper_term
^^^^^^^^^^^^^
gram.y:43.19-42: warning: rule useless in grammar [-Wother]
| PROGRAM IDENTIFIER block
^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:47.19-59: warning: rule useless in grammar [-Wother]
: "{" declarations subprograms sequence "}"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:50.19-24: warning: rule useless in grammar [-Wother]
: %empty
^^^^^^
gram.y:51.19-44: warning: rule useless in grammar [-Wother]
| DECLARE varlist ENDDECLARE
^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:54.19-24: warning: rule useless in grammar [-Wother]
: %empty
^^^^^^
gram.y:55.19-45: warning: rule useless in grammar [-Wother]
| assignment_stat identifier2
^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:58.19-37: warning: rule useless in grammar [-Wother]
identifier2 : ',' assignment_stat
^^^^^^^^^^^^^^^^^^^
gram.y:59.19-37: warning: rule useless in grammar [-Wother]
| ',' assignment_stat
^^^^^^^^^^^^^^^^^^^
gram.y:63.19-22: warning: rule useless in grammar [-Wother]
: func
^^^^
gram.y:64.19-33: warning: rule useless in grammar [-Wother]
| subprograms ','
^^^^^^^^^^^^^^^
gram.y:67.19-47: warning: rule useless in grammar [-Wother]
: PROCEDURE IDENTIFIER funcbody
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:68.19-46: warning: rule useless in grammar [-Wother]
| FUNCTION IDENTIFIER funcbody
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:71.19-34: warning: rule useless in grammar [-Wother]
: formalpars block
^^^^^^^^^^^^^^^^
gram.y:74.19-24: warning: rule useless in grammar [-Wother]
: '('')'
^^^^^^
gram.y:75.19-39: warning: rule useless in grammar [-Wother]
| '(' formalparlist ')'
^^^^^^^^^^^^^^^^^^^^^
gram.y:79.19-31: warning: rule useless in grammar [-Wother]
: formalparitem
^^^^^^^^^^^^^
gram.y:80.19-35: warning: rule useless in grammar [-Wother]
| formalparlist ','
^^^^^^^^^^^^^^^^^
gram.y:84.19-31: warning: rule useless in grammar [-Wother]
: IN IDENTIFIER
^^^^^^^^^^^^^
gram.y:85.19-34: warning: rule useless in grammar [-Wother]
| INOUT IDENTIFIER
^^^^^^^^^^^^^^^^
gram.y:88.19-46: warning: rule useless in grammar [-Wother]
: statement statement_sequence
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:91.19-30: warning: rule useless in grammar [-Wother]
: ";"statement
^^^^^^^^^^^^
gram.y:92.19-50: warning: rule useless in grammar [-Wother]
| ';' statement statement_sequence
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:95.19-34: warning: rule useless in grammar [-Wother]
: '{' sequence '}'
^^^^^^^^^^^^^^^^
gram.y:98.19-30: warning: rule useless in grammar [-Wother]
: brackets_seq
^^^^^^^^^^^^
gram.y:99.19-27: warning: rule useless in grammar [-Wother]
| statement
^^^^^^^^^
gram.y:104.19-24: warning: rule useless in grammar [-Wother]
: %empty
^^^^^^
gram.y:105.19-33: warning: rule useless in grammar [-Wother]
| assignment_stat
^^^^^^^^^^^^^^^
gram.y:106.19-25: warning: rule useless in grammar [-Wother]
| if_stat
^^^^^^^
gram.y:107.19-31: warning: rule useless in grammar [-Wother]
| do_while_stat
^^^^^^^^^^^^^
gram.y:108.19-28: warning: rule useless in grammar [-Wother]
| while_stat
^^^^^^^^^^
gram.y:109.19-29: warning: rule useless in grammar [-Wother]
| select_stat
^^^^^^^^^^^
gram.y:110.19-27: warning: rule useless in grammar [-Wother]
| exit_stat
^^^^^^^^^
gram.y:111.19-29: warning: rule useless in grammar [-Wother]
| return_stat
^^^^^^^^^^^
gram.y:112.19-28: warning: rule useless in grammar [-Wother]
| print_stat
^^^^^^^^^^
gram.y:113.19-27: warning: rule useless in grammar [-Wother]
| call_stat
^^^^^^^^^
gram.y:116.19-45: warning: rule useless in grammar [-Wother]
: IDENTIFIER EXACT IDENTIFIER
^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:120.19-60: warning: rule useless in grammar [-Wother]
: IF '(' condition')' brack_or_stat elsepart
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:123.19-24: warning: rule useless in grammar [-Wother]
: %empty
^^^^^^
gram.y:124.19-36: warning: rule useless in grammar [-Wother]
| ELSE brack_or_stat
^^^^^^^^^^^^^^^^^^
gram.y:127.19-54: warning: rule useless in grammar [-Wother]
: WHILE '(' condition')' brack_or_stat
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:130.19-132.42: warning: rule useless in grammar [-Wother]
: SELECT'(' IDENTIFIER')'
^^^^^^^^^
gram.y:135.19-52: warning: rule useless in grammar [-Wother]
: DECIMAL_CONSTANT ':' brack_or_stat
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:136.19-25: warning: rule useless in grammar [-Wother]
| dec ','
^^^^^^^
gram.y:139.19-58: warning: rule useless in grammar [-Wother]
: DO brack_or_stat WHILE '(' condition ')'
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:142.19-22: warning: rule useless in grammar [-Wother]
: EXIT
^^^^
gram.y:145.19-43: warning: rule useless in grammar [-Wother]
: RETURN '(' expression ')'
^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:148.19-41: warning: rule useless in grammar [-Wother]
: PRINT '('expression ')'
^^^^^^^^^^^^^^^^^^^^^^^
gram.y:151.19-44: warning: rule useless in grammar [-Wother]
: CALL IDENTIFIER actualpars
^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:154.19-24: warning: rule useless in grammar [-Wother]
: '('')'
^^^^^^
gram.y:155.19-37: warning: rule useless in grammar [-Wother]
| '('actualparlist')'
^^^^^^^^^^^^^^^^^^^
gram.y:158.19-31: warning: rule useless in grammar [-Wother]
: actualparitem
^^^^^^^^^^^^^
gram.y:159.19-35: warning: rule useless in grammar [-Wother]
| actualparlist ','
^^^^^^^^^^^^^^^^^
gram.y:162.19-31: warning: rule useless in grammar [-Wother]
: IN expression
^^^^^^^^^^^^^
gram.y:163.19-34: warning: rule useless in grammar [-Wother]
| INOUT IDENTIFIER
^^^^^^^^^^^^^^^^
gram.y:166.19-38: warning: rule useless in grammar [-Wother]
: boolterm or_boolterm
^^^^^^^^^^^^^^^^^^^^
gram.y:169.19-29: warning: rule useless in grammar [-Wother]
: OR boolterm
^^^^^^^^^^^
gram.y:170.19-41: warning: rule useless in grammar [-Wother]
| OR boolterm or_boolterm
^^^^^^^^^^^^^^^^^^^^^^^
gram.y:173.19-43: warning: rule useless in grammar [-Wother]
: boolfactor and_boolfactor
^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:176.19-32: warning: rule useless in grammar [-Wother]
: AND boolfactor
^^^^^^^^^^^^^^
gram.y:177.19-47: warning: rule useless in grammar [-Wother]
| AND boolfactor and_boolfactor
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:180.19-39: warning: rule useless in grammar [-Wother]
: NOT '[' condition ']'
^^^^^^^^^^^^^^^^^^^^^
gram.y:181.19-35: warning: rule useless in grammar [-Wother]
| '[' condition ']'
^^^^^^^^^^^^^^^^^
gram.y:182.19-55: warning: rule useless in grammar [-Wother]
| expression relational_oper expression
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:185.19-50: warning: rule useless in grammar [-Wother]
: optional_sign term add_oper_term
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:188.19-31: warning: rule useless in grammar [-Wother]
: add_oper term
^^^^^^^^^^^^^
gram.y:189.19-45: warning: rule useless in grammar [-Wother]
| add_oper term add_oper_term
^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:192.19-40: warning: rule useless in grammar [-Wother]
: factor mul_oper_factor
^^^^^^^^^^^^^^^^^^^^^^
gram.y:195.19-49: warning: rule useless in grammar [-Wother]
: mul_oper factor mul_oper_factor
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
gram.y:196.19-33: warning: rule useless in grammar [-Wother]
| mul_oper factor
^^^^^^^^^^^^^^^
gram.y:199.19-34: warning: rule useless in grammar [-Wother]
: DECIMAL_CONSTANT
^^^^^^^^^^^^^^^^
gram.y:200.19-28: warning: rule useless in grammar [-Wother]
| expression
^^^^^^^^^^
gram.y:201.19-35: warning: rule useless in grammar [-Wother]
| IDENTIFIER idtail
^^^^^^^^^^^^^^^^^
gram.y:204.19-24: warning: rule useless in grammar [-Wother]
: %empty
^^^^^^
gram.y:205.19-28: warning: rule useless in grammar [-Wother]
| actualpars
^^^^^^^^^^
gram.y:208.19-21: warning: rule useless in grammar [-Wother]
: '='
^^^
gram.y:209.19-21: warning: rule useless in grammar [-Wother]
| '<'
^^^
gram.y:210.19-22: warning: rule useless in grammar [-Wother]
| "<="
^^^^
gram.y:211.19-22: warning: rule useless in grammar [-Wother]
| "<>"
^^^^
gram.y:212.19-22: warning: rule useless in grammar [-Wother]
| ">="
^^^^
gram.y:213.19-21: warning: rule useless in grammar [-Wother]
| '>'
^^^
gram.y:216.19-21: warning: rule useless in grammar [-Wother]
: '+'
^^^
gram.y:217.19-21: warning: rule useless in grammar [-Wother]
| '-'
^^^
gram.y:220.19-21: warning: rule useless in grammar [-Wother]
: '*'
^^^
gram.y:221.19-21: warning: rule useless in grammar [-Wother]
| '/'
^^^
gram.y:224.19-26: warning: rule useless in grammar [-Wother]
: add_oper
^^^^^^^^
gram.y:225.19-24: warning: rule useless in grammar [-Wother]
| %empty
^^^^^^
任何人都可以帮助我吗?
问题是您为 subprograms
制作的作品。
但了解如何自行查找此类问题可能对您(以及您可能偶然发现此问题和答案的任何同学)更有用。
Whosebug 鼓励您提供 "Minimal, Complete and Verifiable Example" (MCVE),您应该花点时间阅读该帮助页面。提出要求并不是因为我们喜欢刁难有问题的人。这是因为将问题减少到最少的行为是调试的关键部分,你会发现当它成为一种习惯时,你会越来越善于发现问题。当然,它也可以帮助任何试图帮助您解决问题的人,因为它消除了所有不相关的噪音。
但是 MCVE 不仅仅是小。它也是 complete:也就是说,它是实际展示问题的摘录。仅仅说 "I think the problem is here, so I will just show this part." 是不够的,您必须实际上 证明 问题出在您认为的地方,方法是创建最小示例并证明它确实会产生同样的问题。
事实上,如果您牢记这一策略,您将以不同的方式编写程序。您无需编写一千行代码,然后将其全部输入编译器,而是编写一些独立的小片段,并在将它们组合成一个整体之前检查每个片段。这样,当您无法解决特定问题时,您已经拥有了 MCVE。
语法相互关联,令人恼火,而且不像人们希望的程序那样模块化。一个生产中的一个小变化可能会导致另一个看似完整的不相关生产的转移减少冲突。尽管如此,您通常可以将语法拆分为或多或少的独立组件。例如,您可以只从定义表达式的语法部分开始:
%token PROGRAM
%token IDENTIFIER
%token DECIMAL_CONSTANT
%token DECLARE ENDDECLARE
%token AND CALL DEFAULT
%token FUNCTION PROCEDURE IN INOUT
%token IF ELSE DO WHILE FOR OR NOT SELECT
%token RETURN EXIT PRINT
%token EQ_LT EQ_GT NE EXACT
%left '+' '-'
%right '*' '/'
%%
expression
: optional_sign term add_oper_term
;
add_oper_term
: add_oper term
| add_oper term add_oper_term
;
term
: factor mul_oper_factor
;
mul_oper_factor
: mul_oper factor
| mul_oper factor mul_oper_factor
;
factor
: DECIMAL_CONSTANT
| expression
| IDENTIFIER idtail
;
idtail
: %empty
| actualpars
;
add_oper
: '+'
| '-'
;
mul_oper
: '*'
| '/'
;
optional_sign
: add_oper
| %empty
;
actualpars
: '('')'
| '('actualparlist')'
;
actualparlist
: actualparitem
| actualparlist ','
;
actualparitem
: IN expression
| INOUT IDENTIFIER
;
这会产生许多 shift/reduce 冲突,您必须解决这些冲突,但它没有无用的产生式。 (请注意,我保留了所有 %token
声明,所以上面的内容不是 相当 最小值。Bison 不关心你是否声明了你从不使用的终端,所以为接下来的步骤保留声明会更容易。)
往上走一步,我们可以添加condition
,这涉及到添加:
condition
: boolterm or_boolterm
;
or_boolterm
: OR boolterm
| OR boolterm or_boolterm
;
boolterm
: boolfactor and_boolfactor
;
and_boolfactor
: AND boolfactor
| AND boolfactor and_boolfactor
;
boolfactor
: NOT '[' condition ']'
| '[' condition ']'
| expression relational_oper expression
;
relational_oper
: '='
| '<'
| "<="
| "<>"
| ">="
| '>'
;
现在有更多shift/reduce冲突,但仍然没有无用的非终端。
下一步是添加语句制作。在这里,我们会发现很多语句使用了非终结符brack_or_stat
,其定义为:
brack_or_stat
: brackets_seq
| statement
;
为了避免与brackets_seq
打交道,我们可以暂时将其添加到终端列表中。 (这是隐藏语法细节的标准技术。)稍后,当我们包含 brackets_seq
的产生式时,我们可以删除 %token
声明。)所以我们现在添加
%token brackets_seq
before the `%%`, and the statement productions after it:
brack_or_stat
: brackets_seq
| statement
;
statement
: %empty
| assignment_stat
| if_stat
| do_while_stat
| while_stat
| select_stat
| exit_stat
| return_stat
| print_stat
| call_stat
;
assignment_stat
: IDENTIFIER EXACT IDENTIFIER
;
if_stat
: IF '(' condition')' brack_or_stat elsepart
;
elsepart
: %empty
| ELSE brack_or_stat
;
while_stat
: WHILE '(' condition')' brack_or_stat
;
select_stat
: SELECT'(' IDENTIFIER')'
dec
DEFAULT":" brack_or_stat
;
dec
: DECIMAL_CONSTANT ':' brack_or_stat
| dec ','
;
do_while_stat
: DO brack_or_stat WHILE '(' condition ')'
;
exit_stat
: EXIT
;
return_stat
: RETURN '(' expression ')'
;
print_stat
: PRINT '('expression ')'
;
call_stat
: CALL IDENTIFIER actualpars
;
现在有更多 shift/reduce 冲突,但没有无用的非终端。
所以现在我们已经查看了一半以上的语法,并且有理由相信问题不在我们所查看的部分。 (虽然还有很多其他问题需要解决。)
所以如果我们假设 statement
没问题,让我们把它变成一个终端,并从测试中删除它和它引用的所有非终端。这给我们留下了一个更简单的程序:(当我通过 bison 复制并粘贴此摘录并 运行 时,它告诉我 assignment_stat
未定义。所以我只是将它添加到 %token
声明。)
%token PROGRAM
%token IDENTIFIER
%token DECIMAL_CONSTANT
%token DECLARE ENDDECLARE
%token AND CALL DEFAULT
%token FUNCTION PROCEDURE IN INOUT
%token IF ELSE DO WHILE FOR OR NOT SELECT
%token RETURN EXIT PRINT
%token EQ_LT EQ_GT NE EXACT
%token statement assignment_stat
%start program
%%
program
: %empty
| PROGRAM IDENTIFIER block
;
block
: "{" declarations subprograms sequence "}"
;
declarations
: %empty
| DECLARE varlist ENDDECLARE
;
varlist
: %empty
| assignment_stat identifier2
;
identifier2 : ',' assignment_stat
| ',' assignment_stat
;
subprograms
: func
| subprograms ','
;
func
: PROCEDURE IDENTIFIER funcbody
| FUNCTION IDENTIFIER funcbody
;
funcbody
: formalpars block
;
formalpars
: '('')'
| '(' formalparlist ')'
;
formalparlist
: formalparitem
| formalparlist ','
;
formalparitem
: IN IDENTIFIER
| INOUT IDENTIFIER
;
sequence
: statement statement_sequence
;
statement_sequence
: ";"statement
| ';' statement statement_sequence
;
brackets_seq
: '{' sequence '}'
;
brack_or_stat
: brackets_seq
| statement
;
现在我们有一个充满 "useless non-terminal" 警告的屏幕。
不过,语法现在简单多了。 (如果它看起来不够简单,您可以继续进行简化练习。例如,一种可能是将声明分开。)事实上,问题可能是可见的:
subprograms
: func
| subprograms ','
func : PROCEDURE IDENTIFIER funcbody
| FUNCTION IDENTIFIER funcbody
funcbody: formalpars block
block: "{" declarations subprograms sequence "}"
请注意这里发生的事情:subprograms
有两个作品。第二个显然是递归的。但是不费吹灰之力就可以看出另一个也是递归的:func
有两个产生式,但都使用funcbody
; funcbody
的唯一作品使用 block
,而 block
使用 subprograms
。
所以subprograms
没有非递归产生式,因此永远无法跳出递归。 func
、funcbody
或 block
.
但是如果block
不能生成任何句子,那么program
(PROGRAM IDENTIFIER block
)的第二次产生式也不能生成任何句子,留下program: %empty
作为唯一有效的生产开始符号。这使得空字符串成为唯一有效的 program
,因此 bison 将所有其他非终端标记为无用。
现在,让我们回到subprograms
(正如我在开头所说,这是紧迫的问题)。定义是:
subprograms
: func
| subprograms ','
现在,这是一个非常奇怪的定义(而且,我认为,这种奇怪现象在您的语法中反复出现)。这是什么意思? subprograms
是 func
或 subprograms
后跟一个逗号。所以它会产生:
func
func ,
func , ,
func , , ,
func , , , ,
等等。单个 func
,后跟零个或多个逗号。它必须有一个函数,不能有更多。
它不能为空的事实是无限递归的原因。一个 block
必须包含一个 subprograms
,一个 subprograms
必须包含一个 func
。但是 func
必须包含 block
。并且没有逃脱那个旋转木马。
所以这里有两个问题:subprograms
不能为空,也不能包含多个func
。您可能正在寻找的是:
function_list: func
| function_list ',' func
subprograms : %empty
| function_list
注意 function_list
使用左递归。那是故意的。 Bison 生产 LR 解析器,它喜欢左递归。
如果您以前研究过 LL 解析器并以某种方式在您的脑海中认识到左递归是邪恶的,忘记那个教训。 LL 解析器无法处理左递归,但 LR 解析器可以同时处理左递归和右递归,并且更好地处理左递归(因为它不会耗尽解析器堆栈)。