reman3/scripts/cparser/Parser.java

203 lines
5.8 KiB
Java

package cparser;
import java.util.*;
import cparser.Tokenizer.Token;
import cparser.Log;
public class Parser {
private Tokenizer.TokenSet tokenSet;
private List<Variable> variables;
private List<Function> functions;
private List<FunctionCall> functionCalls;
private Log log;
public Parser(Tokenizer.TokenSet tokenSet, Log log) {
this.tokenSet = tokenSet;
this.variables = new ArrayList<>();
this.functions = new ArrayList<>();
this.functionCalls = new ArrayList<>();
}
void log(String msg) {
if (log != null) {
log.log(msg);
}
}
int index = 0;
public void parse() {
Tokenizer.Token[] tokens = tokenSet.getTokens();
for (index = 0; index < tokens.length; index++) {
Tokenizer.Token token = tokens[index];
if (token.type == Tokenizer.TokenType.BLOCK_COMMENT || token.type == Tokenizer.TokenType.COMMENT) {
continue;
} else if (token.type == Tokenizer.TokenType.HASH) {
index = parsePreprocessorExpression();
} else if (tokens[index].type == Tokenizer.TokenType.IDENTIFIER) {
if (index + 1 < tokens.length && tokens[index + 1].type == Tokenizer.TokenType.L_PAREN) {
// Function call or declaration/definition
if (index > 0 && (tokens[index - 1].type == Tokenizer.TokenType.IDENTIFIER ||
tokens[index - 1].type == Tokenizer.TokenType.OTHER)) {
// Function declaration or definition
index = parseFunctionDeclaration();
} else {
// Function call
index = parseFunctionCall();
}
} else {
// Variable reference
index = parseVariableReference();
}
}
}
}
// Try to parse prep expression
private int parsePreprocessorExpression() {
int index = this.index;
if (tokenSet.tokens[index].type == Tokenizer.TokenType.HASH) {
int startLine = tokenSet.getLine(index);
while (index < tokenSet.tokens.length) {
if (tokenSet.getLine(index) > startLine) {
break;
}
index++;
}
// Find first next line token
index--;
}
return index;
}
// Try to parse function declaration and return the ending token index
private int parseFunctionDeclaration() {
Tokenizer.Token[] tokens = tokenSet.getTokens();
String name = tokenSet.getTextNoNewlines(tokens[index]);
int endIndex = findClosingParenthesis(index + 1);
if (endIndex == -1)
return index;
boolean isDefinition = false;
if (endIndex + 1 < tokens.length && tokens[endIndex + 1].type == Tokenizer.TokenType.L_BRACE) {
isDefinition = true;
endIndex = findClosingBrace(endIndex + 1);
}
if (endIndex == -1)
return index;
Function function = new Function(name, tokens[index].ofs, tokens[endIndex].ofs + tokens[endIndex].len,
isDefinition);
functions.add(function);
return endIndex - 1;
}
// Try to parse function call and return the ending token index
private int parseFunctionCall() {
Tokenizer.Token[] tokens = tokenSet.getTokens();
String name = tokenSet.getTextNoNewlines(tokens[index]);
int endIndex = findClosingParenthesis(index + 1);
if (endIndex == -1)
return index;
FunctionCall functionCall = new FunctionCall(name, tokens[index].ofs,
tokens[endIndex].ofs + tokens[endIndex].len);
functionCalls.add(functionCall);
return endIndex - 1;
}
// Try to parse variable reference and add it to the list
private int parseVariableReference() {
Tokenizer.Token token = tokenSet.getTokens()[index];
String name = tokenSet.getTextNoNewlines(token);
Variable variable = new Variable(name, token.ofs, token.ofs + token.len);
variables.add(variable);
return index + 1;
}
private int findClosingParenthesis(int startIndex) {
Tokenizer.Token[] tokens = tokenSet.getTokens();
int parenCount = 1;
for (int i = startIndex + 1; i < tokens.length; i++) {
if (tokens[i].type == Tokenizer.TokenType.L_PAREN) {
parenCount++;
} else if (tokens[i].type == Tokenizer.TokenType.R_PAREN) {
parenCount--;
if (parenCount == 0) {
return i;
}
}
}
return -1;
}
private int findClosingBrace(int startIndex) {
Tokenizer.Token[] tokens = tokenSet.getTokens();
int braceCount = 1;
for (int i = startIndex + 1; i < tokens.length; i++) {
if (tokens[i].type == Tokenizer.TokenType.L_BRACE) {
braceCount++;
} else if (tokens[i].type == Tokenizer.TokenType.R_BRACE) {
braceCount--;
if (braceCount == 0) {
return i;
}
}
}
return -1;
}
public List<Variable> getVariables() {
return variables;
}
public List<Function> getFunctions() {
return functions;
}
public List<FunctionCall> getFunctionCalls() {
return functionCalls;
}
public static class Variable {
public final String name;
public final int startOffset;
public final int endOffset;
public Variable(String name, int startOffset, int endOffset) {
this.name = name;
this.startOffset = startOffset;
this.endOffset = endOffset;
}
}
public static class Function {
public final String name;
public final int startOffset;
public final int endOffset;
public final boolean isDefinition;
public Function(String name, int startOffset, int endOffset, boolean isDefinition) {
this.name = name;
this.startOffset = startOffset;
this.endOffset = endOffset;
this.isDefinition = isDefinition;
}
}
public static class FunctionCall {
public final String name;
public final int startOffset;
public final int endOffset;
public FunctionCall(String name, int startOffset, int endOffset) {
this.name = name;
this.startOffset = startOffset;
this.endOffset = endOffset;
}
}
}