Nic*_*ick 5 c parsing antlr abstract-syntax-tree antlr4
是否可以使用标准 C 语法(如官方 ANTLR4 GitHub 存储库中找到的语法)来实现经典的Yacc 词法分析器 hack,以区分 ANTLR4 生成的 C 解析器中的标识符名称和类型名称?
看来可以插入 ANTLR4 词法分析器的临时代码非常有限。在《The Definitive ANTLR4 Reference》一书中,Terrence Parr 说道:
“一种长期存在的常见做法涉及从解析器向词法分析器发送反馈,以便词法分析器可以向解析器发送精确的标记。[...]不幸的是,这对于 ANTLR 语法来说是不可能的,因为 ANTLR 生成的解析器通常在令牌流中向前看以做出解析决策。[...]”
有什么方法可以规避上述问题并实现反馈循环吗?或者在访问解析树时如果不采取疯狂的黑客手段,在 ANTLR4 中实现 C 解析器是不可能的吗?
Def*_*ked -3
不。您逐字引用了您自己问题的答案。
顺便说一句,编写解析器并不难。预警一下,这个递归下降解析器是我凭空写出来的;它尚未经过测试,但它仍然会给您基本的想法:
#include <ctype.h> // isalnum, isalpha, isdigit
#include <stdio.h> // printf
#include <stdlib.h> // atoi
#include <string.h> // strncmp
/* ASCII numbers are positive, and only between 0 and 127.
* We can thus use negative numbers to identify special tokens. */
enum {
TOK_SPACE = -1,
TOK_ID = -2,
TOK_NUM = -3,
TOK_ELSE = -4,
TOK_IF = -5
};
int token_length;
union {
char *s;
int i;
} token_value;
int get_token(char *str) {
token_length = 0;
if (isspace(*str)) {
do {
token_length++;
str++;
} while (isspace(*str));
return TOK_SPACE;
}
if (isalpha(*str) || *str == '_') {
token_value.s = str;
do {
token_length++;
str++;
} while (isalnum(*str) || *str == '_');
if (!strncmp(token_value.s, "else", token_length))
return TOK_ELSE;
if (!strncmp(token_value.s, "if", token_length))
return TOK_IF;
return TOK_ID;
}
if (isdigit(*str)) {
token_value.s = str;
do {
token_length++;
str++;
} while (isdigit(*str));
token_value.i = atoi(str);
return TOK_NUM;
}
token_length = 1;
return *str;
}
int is_conditional(char *str) {
int tok, len = 0, rule_len;
tok = get_token(str);
if (tok == TOK_SPACE) { // accept space
len += token_length;
str += token_length;
tok = get_token(str);
}
if (tok != TOK_ID && tok != TOK_NUM) // require id or number
return 0;
return len + token_length; // return the length of the entire match
}
int is_if_statement(char *str) {
int tok, len = 0, rule_len;
tok = get_token(str);
if (tok == TOK_SPACE) { // accept space
len += token_length;
str += token_length;
tok = get_token(str);
}
if (tok == TOK_IF) { // require 'if'
len += token_length;
str += token_length;
tok = get_token(str);
} else return 0;
if (tok == TOK_SPACE) { // accept space
len += token_length;
str += token_length;
tok = get_token(str);
}
if (tok == '(') { // require l-paren
len++;
str++;
tok = get_token(str);
} else return 0;
rule_len = is_conditional(str);
if (rule_len != 0) { // require conditional
len += rule_len;
str += rule_len;
tok = get_token(str);
} else return 0;
if (tok == TOK_SPACE) { // accept space
len += token_length;
str += token_length;
tok = get_token(str);
}
if (tok == ')') { // require r-paren
len++;
str++;
tok = get_token(str);
} else return 0;
if (tok == TOK_SPACE) { // accept space
len += token_length;
str += token_length;
tok = get_token(str);
}
if (tok != TOK_ID)
return 0;
return len + token_length; // return the length of the entire match
}
void parse(char *str) {
int rule_len;
if ((rule_len = is_if_statement(str)))
printf("an if-statement was matched!\n");
else
printf("the input is not valid code!\n");
str += rule_len;
}
int main(int argc, char *argv[]) {
parse("if (x) y"); // valid!
parse("if (1) ..."); // invalid!
return 0;
}
Run Code Online (Sandbox Code Playgroud)