Created
November 20, 2015 18:13
-
-
Save xoppa/004de0e25cc21c8ac1fe to your computer and use it in GitHub Desktop.
Testing a very basic preprocessor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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