我想解析单个查询的文本。此查询将以分号结束。它会像sql一样。例如:CREATE TABLE 'somename';
我的y文件是
%{
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <stdbool.h>
#include "ast.h"
extern int yylex(void);
extern void yyerror(char const *msg);
QueryNode *queryNode;
%}
%union {
int integer;
char *str;
char chr;
bool boolean;
int intval;
char *strval;
ObjectTypeNode *objectTypeNode;
CreateClauseNode *createClauseNode;
QueryNode *queryNode;
}
%token NUMBER
%token INTNUM
%token<str> CREATE_KEYWORD
%token<str> DATABASE_KEYWORD
%token<str> TABLE_KEYWORD
%token<str> LETTER
%token<str> STRING
%token<str> IDENTIFIER
%token<chr> LEFT_BRACKET RIGHT_BRACKET COMMA SEMICOLON EOL
%type<objectTypeNode> object_type
%type<createClauseNode> create_clause
%type<queryNode> query
%start input
%%
input: SEMICOLON EOL { queryNode = NULL; }
| query SEMICOLON EOL { queryNode = $1; }
;
query: create_clause { $$ = CreateQueryNode($1, CREATE_CLAUSE_TYPE); }
;
create_clause: CREATE_KEYWORD object_type STRING { $$ = CreateCreateClauseNode($2, $3); }
;
object_type: DATABASE_KEYWORD { $$ = CreateObjectTypeNode(DATABASE_OBJECT); }
| TABLE_KEYWORD { $$ = CreateObjectTypeNode(TABLE_OBJECT); }
;
%%
void yyerror(char const *msg) {
printf("Error: %s\n", msg);
}
我的档案是
%{
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdarg.h>
#include "ast.h"
#include "y.tab.h"
%}
%option noyywrap nodefault yylineno case-insensitive
%%
CREATE { yylval.strval = "create"; return CREATE_KEYWORD; }
DATABASE { return DATABASE_KEYWORD; }
TABLE { return TABLE_KEYWORD; }
"(" { return LEFT_BRACKET; }
")" { return RIGHT_BRACKET; }
";" { return SEMICOLON; }
-?[0-9]+ { yylval.intval = atoi(yytext); return INTNUM; }
L?'(\\.|[^\\'])+' |
L?\"(\\.|[^\\"])*\" { yylval.strval = yytext; return STRING; }
[a-zA-Z]+[0-9]* { return IDENTIFIER; }
[a-zA-Z]+ { return LETTER; }
[\n] { printf("eol\n"); return EOL; }
[ \t\f\v] { ; }
. { return *yytext; }
%%
我在其他主要功能中使用yyparse()
功能。 main.c文件是
#include <stdio.h>
#include <stdlib.h>
#include "ast.h"
#include "y.tab.h"
extern QueryNode *queryNode;
int main(int argc, char *argv[]) {
int result = yyparse();
if(result == 0 && queryNode != NULL) {
printf("AST created\n");
} else {
printf("Problem!\n");
}
return 0;
}
当我输入CREATE TABLE 'testo';
时,yyparse不会在int result = yyparse();
行终止并编程等待。我该如何解决?我使用flex和bison。我想用这个输入终止。
答案 0 :(得分:1)
在这个问题的原始版本中,语法规范中的主要规则是:
输入:SEMICOLON {queryNode = NULL; YYACCEPT; } |查询SEMICOLON {queryNode = $ 1; YYACCEPT; } ;
正如我在这个答案的原始版本中所说,这些规则保证一旦遇到分号,yacc就会接受一个后跟分号的查询,因为YYACCEPT
动作:< / p>
yacc&#34;接受&#34;因为你在动作中使用了
YYACCEPT
。YYACCEPT
表示&#34;一旦识别出该产品,即使没有完全消耗,也接受输入。&#34;所以它正在按照你的要求去做。
然后我建议删除YYACCEPT
操作,以便解析器不会返回,直到词法分析器发出输入结束信号:
如果您只想在整个输入与语法匹配时接受输入,请不要拨打
YYACCEPT
。如果开始生产匹配且下一个标记是输入结束标记,Yacc将自动接受。
但当然,当遇到换行符时,这并不会导致阅读停止。它所做的就是确保如果整个输入是一个命令,它将被接受,否则它将被拒绝。但是由于它正在检查以确保命令没有任何内容,它将继续请求输入,直到它得到一些。
如果您希望词法分析器只读取必须是有效命令的单行,您可以通过从解析器操作中删除YYACCEPT
并让扫描器返回文件结束指示来轻松完成此操作。它看到一个换行符:
\n { return 0; }
(返回零是扫描仪发出输入结束信号的方式。)
如果您真正想要的是构建一个读取多行输入的程序,独立解析每一行并在每一行之后返回,那么上述解决方案将正常工作。
您也可以在解析器中玩游戏,就像您的新提案一样,但让扫描程序在看到换行符时返回换行符号。然后,您可以在收到换行符号时接受或拒绝输入,使用YYACCEPT
,YYABORT
和error
制作:
input: SEMICOLON EOL { queryNode = NULL; YYACCEPT; }
| query SEMICOLON EOL { queryNode = $1; YYACCEPT; }
| query error EOL { YYABORT; }
;
在遇到语法错误时,为了刷新行的其余部分,必须生成错误。否则,对解析器的下一次调用将在产生错误的行的中间开始,在一个稍微不可预测的点(因为它将取决于解析器在发出错误信号时是否持有前瞻标记。)
虽然这个解决方案确实有一些优点,但它比读取换行符时只返回0的解决方案要复杂一些。因此很难证明额外的复杂性。
无论如何,这些解决方案都不是真正理想的。在某些时候,您几乎肯定需要处理太长而无法方便地输入一行的输入。
现在您已经包含了完整的扫描程序,我可以看到您将遇到另一个严重问题,因为您不会在将令牌字符串存储到yylval
之前复制它。保留令牌的地址(它是扫描仪的内部输入缓冲区的一部分)是不正确的;扫描仪会在没有警告的情况下更改缓冲区(例如,当需要更多输入时)。特别是,一旦扫描器开始处理下一个令牌,它将覆盖它之前用于终止令牌的NUL字节,这将明显影响令牌的字符串变为两个(或更多) )连续的代币。您可以在此站点上找到有关此问题的大量讨论。