如何在java

时间:2016-12-14 10:40:21

标签: java parsing plsql antlr

我有一个pkb文件。它包含一个包,在该包下它有多个功能。

我必须从中得到以下细节:

  1. 包名称
  2. 函数名称(逐个所有函数)
  3. 功能上的参数
  4. 返回功能类型
  5. 方法:我正在解析pkb文件。我从这些来源获取了语法:

    1. Presto
    2. Antlrv4 Grammer for plsql
    3. 获得这些语法后,我从antlr-4.5.3-complete.jar下载了jar。然后使用

      java -cp org.antlr.v4.Tool grammar.g
      

      我一个接一个地在这些语法上执行这个命令,生成监听器,词法分析器,解析器和其他文件。

      在此之后,我为每个语法在eclipse中创建了两个项目。我将这些生成的文件导入相应的文件并将antlr-4.5.3-complete.jar文件设置到路径中。在此之后,我使用以下代码检查我的.pkb文件是否正确?

      public static void parse(String file) {
          try {
              SqlBaseLexer lex = new SqlBaseLexer(new org.antlr.v4.runtime.ANTLRInputStream(file));
              CommonTokenStream tokens = new CommonTokenStream(lex);
              SqlBaseParser parser = new SqlBaseParser(tokens);
      
              System.err.println(parser.getNumberOfSyntaxErrors()+" Errors");
      
      
          } catch (RecognitionException e) {
              System.err.println(e.toString());
          } catch (java.lang.OutOfMemoryError e) {
              System.err.println(file + ":");
              System.err.println(e.toString());
          } catch (java.lang.ArrayIndexOutOfBoundsException e) {
              System.err.println(file + ":");
              System.err.println(e.toString());
          }       
      }
      

      我在解析文件时没有收到任何错误。 但在此之后,我陷入了下一步的困境。我需要获得所有包名,函数,参数等。

      如何获取这些详细信息?

      我的方法也是正确的,以达到所需的输出。

1 个答案:

答案 0 :(得分:1)

Presto语法是一种通用的SQL语法,不适合解析Oracle包。 PL / SQL的ANTLRv4语法是适合您任务的正确工具。

通常,ANTLR语法本身就是验证器。如果要在解析时进行一些额外的处理,则应使用ANTLR操作(请参阅概述幻灯片in this presentation)。这些是用目标语言(例如Java)编写的文本块,并用花括号括起来(参见documentation)。

使用ANTLR操作至少有两种方法可以解决您的任务。

标准输出

最简单的方法是为某些规则添加println()

要在package_body中打印包名修改plsql.g4规则,如下所示:

package_body
    : BODY package_name (IS | AS) package_obj_body* 
      (BEGIN seq_of_statements | END package_name?) 
      {System.out.println("Package name is "+$package_name.text);} 
    ;

与打印有关函数参数和返回类型的信息类似:在prinln()规则中添加create_function_body。但是打印参数时会出现问题。如果使用$parameter.text,它将根据parameter规则返回名称,类型规范和默认值,不带空格(作为标记序列)。如果您将println()添加到parameter规则并使用$parameter_name.text,则会打印所有参数的名称(包括过程参数,而不仅仅是函数)。因此,您可以为parameter规则添加ANTLR返回值,并将$parameter_name.text分配给返回值:

parameter returns [String p_name] 
: parameter_name (IN | OUT | INOUT | NOCOPY)* 
  type_spec? default_value_part?
  {$p_name=$parameter_name.text;}
;

因此create_function_body的上下文我们可以通过$parameter.p_name访问参数的名称:

create_function_body
: (CREATE (OR REPLACE)?)? FUNCTION function_name 
  {System.out.println("Parameters of function "+$function_name.text+":");}
  ('(' parameter {System.out.println($parameter.p_name);} 
  (',' parameter {System.out.println($parameter.p_name);})* ')')?  
  RETURN type_spec 
  (invoker_rights_clause|parallel_enable_clause|result_cache_clause|DETERMINISTIC)*
  ((PIPELINED? (IS | AS) (DECLARE? declare_spec* body | call_spec))
   | (PIPELINED | AGGREGATE) USING implementation_type_name) ';'
  {System.out.println("Return type of function "
                      +$function_name.text+" is "
                      + $type_spec.text);}
;

积累

此外,您可以将一些计算保存到变量并将其作为解析器类成员进行访问。例如。您可以在变量func_name中累积函数的名称。为此,在语法开头添加@members部分:

grammar plsql;

@members{
  String func_name = "";
}

修改function_name规则如下:

function_name
  : id ('.' id_expression)? {func_name = func_name+$id.text + " ";}
  ;

使用词法分析器和解析器类

以下是运行解析器parse.java的应用程序示例:

import org.antlr.v4.runtime.*;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class parse {
   static String readFile(String path) throws IOException 
   {
       byte[] encoded = Files.readAllBytes(Paths.get(path));
       return new String(encoded, "UTF-8");
   }

   public static void main(String[] args) throws Exception {
       // create input stream `in`
       ANTLRInputStream in = new ANTLRInputStream( readFile(args[0]) );
       // create lexer `lex` with `in` at input
       plsqlLexer lex = new plsqlLexer(in);
       // create token stream `tokens` with `lex` at input
       CommonTokenStream tokens = new CommonTokenStream(lex);
       // create parser with `tokens` at input
       plsqlParser parser = new plsqlParser(tokens);
       // call start rule of parser
       parser.sql_script();
       // print func_name
       System.out.println("Function names: "+parser.func_name);
   }
}

编译并运行

此后由ANTLR生成java代码:

java org.antlr.v4.Tool plsql.g4

并编译您的Java代码:

javac plsqlLexer.java plsqlParser.java plsqlListener.java parse.java

然后为某个.pkb文件运行它:

java parse green_tools.pkb

您可以找到修改后的parse.javaplsql.g4green_tools.pkb here