gpt4 book ai didi

c - 使用 Bison 实现语法。语法控制流意外

转载 作者:太空宇宙 更新时间:2023-11-04 08:23:37 25 4
gpt4 key购买 nike

抽象语法。实际语法如下:

start ->  t1  V1;

V1 --> t2 V1
| t3 V2
;

V2 --> t4
| /* Empty */
;

当控件处于 V2 并遇到 token t3 时。控制回到 V1。好了到此为止。

但是控制并没有停在V1触发t3,而是回到开始,这就是问题所在。

实际语法。解释如下。

%{
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>

void yyerror (char *s);
extern FILE *yyin;

%}

%token MAIN

%token INT_DT INT_LIT /* t_INT_DT --> Integer Data type, i.e. "int"
* t_INT_LIT --> An integer, i.e. "5".
*/

%token VAR // A variable

%token SCANF PRINTF // For the printf and the scanf statements.

%token IF ELSE // For the if and else statements.
%token GOTO

%token OPRTR // For the operator in an expression.

/* Begining of a basic block, BBS, Basic Block Statement.
* BBS_ST = "<bb "
* BBS_END1 ">:"
* BBS_END2 ">;"
* Example:
* <bb 2>:
* Statements;
* goto <bb 3>;
*/
%token BBS_ST // "<bb "// it is "<bb ".
%token BBS_END1 // ">:"
%token BBS_END2 // ">;"

// Opening and closing Braces, i.e. { & }
%token OP_BR // "{"
%token CL_BR // "}"

// For opening and closing Parantheses, ( & )
%token OP_PR //"("
%token CL_PR //")"

%token EQUAL // "="
%token COMMA // ","
%token NBSP // "&"
%token SM_CLN // ";" // For ";"

%token RETURN // For the return statement.

%start begin

%%

begin: MAIN main ;

main: OP_BR functn CL_BR ;

functn: INT_DT VAR SM_CLN functn /*Recursion to stay in functn */
| BBS_ST INT_LIT BBS_END1 bb
;

bb: SCANF var_List CL_PR SM_CLN bb
| PRINTF var_List CL_PR SM_CLN bb
| VAR EQUAL expr SM_CLN bb
| IF OP_PR expr CL_PR bb
| ELSE bb
| GOTO BBS_ST INT_LIT BBS_END2
| RETURN SM_CLN
| /* Empty Rule. */
; /* bb has can't catch BBS_ST as first token, thus it must return
* to the calling rule and functn can catch BBS_ST. */

var_List: COMMA VAR var_List
| /* Empty Rule. */
;

expr: VAR expr2
| INT_LIT expr2
;

expr2: OPRTR expr3
| /* Empty Rule */
;

expr3: VAR
| INT_LIT
;

%%
int main (int argc, char *argv[])
{
#if YYDEBUG == 1
extern int yydebug;
yydebug = 1;
#endif

if (argc == 2)
{
yyin = fopen (argv [1], "r");
if (yyin == NULL)
perror (argv [1]);
}

yyparse ();

fclose (yyin);
return 0;
}


void yyerror (char *s)
{
printf ("Error: %s\n", s);
}

到目前为止,实现了答案中建议的想法,但这没有帮助。

begin:  MAIN main ; 

main: OP_BR functn_Decls CL_BR
;

functn_Decls: functn_Decls INT_DT VAR SM_CLN
| functn
;

functn: functn BBS_ST INT_LIT BBS_END1
| bb
;

bb: bb stmnt
| /* Empty Rule */
;

stmnt: t1 // terminals only.
;

var_List: t2 // terminal just for illustration.
;

expr: t3 // terminal just for illustration.
;

导致输入错误:

main ()
{
<bb 2>:
goto <bb 4>;

<bb 3>:
}

错误:

<bb token BBS_ST 被触发。此时控制在bb中,如bb --> Waiting for a token由于bb中没有以BBS_ST开头的规则,所以返回调用规则。

现在调用规则为functn,其中有一条以BBS_ST开头的规则。问题是,这条规则没有被调用。

相反,控件到达位于 P1 的 functn 的父级。如果在 P1 我添加 BBS_ST,它会捕获此 token 。

请指出为什么会这样?

对应的Flex文件:

%{
// Include the file
#include "Parse_One_Line2.tab.h"
extern YYSTYPE yylval;
extern char *yytext;
%}

LB ^[ \t]*
CH [a-zA-Z]
DI [0-9]

%%

{LB}main[ ]*\([.]*\) return MAIN; // the main() call.

