我有一个pkb文件。它包含一个包,在该包下它有多个功能。
我必须从中得到以下细节:
方法:我正在解析pkb文件。我从这些来源获取了语法:
获得这些语法后,我从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());
}
}
我在解析文件时没有收到任何错误。 但在此之后,我陷入了下一步的困境。我需要获得所有包名,函数,参数等。
如何获取这些详细信息?
我的方法也是正确的,以达到所需的输出。
答案 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.java
,plsql.g4
和green_tools.pkb
here。