2

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

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

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

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

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

==========

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

主.inf:

[ 主要的;
  打印“这是主要的!”;
  如果(0){
  #include "其他.h";
  打印“这是其他功能!”;
];

其他.h:

  } !万一
]; !结束主要

[其他功能;
4

1 回答 1

2

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

这是一个快速演示:

通知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 *.java
java -cp .:antlr-3.3.jar 主要

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

在此处输入图像描述

于 2012-08-24T20:20:37.733 回答