{LB}int[ ] return INT_DT;

[+-]?{CH}({CH}{DI}_)* return VAR;

[+-]?[0-9]+ return INT_LIT;

{LB}scanf[ ]?\(\".*\" return SCANF;

{LB}printf[ ]?\(\".*\" return PRINTF;

{LB}if[ ] return IF; // If statement.

{LB}else[ ] return ELSE; // If statement.

{LB}goto[ ] return GOTO;

{LB}return return RETURN;

\{CLOBBER\}; ;// Ignore it.

"<bb " return BBS_ST; // next integer is a BB Index.

">:" return BBS_END1; // token Greater than Colon.

">;" return BBS_END2;

^;;[^\n]*[\n] ; // Ignore it, comment.

"+"|"-"|"*"|"/"|"%"|"=="|">="|"<="|"<"|">"|"!=" return OPRTR;

^[{] return OP_BR; // It is "{".

^[}] return CL_BR; // It is "}".

"(" return OP_PR; // Paranthesis Open

")" return CL_PR; // Paranthesis Close


";" return SM_CLN;

"=" return EQUAL;

"&" return NBSP;

"," return COMMA;

[\n] ; /* Skip these characters. */

. ; /* Skip. */

%%


int yywrap (void)
{
return 1;
}

使用 YYDEBUG 标志的输出文件。

Starting parse
Entering state 0
Reading a token: Next token is token MAIN ()
Shifting token MAIN ()
Entering state 1
Reading a token: Next token is token OP_BR ()
Shifting token OP_BR ()
Entering state 3
Reading a token: Next token is token INT_DT ()
Shifting token INT_DT ()
Entering state 6
Reading a token: Next token is token VAR ()
Shifting token VAR ()
Entering state 9
Reading a token: Next token is token SM_CLN ()
Shifting token SM_CLN ()
Entering state 12
Reading a token: Next token is token BBS_ST ()
Shifting token BBS_ST ()
Entering state 7
Reading a token: Next token is token INT_LIT ()
Shifting token INT_LIT ()
Entering state 10
Reading a token: Next token is token BBS_END1 ()
Shifting token BBS_END1 ()
Entering state 13
Reading a token: Next token is token GOTO ()
Shifting token GOTO ()
Entering state 20
Reading a token: Next token is token BBS_ST ()
Shifting token BBS_ST ()
Entering state 29
Reading a token: Next token is token INT_LIT ()
Shifting token INT_LIT ()
Entering state 38
Reading a token: Next token is token BBS_END2 ()
Shifting token BBS_END2 ()
Entering state 47
Reducing stack by rule 10 (line 76):
$1 = token GOTO ()
$2 = token BBS_ST ()
$3 = token INT_LIT ()
$4 = token BBS_END2 ()
-> $$ = nterm bb ()
Stack now 0 1 3 6 9 12 7 10 13
Entering state 22
Reducing stack by rule 4 (line 68):
$1 = token BBS_ST ()
$2 = token INT_LIT ()
$3 = token BBS_END1 ()
$4 = nterm bb ()
-> $$ = nterm functn ()
Stack now 0 1 3 6 9 12
Entering state 14
Reducing stack by rule 3 (line 67):
$1 = token INT_DT ()
$2 = token VAR ()
$3 = token SM_CLN ()
$4 = nterm functn ()
-> $$ = nterm functn ()
Stack now 0 1 3
Entering state 8
Reading a token: Next token is token BBS_ST ()
Error: popping nterm functn ()
Stack now 0 1 3
Error: popping token OP_BR ()
Stack now 0 1
Error: popping token MAIN ()
Stack now 0
Cleanup: discarding lookahead token BBS_ST ()
Stack now 0

最佳答案

我重新整理了您的一些规则。问题是当 functn 看到一个 bb 时,它只期望一个。因此,当到达您的 GOTO 时,预计不会有更多 token 。允许 functn 出现在 bb 语句之后应该可以解决此问题并为您提供所需的行为。

functn: INT_DT VAR ";" functn
| bb_stmt functn
| bb_stmt
;

bb_stmt: BBS_ST /*P2*/ INT_LIT ">:" bb
;

如果你想继续强制语句只在函数的顶部,你可以在上面做一些这样的事情:

main:    "{"     functn_decls /*P1*/   "}"   ;

functn_decls: INT_DT VAR ";" functn_decls
| functn
;

functn: bb_stmt functn
| bb_stmt
;

关于c - 使用 Bison 实现语法。语法控制流意外,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32203383/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com