Lex & yacc 解析语句
Lex & yacc parsing statements
我正在尝试使用 lex 和 yacc 构建一种非常简单的语言
通过这样的赋值,它只能有一个 int 变量
a = 1
它可以像这样打印变量
print a
仅当变量名匹配时才打印值,否则打印错误消息
我的 lex 文件是
%{
#include "y.tab.h"
#include <stdlib.h>
void yyerror(char *);
%}
letter [A-z]
digit [0-9]
%%
"print" {return PRINT;}
{letter}+ { yylval.id = yytext;return IDENTIFIER;}
{digit}+ { yylval.num = atoi(yytext);return NUMBER; }
[=\n] return *yytext;
[ \t] ; /* skip whitespace */
. yyerror("invalid character");
%%
int yywrap(void) {
return 1;
}
我的 yacc 文件是
%{
#include <stdio.h>
#include <string.h>
int yylex(void);
void yyerror(char *);
int value;
char *key;
void print_var(char *s);
%}
%union {char *id;int num;}
%start exp
%token <id> IDENTIFIER
%token <num> NUMBER
%token PRINT
%%
exp: IDENTIFIER '=' NUMBER '\n' {key = ;value = ;}
|PRINT IDENTIFIER '\n' {print_var();}
|exp IDENTIFIER '=' NUMBER '\n' {key = ;value = ;}
|exp PRINT IDENTIFIER '\n' {print_var();}
;
%%
void yyerror(char *s) {
fprintf(stderr, "%s\n", s);
}
void print_var(char *s){
if(strcmp(s,key) == 0){
printf("%s:%d\n",key,value);
}else{
printf("%s not found\n",s);
}
}
int main(void) {
yyparse();
return 0;
}
但是当我输入这样的内容时
a = 1
print a
我收到以下错误
一种
未找到
一旦你的 lex 程序 returns 到 yacc(或者基本上,在规则之外的任何地方),yytext
值不一定保持不变。与其让 id
成为指向 yytext
的指针,不如使用 strdup
或其他东西来对 [=12= 中的字符串进行 复制 ].
Flex 的手册中提到了这一点21.3 A Note About yytext And Memory。
在你的语法中,这是唯一显示的规则:
exp: IDENTIFIER '=' NUMBER '\n' {key = ;value = ;}
|PRINT IDENTIFIER '\n' {print_var();}
|exp IDENTIFIER '=' NUMBER '\n' {key = ;value = ;}
|exp PRINT IDENTIFIER '\n' {print_var();}
;
它将一个指针复制到全局变量 key
(再次遇到内存损坏问题)并打印 </code> 标识符。如果您在 lex 程序中分配了 <code>yytext
的副本,您似乎可以安全地在 print_var
中释放它。 key
的两个赋值应该替换为调用设置 key
的函数,同时检查它是否已经设置,例如
void set_key(const char *value)
{
if (key != 0)
free(key);
key = strdup(value);
}
一次分配的 yytext
副本不会超过一个 — 内存量微不足道。
我正在尝试使用 lex 和 yacc 构建一种非常简单的语言 通过这样的赋值,它只能有一个 int 变量
a = 1
它可以像这样打印变量
print a
仅当变量名匹配时才打印值,否则打印错误消息
我的 lex 文件是
%{
#include "y.tab.h"
#include <stdlib.h>
void yyerror(char *);
%}
letter [A-z]
digit [0-9]
%%
"print" {return PRINT;}
{letter}+ { yylval.id = yytext;return IDENTIFIER;}
{digit}+ { yylval.num = atoi(yytext);return NUMBER; }
[=\n] return *yytext;
[ \t] ; /* skip whitespace */
. yyerror("invalid character");
%%
int yywrap(void) {
return 1;
}
我的 yacc 文件是
%{
#include <stdio.h>
#include <string.h>
int yylex(void);
void yyerror(char *);
int value;
char *key;
void print_var(char *s);
%}
%union {char *id;int num;}
%start exp
%token <id> IDENTIFIER
%token <num> NUMBER
%token PRINT
%%
exp: IDENTIFIER '=' NUMBER '\n' {key = ;value = ;}
|PRINT IDENTIFIER '\n' {print_var();}
|exp IDENTIFIER '=' NUMBER '\n' {key = ;value = ;}
|exp PRINT IDENTIFIER '\n' {print_var();}
;
%%
void yyerror(char *s) {
fprintf(stderr, "%s\n", s);
}
void print_var(char *s){
if(strcmp(s,key) == 0){
printf("%s:%d\n",key,value);
}else{
printf("%s not found\n",s);
}
}
int main(void) {
yyparse();
return 0;
}
但是当我输入这样的内容时
a = 1
print a
我收到以下错误 一种 未找到
一旦你的 lex 程序 returns 到 yacc(或者基本上,在规则之外的任何地方),yytext
值不一定保持不变。与其让 id
成为指向 yytext
的指针,不如使用 strdup
或其他东西来对 [=12= 中的字符串进行 复制 ].
Flex 的手册中提到了这一点21.3 A Note About yytext And Memory。
在你的语法中,这是唯一显示的规则:
exp: IDENTIFIER '=' NUMBER '\n' {key = ;value = ;}
|PRINT IDENTIFIER '\n' {print_var();}
|exp IDENTIFIER '=' NUMBER '\n' {key = ;value = ;}
|exp PRINT IDENTIFIER '\n' {print_var();}
;
它将一个指针复制到全局变量 key
(再次遇到内存损坏问题)并打印 </code> 标识符。如果您在 lex 程序中分配了 <code>yytext
的副本,您似乎可以安全地在 print_var
中释放它。 key
的两个赋值应该替换为调用设置 key
的函数,同时检查它是否已经设置,例如
void set_key(const char *value)
{
if (key != 0)
free(key);
key = strdup(value);
}
一次分配的 yytext
副本不会超过一个 — 内存量微不足道。