如何向YACC传递令牌字符串值?Lex&YACC摩尔斯码转英文程序开发咨询
我来帮你一步步解决这两个问题~
问题1:如何将令牌的字符串值传递给YACC程序?
核心是利用YACC提供的yylval联合变量,它是Lex和YACC之间传递令牌附属数据的桥梁,具体步骤如下:
在YACC文件里声明数据类型
首先要在YACC的定义段用%union定义你需要传递的数据类型,比如要传字符串的话:%union { char* str; // 定义字符串类型的成员 }接着给对应的令牌绑定这个类型,比如:
%token <str> I AM // 指定令牌I和AM携带字符串类型的值在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; } %%在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
相关产品推荐
相关产品推荐

