1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-09-08 17:54:40 +00:00

Moved simple macro expander to main source.

This commit is contained in:
jespergravgaard 2020-04-02 08:33:32 +02:00
parent 3bb6efb92d
commit b2466df1e4
6 changed files with 80 additions and 90 deletions

View 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);
}
}

View File

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

View File

@ -8,11 +8,9 @@ grammar Macros;
}
@parser::members {
CMacroExpander macros = new CMacroExpander();
}
@lexer::members {
CMacroExpander macros = new CMacroExpander();
}
stmtSeq

View File

@ -85,7 +85,6 @@ public class MacrosLexer extends Lexer {
}
CMacroExpander macros = new CMacroExpander();
public MacrosLexer(CharStream input) {

View File

@ -90,7 +90,6 @@ public class MacrosParser extends Parser {
public ATN getATN() { return _ATN; }
CMacroExpander macros = new CMacroExpander();
public MacrosParser(TokenStream input) {
super(input);

View File

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