1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-08-01 17:29:45 +00:00

Added an expression parser to use for #if. #169

This commit is contained in:
jespergravgaard 2020-04-06 08:00:55 +02:00
parent 88b2cd86c2
commit 263987f059
3 changed files with 111 additions and 0 deletions

View File

@ -0,0 +1,35 @@
package dk.camelot64.kickc.parser;
import dk.camelot64.kickc.model.CompileError;
import org.antlr.v4.runtime.*;
/**
* Parser for C-expressions.
* <p>
* Used by #if in the preprocessor
*/
public class ExpressionParser {
/**
* Parse an expression
*
* @param tokenSource The tokens to parse
* @return The parsed expression
*/
public static KickCParser.ExprContext parseExpression(TokenSource tokenSource) {
CParser cParser = new CParser(null);
KickCParser kickCParser = new KickCParser(new CommonTokenStream(tokenSource), cParser);
kickCParser.addErrorListener(new BaseErrorListener() {
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
//StatementSource subSource =
// new StatementSource(source.getFileName(), source.getLineNumber() + line, source.getCode(), source.getStartIndex(), source.getStopIndex());
throw new CompileError("Error parsing expression " + msg);
}
});
kickCParser.setBuildParseTree(true);
return kickCParser.expr();
}
}

View File

@ -0,0 +1,73 @@
package dk.camelot64.kickc.parsing;
import dk.camelot64.kickc.parser.*;
import junit.framework.TestCase;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CodePointCharStream;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.junit.Test;
import java.io.IOException;
import java.net.URISyntaxException;
public class TestExpressionParser {
/**
* Test the ExpressionParser
*/
@Test
public void testExpressionParser() {
assertExpression("1", "1");
assertExpression("1+1", "+(1,1)");
assertExpression("1+1*-2", "+(1,*(1,-(2)))");
assertExpression("(1+1)*2", "*([+(1,1)],2)");
assertExpression("FIELDS*2<MAX", "<(*(FIELDS,2),MAX)");
}
private void assertExpression(String expr, String expected) {
CodePointCharStream fragmentCharStream = CharStreams.fromString(expr);
CParser cParser = new CParser(null);
KickCLexer kickCLexer = new KickCLexer(fragmentCharStream, cParser);
KickCParser.ExprContext exprContext = ExpressionParser.parseExpression(kickCLexer);
final KickCParserBaseVisitor<String> exprVisitor = new ExprPrinter();
final String exprOut = exprVisitor.visit(exprContext);
TestCase.assertEquals("Expression output does not match ", expected, exprOut);
}
/** Prints the expression. */
private static class ExprPrinter extends KickCParserBaseVisitor<String> {
@Override
public String visitExprBinary(KickCParser.ExprBinaryContext ctx) {
final String left = this.visit(ctx.expr(0));
String op = ((TerminalNode) ctx.getChild(1)).getSymbol().getText();
final String right = this.visit(ctx.expr(1));
return op+"("+left+","+right+")";
}
@Override
public String visitExprUnary(KickCParser.ExprUnaryContext ctx) {
String op = ((TerminalNode) ctx.getChild(0)).getSymbol().getText();
final String right = this.visit(ctx.expr());
return op+"("+right+")";
}
@Override
public String visitExprPar(KickCParser.ExprParContext ctx) {
final String sub = this.visit(ctx.commaExpr());
return "["+sub+"]";
}
@Override
public String visitExprNumber(KickCParser.ExprNumberContext ctx) {
return ctx.NUMBER().getText();
}
@Override
public String visitExprId(KickCParser.ExprIdContext ctx) {
return ctx.NAME().getText();
}
}
}

View File

@ -14,6 +14,9 @@ import java.nio.file.Paths;
public class TestKickAssRun {
/**
* Test running KickAsm assembler to compile an ASM file
*/
@Test
public void testKickAssRun() throws IOException, URISyntaxException {
ReferenceHelper asmHelper = new ReferenceHelperFolder("src/test/java/dk/camelot64/kickc/test/");