1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-10-21 02:24:34 +00:00

Working on a proof-of-concept preprocessor lexer. #169

This commit is contained in:
jespergravgaard 2020-04-01 01:35:46 +02:00
parent 244f329ab0
commit bc4dd9ea47
13 changed files with 1398 additions and 0 deletions

View File

@ -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<String, String> 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!");
}
}
}

View File

@ -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 ;

View File

@ -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]

View File

@ -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

View File

@ -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}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterStmtSeq(MacrosParser.StmtSeqContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitStmtSeq(MacrosParser.StmtSeqContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterStmtExpr(MacrosParser.StmtExprContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitStmtExpr(MacrosParser.StmtExprContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterExprCast(MacrosParser.ExprCastContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitExprCast(MacrosParser.ExprCastContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterExprBinary(MacrosParser.ExprBinaryContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitExprBinary(MacrosParser.ExprBinaryContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterExprPar(MacrosParser.ExprParContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitExprPar(MacrosParser.ExprParContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterExprNumber(MacrosParser.ExprNumberContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitExprNumber(MacrosParser.ExprNumberContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterExprName(MacrosParser.ExprNameContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitExprName(MacrosParser.ExprNameContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterEveryRule(ParserRuleContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitEveryRule(ParserRuleContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void visitTerminal(TerminalNode node) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void visitErrorNode(ErrorNode node) { }
}

View File

@ -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 <T> The return type of the visit operation. Use {@link Void} for
* operations with no return type.
*/
public class MacrosBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements MacrosVisitor<T> {
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitStmtSeq(MacrosParser.StmtSeqContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitStmtExpr(MacrosParser.StmtExprContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitExprCast(MacrosParser.ExprCastContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitExprBinary(MacrosParser.ExprBinaryContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitExprPar(MacrosParser.ExprParContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitExprNumber(MacrosParser.ExprNumberContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitExprName(MacrosParser.ExprNameContext ctx) { return visitChildren(ctx); }
}

View File

@ -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]

View File

@ -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] = "<INVALID>";
}
}
}
@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<L\3\b"+
"\2\2";
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);
}
}
}

View File

@ -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

View File

@ -0,0 +1,94 @@
// 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.ParseTreeListener;
/**
* This interface defines a complete listener for a parse tree produced by
* {@link MacrosParser}.
*/
public interface MacrosListener extends ParseTreeListener {
/**
* Enter a parse tree produced by {@link MacrosParser#stmtSeq}.
* @param ctx the parse tree
*/
void enterStmtSeq(MacrosParser.StmtSeqContext ctx);
/**
* Exit a parse tree produced by {@link MacrosParser#stmtSeq}.
* @param ctx the parse tree
*/
void exitStmtSeq(MacrosParser.StmtSeqContext ctx);
/**
* Enter a parse tree produced by the {@code stmtExpr}
* labeled alternative in {@link MacrosParser#stmt}.
* @param ctx the parse tree
*/
void enterStmtExpr(MacrosParser.StmtExprContext ctx);
/**
* Exit a parse tree produced by the {@code stmtExpr}
* labeled alternative in {@link MacrosParser#stmt}.
* @param ctx the parse tree
*/
void exitStmtExpr(MacrosParser.StmtExprContext ctx);
/**
* Enter a parse tree produced by the {@code exprCast}
* labeled alternative in {@link MacrosParser#expr}.
* @param ctx the parse tree
*/
void enterExprCast(MacrosParser.ExprCastContext ctx);
/**
* Exit a parse tree produced by the {@code exprCast}
* labeled alternative in {@link MacrosParser#expr}.
* @param ctx the parse tree
*/
void exitExprCast(MacrosParser.ExprCastContext ctx);
/**
* Enter a parse tree produced by the {@code exprBinary}
* labeled alternative in {@link MacrosParser#expr}.
* @param ctx the parse tree
*/
void enterExprBinary(MacrosParser.ExprBinaryContext ctx);
/**
* Exit a parse tree produced by the {@code exprBinary}
* labeled alternative in {@link MacrosParser#expr}.
* @param ctx the parse tree
*/
void exitExprBinary(MacrosParser.ExprBinaryContext ctx);
/**
* Enter a parse tree produced by the {@code exprPar}
* labeled alternative in {@link MacrosParser#expr}.
* @param ctx the parse tree
*/
void enterExprPar(MacrosParser.ExprParContext ctx);
/**
* Exit a parse tree produced by the {@code exprPar}
* labeled alternative in {@link MacrosParser#expr}.
* @param ctx the parse tree
*/
void exitExprPar(MacrosParser.ExprParContext ctx);
/**
* Enter a parse tree produced by the {@code exprNumber}
* labeled alternative in {@link MacrosParser#expr}.
* @param ctx the parse tree
*/
void enterExprNumber(MacrosParser.ExprNumberContext ctx);
/**
* Exit a parse tree produced by the {@code exprNumber}
* labeled alternative in {@link MacrosParser#expr}.
* @param ctx the parse tree
*/
void exitExprNumber(MacrosParser.ExprNumberContext ctx);
/**
* Enter a parse tree produced by the {@code exprName}
* labeled alternative in {@link MacrosParser#expr}.
* @param ctx the parse tree
*/
void enterExprName(MacrosParser.ExprNameContext ctx);
/**
* Exit a parse tree produced by the {@code exprName}
* labeled alternative in {@link MacrosParser#expr}.
* @param ctx the parse tree
*/
void exitExprName(MacrosParser.ExprNameContext ctx);
}

View File

@ -0,0 +1,511 @@
// 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.atn.*;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.misc.*;
import org.antlr.v4.runtime.tree.*;
import java.util.List;
import java.util.Iterator;
import java.util.ArrayList;
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
public class MacrosParser extends Parser {
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 final int
RULE_stmtSeq = 0, RULE_stmt = 1, RULE_expr = 2;
private static String[] makeRuleNames() {
return new String[] {
"stmtSeq", "stmt", "expr"
};
}
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] = "<INVALID>";
}
}
}
@Override
@Deprecated
public String[] getTokenNames() {
return tokenNames;
}
@Override
public Vocabulary getVocabulary() {
return VOCABULARY;
}
@Override
public String getGrammarFileName() { return "Macros.g4"; }
@Override
public String[] getRuleNames() { return ruleNames; }
@Override
public String getSerializedATN() { return _serializedATN; }
@Override
public ATN getATN() { return _ATN; }
CMacroExpander macros = new CMacroExpander();
public MacrosParser(TokenStream input) {
super(input);
_interp = new ParserATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
}
public static class StmtSeqContext extends ParserRuleContext {
public List<StmtContext> 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> T accept(ParseTreeVisitor<? extends T> visitor) {
if ( visitor instanceof MacrosVisitor ) return ((MacrosVisitor<? extends T>)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> T accept(ParseTreeVisitor<? extends T> visitor) {
if ( visitor instanceof MacrosVisitor ) return ((MacrosVisitor<? extends T>)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> T accept(ParseTreeVisitor<? extends T> visitor) {
if ( visitor instanceof MacrosVisitor ) return ((MacrosVisitor<? extends T>)visitor).visitExprCast(this);
else return visitor.visitChildren(this);
}
}
public static class ExprBinaryContext extends ExprContext {
public List<ExprContext> 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> T accept(ParseTreeVisitor<? extends T> visitor) {
if ( visitor instanceof MacrosVisitor ) return ((MacrosVisitor<? extends T>)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> T accept(ParseTreeVisitor<? extends T> visitor) {
if ( visitor instanceof MacrosVisitor ) return ((MacrosVisitor<? extends T>)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> T accept(ParseTreeVisitor<? extends T> visitor) {
if ( visitor instanceof MacrosVisitor ) return ((MacrosVisitor<? extends T>)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> T accept(ParseTreeVisitor<? extends T> visitor) {
if ( visitor instanceof MacrosVisitor ) return ((MacrosVisitor<? extends T>)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);
}
}
}

View File

@ -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 <T> The return type of the visit operation. Use {@link Void} for
* operations with no return type.
*/
public interface MacrosVisitor<T> extends ParseTreeVisitor<T> {
/**
* 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);
}

View File

@ -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<String, Token> macros = new LinkedHashMap<>();
final ArrayList<Token> 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<Object> {
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;
}
}
}