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

如何向YACC传递令牌字符串值?Lex&YACC摩尔斯码转英文程序开发咨询

我来帮你一步步解决这两个问题~

问题1:如何将令牌的字符串值传递给YACC程序?

核心是利用YACC提供的yylval联合变量,它是Lex和YACC之间传递令牌附属数据的桥梁,具体步骤如下:

  1. 在YACC文件里声明数据类型
    首先要在YACC的定义段用%union定义你需要传递的数据类型,比如要传字符串的话:

    %union {
        char* str;  // 定义字符串类型的成员
    }
    

    接着给对应的令牌绑定这个类型,比如:

    %token <str> I AM  // 指定令牌I和AM携带字符串类型的值
    
  2. 在Lex文件里赋值并传递
    Lex文件需要包含YACC生成的头文件(默认是y.tab.h),这样才能识别yylval的结构。然后在匹配令牌的动作里给yylval.str赋值:

    %{
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "y.tab.h"  // 必须包含这个头文件
    %}
    
    %%
    ".." { 
        yylval.str = strdup(yytext);  // strdup自动分配内存并拷贝字符串,比calloc+strcpy更简洁
        return I;
    }
    "..--" {  // 修正正则写法,直接写完整摩尔斯码即可,不需要用"."连接
        yylval.str = strdup(yytext);
        return AM;
    }
    %%
    
  3. 在YACC规则里使用传递的值
    在YACC的语法规则中,你可以用$n来访问第n个令牌的str值,比如:

    sentence: I AM { printf("识别到短语:%s %s\n", $1, $2); free($1); free($2); }
    

    注意:如果用了动态分配内存(比如strdup),记得用完后free,避免内存泄漏哦~

问题2:摩尔斯码转英文的Lex/YACC程序实现

你的代码思路是对的,但有几个细节需要修正,我给你整理了完整的可运行版本:

第一步:编写YACC文件(命名为morse.y)

这个文件负责定义语法规则,把识别到的摩尔斯码令牌转换成英文输出:

%{
#include <stdio.h>
#include <string.h>
%}

// 定义要传递的数据类型:单个字符(比字符串更适合单字母转换)
%union {
    char c;
}

// 声明令牌,绑定字符类型
%token <c> A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
%token NEWLINE NEWPARA OVER SOS

%%

// 顶层语法:接受多行输入
input: /* 空规则 */
     | input line
     ;

// 行规则:处理特殊符号或单词
line: NEWLINE       { printf("\n"); }
    | NEWPARA       { printf("\n\n"); }
    | OVER          { printf("[会话结束]\n"); return 0; }
    | SOS           { printf("[求救信号SOS]\n"); }
    | word line     { printf(" "); }  // 单词之间加空格
    ;

// 单词规则:由多个字母组成
word: letter
    | word letter   { printf("%c", $2); }  // 逐个输出字母
    ;

// 字母规则:匹配单个字母令牌
letter: A           { printf("%c", $1); }
      | B           { printf("%c", $1); }
      | C           { printf("%c", $1); }
      | D           { printf("%c", $1); }
      | E           { printf("%c", $1); }
      | F           { printf("%c", $1); }
      | G           { printf("%c", $1); }
      | H           { printf("%c", $1); }
      | I           { printf("%c", $1); }
      | J           { printf("%c", $1); }
      | K           { printf("%c", $1); }
      | L           { printf("%c", $1); }
      | M           { printf("%c", $1); }
      | N           { printf("%c", $1); }
      | O           { printf("%c", $1); }
      | P           { printf("%c", $1); }
      | Q           { printf("%c", $1); }
      | R           { printf("%c", $1); }
      | S           { printf("%c", $1); }
      | T           { printf("%c", $1); }
      | U           { printf("%c", $1); }
      | V           { printf("%c", $1); }
      | W           { printf("%c", $1); }
      | X           { printf("%c", $1); }
      | Y           { printf("%c", $1); }
      | Z           { printf("%c", $1); }
      ;

%%

// 主函数
int main() {
    printf("输入摩尔斯码(字母间用空格分隔,特殊码:..-.-=换行,-...-=换段,K=结束,...---...=SOS):\n");
    yyparse();
    return 0;
}

// 错误处理函数
int yyerror(char* msg) {
    fprintf(stderr, "解析错误:%s\n", msg);
    return 1;
}

第二步:编写Lex文件(命名为morse.l)

这个文件负责匹配摩尔斯码,生成对应的令牌:

%{
#include <stdio.h>
#include "y.tab.h"
%}

// 定义特殊符号的正则(注意转义点,因为点在正则里代表任意字符)
NEWLINE  "\.\.-\.-"
NEWPARA  "\-\.\.\-\-"
OVER     "K"
SOS      "\.\.\.\-\-\-\.\.\."

// 定义每个字母对应的摩尔斯码正则
A        "\.\-"
B        "\-\.\.\."
C        "\-\.\-\."
D        "\-\.\."
E        "\."
F        "\.\.\-\."
G        "\-\-\."
H        "\.\.\.\."
I        "\.\."
J        "\.\-\-\-"
K        "\-\.\-"
L        "\.\-\.\."
M        "\-\-"
N        "\-\."
O        "\-\-\-"
P        "\.\-\-\."
Q        "\-\-\.\-"
R        "\.\-\."
S        "\.\.\."
T        "\-"
U        "\.\.\-"
V        "\.\.\.\-"
W        "\.\-\-"
X        "\-\.\.\-"
Y        "\-\.\-\-"
Z        "\-\-\.\.\."

%%

// 匹配特殊符号
{NEWLINE}   { return NEWLINE; }
{NEWPARA}   { return NEWPARA; }
{OVER}      { return OVER; }
{SOS}       { return SOS; }

// 匹配字母摩尔斯码,赋值并返回令牌
{A}         { yylval.c = 'A'; return A; }
{B}         { yylval.c = 'B'; return B; }
{C}         { yylval.c = 'C'; return C; }
{D}         { yylval.c = 'D'; return D; }
{E}         { yylval.c = 'E'; return E; }
{F}         { yylval.c = 'F'; return F; }
{G}         { yylval.c = 'G'; return G; }
{H}         { yylval.c = 'H'; return H; }
{I}         { yylval.c = 'I'; return I; }
{J}         { yylval.c = 'J'; return J; }
{K}         { yylval.c = 'K'; return K; }
{L}         { yylval.c = 'L'; return L; }
{M}         { yylval.c = 'M'; return M; }
{N}         { yylval.c = 'N'; return N; }
{O}         { yylval.c = 'O'; return O; }
{P}         { yylval.c = 'P'; return P; }
{Q}         { yylval.c = 'Q'; return Q; }
{R}         { yylval.c = 'R'; return R; }
{S}         { yylval.c = 'S'; return S; }
{T}         { yylval.c = 'T'; return T; }
{U}         { yylval.c = 'U'; return U; }
{V}         { yylval.c = 'V'; return V; }
{W}         { yylval.c = 'W'; return W; }
{X}         { yylval.c = 'X'; return X; }
{Y}         { yylval.c = 'Y'; return Y; }
{Z}         { yylval.c = 'Z'; return Z; }

[ \t]       { /* 忽略空格和制表符,作为字母之间的分隔符 */ }
.           { fprintf(stderr, "未知字符:%s\n", yytext); }

%%

int yywrap() {
    return 1;  // 表示没有更多输入
}

第三步:编译运行

在终端执行以下命令:

# 生成YACC的C文件和头文件
yacc -d morse.y
# 生成Lex的C文件
lex morse.l
# 编译生成可执行文件
gcc y.tab.c lex.yy.c -o morse -ly -ll
# 运行程序
./morse

现在你输入摩尔斯码(比如.. .- --),程序就会输出IAM啦~

内容的提问来源于stack exchange,提问作者Avani Ranade

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:18:08