add procedure

This commit is contained in:
XudongXie 2024-09-17 14:28:30 +08:00
parent f0a909f288
commit 9a54d05f12
13 changed files with 408 additions and 44 deletions

View File

@ -4,17 +4,18 @@
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="d8d12963-4777-48e3-9669-309cf5e41d60" name="更改" comment="add document of Procedure">
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureBeginNode.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureColumnNode.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureEndNode.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureNode.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureObjNode.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedurePLStatementNode.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureRetDefNode.java" afterDir="false" />
<list default="true" id="d8d12963-4777-48e3-9669-309cf5e41d60" name="更改" comment="add ast classes of procedure">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Document/Procedure in Oracle" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Document/Procedure in Oracle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/CreateTable/ColumnNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/CreateTable/ColumnNode.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Document/Todolist" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Document/Todolist" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Generator/OpenGaussGenerator.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Generator/OpenGaussGenerator.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Lexer/OracleLexer.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Lexer/OracleLexer.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Main.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Main.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/Exception/ExceptionEndNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Exception/ExceptionEndNode.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureColumnNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureColumnNode.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedurePLStatementNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedurePLStatementNode.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureRetDefNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureRetDefNode.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/OracleParser.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/OracleParser.java" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -112,13 +113,6 @@
<option name="presentableId" value="Default" />
<updated>1723106789329</updated>
</task>
<task id="LOCAL-00031" summary="add some comments">
<created>1725981511612</created>
<option name="number" value="00031" />
<option name="presentableId" value="LOCAL-00031" />
<option name="project" value="LOCAL" />
<updated>1725981511612</updated>
</task>
<task id="LOCAL-00032" summary="add parseSelect">
<created>1725981975960</created>
<option name="number" value="00032" />
@ -455,7 +449,14 @@
<option name="project" value="LOCAL" />
<updated>1726491998609</updated>
</task>
<option name="localTasksCounter" value="80" />
<task id="LOCAL-00080" summary="add ast classes of procedure">
<created>1726496640760</created>
<option name="number" value="00080" />
<option name="presentableId" value="LOCAL-00080" />
<option name="project" value="LOCAL" />
<updated>1726496640760</updated>
</task>
<option name="localTasksCounter" value="81" />
<servers />
</component>
<component name="Vcs.Log.Tabs.Properties">
@ -470,7 +471,6 @@
</option>
</component>
<component name="VcsManagerConfiguration">
<MESSAGE value="add Delete ast class" />
<MESSAGE value="add Delete" />
<MESSAGE value="add alter table grammar document" />
<MESSAGE value="add alter table ast class" />
@ -495,7 +495,8 @@
<MESSAGE value="revise" />
<MESSAGE value="add exception" />
<MESSAGE value="add document of Procedure" />
<option name="LAST_COMMIT_MESSAGE" value="add document of Procedure" />
<MESSAGE value="add ast classes of procedure" />
<option name="LAST_COMMIT_MESSAGE" value="add ast classes of procedure" />
</component>
<component name="XDebuggerManager">
<watches-manager>

View File

