Sql 如何使用正确的行号和字符索引在ANTLR4中实现独立岛语法?

Sql 如何使用正确的行号和字符索引在ANTLR4中实现独立岛语法?,sql,parsing,antlr4,cobol,Sql,Parsing,Antlr4,Cobol,我一直在开发一个支持嵌入式SQL语句的COBOL语法。对于不熟悉COBOL的人,这里有一个例子 MOVE A TO B. EXEC SQL SELECT C FROM T WHERE ID=1 INTO :E END-EXEC MOVE F TO G “EXEC-SQL”和“END-EXEC”之间的代码使用(特别增强的)SQL语法,这是孤岛语法的完美示例 我知道这可以通过ANTLR4中的Lexer模式实现。但我还有另一个要求,即SQL语法应该与COBOL语法分离,以便在嵌入其他

我一直在开发一个支持嵌入式SQL语句的COBOL语法。对于不熟悉COBOL的人,这里有一个例子

MOVE A TO B.
EXEC SQL
    SELECT C FROM T WHERE ID=1
    INTO :E
END-EXEC
MOVE F TO G
“EXEC-SQL”和“END-EXEC”之间的代码使用(特别增强的)SQL语法,这是孤岛语法的完美示例

我知道这可以通过ANTLR4中的Lexer模式实现。但我还有另一个要求,即SQL语法应该与COBOL语法分离,以便在嵌入其他语言(如PL1)时可以重用SQL语法,而无需复制粘贴编程

因此,我所做的是使用一个简单的lexer模式来捕获“execsql”和“END-EXEC”之间的任何内容,将SQL代码提取为字符串,并将其交给一个单独的SQL lexer(和解析器)

这可以正常工作,但有一个缺点-SQL解析器中识别的标记的行号和字符索引从提取的SQL代码字符串开始计算,而不是从原始COBOL程序开始计算。当涉及到追溯到源代码时,例如,如果有解析错误,行号就会被证明是错误的

所以问题是:在ANTLR 4中是否有一种更简单的方法来分别实现孤岛语法(lexer和parser都是分开的),但仍然在为孤岛部分生成的标记中保留正确的行号和字符索引


更新:我发现Antlr4中有语法导入功能,我的同事告诉我我们一直在尝试,但失败了。问题是导入语法中的-lexer模式没有得到很好的支持,这会导致编译错误。正在跟踪此问题。

要扩展Bill的注释,在实例化SQL解析器/词法分析器时,将EXEC块开头的行偏移量传递给它。实现一个自定义SQL标记,将行号报告为偏移量加上SQL文本相对行号。让您的SQL令牌工厂将偏移量作为常量注入到生成的每个令牌中

更新

使用模式来实现惯用的孤岛语法,无论是否使用includes(至少对我来说这很有效),都是最自然的方法

除此之外,可以通过lexer或解析器中的操作、lexer的token emit()方法(或相关方法)的重写,以及访问基本语法的解析树来启动外部SQL块解析器进程

在任何特定情况下,只有你才能平衡哪些是可接受的、可取的或必要的

例如,如果解析树求值提供了一个用于动态执行SQL exec块的值,或者相反,取决于这样一个执行返回的值,那么您实际上被迫使用符号表,并将SQL执行的启动推迟到walker。当然,您可以缓存每个不同生成的SQL解析树,并使用特定于实例的数据重新初始化它们的符号表,以便重用,而无需重新划分SQL块


这取决于您的实际需求。

实际上,我们所做的与这里描述的@GRosenberg完全相同。定制代币厂很好。我在这里只是想看看是否还有其他更好、更简单的解决方案,我应该知道。特别是如果我不必在语法中编写动作来捕获EXEC块、构造令牌工厂、lexer、解析器并运行它们,我会很感兴趣,因为这一要求对于所有孤岛语法情况都非常普遍。我们做各种分析,比如提取调用层次结构、查找死代码,但这似乎对这个问题并不重要。