You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用YACC正确实现if语句?代码正确性核查求助

你的多分支if语句YACC实现的隐藏问题与修复方案

嘿,我仔细过了你的Lex和YACC代码,虽然表面上能运行,但确实藏着几个会导致逻辑错误的问题——尤其是多分支elseif的执行逻辑和变量处理部分。下面给你拆解问题并附上修复后的完整代码:

发现的核心问题

  • 令牌定义错误:YACC代码中$token _VAR是语法错误(应为%token),且Lex里根本没有对应_VAR的匹配规则。你实际需要的是匹配变量x/y,完全不需要这个冗余令牌。
  • 多分支逻辑混乱:当前else_condition的实现会导致所有满足条件的分支都会赋值z,而非仅第一个匹配的分支;而且else分支会无条件覆盖z的值,哪怕前面的if/elseif已经匹配成功,完全违背多分支if的“互斥执行”逻辑。
  • Condition语义值错误:原规则中引用_VAR的$3无法获取变量值(因为没有给_VAR绑定语义类型),必须直接读取全局变量x/y的实际值来做判断。
  • 分支执行顺序错误:原if_condition的动作只处理了if分支的赋值,但else_condition的动作是直接修改z,导致if满足时else的赋值也会执行,彻底搞反了逻辑。

修复后的代码

Lex文件(lex.l)

%{
#include "y.tab.h"
void yyerror (char *s);
int yylex();
%}
%%
"print"     {return PRINT;}
"exit"      {return EXIT_COMMAND;}
"if"        {return IF;}
"elseif"    {return ELSEIF;}
"elif"      {return ELSEIF;}
"else"      {return ELSE;}
"("         {return LP;}
")"         {return RP;}
"{"         {return GLP;}
"}"         {return GRP;}
"=="        {return EQEQ;}
"="         {return EQ;}
"!="        {return NEQ;}
";"         {return SEMI;}
"<"         {return LT;}
">"         {return GT;}
"x"         {return _X;}
"y"         {return _Y;}
"z"         {return _Z;}
[-]?[0-9]+  {yylval.val = atoi(yytext); return NUMBER;}
[ \t\n]+    ; /* 忽略空白字符 */
.           {yyerror("Carattere non riconosciuto");}
%%

YACC文件(yacc.y)

%{
void yyerror (char *s);
int yylex();
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 全局变量,未初始化默认0
int x = 0, y = 0, z = 0;
// 标记是否已经找到匹配的分支,确保互斥执行
int branch_matched = 0;
%}

%union {
    int val;
}

%token PRINT
%token EXIT_COMMAND
%token IF
%token ELSEIF
%token ELSE
%token _X
%token _Y
%token _Z
%token<val> NUMBER
%token LP RP GLP GRP
%token EQEQ EQ NEQ SEMI LT GT

%type<val> condition
%type<val> then

%right EQ
%start main_program

%%

main_program:
    | main_program rule
    ;

rule: '\n'
    | init_variables
    | if_condition
    | printing
    | EXIT_COMMAND {printf("Uscita dal programma in corso...\n"); exit(0);}
    | error '\n' {yyerrok; printf("Riga ignorata a causa di errore\n");} /* 跳过错误行 */
    ;

printing: PRINT _X {printf("\nx=%d\n", x);}
        | PRINT _Y {printf("\ny=%d\n", y);}
        | PRINT _Z {printf("\nz=%d\n", z);}
        ;

init_variables: _X EQ NUMBER SEMI {x = $3;}
              | _Y EQ NUMBER SEMI {y = $3;}
              ;

// 重置分支标记,处理if分支,再递归处理else/elseif分支
if_condition: IF LP condition RP GLP then GRP {
                branch_matched = ($3 == 1);
                if (branch_matched) z = $6;
              }
              else_condition {
                printf("\nz=%d\n", z);
                // 重置标记,避免影响下一个if语句
                branch_matched = 0;
              }
              ;

// 多分支核心逻辑:仅当前面无匹配分支时,才检查当前条件
else_condition: /* 空:无else/elseif分支 */
              | ELSEIF LP condition RP GLP then GRP {
                  if (!branch_matched && $3 == 1) {
                      z = $6;
                      branch_matched = 1;
                  }
                }
                else_condition
              | ELSE GLP then GRP {
                  if (!branch_matched) {
                      z = $3;
                  }
                }
              ;

condition: _X LT NUMBER       {$$ = (x < $3) ? 1 : 0;}
         | _X GT NUMBER       {$$ = (x > $3) ? 1 : 0;}
         | _X EQEQ NUMBER     {$$ = (x == $3) ? 1 : 0;}
         | _X NEQ NUMBER      {$$ = (x != $3) ? 1 : 0;}
         | _X LT _Y           {$$ = (x < y) ? 1 : 0;}
         | _X GT _Y           {$$ = (x > y) ? 1 : 0;}
         | _X EQEQ _Y         {$$ = (x == y) ? 1 : 0;}
         | _X NEQ _Y          {$$ = (x != y) ? 1 : 0;}
         | _Y LT NUMBER       {$$ = (y < $3) ? 1 : 0;}
         | _Y GT NUMBER       {$$ = (y > $3) ? 1 : 0;}
         | _Y EQEQ NUMBER     {$$ = (y == $3) ? 1 : 0;}
         | _Y NEQ NUMBER      {$$ = (y != $3) ? 1 : 0;}
         | _Y LT _X           {$$ = (y < x) ? 1 : 0;}
         | _Y GT _X           {$$ = (y > x) ? 1 : 0;}
         | _Y EQEQ _X         {$$ = (y == x) ? 1 : 0;}
         | _Y NEQ _X          {$$ = (y != x) ? 1 : 0;}
         ;

then: _Z EQ NUMBER SEMI {$$ = $3;}
     ;

%%

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

int yywrap(){
    return 1;
}

int main (void){
    printf("Inserisci comandi (init x/y, if/elseif/else, print x/y/z, exit):\n");
    return yyparse();
}

关键修复说明

  1. 新增分支匹配标记:用全局变量branch_matched跟踪是否已有分支匹配,确保只有第一个满足条件的分支执行赋值,且else分支仅在无任何匹配时生效。
  2. 重构Condition规则:移除无效的_VAR令牌,直接处理x/y之间的比较,正确读取全局变量值进行条件判断。
  3. 修正多分支逻辑:递归处理elseif分支,严格遵循“前面无匹配才检查当前条件”的规则;else分支仅在所有前面分支都不满足时执行。
  4. 优化错误处理:修正YACC语法错误,Lex中添加未知字符错误提示,优化错误行跳过逻辑,提升用户体验。

内容的提问来源于stack exchange,提问作者Fiorelo Odobashi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:46:06