mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-26 03:32:23 +00:00
Moved simple macro expander to main source.
This commit is contained in:
parent
3bb6efb92d
commit
b2466df1e4
75
src/main/java/dk/camelot64/kickc/macros/CMacroExpander.java
Normal file
75
src/main/java/dk/camelot64/kickc/macros/CMacroExpander.java
Normal file
@ -0,0 +1,75 @@
|
||||
package dk.camelot64.kickc.macros;
|
||||
|
||||
import org.antlr.v4.runtime.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* C Macro expander.
|
||||
*
|
||||
* The macro expander takes one token source as input and produces a new expanded token source as output
|
||||
*/
|
||||
public class CMacroExpander {
|
||||
|
||||
/** The channel containing whitespace. */
|
||||
private final int channelWhitespace;
|
||||
/** The token type for tokens containing whitespace. */
|
||||
private final int tokenWhitespace;
|
||||
/** The token type for #define. */
|
||||
private final int tokenDefine;
|
||||
/** The token type for identifiers. */
|
||||
private final int tokenIdentifier;
|
||||
|
||||
public CMacroExpander(int channelWhitespace, int tokenWhitespace, int tokenDefine, int tokenIdentifier) {
|
||||
this.channelWhitespace = channelWhitespace;
|
||||
this.tokenWhitespace = tokenWhitespace;
|
||||
this.tokenDefine = tokenDefine;
|
||||
this.tokenIdentifier = tokenIdentifier;
|
||||
}
|
||||
|
||||
public TokenSource expandMacros(TokenSource inputTokenSource) {
|
||||
Map<String, List<Token>> macros = new LinkedHashMap<>();
|
||||
final ArrayList<Token> expandedTokens = new ArrayList<>();
|
||||
Token inputToken = inputTokenSource.nextToken();
|
||||
while(inputToken.getType() != Token.EOF) {
|
||||
if(inputToken.getType() == tokenDefine) {
|
||||
// #define a new macro - find the name
|
||||
Token macroName = inputTokenSource.nextToken();
|
||||
while(macroName.getType() == tokenWhitespace)
|
||||
macroName = inputTokenSource.nextToken();
|
||||
// Find body by gobbling tokens until the line ends
|
||||
final ArrayList<Token> macroBody = new ArrayList<>();
|
||||
boolean macroRead = true;
|
||||
while(macroRead) {
|
||||
final Token bodyToken = inputTokenSource.nextToken();
|
||||
if(bodyToken.getChannel() == channelWhitespace && bodyToken.getText().contains("\n")) {
|
||||
macroRead = false;
|
||||
} else {
|
||||
macroBody.add(bodyToken);
|
||||
}
|
||||
}
|
||||
macros.put(macroName.getText(), macroBody);
|
||||
} else {
|
||||
if(inputToken.getType() == tokenIdentifier && macros.containsKey(inputToken.getText())) {
|
||||
// Macro expansion is needed
|
||||
final List<Token> macroBody = macros.get(inputToken.getText());
|
||||
for(Token bodyToken : macroBody) {
|
||||
final CommonToken expandedToken = new CommonToken(inputToken);
|
||||
expandedToken.setText(bodyToken.getText());
|
||||
expandedToken.setType(bodyToken.getType());
|
||||
expandedToken.setChannel(bodyToken.getChannel());
|
||||
expandedTokens.add(expandedToken);
|
||||
}
|
||||
} else {
|
||||
expandedTokens.add(inputToken);
|
||||
}
|
||||
}
|
||||
inputToken = inputTokenSource.nextToken();
|
||||
}
|
||||
return new ListTokenSource(expandedTokens);
|
||||
}
|
||||
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
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!");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -8,11 +8,9 @@ grammar Macros;
|
||||
}
|
||||
|
||||
@parser::members {
|
||||
CMacroExpander macros = new CMacroExpander();
|
||||
}
|
||||
|
||||
@lexer::members {
|
||||
CMacroExpander macros = new CMacroExpander();
|
||||
}
|
||||
|
||||
stmtSeq
|
||||
|
@ -85,7 +85,6 @@ public class MacrosLexer extends Lexer {
|
||||
}
|
||||
|
||||
|
||||
CMacroExpander macros = new CMacroExpander();
|
||||
|
||||
|
||||
public MacrosLexer(CharStream input) {
|
||||
|
@ -90,7 +90,6 @@ public class MacrosParser extends Parser {
|
||||
public ATN getATN() { return _ATN; }
|
||||
|
||||
|
||||
CMacroExpander macros = new CMacroExpander();
|
||||
|
||||
public MacrosParser(TokenStream input) {
|
||||
super(input);
|
||||
|
@ -1,21 +1,16 @@
|
||||
package dk.camelot64.kickc.parsing.macros;
|
||||
|
||||
import dk.camelot64.kickc.macros.CMacroExpander;
|
||||
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.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
|
||||
public class TestMacrosParser {
|
||||
|
||||
public static final int CHANNEL_WHITESPACE = 1;
|
||||
private int CHANNEL_WHITESPACE = 1;
|
||||
|
||||
/**
|
||||
* Test some parsing without macros
|
||||
@ -72,48 +67,9 @@ public class TestMacrosParser {
|
||||
}
|
||||
});
|
||||
|
||||
Map<String, List<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 - find name
|
||||
Token name = lexer.nextToken();
|
||||
while(name.getType()==MacrosLexer.WHITESPACE)
|
||||
name = lexer.nextToken();
|
||||
// Find value by gobbling tokens until the line ends
|
||||
final ArrayList<Token> macroValue = new ArrayList<>();
|
||||
boolean macroRead = true;
|
||||
while(macroRead) {
|
||||
final Token value = lexer.nextToken();
|
||||
final String text = value.getText();
|
||||
if(value.getChannel()== CHANNEL_WHITESPACE && value.getText().contains("\n")) {
|
||||
macroRead = false;
|
||||
} else {
|
||||
macroValue.add(value);
|
||||
}
|
||||
}
|
||||
macros.put(name.getText(), macroValue);
|
||||
} else if(token.getType()==MacrosLexer.IDENTIFIER && macros.containsKey(token.getText())){
|
||||
// Unfold a macro
|
||||
final List<Token> macroValue = macros.get(token.getText());
|
||||
for(Token macroToken : macroValue) {
|
||||
final CommonToken newToken = new CommonToken(token);
|
||||
newToken.setText(macroToken.getText());
|
||||
newToken.setType(macroToken.getType());
|
||||
newToken.setChannel(macroToken.getChannel());
|
||||
finalTokens.add(newToken);
|
||||
}
|
||||
} else {
|
||||
finalTokens.add(token);
|
||||
}
|
||||
token = lexer.nextToken();
|
||||
}
|
||||
MacrosParser parser = new MacrosParser(new CommonTokenStream(new ListTokenSource(finalTokens)));
|
||||
|
||||
//CommonTokenStream tokenStream = new CommonTokenStream(lexer);
|
||||
//MacrosParser parser = new MacrosParser(tokenStream);
|
||||
|
||||
final CMacroExpander cMacroExpander = new CMacroExpander(CHANNEL_WHITESPACE, MacrosLexer.WHITESPACE, MacrosLexer.DEFINE, MacrosLexer.IDENTIFIER);
|
||||
final TokenSource expandedTokenSource = cMacroExpander.expandMacros(lexer);
|
||||
MacrosParser parser = new MacrosParser(new CommonTokenStream(expandedTokenSource));
|
||||
parser.setBuildParseTree(true);
|
||||
parser.addErrorListener(new BaseErrorListener() {
|
||||
@Override
|
||||
|
Loading…
Reference in New Issue
Block a user