@ -6,15 +6,30 @@ BEGIN
-- Exception handling
END [procedure_name]; -- [procedure_name] should be removed in OpenGauss
Example: CREATE OR REPLACE PROCEDURE update_salary(
Example: CREATE OR REPLACE PROCEDURE update_salary (
employee_id IN NUMBER,
new_salary IN OUT NUMBER
) IS
v_employee employees%ROWTYPE;
BEGIN
SELECT * INTO v_employee FROM employees WHERE employee_id = employee_id;
IF new_salary < 3000 THEN
new_salary := new_salary * 1.1;
ELSE
new_salary := new_salary * 1.05;
END IF;
UPDATE employees SET salary = new_salary WHERE employee_id = employee_id;
COMMIT;
DBMS_OUTPUT.PUT_LINE('Updated Salary: ' || new_salary);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Employee not found.');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('Multiple employees found.');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('An error occurred: ' || SQLERRM);
END update_salary;
/

View File

@ -15,7 +15,7 @@ Operation
 continue、exit 1
 return ***
 exception 1
 commit、rollback、execute ****
 commit、rollback、execute ***
 alter table 1
 create table 1
 drop table 1
@ -24,4 +24,4 @@ Object
 view 1
 function ***
 procedure ***
 trigger *****
 trigger ****

View File

@ -22,6 +22,10 @@ import Parser.AST.Loop.ForNode;
import Parser.AST.Loop.LoopBodyNode;
import Parser.AST.Loop.LoopNode;
import Parser.AST.Loop.WhileNode;
import Parser.AST.Procedure.ProcedureColumnNode;
import Parser.AST.Procedure.ProcedureEndNode;
import Parser.AST.Procedure.ProcedureNode;
import Parser.AST.Procedure.ProcedureRetDefNode;
import Parser.AST.Select.SelectNode;
import Parser.AST.Update.UpdateNode;
import Parser.AST.View.ViewCreateNode;
@ -75,6 +79,9 @@ public class OpenGaussGenerator {
else if (node instanceof ExceptionNode) {
return GenExceptionSQL(node);
}
else if (node instanceof ProcedureNode) {
return GenProcedureSQL(node);
}
else {
try {
throw new GenerateFailedException("Root node:" + node.getClass() + "(Unsupported node type!)");
@ -145,6 +152,12 @@ public class OpenGaussGenerator {
return node.toQueryString();
}
private String GenProcedureSQL(ASTNode node) {
visitPL(node);
System.out.println(node.getASTString());
return node.toQueryString();
}
private void visitCrt(ASTNode node) {
if (node instanceof ColumnNode) {
ColumnTypeConvert((ColumnNode) node);
@ -240,6 +253,24 @@ public class OpenGaussGenerator {
visitCreateView(child);
}
}
private void visitPL(ASTNode node) {
if (node instanceof ProcedureRetDefNode) {
PLConvert(node);
}
else if (node instanceof ProcedureColumnNode) {
ColumnTypeConvert((ProcedureColumnNode) node);
}
else if (node instanceof ProcedureEndNode) {
PLConvert(node);
}
else if (node instanceof ExceptionNode) {
visitException(node);
}
for (ASTNode child : node.getChildren()) {
visitPL(child);
}
}
private void PLConvert(ASTNode node) {
if (node.checkExistsByRegex("(?i)DBMS_OUTPUT.PUT_LINE\\(.*?\\)")) {
String printObj = "";
@ -304,6 +335,30 @@ public class OpenGaussGenerator {
}
}
if (node instanceof ProcedureRetDefNode) {
List<Token> tokens = new ArrayList<>();
tokens.add(new Token(Token.TokenType.KEYWORD, "AS"));
tokens.add(new Token(Token.TokenType.KEYWORD, "$$"));
for (Token token: node.getTokens()) {
if (token.hasType(Token.TokenType.KEYWORD) && token.getValue().equalsIgnoreCase("IS")) {
tokens.add(new Token(Token.TokenType.KEYWORD, "DECLARE"));
}
else {
tokens.add(token);
}
}
node.setTokens(tokens);
}
if (node instanceof ProcedureEndNode) {
List<Token> tokens = new ArrayList<>();
tokens.add(new Token(Token.TokenType.KEYWORD, "END"));
tokens.add(new Token(Token.TokenType.SYMBOL, ";"));
tokens.add(new Token(Token.TokenType.KEYWORD, "$$"));
tokens.add(new Token(Token.TokenType.KEYWORD, "LANGUAGE"));
tokens.add(new Token(Token.TokenType.KEYWORD, "plpgsql"));
tokens.add(new Token(Token.TokenType.SYMBOL, ";"));
node.setTokens(tokens);
}
}

View File

@ -35,6 +35,8 @@ public class OracleLexer {
, "LOOP", "EXIT", "WHILE", "FOR", "IN", "CONTINUE"
// Exception
, "EXCEPTION", "SQLERRM", "ZERO_DIVIDE", "INVALID_NUMBER", "OTHERS"
// Procedure
, "PROCEDURE", "IS", "IN", "OUT", "$$"
};
private static final Pattern TOKEN_PATTERN = Pattern.compile(
"(NUMBER\\(.*?\\))|" + // NUMBER() function
@ -78,6 +80,7 @@ public class OracleLexer {
"(:=)|" +
"(\\.\\.)|" +
"(\\b[A-Za-z_][A-Za-z0-9_]*(%[A-Za-z_][A-Za-z0-9_]*)*\\b)|" + // Keywords and identifiers
"(\\b[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*)*\\b)|" + // Keywords and identifiers
"(\\b[A-Za-z_][A-Za-z0-9_]*\\b)|" + // Keywords and identifiers
"(\\d+\\.?\\d*)|" + // Numbers (integer or decimal)
@ -178,6 +181,8 @@ public class OracleLexer {
else if (isKeyword(tokenValue)) {
return new Token(Token.TokenType.KEYWORD, tokenValue);
} else if (tokenValue.matches("[A-Za-z_][A-Za-z0-9_]*(%[A-Za-z_][A-Za-z0-9_]*)*")) {
return new Token(Token.TokenType.IDENTIFIER, tokenValue);
} else if (tokenValue.matches("[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*)*")) {
return new Token(Token.TokenType.IDENTIFIER, tokenValue);
} else if (tokenValue.matches("[a-zA-Z_][a-zA-Z0-9_]*")) {

View File

@ -22,11 +22,11 @@ public class Main {
// String sql = "DROP TABLE employees CASCADE CONSTRAINTS;";
// String sql = "SELECT e.first_name, d.department_name FROM employees e JOIN departments d Using e.department_id = d.department_id;";
// String sql = "employees e JOIN departments d ON e.department_id = d.department_id;";
// String sql = "UPDATE employees e\n" +
// "JOIN departments d using e.department_id = d.department_id\n" +
// "SET e.salary = e.salary * 1.10,\n" +
// " d.budget = d.budget * 1.10\n" +
// "WHERE d.department_name = 'Sales';";
String sql = "UPDATE employees e\n" +
"JOIN departments d using e.department_id = d.department_id\n" +
"SET e.salary = e.salary * 1.10,\n" +
" d.budget = d.budget * 1.10\n" +
"WHERE d.department_name = 'Sales';";
// String sql = "DELETE FROM employees e\n" +
// "WHERE e.department_id IN (\n" +
// " SELECT d.department_id\n" +
@ -51,20 +51,47 @@ public class Main {
// " v_counter := v_counter + 1;\n" +
// " EXIT WHEN v_counter > 10;\n" +
// " END LOOP;";
String sql = "EXCEPTION\n" +
" WHEN e_custom_exception THEN\n" +
" DBMS_OUTPUT.PUT_LINE('Caught an exception: Custom exception raised');\n" +
" WHEN ZERO_DIVIDE THEN\n" +
" DBMS_OUTPUT.PUT_LINE('Caught an exception: Division by zero');\n" +
" WHEN INVALID_NUMBER THEN\n" +
" DBMS_OUTPUT.PUT_LINE('Caught an exception: Invalid number');\n" +
" WHEN OTHERS THEN\n" +
" DBMS_OUTPUT.PUT_LINE('Caught an exception: ' || SQLERRM);";
// String sql = "EXCEPTION\n" +
// " WHEN e_custom_exception THEN\n" +
// " DBMS_OUTPUT.PUT_LINE('Caught an exception: Custom exception raised');\n" +
// " WHEN ZERO_DIVIDE THEN\n" +
// " DBMS_OUTPUT.PUT_LINE('Caught an exception: Division by zero');\n" +
// " WHEN INVALID_NUMBER THEN\n" +
// " DBMS_OUTPUT.PUT_LINE('Caught an exception: Invalid number');\n" +
// " WHEN OTHERS THEN\n" +
// " DBMS_OUTPUT.PUT_LINE('Caught an exception: ' || SQLERRM);";
// String sql = "CREATE OR REPLACE PROCEDURE update_salary (\n" +
// " employee_id IN NUMBER,\n" +
// " new_salary IN OUT NUMBER\n" +
// " ) IS\n" +
// " v_employee employees%ROWTYPE;\n" +
// " BEGIN\n" +
// " SELECT * INTO v_employee FROM employees WHERE employee_id = employee_id;\n" +
// "\n" +
// " IF new_salary < 3000 THEN\n" +
// " new_salary := new_salary * 1.1;\n" +
// " ELSE\n" +
// " new_salary := new_salary * 1.05;\n" +
// " END IF;\n" +
// "\n" +
// " UPDATE employees SET salary = new_salary WHERE employee_id = employee_id;\n" +
// " COMMIT;\n" +
// "\n" +
// " DBMS_OUTPUT.PUT_LINE('Updated Salary: ' || new_salary);\n" +
// " EXCEPTION\n" +
// " WHEN NO_DATA_FOUND THEN\n" +
// " DBMS_OUTPUT.PUT_LINE('Employee not found.');\n" +
// " WHEN TOO_MANY_ROWS THEN\n" +
// " DBMS_OUTPUT.PUT_LINE('Multiple employees found.');\n" +
// " WHEN OTHERS THEN\n" +
// " DBMS_OUTPUT.PUT_LINE('An error occurred: ' || SQLERRM);\n" +
// " END update_salary;\n" +
// " /";
OracleLexer lexer = new OracleLexer(sql);
lexer.printTokens();
// OracleParser parser = new OracleParser(lexer);
// ASTNode root = parser.parse();
ASTNode root = OracleParser.parseException(lexer.getTokens());
OracleParser parser = new OracleParser(lexer);
ASTNode root = parser.parse();
// ASTNode root = OracleParser.parseException(lexer.getTokens());
// ASTNode root = OracleParser.parseLoop(lexer.getTokens());
// ASTNode root = OracleParser.parseIFELSE(lexer.getTokens());
// ASTNode root = OracleParser.parseCaseWhen(lexer.getTokens());

View File

@ -22,6 +22,9 @@ public class ExceptionEndNode extends ASTNode {
@Override
public void visit(ASTNode node, StringBuilder queryString) {
queryString.append(toString());
for (ASTNode child : node.getChildren()) {
child.visit(child, queryString);
}
}
}

View File

@ -16,6 +16,7 @@ public class ProcedureColumnNode extends ASTNode implements ColumnType {
public ProcedureColumnNode() {
super();
setTokens(new ArrayList<>());
setInOut(new ArrayList<>());
}
public ProcedureColumnNode(ASTNode node)
@ -31,9 +32,9 @@ public class ProcedureColumnNode extends ASTNode implements ColumnType {
@Override
public void visit(ASTNode node, StringBuilder queryString)
{
if (node.hasChild() && !(node.getChildren().get(0) instanceof ProcedureColumnNode) )
if (node.hasChild() && (node.getChildren().get(0) instanceof ProcedureColumnNode) )
queryString.append(toString() + ", ");
else if (node.hasChild() && (node.getChildren().get(0) instanceof ProcedureColumnNode))
else if (node.hasChild() && !(node.getChildren().get(0) instanceof ProcedureColumnNode))
queryString.append(toString() + " ");
for (ASTNode child : getChildren())
{

View File

@ -9,6 +9,7 @@ import java.util.List;
public class ProcedurePLStatementNode extends ASTNode {
public ProcedurePLStatementNode() {
super();
setTokens(new ArrayList<>());
}
public ProcedurePLStatementNode(ASTNode node) {
super(node);

View File

@ -9,6 +9,7 @@ import java.util.List;
public class ProcedureRetDefNode extends ASTNode {
public ProcedureRetDefNode() {
super();
setTokens(new ArrayList<>());
}
public ProcedureRetDefNode(ASTNode node) {

View File

@ -18,7 +18,7 @@ public class UpdateObjNode extends ASTNode {
public void visit(ASTNode node, StringBuilder queryString) {
queryString.append(toString() + " ");
for (ASTNode child : getChildren()) {
child.visit(this, queryString);
child.visit(child, queryString);
}
}
}

View File

@ -18,7 +18,7 @@ public class UpdateSetNode extends ASTNode {
public void visit(ASTNode node, StringBuilder queryString) {
queryString.append(toString() + " ");
for (ASTNode child : getChildren()) {
child.visit(this, queryString);
child.visit(child, queryString);
}
}
}

View File

@ -26,6 +26,7 @@ import Parser.AST.Insert.InsertNode;
import Parser.AST.Insert.InsertObjNode;
import Parser.AST.Join.*;
import Parser.AST.Loop.*;
import Parser.AST.Procedure.*;
import Parser.AST.Select.*;
import Parser.AST.Update.*;
import Parser.AST.View.ViewCreateNode;
@ -73,6 +74,12 @@ public class OracleParser {
|| lexer.getTokens().get(0).getValue().equalsIgnoreCase("WHILE")
) {
return parseLoop(lexer.getTokens());
} else if (
(lexer.getTokens().get(0).getValue().equalsIgnoreCase("CREATE") && lexer.getTokens().get(1).getValue().equalsIgnoreCase("PROCEDURE"))
|| (lexer.getTokens().get(0).getValue().equalsIgnoreCase("CREATE") && lexer.getTokens().get(1).getValue().equalsIgnoreCase("OR") && lexer.getTokens().get(2).getValue().equalsIgnoreCase("REPLACE") && lexer.getTokens().get(3).getValue().equalsIgnoreCase("PROCEDURE"))
)
{
return parseProcedure(lexer.getTokens());
}
else {
try {
@ -1642,4 +1649,252 @@ public class OracleParser {
return root;
}
/**
* Create PROCEDURE
* Grammar: CREATE [OR REPLACE] PROCEDURE procedure_name ([parameter_list])
* IS [LOCAL DECLARATIONS]
* BEGIN
* -- PL/SQL statements
* [EXCEPTION]
* -- Exception handling
* END [procedure_name];
* Example: CREATE OR REPLACE PROCEDURE update_salary(
* employee_id IN NUMBER,
* new_salary IN OUT NUMBER
* ) IS
* BEGIN
* IF new_salary < 3000 THEN
* new_salary := new_salary * 1.1;
* ELSE
* new_salary := new_salary * 1.05;
* END IF;
* END update_salary;
* /
*/
private ASTNode parseProcedure(List<Token> parseTokens) {
ASTNode root = new ProcedureNode(new ArrayList<>());
ASTNode currentNode = root;
for (int i = 0; i < parseTokens.size(); i++) {
// match CREATE PROCEDURE
if (root.getTokens().isEmpty()) {
for (int j = i; j < parseTokens.size(); j++) {
root.addToken(parseTokens.get(j));
if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equalsIgnoreCase("PROCEDURE")) {
i = j;
break;
}
}
}
// match procedure name
else if (currentNode == root && parseTokens.get(i).hasType(Token.TokenType.IDENTIFIER)) {
ASTNode childNode = new ProcedureObjNode();
childNode.addToken(parseTokens.get(i));
currentNode.addChild(childNode);
currentNode = childNode;
}
// match parameter list
else if (currentNode instanceof ProcedureObjNode && parseTokens.get(i).hasType(Token.TokenType.SYMBOL) && parseTokens.get(i).getValue().equals("(")) {
i++;
for (int ii = i; ii < parseTokens.size(); ii++) {
if (parseTokens.get(ii).hasType(Token.TokenType.KEYWORD) && parseTokens.get(ii).getValue().equalsIgnoreCase("IS")) {
i = ii - 1;
break;
}
List<Token> tokens = new ArrayList<>();
ProcedureColumnNode child = new ProcedureColumnNode();
child.setName(parseTokens.get(ii));
tokens.add(parseTokens.get(ii));
List<Token> constraint = new ArrayList<>();
boolean typeMatch = false;
int typeIdx = -1;
for (int j = ii + 1; j < parseTokens.size(); j++) {
if (!typeMatch && !(parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && (parseTokens.get(j).getValue().equalsIgnoreCase("IN") || parseTokens.get(j).getValue().equalsIgnoreCase("OUT"))))
{
child.setType(parseTokens.get(j));
typeMatch = true;
typeIdx = j;
}
if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && (parseTokens.get(j).getValue().equalsIgnoreCase("IN") || parseTokens.get(j).getValue().equalsIgnoreCase("OUT"))) {
child.addInOut(parseTokens.get(j));
}
// Check () or REFERENCES other_table(other_column)
if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) &&
(parseTokens.get(j).getValue().equalsIgnoreCase("REFERENCES")
|| parseTokens.get(j).getValue().equalsIgnoreCase("CHECK"))) {
tokens.add(parseTokens.get(j));
if (!(parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && (parseTokens.get(j).getValue().equalsIgnoreCase("IN") || parseTokens.get(j).getValue().equalsIgnoreCase("OUT"))))
constraint.add(parseTokens.get(j));
Stack<String> stack = new Stack<>();
for (int k = j + 1; k < parseTokens.size(); k++) {
tokens.add(parseTokens.get(k));
if (!(parseTokens.get(k).hasType(Token.TokenType.KEYWORD) && (parseTokens.get(k).getValue().equalsIgnoreCase("IN") || parseTokens.get(k).getValue().equalsIgnoreCase("OUT"))))
constraint.add(parseTokens.get(k));
if (parseTokens.get(k).getValue().equals("(")) {
stack.push("(");
for (int t = k + 1; t < parseTokens.size(); t++) {
tokens.add(parseTokens.get(t));
if (!(parseTokens.get(t).hasType(Token.TokenType.KEYWORD) && (parseTokens.get(t).getValue().equalsIgnoreCase("IN") || parseTokens.get(t).getValue().equalsIgnoreCase("OUT"))))
constraint.add(parseTokens.get(t));
if (parseTokens.get(t).getValue().equals("(")) {
stack.push("(");
} else if (parseTokens.get(t).getValue().equals(")")) {
stack.pop();
if (stack.empty()) {
ii = t;
break;
}
}
}
break;
}
}
break;
}
if ((parseTokens.get(j).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j).getValue().equals(",")) ||
(parseTokens.get(j).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j).getValue().equals(")"))) {
ii = j;
break;
}
tokens.add(parseTokens.get(j));
if (typeMatch && j != typeIdx) {
if (!(parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && (parseTokens.get(j).getValue().equalsIgnoreCase("IN") || parseTokens.get(j).getValue().equalsIgnoreCase("OUT"))))
constraint.add(parseTokens.get(j));
}
}
child.setTokens(tokens);
child.setConstraint(constraint);
currentNode.addChild(child);
currentNode = child;
}
}
// match procedure return definition
else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("IS")) {
ASTNode childNode = new ProcedureRetDefNode();
for (int j = i; j < parseTokens.size(); j++) {
if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equalsIgnoreCase("BEGIN")) {
i = j - 1;
break;
}
childNode.addToken(parseTokens.get(j));
}
currentNode.addChild(childNode);
currentNode = childNode;
}
// match procedure begin
else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("BEGIN")) {
ASTNode childNode = new ProcedureBeginNode();
childNode.addToken(parseTokens.get(i));
currentNode.addChild(childNode);
currentNode = childNode;
}
// match procedure body
else if (currentNode instanceof ProcedureBeginNode) {
for (int ii = i; ii < parseTokens.size(); ii++) {
if (parseTokens.get(ii).hasType(Token.TokenType.KEYWORD) && parseTokens.get(ii).getValue().equalsIgnoreCase("END")) {
i = ii - 1;
break;
}
else if (parseTokens.get(ii).hasType(Token.TokenType.KEYWORD) && parseTokens.get(ii).getValue().equalsIgnoreCase("EXCEPTION")) {
i = ii - 1;
break;
}
else if (parseTokens.get(ii).hasType(Token.TokenType.KEYWORD) && parseTokens.get(ii).getValue().equalsIgnoreCase("IF")) {
int index = -1;
for (int j = ii; j < parseTokens.size(); j++) {
if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equalsIgnoreCase("END")
&& j + 1 < parseTokens.size() && parseTokens.get(j + 1).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j + 1).getValue().equalsIgnoreCase("IF")
&& j + 2 < parseTokens.size() && parseTokens.get(j + 2).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j + 2).getValue().equals(";") ) {
index = j + 2;
break;
}
}
if (index == -1) {
try {
throw new ParseFailedException("There exists syntax error and no END if block is found!");
} catch (ParseFailedException e) {
e.printStackTrace();
}
}
else {
ASTNode childNode = parseIFELSE(parseTokens.subList(ii, index + 1));
currentNode.addChild(childNode);
currentNode = childNode.getDeepestChild();
ii = index;
}
}
else {
ASTNode childNode = new ProcedurePLStatementNode();
for (int j = ii; j < parseTokens.size(); j++) {
childNode.addToken(parseTokens.get(j));
if (parseTokens.get(j).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j).getValue().equals(";")) {
ii = j;
break;
}
}
currentNode.addChild(childNode);
currentNode = childNode;
}
}
}
// match exception
else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("EXCEPTION")) {
int index = -1;
for (int j = i; j < parseTokens.size(); j++) {
if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equalsIgnoreCase("END")) {
index = j;
break;
}
}
if (index == -1) {
try {
throw new ParseFailedException("There exists syntax error and no END block is found!");
} catch (ParseFailedException e) {
e.printStackTrace();
}
}
ASTNode childNode = parseException(parseTokens.subList(i, index + 1));
currentNode.addChild(childNode);
currentNode = childNode.getDeepestChild();
childNode = new ProcedureEndNode();
for (int j = index; j < parseTokens.size(); j++) {
childNode.addToken(parseTokens.get(j));
if (parseTokens.get(j).hasType(Token.TokenType.EOF)) {
break;
}
}
currentNode.addChild(childNode);
currentNode = childNode;
break;
}
// match procedure end
else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("END")) {
ASTNode childNode = new ProcedureEndNode();
for (int j = i; j < parseTokens.size(); j++) {
childNode.addToken(parseTokens.get(j));
if (parseTokens.get(j).hasType(Token.TokenType.EOF)) {
break;
}
}
currentNode.addChild(childNode);
currentNode = childNode;
break;
}
else if (parseTokens.get(i).hasType(Token.TokenType.EOF)) {
break;
}
else {
try {
throw new ParseFailedException("Failed to parse:" + parseTokens.get(i));
}
catch (ParseFailedException e) {
e.printStackTrace();
}
}
}
return root;
}
}