我在使用Ragel时遇到了一些问题,主要是由于我仍然试图掌握整个事情是如何工作的。
我正试图为一种类似于SQL(但不太灵活)的语言做一个简单的解析器,在那里你有函数(全部大写),标识符(全部小写),你可以在函数内嵌套函数。
到目前为止我写的是:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
typedef struct Parser {
int current_line;
int nesting;
/* Ragel FSM */
int cs;
const char *ts;
const char *te;
int act;
} Parser;
%%{
machine gql;
access parser->;
Function = [A-Z][A-Z_]+ ;
Identifier = [a-z][a-z_]+ ;
Integer = [0-9]+ ;
Parameter = ( Identifier | Integer )+ ;
WhiteSpace = [ trn] ;
action function_call {
parser->nesting++;
printf("FUNCTION CALLn");
}
action function_finish {
parser->nesting--;
printf("FUNCTION FINISH!n");
}
action function_add_identifier {
printf("FUNCTION ADD IDENTIFIERn");
}
FunctionCall =
Function @function_call WhiteSpace* "("
Parameter %function_add_identifier
( WhiteSpace* ',' WhiteSpace* Parameter %function_add_identifier )* WhiteSpace*
%function_finish ')' ;
main := FunctionCall ;
}%%
%% write data;
void Parser_Init(Parser *parser) {
parser->current_line = 1;
parser->nesting = 0;
%% write init;
}
void Parser_Execute(Parser *parser, const char *buffer, size_t len) {
if(len == 0) return;
const char *p, *pe, *eof;
p = buffer;
pe = buffer+len;
eof = pe;
%% write exec;
}
int main(int argc, char *argv[]) {
Parser *parser = malloc(sizeof(Parser));
Parser_Init(parser);
printf("Parsing:n%snnn", argv[1]);
Parser_Execute(parser, argv[1], sizeof(argv[1]));
printf("Parsed %d linesn", parser->current_line);
return 0;
}
每个字符调用一次function_call
动作,而不是拾取Parameter
s,我无法想象如何使函数在函数内工作。
我哪里做错了,有什么建议吗?
标准方法是创建一个词法分析器(用Ragel或GNU Flex编写),它只对语言输入进行标记。然后,这些令牌被解析器(不是用Ragel编写的)使用,该解析器能够解析递归结构(例如嵌套函数)-使用像GNU Bison这样的解析器生成器。
请注意,Ragel包含(作为高级功能)管理堆栈的指令(它使您能够解析递归结构)-但是这样您就离开了常规语言的领域,否则您将在Ragel规范中使用。因此,您可以编写一个能够使用Ragel完全解析嵌套函数的解析器。但是一个适当的分层架构(第一层:词法分析器,第二层:解析器,…)简化了任务,即各部分更容易调试,测试和维护。