forked from opengaussexamples/examples
AST node
This commit is contained in:
parent
db166f7b5c
commit
d4aa1c1ffd
|
|
@ -4,16 +4,12 @@
|
|||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="d8d12963-4777-48e3-9669-309cf5e41d60" name="更改" comment="init">
|
||||
<change afterPath="$PROJECT_DIR$/.idea/compiler.xml" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/.idea/encodings.xml" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/.idea/jarRepositories.xml" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/Lexer/OracleLexer.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/Lexer/Token.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/Main.java" afterDir="false" />
|
||||
<list default="true" id="d8d12963-4777-48e3-9669-309cf5e41d60" name="更改" comment="lexer">
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/ASTNode.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/org/example/App.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/test/java/org/example/AppTest.java" beforeDir="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/Lexer/Token.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Lexer/Token.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/Main.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Main.java" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
|
|
@ -45,13 +41,13 @@
|
|||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"SHARE_PROJECT_CONFIGURATION_FILES": "true"
|
||||
<component name="PropertiesComponent">{
|
||||
"keyToString": {
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"SHARE_PROJECT_CONFIGURATION_FILES": "true"
|
||||
}
|
||||
}]]></component>
|
||||
}</component>
|
||||
<component name="RunManager" selected="应用程序.Main">
|
||||
<configuration name="App" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true">
|
||||
<option name="MAIN_CLASS_NAME" value="org.example.App" />
|
||||
|
|
@ -113,7 +109,14 @@
|
|||
<option name="project" value="LOCAL" />
|
||||
<updated>1723106890550</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="2" />
|
||||
<task id="LOCAL-00002" summary="lexer">
|
||||
<created>1723818930161</created>
|
||||
<option name="number" value="00002" />
|
||||
<option name="presentableId" value="LOCAL-00002" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1723818930161</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="3" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="Vcs.Log.Tabs.Properties">
|
||||
|
|
@ -129,6 +132,7 @@
|
|||
</component>
|
||||
<component name="VcsManagerConfiguration">
|
||||
<MESSAGE value="init" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="init" />
|
||||
<MESSAGE value="lexer" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="lexer" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -8,7 +8,8 @@ import java.util.regex.Pattern;
|
|||
|
||||
|
||||
public class OracleLexer {
|
||||
public static final String[] keywords = {"SELECT", "FROM", "WHERE", "AND", "OR", "INSERT", "UPDATE", "DELETE", "now()"};
|
||||
public static final String[] keywords = {"SELECT", "FROM", "WHERE", "AND", "OR", "INSERT", "UPDATE", "DELETE",
|
||||
"now()"};
|
||||
private static final Pattern TOKEN_PATTERN = Pattern.compile(
|
||||
"(now\\(\\))|" + // now() function
|
||||
"(\\b[A-Za-z_][A-Za-z0-9_]*\\b)|" + // Keywords and identifiers
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ public class Token {
|
|||
KEYWORD, IDENTIFIER, NUMBER, OPERATOR, STRING, SYMBOL, EOF
|
||||
}
|
||||
|
||||
private final TokenType type;
|
||||
private TokenType type;
|
||||
private final String value;
|
||||
|
||||
public Token(TokenType type, String value) {
|
||||
|
|
@ -21,6 +21,10 @@ public class Token {
|
|||
return value;
|
||||
}
|
||||
|
||||
public boolean hasType(TokenType type) {
|
||||
return this.type == type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Token{" +
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import java.util.List;
|
|||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
String sql = "SELECT now() FROM table WHERE name = 'John Doe';";
|
||||
String sql = "SELECT adef FROM table WHERE name = 'John Doe';";
|
||||
OracleLexer lexer = new OracleLexer(sql);
|
||||
List<Token> tokens = lexer.tokenize();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,145 @@
|
|||
package Parser;
|
||||
|
||||
import Lexer.Token;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class ASTNode {
|
||||
private Token token;
|
||||
private ASTNode parent;
|
||||
private List<ASTNode> children = new ArrayList<>();
|
||||
|
||||
public ASTNode(Token token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public ASTNode(ASTNode node) {
|
||||
this.token = node.token;
|
||||
this.parent = node.parent;
|
||||
this.children = new ArrayList<>(node.children);
|
||||
}
|
||||
|
||||
public Token getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(Token token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public ASTNode getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void setParent(ASTNode parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public List<ASTNode> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
public ASTNode getChildByName(String childName) {
|
||||
for (ASTNode child : children) {
|
||||
if (child.toString().equals(childName)) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<ASTNode> getChildrenByName(String childName) {
|
||||
List<ASTNode> nodes = new ArrayList<>();
|
||||
for (ASTNode child : children) {
|
||||
if (child.toString().equals(childName)) {
|
||||
nodes.add(child);
|
||||
}
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将对应名称的node更新为新的child
|
||||
*/
|
||||
public void setChildrenByName(String childName, ASTNode child) {
|
||||
for (int i = 0; i < this.children.size(); i++) {
|
||||
if (this.children.get(i).getToken().getValue().contains(childName)) {
|
||||
this.children.set(i, child);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addChild(ASTNode childNode) {
|
||||
childNode.setParent(this);
|
||||
children.add(childNode);
|
||||
}
|
||||
|
||||
public void replaceChild(ASTNode oldChild, ASTNode newChild) {
|
||||
newChild.setParent(this);
|
||||
children.set(children.indexOf(oldChild), newChild);
|
||||
}
|
||||
|
||||
// add a child node at position index of children
|
||||
public void addChild(int index, ASTNode childNode) {
|
||||
childNode.setParent(this);
|
||||
children.add(index, childNode);
|
||||
}
|
||||
|
||||
public void removeChild(ASTNode childNode) {
|
||||
children.remove(childNode);
|
||||
}
|
||||
|
||||
public String toQueryString() {
|
||||
StringBuilder queryString = new StringBuilder();
|
||||
visit(this, queryString, false);
|
||||
return queryString.toString();
|
||||
}
|
||||
|
||||
private void visit(ASTNode node, StringBuilder queryString, boolean hasPrespace) {
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
if (node.getToken().hasType(Token.TokenType.KEYWORD)) {
|
||||
String value = node.getToken().getValue();
|
||||
if (value == null || value.trim().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
boolean preSpace = true;
|
||||
if (queryString.length() == 0) {
|
||||
preSpace = false;
|
||||
} else if (queryString.charAt(queryString.length() - 1) == '(') {
|
||||
preSpace = false;
|
||||
} else if (Arrays.asList(",", ";", ")").contains(value)) {
|
||||
preSpace = false;
|
||||
} else if (!hasPrespace) {
|
||||
// If the token does not have pre space, we should not add, either.
|
||||
preSpace = false;
|
||||
}
|
||||
if (preSpace) {
|
||||
queryString.append(" ");
|
||||
}
|
||||
queryString.append(value);
|
||||
} else {
|
||||
for (int i = 0; i < node.getChildren().size(); i++) {
|
||||
ASTNode childNode = node.getChildren().get(i);
|
||||
if (i == 0) {
|
||||
visit(childNode, queryString, hasPrespace || childNode.getToken().hasPreSpace());
|
||||
} else {
|
||||
visit(childNode, queryString, childNode.getToken().hasPreSpace());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return token.getValue();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue