gpt4 book ai didi

c# - 我的 ANTLR 解析器(不是词法分析器)如何触发词法 "include"(不是 AST 拼接)?

转载 作者:太空宇宙 更新时间:2023-11-03 11:17:50 24 4
gpt4 key购买 nike

ANTLR 网站描述了two approaches实现“包括”指令。第一种方法是识别词法分析器中的指令并按词法包含文件(通过将 CharStream 压入堆栈并将其替换为读取新文件的指令);二是识别解析器中的指令,启动子解析器解析新文件,并拼接子解析器生成的AST。这些都不是我需要的。

在我正在解析的语言中,识别词法分析器中的指令是不切实际的,原因如下:

  1. 没有独立的字符模式总是表示“这是一个包含指令”。例如,Include "foo"; 在顶层是一个 include 指令,但在 Array bar --> Include "foo";Constant Include "foo "; 单词 Include 是一个标识符。
  2. 要包含的文件的名称可以字符串或常量标识符的形式给出,并且可以使用任意复杂的表达式定义此类常量。

所以我想触发解析器的包含。但是要执行包含,我不能启动子解析器并将 AST 拼接在一起;我必须拼接 token 。 block 在主文件中以 { 开头并在包含文件中以 } 终止是合法的。包含在函数中的文件甚至可以关闭函数定义并启动新的定义。

似乎我需要类似于第一种方法的东西,但在 TokenStreams 级别而不是 CharStreams 级别。这是一种可行的方法吗?我需要在堆栈中保留多少状态,以及如何使解析器切换回原始 token 流而不是在遇到 EOF 时终止?或者有更好的方法来处理这个问题吗?

==========

这是该语言的一个示例,演示了在主文件中打开的 block 可以在包含的文件中关闭(反之亦然)。请注意,当指令在函数内部时,Include 之前的 # 是必需的,但在函数外部是可选的。

主要文件:

[ Main;  print "This is Main!";  if (0) {  #include "other.h";  print "This is OtherFunction!";];

其他.h:

  } ! end if];  ! end Main[ OtherFunction;

最佳答案

每个 Include 语句都有可能让您的解析器创建一个新的词法分析器实例,并将词法分析器创建的这些新标记插入到解析器当前所在的索引处(参见 解析器的 @members block 中的 insertTokens(...) 方法。)。

这是一个快速演示:

通知6.g

grammar Inform6;

options {
output=AST;
}

tokens {
STATS;
F_DECL;
F_CALL;
EXPRS;
}

@parser::header {
import java.util.Map;
import java.util.HashMap;
}

@parser::members {
private Map<String, String> memory = new HashMap<String, String>();

private void putInMemory(String key, String str) {
String value;
if(str.startsWith("\"")) {
value = str.substring(1, str.length() - 1);
}
else {
value = memory.get(str);
}
memory.put(key, value);
}

private void insertTokens(String fileName) {
// possibly strip quotes from `fileName` in case it's a Str-token
try {
CommonTokenStream thatStream = new CommonTokenStream(new Inform6Lexer(new ANTLRFileStream(fileName)));
thatStream.fill();
List extraTokens = thatStream.getTokens();
extraTokens.remove(extraTokens.size() - 1); // remove EOF
CommonTokenStream thisStream = (CommonTokenStream)this.getTokenStream();
thisStream.getTokens().addAll(thisStream.index(), extraTokens);
} catch(Exception e) {
e.printStackTrace();
}
}
}

parse
: stats EOF -> stats
;

stats
: stat* -> ^(STATS stat*)
;

stat
: function_decl
| function_call
| include
| constant
| if_stat
;

if_stat
: If '(' expr ')' '{' stats '}' -> ^(If expr stats)
;

function_decl
: '[' id ';' stats ']' ';' -> ^(F_DECL id stats)
;

function_call
: Id exprs ';' -> ^(F_CALL Id exprs)
;

include
: Include Str ';' {insertTokens($Str.text);} -> /* omit statement from AST */
| Include id ';' {insertTokens(memory.get($id.text));} -> /* omit statement from AST */
;

constant
: Constant id expr ';' {putInMemory($id.text, $expr.text);} -> ^(Constant id expr)
;

exprs
: expr (',' expr)* -> ^(EXPRS expr+)
;

expr
: add_expr
;

add_expr
: mult_expr (('+' | '-')^ mult_expr)*
;

mult_expr
: atom (('*' | '/')^ atom)*
;

atom
: id
| Num
| Str
| '(' expr ')' -> expr
;

id
: Id
| Include
;

Comment : '!' ~('\r' | '\n')* {skip();};
Space : (' ' | '\t' | '\r' | '\n')+ {skip();};
If : 'if';
Include : 'Include';
Constant : 'Constant';
Id : ('a'..'z' | 'A'..'Z') ('a'..'z' | 'A'..'Z' | '0'..'9')+;
Str : '"' ~'"'* '"';
Num : '0'..'9'+ ('.' '0'..'9'+)?;

主文件

Constant IMPORT "other.h";

[ Main;
print "This is Main!";
if (0) {

Include IMPORT;

print "This is OtherFunction!";
];

其他.h

  } ! end if
]; ! end Main

[ OtherFunction;

主程序.java

import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;

public class Main {
public static void main(String[] args) throws Exception {
// create lexer & parser
Inform6Lexer lexer = new Inform6Lexer(new ANTLRFileStream("main.inf"));
Inform6Parser parser = new Inform6Parser(new CommonTokenStream(lexer));

// print the AST
DOTTreeGenerator gen = new DOTTreeGenerator();
StringTemplate st = gen.toDOT((CommonTree)parser.parse().getTree());
System.out.println(st);
}
}

要运行演示,请在命令行上执行以下操作:

java -cp antlr-3.3.jar org.antlr.Tool Inform6.g javac -cp antlr-3.3.jar *.javajava -cp .:antlr-3.3.jar Main

您将看到的输出对应于以下 AST:

enter image description here

关于c# - 我的 ANTLR 解析器(不是词法分析器)如何触发词法 "include"(不是 AST 拼接)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12104324/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com