diff --git a/src/test/java/dk/camelot64/kickc/parsing/macros/CMacroExpander.java b/src/test/java/dk/camelot64/kickc/parsing/macros/CMacroExpander.java new file mode 100644 index 000000000..87d0835c8 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/parsing/macros/CMacroExpander.java @@ -0,0 +1,37 @@ +package dk.camelot64.kickc.parsing.macros; + +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.TokenStreamRewriter; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Capable of defining and expanding C macros + */ +public class CMacroExpander { + + Map macros; + TokenStreamRewriter rewriter; + + public CMacroExpander() { + this.macros = new LinkedHashMap<>(); + macros.put("A", "a"); + } + + public void setRewriter(TokenStreamRewriter rewriter) { + this.rewriter = rewriter; + } + + public void define(String macroDefine) { + System.out.println("Macro defined: "+macroDefine); + } + + public void expand(String text) { + final String expanded = macros.get(text); + if(expanded != null) { + throw new RuntimeException("Macro expansion!"); + } + } + +} diff --git a/src/test/java/dk/camelot64/kickc/parsing/macros/Macros.g4 b/src/test/java/dk/camelot64/kickc/parsing/macros/Macros.g4 new file mode 100644 index 000000000..65ff90aad --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/parsing/macros/Macros.g4 @@ -0,0 +1,42 @@ +/** + * Minimal grammar implementing C macros + */ + +grammar Macros; + +@header { +} + +@parser::members { + CMacroExpander macros = new CMacroExpander(); +} + +@lexer::members { + CMacroExpander macros = new CMacroExpander(); +} + +stmtSeq + : stmt* + ; + +stmt + : expr ';' #stmtExpr + ; + +expr + : '(' SIMPLETYPE ')' expr #exprCast + | IDENTIFIER #exprName + | NUMBER #exprNumber + | '(' expr ')' #exprPar + | expr '*' expr #exprBinary + | expr '/' expr #exprBinary + | expr '+' expr #exprBinary + | expr '-' expr #exprBinary + ; + +SIMPLETYPE: 'char' | 'int' ; +IDENTIFIER: [a-zA-Z_]+ ; +NUMBER: [0-9]+ ; +DEFINE: '#define' ; +DEFINE_CONTINUE: '\\\n' ; +WHITESPACE: [ \t\r\n]+ -> skip ; diff --git a/src/test/java/dk/camelot64/kickc/parsing/macros/Macros.interp b/src/test/java/dk/camelot64/kickc/parsing/macros/Macros.interp new file mode 100644 index 000000000..b0575fc2b --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/parsing/macros/Macros.interp @@ -0,0 +1,40 @@ +token literal names: +null +';' +'(' +')' +'*' +'/' +'+' +'-' +null +null +null +'#define' +'\\\n' +null + +token symbolic names: +null +null +null +null +null +null +null +null +SIMPLETYPE +IDENTIFIER +NUMBER +DEFINE +DEFINE_CONTINUE +WHITESPACE + +rule names: +stmtSeq +stmt +expr + + +atn: +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 15, 48, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 3, 2, 7, 2, 10, 10, 2, 12, 2, 14, 2, 13, 11, 2, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 29, 10, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 7, 4, 43, 10, 4, 12, 4, 14, 4, 46, 11, 4, 3, 4, 2, 3, 6, 5, 2, 4, 6, 2, 2, 2, 52, 2, 11, 3, 2, 2, 2, 4, 14, 3, 2, 2, 2, 6, 28, 3, 2, 2, 2, 8, 10, 5, 4, 3, 2, 9, 8, 3, 2, 2, 2, 10, 13, 3, 2, 2, 2, 11, 9, 3, 2, 2, 2, 11, 12, 3, 2, 2, 2, 12, 3, 3, 2, 2, 2, 13, 11, 3, 2, 2, 2, 14, 15, 5, 6, 4, 2, 15, 16, 7, 3, 2, 2, 16, 5, 3, 2, 2, 2, 17, 18, 8, 4, 1, 2, 18, 19, 7, 4, 2, 2, 19, 20, 7, 10, 2, 2, 20, 21, 7, 5, 2, 2, 21, 29, 5, 6, 4, 10, 22, 29, 7, 11, 2, 2, 23, 29, 7, 12, 2, 2, 24, 25, 7, 4, 2, 2, 25, 26, 5, 6, 4, 2, 26, 27, 7, 5, 2, 2, 27, 29, 3, 2, 2, 2, 28, 17, 3, 2, 2, 2, 28, 22, 3, 2, 2, 2, 28, 23, 3, 2, 2, 2, 28, 24, 3, 2, 2, 2, 29, 44, 3, 2, 2, 2, 30, 31, 12, 6, 2, 2, 31, 32, 7, 6, 2, 2, 32, 43, 5, 6, 4, 7, 33, 34, 12, 5, 2, 2, 34, 35, 7, 7, 2, 2, 35, 43, 5, 6, 4, 6, 36, 37, 12, 4, 2, 2, 37, 38, 7, 8, 2, 2, 38, 43, 5, 6, 4, 5, 39, 40, 12, 3, 2, 2, 40, 41, 7, 9, 2, 2, 41, 43, 5, 6, 4, 4, 42, 30, 3, 2, 2, 2, 42, 33, 3, 2, 2, 2, 42, 36, 3, 2, 2, 2, 42, 39, 3, 2, 2, 2, 43, 46, 3, 2, 2, 2, 44, 42, 3, 2, 2, 2, 44, 45, 3, 2, 2, 2, 45, 7, 3, 2, 2, 2, 46, 44, 3, 2, 2, 2, 6, 11, 28, 42, 44] \ No newline at end of file diff --git a/src/test/java/dk/camelot64/kickc/parsing/macros/Macros.tokens b/src/test/java/dk/camelot64/kickc/parsing/macros/Macros.tokens new file mode 100644 index 000000000..873a49397 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/parsing/macros/Macros.tokens @@ -0,0 +1,22 @@ +T__0=1 +T__1=2 +T__2=3 +T__3=4 +T__4=5 +T__5=6 +T__6=7 +SIMPLETYPE=8 +IDENTIFIER=9 +NUMBER=10 +DEFINE=11 +DEFINE_CONTINUE=12 +WHITESPACE=13 +';'=1 +'('=2 +')'=3 +'*'=4 +'/'=5 +'+'=6 +'-'=7 +'#define'=11 +'\\\n'=12 diff --git a/src/test/java/dk/camelot64/kickc/parsing/macros/MacrosBaseListener.java b/src/test/java/dk/camelot64/kickc/parsing/macros/MacrosBaseListener.java new file mode 100644 index 000000000..cd6a72974 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/parsing/macros/MacrosBaseListener.java @@ -0,0 +1,125 @@ +// Generated from /Users/jespergravgaard/c64/kickc/src/test/java/dk/camelot64/kickc/parsing/macros/Macros.g4 by ANTLR 4.7.2 +package dk.camelot64.kickc.parsing.macros; + + + +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.tree.ErrorNode; +import org.antlr.v4.runtime.tree.TerminalNode; + +/** + * This class provides an empty implementation of {@link MacrosListener}, + * which can be extended to create a listener which only needs to handle a subset + * of the available methods. + */ +public class MacrosBaseListener implements MacrosListener { + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterStmtSeq(MacrosParser.StmtSeqContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitStmtSeq(MacrosParser.StmtSeqContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterStmtExpr(MacrosParser.StmtExprContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitStmtExpr(MacrosParser.StmtExprContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterExprCast(MacrosParser.ExprCastContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitExprCast(MacrosParser.ExprCastContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterExprBinary(MacrosParser.ExprBinaryContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitExprBinary(MacrosParser.ExprBinaryContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterExprPar(MacrosParser.ExprParContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitExprPar(MacrosParser.ExprParContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterExprNumber(MacrosParser.ExprNumberContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitExprNumber(MacrosParser.ExprNumberContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterExprName(MacrosParser.ExprNameContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitExprName(MacrosParser.ExprNameContext ctx) { } + + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterEveryRule(ParserRuleContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitEveryRule(ParserRuleContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void visitTerminal(TerminalNode node) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void visitErrorNode(ErrorNode node) { } +} \ No newline at end of file diff --git a/src/test/java/dk/camelot64/kickc/parsing/macros/MacrosBaseVisitor.java b/src/test/java/dk/camelot64/kickc/parsing/macros/MacrosBaseVisitor.java new file mode 100644 index 000000000..1aa7f4efa --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/parsing/macros/MacrosBaseVisitor.java @@ -0,0 +1,65 @@ +// Generated from /Users/jespergravgaard/c64/kickc/src/test/java/dk/camelot64/kickc/parsing/macros/Macros.g4 by ANTLR 4.7.2 +package dk.camelot64.kickc.parsing.macros; + + +import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor; + +/** + * This class provides an empty implementation of {@link MacrosVisitor}, + * which can be extended to create a visitor which only needs to handle a subset + * of the available methods. + * + * @param The return type of the visit operation. Use {@link Void} for + * operations with no return type. + */ +public class MacrosBaseVisitor extends AbstractParseTreeVisitor implements MacrosVisitor { + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitStmtSeq(MacrosParser.StmtSeqContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitStmtExpr(MacrosParser.StmtExprContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitExprCast(MacrosParser.ExprCastContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitExprBinary(MacrosParser.ExprBinaryContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitExprPar(MacrosParser.ExprParContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitExprNumber(MacrosParser.ExprNumberContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitExprName(MacrosParser.ExprNameContext ctx) { return visitChildren(ctx); } +} \ No newline at end of file diff --git a/src/test/java/dk/camelot64/kickc/parsing/macros/MacrosLexer.interp b/src/test/java/dk/camelot64/kickc/parsing/macros/MacrosLexer.interp new file mode 100644 index 000000000..17b156618 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/parsing/macros/MacrosLexer.interp @@ -0,0 +1,56 @@ +token literal names: +null +';' +'(' +')' +'*' +'/' +'+' +'-' +null +null +null +'#define' +'\\\n' +null + +token symbolic names: +null +null +null +null +null +null +null +null +SIMPLETYPE +IDENTIFIER +NUMBER +DEFINE +DEFINE_CONTINUE +WHITESPACE + +rule names: +T__0 +T__1 +T__2 +T__3 +T__4 +T__5 +T__6 +SIMPLETYPE +IDENTIFIER +NUMBER +DEFINE +DEFINE_CONTINUE +WHITESPACE + +channel names: +DEFAULT_TOKEN_CHANNEL +HIDDEN + +mode names: +DEFAULT_MODE + +atn: +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 15, 80, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 3, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 5, 9, 51, 10, 9, 3, 10, 6, 10, 54, 10, 10, 13, 10, 14, 10, 55, 3, 11, 6, 11, 59, 10, 11, 13, 11, 14, 11, 60, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 14, 6, 14, 75, 10, 14, 13, 14, 14, 14, 76, 3, 14, 3, 14, 2, 2, 15, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 3, 2, 5, 5, 2, 67, 92, 97, 97, 99, 124, 3, 2, 50, 59, 5, 2, 11, 12, 15, 15, 34, 34, 2, 83, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 3, 29, 3, 2, 2, 2, 5, 31, 3, 2, 2, 2, 7, 33, 3, 2, 2, 2, 9, 35, 3, 2, 2, 2, 11, 37, 3, 2, 2, 2, 13, 39, 3, 2, 2, 2, 15, 41, 3, 2, 2, 2, 17, 50, 3, 2, 2, 2, 19, 53, 3, 2, 2, 2, 21, 58, 3, 2, 2, 2, 23, 62, 3, 2, 2, 2, 25, 70, 3, 2, 2, 2, 27, 74, 3, 2, 2, 2, 29, 30, 7, 61, 2, 2, 30, 4, 3, 2, 2, 2, 31, 32, 7, 42, 2, 2, 32, 6, 3, 2, 2, 2, 33, 34, 7, 43, 2, 2, 34, 8, 3, 2, 2, 2, 35, 36, 7, 44, 2, 2, 36, 10, 3, 2, 2, 2, 37, 38, 7, 49, 2, 2, 38, 12, 3, 2, 2, 2, 39, 40, 7, 45, 2, 2, 40, 14, 3, 2, 2, 2, 41, 42, 7, 47, 2, 2, 42, 16, 3, 2, 2, 2, 43, 44, 7, 101, 2, 2, 44, 45, 7, 106, 2, 2, 45, 46, 7, 99, 2, 2, 46, 51, 7, 116, 2, 2, 47, 48, 7, 107, 2, 2, 48, 49, 7, 112, 2, 2, 49, 51, 7, 118, 2, 2, 50, 43, 3, 2, 2, 2, 50, 47, 3, 2, 2, 2, 51, 18, 3, 2, 2, 2, 52, 54, 9, 2, 2, 2, 53, 52, 3, 2, 2, 2, 54, 55, 3, 2, 2, 2, 55, 53, 3, 2, 2, 2, 55, 56, 3, 2, 2, 2, 56, 20, 3, 2, 2, 2, 57, 59, 9, 3, 2, 2, 58, 57, 3, 2, 2, 2, 59, 60, 3, 2, 2, 2, 60, 58, 3, 2, 2, 2, 60, 61, 3, 2, 2, 2, 61, 22, 3, 2, 2, 2, 62, 63, 7, 37, 2, 2, 63, 64, 7, 102, 2, 2, 64, 65, 7, 103, 2, 2, 65, 66, 7, 104, 2, 2, 66, 67, 7, 107, 2, 2, 67, 68, 7, 112, 2, 2, 68, 69, 7, 103, 2, 2, 69, 24, 3, 2, 2, 2, 70, 71, 7, 94, 2, 2, 71, 72, 7, 12, 2, 2, 72, 26, 3, 2, 2, 2, 73, 75, 9, 4, 2, 2, 74, 73, 3, 2, 2, 2, 75, 76, 3, 2, 2, 2, 76, 74, 3, 2, 2, 2, 76, 77, 3, 2, 2, 2, 77, 78, 3, 2, 2, 2, 78, 79, 8, 14, 2, 2, 79, 28, 3, 2, 2, 2, 7, 2, 50, 55, 60, 76, 3, 8, 2, 2] \ No newline at end of file diff --git a/src/test/java/dk/camelot64/kickc/parsing/macros/MacrosLexer.java b/src/test/java/dk/camelot64/kickc/parsing/macros/MacrosLexer.java new file mode 100644 index 000000000..e4b498257 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/parsing/macros/MacrosLexer.java @@ -0,0 +1,145 @@ +// Generated from /Users/jespergravgaard/c64/kickc/src/test/java/dk/camelot64/kickc/parsing/macros/Macros.g4 by ANTLR 4.7.2 +package dk.camelot64.kickc.parsing.macros; + + +import org.antlr.v4.runtime.Lexer; +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.TokenStream; +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.atn.*; +import org.antlr.v4.runtime.dfa.DFA; +import org.antlr.v4.runtime.misc.*; + +@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) +public class MacrosLexer extends Lexer { + static { RuntimeMetaData.checkVersion("4.7.2", RuntimeMetaData.VERSION); } + + protected static final DFA[] _decisionToDFA; + protected static final PredictionContextCache _sharedContextCache = + new PredictionContextCache(); + public static final int + T__0=1, T__1=2, T__2=3, T__3=4, T__4=5, T__5=6, T__6=7, SIMPLETYPE=8, + IDENTIFIER=9, NUMBER=10, DEFINE=11, DEFINE_CONTINUE=12, WHITESPACE=13; + public static String[] channelNames = { + "DEFAULT_TOKEN_CHANNEL", "HIDDEN" + }; + + public static String[] modeNames = { + "DEFAULT_MODE" + }; + + private static String[] makeRuleNames() { + return new String[] { + "T__0", "T__1", "T__2", "T__3", "T__4", "T__5", "T__6", "SIMPLETYPE", + "IDENTIFIER", "NUMBER", "DEFINE", "DEFINE_CONTINUE", "WHITESPACE" + }; + } + public static final String[] ruleNames = makeRuleNames(); + + private static String[] makeLiteralNames() { + return new String[] { + null, "';'", "'('", "')'", "'*'", "'/'", "'+'", "'-'", null, null, null, + "'#define'", "'\\\n'" + }; + } + private static final String[] _LITERAL_NAMES = makeLiteralNames(); + private static String[] makeSymbolicNames() { + return new String[] { + null, null, null, null, null, null, null, null, "SIMPLETYPE", "IDENTIFIER", + "NUMBER", "DEFINE", "DEFINE_CONTINUE", "WHITESPACE" + }; + } + private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); + public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); + + /** + * @deprecated Use {@link #VOCABULARY} instead. + */ + @Deprecated + public static final String[] tokenNames; + static { + tokenNames = new String[_SYMBOLIC_NAMES.length]; + for (int i = 0; i < tokenNames.length; i++) { + tokenNames[i] = VOCABULARY.getLiteralName(i); + if (tokenNames[i] == null) { + tokenNames[i] = VOCABULARY.getSymbolicName(i); + } + + if (tokenNames[i] == null) { + tokenNames[i] = ""; + } + } + } + + @Override + @Deprecated + public String[] getTokenNames() { + return tokenNames; + } + + @Override + + public Vocabulary getVocabulary() { + return VOCABULARY; + } + + + CMacroExpander macros = new CMacroExpander(); + + + public MacrosLexer(CharStream input) { + super(input); + _interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); + } + + @Override + public String getGrammarFileName() { return "Macros.g4"; } + + @Override + public String[] getRuleNames() { return ruleNames; } + + @Override + public String getSerializedATN() { return _serializedATN; } + + @Override + public String[] getChannelNames() { return channelNames; } + + @Override + public String[] getModeNames() { return modeNames; } + + @Override + public ATN getATN() { return _ATN; } + + public static final String _serializedATN = + "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\17P\b\1\4\2\t\2\4"+ + "\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t"+ + "\13\4\f\t\f\4\r\t\r\4\16\t\16\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\6\3\6"+ + "\3\7\3\7\3\b\3\b\3\t\3\t\3\t\3\t\3\t\3\t\3\t\5\t\63\n\t\3\n\6\n\66\n\n"+ + "\r\n\16\n\67\3\13\6\13;\n\13\r\13\16\13<\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3"+ + "\f\3\r\3\r\3\r\3\16\6\16K\n\16\r\16\16\16L\3\16\3\16\2\2\17\3\3\5\4\7"+ + "\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16\33\17\3\2\5\5\2C\\aac"+ + "|\3\2\62;\5\2\13\f\17\17\"\"\2S\2\3\3\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2"+ + "\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2"+ + "\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2\2\3\35\3\2\2\2"+ + "\5\37\3\2\2\2\7!\3\2\2\2\t#\3\2\2\2\13%\3\2\2\2\r\'\3\2\2\2\17)\3\2\2"+ + "\2\21\62\3\2\2\2\23\65\3\2\2\2\25:\3\2\2\2\27>\3\2\2\2\31F\3\2\2\2\33"+ + "J\3\2\2\2\35\36\7=\2\2\36\4\3\2\2\2\37 \7*\2\2 \6\3\2\2\2!\"\7+\2\2\""+ + "\b\3\2\2\2#$\7,\2\2$\n\3\2\2\2%&\7\61\2\2&\f\3\2\2\2\'(\7-\2\2(\16\3\2"+ + "\2\2)*\7/\2\2*\20\3\2\2\2+,\7e\2\2,-\7j\2\2-.\7c\2\2.\63\7t\2\2/\60\7"+ + "k\2\2\60\61\7p\2\2\61\63\7v\2\2\62+\3\2\2\2\62/\3\2\2\2\63\22\3\2\2\2"+ + "\64\66\t\2\2\2\65\64\3\2\2\2\66\67\3\2\2\2\67\65\3\2\2\2\678\3\2\2\28"+ + "\24\3\2\2\29;\t\3\2\2:9\3\2\2\2;<\3\2\2\2<:\3\2\2\2<=\3\2\2\2=\26\3\2"+ + "\2\2>?\7%\2\2?@\7f\2\2@A\7g\2\2AB\7h\2\2BC\7k\2\2CD\7p\2\2DE\7g\2\2E\30"+ + "\3\2\2\2FG\7^\2\2GH\7\f\2\2H\32\3\2\2\2IK\t\4\2\2JI\3\2\2\2KL\3\2\2\2"+ + "LJ\3\2\2\2LM\3\2\2\2MN\3\2\2\2NO\b\16\2\2O\34\3\2\2\2\7\2\62\67 stmt() { + return getRuleContexts(StmtContext.class); + } + public StmtContext stmt(int i) { + return getRuleContext(StmtContext.class,i); + } + public StmtSeqContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_stmtSeq; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof MacrosListener ) ((MacrosListener)listener).enterStmtSeq(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof MacrosListener ) ((MacrosListener)listener).exitStmtSeq(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof MacrosVisitor ) return ((MacrosVisitor)visitor).visitStmtSeq(this); + else return visitor.visitChildren(this); + } + } + + public final StmtSeqContext stmtSeq() throws RecognitionException { + StmtSeqContext _localctx = new StmtSeqContext(_ctx, getState()); + enterRule(_localctx, 0, RULE_stmtSeq); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(9); + _errHandler.sync(this); + _la = _input.LA(1); + while ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__1) | (1L << IDENTIFIER) | (1L << NUMBER))) != 0)) { + { + { + setState(6); + stmt(); + } + } + setState(11); + _errHandler.sync(this); + _la = _input.LA(1); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class StmtContext extends ParserRuleContext { + public StmtContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_stmt; } + + public StmtContext() { } + public void copyFrom(StmtContext ctx) { + super.copyFrom(ctx); + } + } + public static class StmtExprContext extends StmtContext { + public ExprContext expr() { + return getRuleContext(ExprContext.class,0); + } + public StmtExprContext(StmtContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof MacrosListener ) ((MacrosListener)listener).enterStmtExpr(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof MacrosListener ) ((MacrosListener)listener).exitStmtExpr(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof MacrosVisitor ) return ((MacrosVisitor)visitor).visitStmtExpr(this); + else return visitor.visitChildren(this); + } + } + + public final StmtContext stmt() throws RecognitionException { + StmtContext _localctx = new StmtContext(_ctx, getState()); + enterRule(_localctx, 2, RULE_stmt); + try { + _localctx = new StmtExprContext(_localctx); + enterOuterAlt(_localctx, 1); + { + setState(12); + expr(0); + setState(13); + match(T__0); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ExprContext extends ParserRuleContext { + public ExprContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_expr; } + + public ExprContext() { } + public void copyFrom(ExprContext ctx) { + super.copyFrom(ctx); + } + } + public static class ExprCastContext extends ExprContext { + public TerminalNode SIMPLETYPE() { return getToken(MacrosParser.SIMPLETYPE, 0); } + public ExprContext expr() { + return getRuleContext(ExprContext.class,0); + } + public ExprCastContext(ExprContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof MacrosListener ) ((MacrosListener)listener).enterExprCast(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof MacrosListener ) ((MacrosListener)listener).exitExprCast(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof MacrosVisitor ) return ((MacrosVisitor)visitor).visitExprCast(this); + else return visitor.visitChildren(this); + } + } + public static class ExprBinaryContext extends ExprContext { + public List expr() { + return getRuleContexts(ExprContext.class); + } + public ExprContext expr(int i) { + return getRuleContext(ExprContext.class,i); + } + public ExprBinaryContext(ExprContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof MacrosListener ) ((MacrosListener)listener).enterExprBinary(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof MacrosListener ) ((MacrosListener)listener).exitExprBinary(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof MacrosVisitor ) return ((MacrosVisitor)visitor).visitExprBinary(this); + else return visitor.visitChildren(this); + } + } + public static class ExprParContext extends ExprContext { + public ExprContext expr() { + return getRuleContext(ExprContext.class,0); + } + public ExprParContext(ExprContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof MacrosListener ) ((MacrosListener)listener).enterExprPar(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof MacrosListener ) ((MacrosListener)listener).exitExprPar(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof MacrosVisitor ) return ((MacrosVisitor)visitor).visitExprPar(this); + else return visitor.visitChildren(this); + } + } + public static class ExprNumberContext extends ExprContext { + public TerminalNode NUMBER() { return getToken(MacrosParser.NUMBER, 0); } + public ExprNumberContext(ExprContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof MacrosListener ) ((MacrosListener)listener).enterExprNumber(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof MacrosListener ) ((MacrosListener)listener).exitExprNumber(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof MacrosVisitor ) return ((MacrosVisitor)visitor).visitExprNumber(this); + else return visitor.visitChildren(this); + } + } + public static class ExprNameContext extends ExprContext { + public TerminalNode IDENTIFIER() { return getToken(MacrosParser.IDENTIFIER, 0); } + public ExprNameContext(ExprContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof MacrosListener ) ((MacrosListener)listener).enterExprName(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof MacrosListener ) ((MacrosListener)listener).exitExprName(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof MacrosVisitor ) return ((MacrosVisitor)visitor).visitExprName(this); + else return visitor.visitChildren(this); + } + } + + public final ExprContext expr() throws RecognitionException { + return expr(0); + } + + private ExprContext expr(int _p) throws RecognitionException { + ParserRuleContext _parentctx = _ctx; + int _parentState = getState(); + ExprContext _localctx = new ExprContext(_ctx, _parentState); + ExprContext _prevctx = _localctx; + int _startState = 4; + enterRecursionRule(_localctx, 4, RULE_expr, _p); + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(26); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,1,_ctx) ) { + case 1: + { + _localctx = new ExprCastContext(_localctx); + _ctx = _localctx; + _prevctx = _localctx; + + setState(16); + match(T__1); + setState(17); + match(SIMPLETYPE); + setState(18); + match(T__2); + setState(19); + expr(8); + } + break; + case 2: + { + _localctx = new ExprNameContext(_localctx); + _ctx = _localctx; + _prevctx = _localctx; + setState(20); + match(IDENTIFIER); + } + break; + case 3: + { + _localctx = new ExprNumberContext(_localctx); + _ctx = _localctx; + _prevctx = _localctx; + setState(21); + match(NUMBER); + } + break; + case 4: + { + _localctx = new ExprParContext(_localctx); + _ctx = _localctx; + _prevctx = _localctx; + setState(22); + match(T__1); + setState(23); + expr(0); + setState(24); + match(T__2); + } + break; + } + _ctx.stop = _input.LT(-1); + setState(42); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,3,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + if ( _parseListeners!=null ) triggerExitRuleEvent(); + _prevctx = _localctx; + { + setState(40); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,2,_ctx) ) { + case 1: + { + _localctx = new ExprBinaryContext(new ExprContext(_parentctx, _parentState)); + pushNewRecursionContext(_localctx, _startState, RULE_expr); + setState(28); + if (!(precpred(_ctx, 4))) throw new FailedPredicateException(this, "precpred(_ctx, 4)"); + setState(29); + match(T__3); + setState(30); + expr(5); + } + break; + case 2: + { + _localctx = new ExprBinaryContext(new ExprContext(_parentctx, _parentState)); + pushNewRecursionContext(_localctx, _startState, RULE_expr); + setState(31); + if (!(precpred(_ctx, 3))) throw new FailedPredicateException(this, "precpred(_ctx, 3)"); + setState(32); + match(T__4); + setState(33); + expr(4); + } + break; + case 3: + { + _localctx = new ExprBinaryContext(new ExprContext(_parentctx, _parentState)); + pushNewRecursionContext(_localctx, _startState, RULE_expr); + setState(34); + if (!(precpred(_ctx, 2))) throw new FailedPredicateException(this, "precpred(_ctx, 2)"); + setState(35); + match(T__5); + setState(36); + expr(3); + } + break; + case 4: + { + _localctx = new ExprBinaryContext(new ExprContext(_parentctx, _parentState)); + pushNewRecursionContext(_localctx, _startState, RULE_expr); + setState(37); + if (!(precpred(_ctx, 1))) throw new FailedPredicateException(this, "precpred(_ctx, 1)"); + setState(38); + match(T__6); + setState(39); + expr(2); + } + break; + } + } + } + setState(44); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,3,_ctx); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + unrollRecursionContexts(_parentctx); + } + return _localctx; + } + + public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) { + switch (ruleIndex) { + case 2: + return expr_sempred((ExprContext)_localctx, predIndex); + } + return true; + } + private boolean expr_sempred(ExprContext _localctx, int predIndex) { + switch (predIndex) { + case 0: + return precpred(_ctx, 4); + case 1: + return precpred(_ctx, 3); + case 2: + return precpred(_ctx, 2); + case 3: + return precpred(_ctx, 1); + } + return true; + } + + public static final String _serializedATN = + "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\17\60\4\2\t\2\4\3"+ + "\t\3\4\4\t\4\3\2\7\2\n\n\2\f\2\16\2\r\13\2\3\3\3\3\3\3\3\4\3\4\3\4\3\4"+ + "\3\4\3\4\3\4\3\4\3\4\3\4\3\4\5\4\35\n\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3"+ + "\4\3\4\3\4\3\4\3\4\7\4+\n\4\f\4\16\4.\13\4\3\4\2\3\6\5\2\4\6\2\2\2\64"+ + "\2\13\3\2\2\2\4\16\3\2\2\2\6\34\3\2\2\2\b\n\5\4\3\2\t\b\3\2\2\2\n\r\3"+ + "\2\2\2\13\t\3\2\2\2\13\f\3\2\2\2\f\3\3\2\2\2\r\13\3\2\2\2\16\17\5\6\4"+ + "\2\17\20\7\3\2\2\20\5\3\2\2\2\21\22\b\4\1\2\22\23\7\4\2\2\23\24\7\n\2"+ + "\2\24\25\7\5\2\2\25\35\5\6\4\n\26\35\7\13\2\2\27\35\7\f\2\2\30\31\7\4"+ + "\2\2\31\32\5\6\4\2\32\33\7\5\2\2\33\35\3\2\2\2\34\21\3\2\2\2\34\26\3\2"+ + "\2\2\34\27\3\2\2\2\34\30\3\2\2\2\35,\3\2\2\2\36\37\f\6\2\2\37 \7\6\2\2"+ + " +\5\6\4\7!\"\f\5\2\2\"#\7\7\2\2#+\5\6\4\6$%\f\4\2\2%&\7\b\2\2&+\5\6\4"+ + "\5\'(\f\3\2\2()\7\t\2\2)+\5\6\4\4*\36\3\2\2\2*!\3\2\2\2*$\3\2\2\2*\'\3"+ + "\2\2\2+.\3\2\2\2,*\3\2\2\2,-\3\2\2\2-\7\3\2\2\2.,\3\2\2\2\6\13\34*,"; + public static final ATN _ATN = + new ATNDeserializer().deserialize(_serializedATN.toCharArray()); + static { + _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; + for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) { + _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i); + } + } +} \ No newline at end of file diff --git a/src/test/java/dk/camelot64/kickc/parsing/macros/MacrosVisitor.java b/src/test/java/dk/camelot64/kickc/parsing/macros/MacrosVisitor.java new file mode 100644 index 000000000..1966fac6c --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/parsing/macros/MacrosVisitor.java @@ -0,0 +1,63 @@ +// Generated from /Users/jespergravgaard/c64/kickc/src/test/java/dk/camelot64/kickc/parsing/macros/Macros.g4 by ANTLR 4.7.2 +package dk.camelot64.kickc.parsing.macros; + + +import org.antlr.v4.runtime.tree.ParseTreeVisitor; + +/** + * This interface defines a complete generic visitor for a parse tree produced + * by {@link MacrosParser}. + * + * @param The return type of the visit operation. Use {@link Void} for + * operations with no return type. + */ +public interface MacrosVisitor extends ParseTreeVisitor { + /** + * Visit a parse tree produced by {@link MacrosParser#stmtSeq}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitStmtSeq(MacrosParser.StmtSeqContext ctx); + /** + * Visit a parse tree produced by the {@code stmtExpr} + * labeled alternative in {@link MacrosParser#stmt}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitStmtExpr(MacrosParser.StmtExprContext ctx); + /** + * Visit a parse tree produced by the {@code exprCast} + * labeled alternative in {@link MacrosParser#expr}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitExprCast(MacrosParser.ExprCastContext ctx); + /** + * Visit a parse tree produced by the {@code exprBinary} + * labeled alternative in {@link MacrosParser#expr}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitExprBinary(MacrosParser.ExprBinaryContext ctx); + /** + * Visit a parse tree produced by the {@code exprPar} + * labeled alternative in {@link MacrosParser#expr}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitExprPar(MacrosParser.ExprParContext ctx); + /** + * Visit a parse tree produced by the {@code exprNumber} + * labeled alternative in {@link MacrosParser#expr}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitExprNumber(MacrosParser.ExprNumberContext ctx); + /** + * Visit a parse tree produced by the {@code exprName} + * labeled alternative in {@link MacrosParser#expr}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitExprName(MacrosParser.ExprNameContext ctx); +} \ No newline at end of file diff --git a/src/test/java/dk/camelot64/kickc/parsing/macros/TestMacrosParser.java b/src/test/java/dk/camelot64/kickc/parsing/macros/TestMacrosParser.java new file mode 100644 index 000000000..74639ada9 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/parsing/macros/TestMacrosParser.java @@ -0,0 +1,176 @@ +package dk.camelot64.kickc.parsing.macros; + +import dk.camelot64.kickc.model.CompileError; +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.misc.Pair; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + + +public class TestMacrosParser { + + /** + * Test some parsing without macros + */ + @Test + public void testParserSimple() { + // Simple addition + assertEquals("+(name:a,num:7);", parse("a+7;")); + // Addition & multiplication + assertEquals("+(name:a,*(name:b,name:c));", parse("a+b*c;")); + // Addition and a cast + assertEquals("+(cast(char,name:b),num:1);", parse("(char)b+1;")); + } + + /** + * Test parsing with simple defines + */ + @Test + public void testParserDefine() { + // A simple unused define + assertEquals("+(name:b,num:1);*(name:c,num:2);", parse("#define A a\nb+1;\nc*2;\n")); + // A simple used define + assertEquals("+(*(name:axe,num:2),name:axe);", parse("#define A axe\nA*2+A;")); + // A define using a special token class + assertEquals("+(name:axe,num:1);", parse("#define A axe\n#define B +\nA B 1;")); + } + + /** + * Parse a program with macros and return the resulting syntax tree + * + * @param program The program parse + * @return The parse-tree in string form + */ + private String parse(String program) { + final CharStream fileStream = CharStreams.fromString(program); + // typedefs shared between lexer and parser + MacrosLexer lexer = new MacrosLexer(fileStream); + lexer.addErrorListener(new BaseErrorListener() { + @Override + public void syntaxError( + Recognizer recognizer, + Object offendingSymbol, + int line, + int charPositionInLine, + String msg, + RecognitionException e) { + throw new CompileError("Error parsing file " + fileStream.getSourceName() + "\n - Line: " + line + "\n - Message: " + msg); + } + }); + + Map macros = new LinkedHashMap<>(); + final ArrayList finalTokens = new ArrayList<>(); + Token token = lexer.nextToken(); + while(token.getType() != Token.EOF) { + if(token.getType() == MacrosLexer.DEFINE) { + // Define a new macro + final Token name = lexer.nextToken(); + // TODO: Gobble tokens until newline + final Token value = lexer.nextToken(); + //System.out.println("Defining " + name.getText() + " to " + value.getText()); + macros.put(name.getText(), value); + } else if(token.getType()==MacrosLexer.IDENTIFIER && macros.containsKey(token.getText())){ + // Unfold a macro + final CommonToken newToken = new CommonToken(token); + final Token unfold = macros.get(token.getText()); + newToken.setText(unfold.getText()); + newToken.setType(unfold.getType()); + newToken.setChannel(unfold.getChannel()); + finalTokens.add(newToken); + } else { + finalTokens.add(token); + } + token = lexer.nextToken(); + } + + MacrosParser parser = new MacrosParser(new BufferedTokenStream(new ListTokenSource(finalTokens))); + parser.setBuildParseTree(true); + parser.addErrorListener(new BaseErrorListener() { + @Override + public void syntaxError( + Recognizer recognizer, + Object offendingSymbol, + int line, + int charPositionInLine, + String msg, + RecognitionException e) { + throw new CompileError("Error parsing file " + fileStream.getSourceName() + "\n - Line: " + line + "\n - Message: " + msg); + } + }); + + MacrosPrinter printVisitor = new MacrosPrinter(); + printVisitor.visit(parser.stmtSeq()); + return printVisitor.getOut().toString(); + } + + private static class MacrosPrinter extends MacrosBaseVisitor { + + StringBuilder out = new StringBuilder(); + + public StringBuilder getOut() { + return out; + } + + @Override + public Object visitStmtSeq(MacrosParser.StmtSeqContext ctx) { + for(MacrosParser.StmtContext stmtContext : ctx.stmt()) { + this.visit(stmtContext); + out.append(";"); + } + return null; + } + + @Override + public Object visitStmtExpr(MacrosParser.StmtExprContext ctx) { + this.visit(ctx.expr()); + return null; + } + + @Override + public Object visitExprName(MacrosParser.ExprNameContext ctx) { + out.append("name:").append(ctx.getText()); + return null; + } + + @Override + public Object visitExprNumber(MacrosParser.ExprNumberContext ctx) { + return out.append("num:").append(ctx.getText()); + } + + @Override + public Object visitExprCast(MacrosParser.ExprCastContext ctx) { + out.append("cast("); + out.append(ctx.SIMPLETYPE().getText()); + out.append(","); + this.visit(ctx.expr()); + out.append(")"); + return null; + } + + @Override + public Object visitExprBinary(MacrosParser.ExprBinaryContext ctx) { + String fct = ctx.getChild(1).getText(); + out.append(fct).append("("); + this.visit(ctx.expr(0)); + out.append(","); + this.visit(ctx.expr(1)); + out.append(")"); + return null; + } + + + @Override + public Object visitExprPar(MacrosParser.ExprParContext ctx) { + out.append("("); + this.visit(ctx.expr()); + out.append(")"); + return null; + } + + } +}