This commit is contained in:
XudongXie 2024-08-17 13:15:41 +08:00
parent db166f7b5c
commit d4aa1c1ffd
5 changed files with 174 additions and 20 deletions

View File

@ -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">{
&quot;keyToString&quot;: {
&quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;SHARE_PROJECT_CONFIGURATION_FILES&quot;: &quot;true&quot;
}
}]]></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>

View File

@ -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

View File

@ -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{" +

View File

@ -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();

View File

@ -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();
}
}