package cparser; import java.util.*; import cparser.Tokenizer.Token; import cparser.Log; public class Parser { private Tokenizer.TokenSet tokenSet; private List variables; private List functions; private List 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 getVariables() { return variables; } public List getFunctions() { return functions; } public List 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; } } }