195 lines
5.7 KiB
Java
195 lines
5.7 KiB
Java
package re3lib;
|
|
|
|
import java.util.*;
|
|
|
|
import re3lib.CTokenizer.Token;
|
|
|
|
public class CParser {
|
|
private CTokenizer.TokenSet tokenSet;
|
|
private List<Variable> variables;
|
|
private List<Function> functions;
|
|
private List<FunctionCall> functionCalls;
|
|
|
|
public CParser(CTokenizer.TokenSet tokenSet) {
|
|
this.tokenSet = tokenSet;
|
|
this.variables = new ArrayList<>();
|
|
this.functions = new ArrayList<>();
|
|
this.functionCalls = new ArrayList<>();
|
|
}
|
|
|
|
int index = 0;
|
|
|
|
public void parse() {
|
|
CTokenizer.Token[] tokens = tokenSet.getTokens();
|
|
for (index = 0; index < tokens.length; index++) {
|
|
CTokenizer.Token token = tokens[index];
|
|
if (token.type == CTokenizer.TokenType.BLOCK_COMMENT || token.type == CTokenizer.TokenType.COMMENT) {
|
|
continue;
|
|
} else if (token.type == CTokenizer.TokenType.HASH) {
|
|
index = parsePreprocessorExpression();
|
|
} else if (tokens[index].type == CTokenizer.TokenType.IDENTIFIER) {
|
|
if (index + 1 < tokens.length && tokens[index + 1].type == CTokenizer.TokenType.L_PAREN) {
|
|
// Function call or declaration/definition
|
|
if (index > 0 && (tokens[index - 1].type == CTokenizer.TokenType.IDENTIFIER ||
|
|
tokens[index - 1].type == CTokenizer.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 == CTokenizer.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() {
|
|
CTokenizer.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 == CTokenizer.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() {
|
|
CTokenizer.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() {
|
|
CTokenizer.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) {
|
|
CTokenizer.Token[] tokens = tokenSet.getTokens();
|
|
int parenCount = 1;
|
|
for (int i = startIndex + 1; i < tokens.length; i++) {
|
|
if (tokens[i].type == CTokenizer.TokenType.L_PAREN) {
|
|
parenCount++;
|
|
} else if (tokens[i].type == CTokenizer.TokenType.R_PAREN) {
|
|
parenCount--;
|
|
if (parenCount == 0) {
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
private int findClosingBrace(int startIndex) {
|
|
CTokenizer.Token[] tokens = tokenSet.getTokens();
|
|
int braceCount = 1;
|
|
for (int i = startIndex + 1; i < tokens.length; i++) {
|
|
if (tokens[i].type == CTokenizer.TokenType.L_BRACE) {
|
|
braceCount++;
|
|
} else if (tokens[i].type == CTokenizer.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;
|
|
}
|
|
}
|
|
}
|