如何使用 yacc 从 char 数组中解析?
How to parse from char array using yacc?
我正在尝试从缓冲区解析字符串。
莱克斯代码
%{
#include <stdio.h>
#include "y.tab.h"
%}
%%
"Type:[0-9]+" {
printf("lex-TYPE\n");
return TYPE;
};
%%
Yacc 码
%{
#include <stdio.h>
#include <string.h>
extern char *yytext;
%}
%start general
%token TYPE
%%
general: |
general TYPE {
printf("gen %c\n", yytext[strlen("TYPE:")]);
}
;
%%
C代码
#include <stdio.h>
#include "y.tab.h"
int main()
{
printf("6\n");
yy_scan_buffer("TYPE:0 ");
printf("8\n");
// yylex();
yyparse();
return 0;
}
void yyerror(char *s)
{
fprintf( stderr, "%s\n" ,s);
}
int yywrap()
{
return(1);
}
编译
# lex bnf.lex
# yacc -d bnf.yacc
# cc main.c y.tab.c lex.yy.c -o test
# ./test
输出:
6
8
TYPE:) <--this is input from keyboard
TYPE:) <--I don't know why it is copied
^C
我没看到它识别我的词素,我不明白为什么它不从 yy_scan_buffer 上传我的缓冲区?
我想把不同的字符串作为参数,解析它并做一些魔术。
你能帮帮我吗?
#UPD
C代码
#include <stdio.h>
#include "y.tab.h"
int main()
{
printf("6\n");
yyscan_t scanner;
YY_BUFFER_STATE buf;
yylex_init(&scanner);
buf = yy_scan_string("TYPE:102 ", scanner);
yylex(scanner);
yy_delete_buffer(buf, scanner);
yylex_destroy(scanner);
printf("8\n");
yylex();
// yyparse();
return 0;
}
输出
# cc main.c y.tab.c lex.yy.c -o test
main.c: In function ‘main’:
main.c:7: error: ‘yyscan_t’ undeclared (first use in this function)
main.c:7: error: (Each undeclared identifier is reported only once
main.c:7: error: for each function it appears in.)
main.c:7: error: expected ‘;’ before ‘scanner’
main.c:8: error: ‘YY_BUFFER_STATE’ undeclared (first use in this function)
main.c:8: error: expected ‘;’ before ‘buf’
main.c:9: error: ‘scanner’ undeclared (first use in this function)
main.c:10: error: ‘buf’ undeclared (first use in this function)
这是第二种将字符串传入yacc的方法,但是有很多不知道为什么会出现的错误
你能帮帮我吗?
#UPD
# lex --version
flex 2.5.35
# yacc --version
bison (GNU Bison) 2.3
UPD
再试一次
typedef struct yy_buffer_state * YY_BUFFER_STATE;
extern int yyparse();
extern YY_BUFFER_STATE yy_scan_string(char * str);
extern void yy_delete_buffer(YY_BUFFER_STATE buffer);
int main()
{
printf("6\n");
char string[] = "TYPE:12";
YY_BUFFER_STATE buffer = yy_scan_string(string);
yyparse();
yy_delete_buffer(buffer);
printf("8\n");
// yylex();
// yyparse();
return 0;
}
输出
# ./test
6
TYPE:128
#
所以,它没有找到任何词素。为什么?
UPD
在 John Bollinger 的回答后,我将我的 .lex 和 .c 文件替换为他的。
已删除Type:[0-9]+
添加到 lex
Type: {
printf("lex-TYPE\n");
return TYPE;
};
[0-9]+ {
printf("lex-D\n");
return DIGIT;
};
已更改 yacc
%%
general: |
general TYPE DIGIT {
printf("gen %c\n", yytext[0]);
}
;
%%
现在我明白了
# ./test
6
8
TYPE:lex-D
syntax error
所以,我终于匹配了模式,但为什么失败了?
TYPE:) <--this is input from keyboard
TYPE:) <--I don't know why it is copied
这里似乎有两个问题:
为什么读取的输入是从键盘而不是指定的缓冲区
- 因为你没有正确设置内存缓冲区,并且
- 因为你没有正确调用
yy_scan_buffer()
。
为什么输入回显到输出:
因为它不匹配任何词法分析器规则,并且因为在提供的扫描器定义中未覆盖的默认规则将其他不匹配的字符写入标准输出。
更详细:
The docs for yy_scan_buffer()
指定它
scans in place the buffer starting at base, consisting of size bytes,
the last two bytes of which must be YY_END_OF_BUFFER_CHAR
(ASCII
NUL). These last two bytes are not scanned; thus, scanning consists of
base[0]
through base[size-2]
, inclusive.
和
If you fail to set up base in this manner (i.e., forget the final two
YY_END_OF_BUFFER_CHAR
bytes), then yy_scan_buffer()
returns a
NULL
pointer instead of creating a new input buffer.
(强调已添加。)
您没有确保提供的缓冲区的最后 两个 字符是 YY_END_OF_BUFFER_CHAR
,缓冲区设置不正确。如果您检查了函数的 return 值,您就会发现这个问题,因为您应该始终对可能失败的函数执行此操作,并通过它们的 return 值(很多)告知该问题.
此外,yy_scan_buffer()
需要两个参数,第一个是指向缓冲区的指针,第二个是它的有效大小。尽管如此,您通过使用错误数量的参数调用它会引发未定义的行为。也许您正在寻找 yy_scan_string()
。
然而,此外,您的编译器应该警告您调用之前未声明的函数。目前还不清楚任何缓冲区操作机制在多大程度上是为了在外部进行调整,而不是通过你的扫描器规则,但至少你应该限制自己在扫描器定义(包括用户代码部分)中使用它们).
至于为什么输入不匹配,其实有两个问题。首先,你引用了模式。引号并不特殊,因此 Flex 正在寻找包含文字引号的输入。其次,您的输入不包含与模式的 [0-9]+
部分匹配的内容。这些中的任何一个本身都足以防止显示的输入(或内存缓冲区的预期内容)匹配。
这里是扫描器定义的一个版本,它与主 C 源文件中的补充代码一起工作,看起来就像您想要的那样:
%{
#include <stdio.h>
#include "y.tab.h"
%}
%%
Type:[0-9]+ {
printf("lex-TYPE\n");
return TYPE;
};
%%
static YY_BUFFER_STATE my_string_buffer;
int my_scan_string(const char *s) {
// insist on cleaning up any existing buffer before setting up a new one
if (my_string_buffer != NULL) return -1;
// Set up and switch to a buffer for scanning the contents of the
// specified string. A copy of the string will be made.
my_string_buffer = yy_scan_string(s);
return (my_string_buffer == NULL) ? -1 : 0;
}
void my_cleanup(void) {
// No effect if my_string_buffer is NULL
yy_delete_buffer(my_string_buffer);
// ... but avoid trying to free the same buffer twice
my_string_buffer = NULL;
}
请注意,单个扫描器规则中的模式已更正,但更重要的是,依赖于扫描器内部接口的代码出现在扫描器定义中,在"user code" 部分。这确保您无需猜测或复制内部接口。
这不需要对您的解析器定义进行任何更改,但确实需要对您的主要源文件进行更改:
#include <stdio.h>
#include "y.tab.h"
int my_scan_string(const char *s);
void my_cleanup(void);
int main()
{
printf("6\n");
if (my_scan_string("TYPE:0 ") != 0) {
fputs("error setting up an internal buffer\n", stderr);
exit(1);
}
printf("8\n");
yyparse();
my_cleanup();
return 0;
}
void yyerror(char *s) {
fprintf(stderr, "%s\n" ,s);
}
int yywrap(void) {
return 1;
}
我正在尝试从缓冲区解析字符串。
莱克斯代码
%{
#include <stdio.h>
#include "y.tab.h"
%}
%%
"Type:[0-9]+" {
printf("lex-TYPE\n");
return TYPE;
};
%%
Yacc 码
%{
#include <stdio.h>
#include <string.h>
extern char *yytext;
%}
%start general
%token TYPE
%%
general: |
general TYPE {
printf("gen %c\n", yytext[strlen("TYPE:")]);
}
;
%%
C代码
#include <stdio.h>
#include "y.tab.h"
int main()
{
printf("6\n");
yy_scan_buffer("TYPE:0 ");
printf("8\n");
// yylex();
yyparse();
return 0;
}
void yyerror(char *s)
{
fprintf( stderr, "%s\n" ,s);
}
int yywrap()
{
return(1);
}
编译
# lex bnf.lex
# yacc -d bnf.yacc
# cc main.c y.tab.c lex.yy.c -o test
# ./test
输出:
6
8
TYPE:) <--this is input from keyboard
TYPE:) <--I don't know why it is copied
^C
我没看到它识别我的词素,我不明白为什么它不从 yy_scan_buffer 上传我的缓冲区?
我想把不同的字符串作为参数,解析它并做一些魔术。
你能帮帮我吗?
#UPD
C代码
#include <stdio.h>
#include "y.tab.h"
int main()
{
printf("6\n");
yyscan_t scanner;
YY_BUFFER_STATE buf;
yylex_init(&scanner);
buf = yy_scan_string("TYPE:102 ", scanner);
yylex(scanner);
yy_delete_buffer(buf, scanner);
yylex_destroy(scanner);
printf("8\n");
yylex();
// yyparse();
return 0;
}
输出
# cc main.c y.tab.c lex.yy.c -o test
main.c: In function ‘main’:
main.c:7: error: ‘yyscan_t’ undeclared (first use in this function)
main.c:7: error: (Each undeclared identifier is reported only once
main.c:7: error: for each function it appears in.)
main.c:7: error: expected ‘;’ before ‘scanner’
main.c:8: error: ‘YY_BUFFER_STATE’ undeclared (first use in this function)
main.c:8: error: expected ‘;’ before ‘buf’
main.c:9: error: ‘scanner’ undeclared (first use in this function)
main.c:10: error: ‘buf’ undeclared (first use in this function)
这是第二种将字符串传入yacc的方法,但是有很多不知道为什么会出现的错误
你能帮帮我吗?
#UPD
# lex --version
flex 2.5.35
# yacc --version
bison (GNU Bison) 2.3
UPD
再试一次
typedef struct yy_buffer_state * YY_BUFFER_STATE;
extern int yyparse();
extern YY_BUFFER_STATE yy_scan_string(char * str);
extern void yy_delete_buffer(YY_BUFFER_STATE buffer);
int main()
{
printf("6\n");
char string[] = "TYPE:12";
YY_BUFFER_STATE buffer = yy_scan_string(string);
yyparse();
yy_delete_buffer(buffer);
printf("8\n");
// yylex();
// yyparse();
return 0;
}
输出
# ./test
6
TYPE:128
#
所以,它没有找到任何词素。为什么?
UPD
在 John Bollinger 的回答后,我将我的 .lex 和 .c 文件替换为他的。
已删除Type:[0-9]+
添加到 lex
Type: {
printf("lex-TYPE\n");
return TYPE;
};
[0-9]+ {
printf("lex-D\n");
return DIGIT;
};
已更改 yacc
%%
general: |
general TYPE DIGIT {
printf("gen %c\n", yytext[0]);
}
;
%%
现在我明白了
# ./test
6
8
TYPE:lex-D
syntax error
所以,我终于匹配了模式,但为什么失败了?
TYPE:) <--this is input from keyboard TYPE:) <--I don't know why it is copied
这里似乎有两个问题:
为什么读取的输入是从键盘而不是指定的缓冲区
- 因为你没有正确设置内存缓冲区,并且
- 因为你没有正确调用
yy_scan_buffer()
。
为什么输入回显到输出:
因为它不匹配任何词法分析器规则,并且因为在提供的扫描器定义中未覆盖的默认规则将其他不匹配的字符写入标准输出。
更详细:
The docs for yy_scan_buffer()
指定它
scans in place the buffer starting at base, consisting of size bytes, the last two bytes of which must be
YY_END_OF_BUFFER_CHAR
(ASCII NUL). These last two bytes are not scanned; thus, scanning consists ofbase[0]
throughbase[size-2]
, inclusive.
和
If you fail to set up base in this manner (i.e., forget the final two
YY_END_OF_BUFFER_CHAR
bytes), thenyy_scan_buffer()
returns aNULL
pointer instead of creating a new input buffer.
(强调已添加。)
您没有确保提供的缓冲区的最后 两个 字符是 YY_END_OF_BUFFER_CHAR
,缓冲区设置不正确。如果您检查了函数的 return 值,您就会发现这个问题,因为您应该始终对可能失败的函数执行此操作,并通过它们的 return 值(很多)告知该问题.
此外,yy_scan_buffer()
需要两个参数,第一个是指向缓冲区的指针,第二个是它的有效大小。尽管如此,您通过使用错误数量的参数调用它会引发未定义的行为。也许您正在寻找 yy_scan_string()
。
然而,此外,您的编译器应该警告您调用之前未声明的函数。目前还不清楚任何缓冲区操作机制在多大程度上是为了在外部进行调整,而不是通过你的扫描器规则,但至少你应该限制自己在扫描器定义(包括用户代码部分)中使用它们).
至于为什么输入不匹配,其实有两个问题。首先,你引用了模式。引号并不特殊,因此 Flex 正在寻找包含文字引号的输入。其次,您的输入不包含与模式的 [0-9]+
部分匹配的内容。这些中的任何一个本身都足以防止显示的输入(或内存缓冲区的预期内容)匹配。
这里是扫描器定义的一个版本,它与主 C 源文件中的补充代码一起工作,看起来就像您想要的那样:
%{
#include <stdio.h>
#include "y.tab.h"
%}
%%
Type:[0-9]+ {
printf("lex-TYPE\n");
return TYPE;
};
%%
static YY_BUFFER_STATE my_string_buffer;
int my_scan_string(const char *s) {
// insist on cleaning up any existing buffer before setting up a new one
if (my_string_buffer != NULL) return -1;
// Set up and switch to a buffer for scanning the contents of the
// specified string. A copy of the string will be made.
my_string_buffer = yy_scan_string(s);
return (my_string_buffer == NULL) ? -1 : 0;
}
void my_cleanup(void) {
// No effect if my_string_buffer is NULL
yy_delete_buffer(my_string_buffer);
// ... but avoid trying to free the same buffer twice
my_string_buffer = NULL;
}
请注意,单个扫描器规则中的模式已更正,但更重要的是,依赖于扫描器内部接口的代码出现在扫描器定义中,在"user code" 部分。这确保您无需猜测或复制内部接口。
这不需要对您的解析器定义进行任何更改,但确实需要对您的主要源文件进行更改:
#include <stdio.h>
#include "y.tab.h"
int my_scan_string(const char *s);
void my_cleanup(void);
int main()
{
printf("6\n");
if (my_scan_string("TYPE:0 ") != 0) {
fputs("error setting up an internal buffer\n", stderr);
exit(1);
}
printf("8\n");
yyparse();
my_cleanup();
return 0;
}
void yyerror(char *s) {
fprintf(stderr, "%s\n" ,s);
}
int yywrap(void) {
return 1;
}