You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将C实现的词法分析器Token输入ANTLR4解析器语法测试?

问题描述

我已使用ANTLR4编写了如下IFJ23解析器语法:

parser grammar IFJ23;

tokens {
    Identifier, Type,
    LeftBracket, RightBracket,
    LeftCurlyBracket, RightCurlyBracket,
    Semicolon, Colon, Arrow, Comma,

    /** Keywords */
    FunctionKeyword
}

swiftFile
    : functionDeclaration swiftFile
    ;



/** Statements */
statement
    : declaration Semicolon?
    ;

statements
    : statement statements?
    ;

codeBlock
    : LeftCurlyBracket statements? RightCurlyBracket
    ;



/** Declarations */
declaration
    : functionDeclaration
//    | variableDeclaration
    ;



/** Function declarations */
functionDeclaration
    : FunctionKeyword Identifier functionSignature functionBody
    ;

functionSignature
    : parameterClause functionResult?
    ;

functionBody
    : codeBlock
    ;

parameterClause
    : LeftBracket RightBracket
    | LeftBracket parameterList RightBracket
    ;

functionResult
    : Arrow Type
    ;

parameterList
    : parameter
    | parameter Comma parameterList
    ;

parameter
    : externalParameterName? localParameterName typeAnnotation
    ;

externalParameterName
    : Identifier
    ;

localParameterName
    : Identifier
    ;

typeAnnotation
    : Colon Type
    ;

目前我有一个用C语言实现的可用词法分析器,能为文件生成Token列表。想知道有没有办法让ANTLR4接收这个Token列表并生成语法树,同时需要匹配tokens{}列表中的Token与我词法分析器生成的对应Token类型。


解决方法

1. 对齐Token类型编号

ANTLR4解析器依赖Token的类型编号匹配语法规则,所以第一步必须让你的C词法分析器生成的Token类型编号,和ANTLR语法里tokens{}定义的完全对应:

  • 生成ANTLR解析器代码后,查看自动生成的头文件(比如IFJ23Parser.h),里面会给tokens{}里的每个Token分配唯一整数编号,比如IFJ23Parser_Identifier、IFJ23Parser_FunctionKeyword这类。
  • 在你的C词法分析器中,把你自己定义的Token枚举(比如你写的IDENTIFIER)对应到这些ANTLR生成的编号上。

2. 转换自定义Token为ANTLR兼容格式

ANTLR解析器只认实现了它自身Token接口的对象(C目标中是antlr4c_Token)。你需要把C词法分析器输出的Token转换成ANTLR能识别的实例:

  • 每个转换后的Token需要包含:类型编号、文本内容、行号、列号这些核心信息。
  • 直接使用ANTLR C目标提供的antlr4c_CommonToken结构体即可,填充对应的字段即可完成转换。

3. 构造Token流供解析器读取

ANTLR解析器需要通过TokenStream来读取Token序列,你可以借助antlr4c_ListTokenSource将你的Token列表转换为Token源,再用antlr4c_CommonTokenStream包装这个源:

// 假设你的C词法分析器生成了token_list数组,每个元素包含type、text、line、column字段
antlr4c_ListTokenSource *token_source = antlr4c_ListTokenSource_new();
for (int i = 0; i < token_count; i++) {
    YourToken *your_token = &token_list[i];
    // 构造ANTLR兼容的CommonToken
    antlr4c_CommonToken *antlr_token = antlr4c_CommonToken_new(
        your_token->type, // 这里必须是ANTLR对应的类型编号
        your_token->text
    );
    antlr4c_Token_setLine((antlr4c_Token*)antlr_token, your_token->line);
    antlr4c_Token_setCharPositionInLine((antlr4c_Token*)antlr_token, your_token->column);
    antlr4c_ListTokenSource_add(token_source, (antlr4c_Token*)antlr_token);
}

antlr4c_CommonTokenStream *token_stream = antlr4c_CommonTokenStream_new((antlr4c_TokenSource*)token_source);

4. 启动解析生成语法树

有了TokenStream后,就可以实例化解析器并调用语法的起始规则生成语法树:

antlr4c_IFJ23Parser *parser = antlr4c_IFJ23Parser_new((antlr4c_TokenStream*)token_stream);
antlr4c_ParseTree *parse_tree = antlr4c_IFJ23Parser_swiftFile(parser);

5. 自定义错误处理(可选)

如果需要捕获并处理解析错误,可以给解析器添加自定义错误监听器:

typedef struct {
    antlr4c_BaseErrorListener base;
} CustomErrorListener;

void custom_syntax_error(antlr4c_Recognizer *recognizer, antlr4c_Token *offending_symbol, size_t line, size_t char_pos, const char *msg, void *ctx) {
    fprintf(stderr, "语法错误:第%zu行,第%zu列:%s\n", line, char_pos, msg);
}

CustomErrorListener* custom_error_listener_new() {
    CustomErrorListener *listener = malloc(sizeof(CustomErrorListener));
    antlr4c_BaseErrorListener_init(&listener->base);
    listener->base.syntaxError = custom_syntax_error;
    return listener;
}

// 替换默认错误监听器,使用自定义逻辑
antlr4c_Parser_removeErrorListeners((antlr4c_Parser*)parser);
antlr4c_Parser_addErrorListener((antlr4c_Parser*)parser, (antlr4c_ErrorListener*)custom_error_listener_new());

内容的提问来源于stack exchange,提问作者Dj Sushi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 12:51:11