Skip to content

Instantly share code, notes, and snippets.

@xoppa
Created November 20, 2015 18:13
Show Gist options
  • Save xoppa/004de0e25cc21c8ac1fe to your computer and use it in GitHub Desktop.
Save xoppa/004de0e25cc21c8ac1fe to your computer and use it in GitHub Desktop.
Testing a very basic preprocessor
package com.badlogic.gdx.tests.preprocessor;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.StringBuilder;
public class Preprocessor {
private final static boolean isNewline (final char c) {
return c == '\n';
}
private final static boolean isSpace (final char c) {
return c == ' ' || c == '\t' || c == '\f' || c == '\r' || c == '\n';
}
public final static int DEFAULT = 1;
public final static int START_OF_LINE = 2;
public final static int LINE_COMMENT = 3;
public final static int BLOCK_COMMENT = 4;
public final static int MACRO = 5;
public final static int MACRO_MULTILINE = 6;
protected static class Source {
protected String name;
protected CharSequence content;
protected int line;
protected int column;
protected int index;
protected int size;
public Source (CharSequence content) {
this.content = content;
this.size = content.length();
}
}
Array<Source> sourceStack = new Array<Source>();
Source source;
StringBuilder output = new StringBuilder();
int state;
char previous;
StringBuilder macro = new StringBuilder();
protected void reset() {
source = null;
output.setLength(0);
macro.setLength(0);
sourceStack.clear();
state = DEFAULT;
previous = '\0';
}
public CharSequence parse (CharSequence code) {
if (code.length() == 0)
return code;
reset();
source = new Source(code);
while (true) {
char c = source.content.charAt(source.index++);
if (isNewline(c)) {
source.line++;
source.column = 0;
} else
source.column++;
add(c);
if (source.index >= source.size) {
add('\n');
if (sourceStack.size < 1) break;
source = sourceStack.pop();
previous = 0;
state = START_OF_LINE;
}
}
return output;
}
protected void load (final Source source) {
if (this.source != null) sourceStack.add(this.source);
this.source = source;
}
protected void add (final char c) {
switch (state) {
case LINE_COMMENT:
if (isNewline(c)) state = START_OF_LINE;
break;
case BLOCK_COMMENT:
if (previous == '*' && c == '/') state = DEFAULT;
break;
case MACRO_MULTILINE:
if (isNewline(c)) {
state = MACRO;
macro.append(c);
}
break;
case MACRO:
if (isNewline(c)) {
state = START_OF_LINE;
parseMacro(macro);
macro.setLength(0);
} else if (previous == '/' && c == '/') {
macro.length--;
state = LINE_COMMENT;
} else {
macro.append(c);
if (c == '\\')
state = MACRO_MULTILINE;
}
break;
case START_OF_LINE:
if (c == '#') {
state = MACRO;
break;
}
if (!isSpace(c))
state = DEFAULT;
//fall thru to default:
default:
if (isNewline(c))
state = START_OF_LINE;
else if (previous == '/' && c == '/')
state = LINE_COMMENT;
else if (previous == '/' && c == '*') state = BLOCK_COMMENT;
}
if (state != MACRO && state != MACRO_MULTILINE)
output.append(c);
previous = c;
}
StringBuilder keyword = new StringBuilder();
protected void parseMacro (final CharSequence macro) {
keyword.setLength(0);
final int len = macro.length();
int index;
for (index = 0; index < len; ++index) {
final char c = macro.charAt(index);
if (isSpace(c))
break;
keyword.append(c);
}
String kw = keyword.toString();
if (kw.equals("if"))
execIf(macro, index);
else if (kw.equals("ifdef"))
execIfdef(macro, index);
else if (kw.equals("ifndef"))
execIfndef(macro, index);
else if (kw.equals("else"))
execElse(macro, index);
else if (kw.equals("elif"))
execElif(macro, index);
else if (kw.equals("endif"))
execEndif(macro, index);
else if (kw.equals("define"))
execDefine(macro, index);
else if (kw.equals("undef"))
execUndef(macro, index);
else if (kw.equals("include"))
execInclude(macro, index);
else
execUnknown(keyword, macro, index);
Gdx.app.log("Preprocessor", "#" + macro.toString());
output.append("<#!").append(macro).append("!#>");
}
protected void execIf(final CharSequence macro, int index) {
Gdx.app.log("Test", "EXECIF: "+macro);
}
protected void execIfdef(final CharSequence macro, int index) {
Gdx.app.log("Test", "EXECIFDEF: "+macro);
}
protected void execIfndef(final CharSequence macro, int index) {
Gdx.app.log("Test", "EXECIFDEF: "+macro);
}
protected void execElse(final CharSequence macro, int index) {
Gdx.app.log("Test", "EXECELSE: "+macro);
}
protected void execElif(final CharSequence macro, int index) {
Gdx.app.log("Test", "EXECELIF: "+macro);
}
protected void execEndif(final CharSequence macro, int index) {
Gdx.app.log("Test", "EXECENDIF: "+macro);
}
protected void execDefine(final CharSequence macro, int index) {
Gdx.app.log("Test", "EXECDEFINE: "+macro);
}
protected void execUndef(final CharSequence macro, int index) {
Gdx.app.log("Test", "EXECUNDEF: "+macro);
}
protected void execInclude(final CharSequence macro, int index) {
Gdx.app.log("Test", "EXECINCLUDE: "+macro);
}
protected void execUnknown(final CharSequence keyword, CharSequence macro, int index) {
Gdx.app.log("Test", "EXECUNKOWN: "+macro);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment