Skip to content

Instantly share code, notes, and snippets.

@glennismade
Created February 2, 2018 12:04
Show Gist options
  • Save glennismade/a09cbd6a7efe1fee791045badb18d607 to your computer and use it in GitHub Desktop.
Save glennismade/a09cbd6a7efe1fee791045badb18d607 to your computer and use it in GitHub Desktop.
Basic Java Compiler with Simplified Syntax
package glenn.compiler.gh;
/**
* represents a type of veriable
*/
public enum BuiltInType implements Type {
STRING, INTEGER, VOID, FLOAT
}
package glenn.compiler.gh.parser;
import glenn.compiler.gh.block.Blk;
import glenn.compiler.gh.block.Class;
import glenn.compiler.gh.lex.Tokenizer;
/**
* Created by glennhealy on 01/03/2016.
*/
public class ClassPars extends Parser<Class> {
@Override
public boolean shouldParse(String line) {
return line.matches("class [a-zA-Z][a-zA-Z0-9]*");
}
@Override
public Class parse(Blk superBlk, Tokenizer tokenizer) {
tokenizer.nextTok(); // Skip the class token.
String name = tokenizer.nextTok().getToken(); // Get the string value of the next token.
return new Class(name);
}
}
package glenn.compiler.gh.lex;
/**
* Created by glennhealy on 28/02/2016.
*/
public class Tok {
private String token;
private TokType type;
public Tok(String token, TokType type) {
this.token = token;
this.type = type;
}
public String getToken() {
return token;
}
public TokType getType() {
return type;
}
}
package glenn.compiler.gh;
/**
* Created by glennhealy on 02/03/2016.
*/
public interface Type {
public static Type match(String str) {
try {
return BuiltInType.valueOf(str.toUpperCase());
}
catch (Exception e) {
// TODO: Match str to a class.
return null;
}
}
}
package glenn.compiler.gh;
import glenn.compiler.gh.block.Blk;
/**
* Created by glennhealy on 02/03/2016.
*/
public class Variable extends Value {
private Blk blk;
private String name;
public Variable(Blk blk, Type type, String name, Object value) {
super(type, value);
this.blk = blk;
this.name = name;
}
public Blk getBlk() {
return blk;
}
public String getName() {
return name;
}
}
package glenn.compiler.gh.lex;
import java.util.regex.Pattern;
/**
* Created by glennhealy on 28/02/2016.
*/
public class TokData {
private Pattern pattern;
private TokType type;
public TokData(Pattern pattern, TokType type){
this.pattern = pattern;
this.type = type;
}
public Pattern getPattern() {
return pattern;
}
public TokType getType() {
return type;
}
}
package glenn.compiler.gh.lex;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by glennhealy on 28/02/2016.
*/
public class Tokenizer {
private ArrayList<TokData> tokDatas;
private String str;
private Tok lastToken;
private boolean pushBack;
public Tokenizer(String str) {
this.tokDatas = new ArrayList<TokData>();
this.str = str;
tokDatas.add(new TokData(Pattern.compile("^([a-zA-Z][a-zA-Z0-9]*)"), TokType.IDENTIFIER));
tokDatas.add(new TokData(Pattern.compile("^((-)?[0-9]+)"), TokType.INTEGER_LITERAL));
tokDatas.add(new TokData(Pattern.compile("^([+-]?\\d*\\.?\\d*)$"), TokType.FLOAT_LITERAL));
tokDatas.add(new TokData(Pattern.compile("^(\".*\")"), TokType.STRING_LITERAL));
for (String t : new String[] { "=", "\\(", "\\)", "\\.", "\\," }) {
tokDatas.add(new TokData(Pattern.compile("^(" + t + ")"), TokType.TOKEN));
}
}
public Tok nextTok() {
str = str.trim();
if (pushBack) {
pushBack = false;
return lastToken;
}
if (str.isEmpty()) {
return (lastToken = new Tok("", TokType.EMPTY));
}
for (TokData data : tokDatas) {
Matcher matcher = data.getPattern().matcher(str);
if (matcher.find()) {
String token = matcher.group().trim();
str = matcher.replaceFirst("");
if (data.getType() == TokType.STRING_LITERAL) {
return (lastToken = new Tok(token.substring(1, token.length() - 1), TokType.STRING_LITERAL));
}
else {
return (lastToken = new Tok(token, data.getType()));
}
}
}
throw new IllegalStateException("Could not parse " + str);
}
public boolean hasNextToken() {
return !str.isEmpty();
}
public void pushBack() {
if (lastToken != null) {
this.pushBack = true;
}
}
}
package glenn.compiler.gh;
/**
* Created by glennhealy on 01/03/2016.
*/
public class Parameter {
private String name;
private Type type;
public Parameter(Type type, String name){
this.type = type;
this.name = name;
}
public String getName(){
return name;
}
public Type getType(){
return type;
}
}
package glenn.compiler.gh.parser;
import glenn.compiler.gh.block.Blk;
import glenn.compiler.gh.block.Class;
import glenn.compiler.gh.lex.Tokenizer;
/**
* Created by glennhealy on 01/03/2016.
*/
public class ClassPars extends Parser<Class> {
@Override
public boolean shouldParse(String line) {
return line.matches("class [a-zA-Z][a-zA-Z0-9]*");
}
@Override
public Class parse(Blk superBlk, Tokenizer tokenizer) {
tokenizer.nextTok(); // Skip the class token.
String name = tokenizer.nextTok().getToken(); // Get the string value of the next token.
return new Class(name);
}
}
package glenn.compiler.gh.parser;
import java.util.ArrayList;
import glenn.compiler.gh.BuiltInType;
import glenn.compiler.gh.block.Blk;
import glenn.compiler.gh.block.Method;
import glenn.compiler.gh.Parameter;
import glenn.compiler.gh.lex.Tok;
import glenn.compiler.gh.lex.Tokenizer;
/**
* Created by glennhealy on 01/03/2016.
*/
public class MethodPars extends Parser<Method> {
@Override
public boolean shouldParse(String line) {
return line.matches("method [a-zA-Z][a-zA-Z0-9]* requires \\(([a-zA-Z][a-zA-Z0-9]* [a-zA-Z][a-zA-Z0-9]*)*\\) returns [a-zA-Z][a-zA-Z0-9]*");
}
@Override
public Method parse(Blk superBlk, Tokenizer tokenizer) {
tokenizer.nextTok(); // Skip the method token.
String name = tokenizer.nextTok().getToken();
tokenizer.nextTok(); // Skip the requires token.
tokenizer.nextTok(); // Skip the ( token.
Tok first = tokenizer.nextTok();
ArrayList<Parameter> params = new ArrayList<>();
if (!first.getToken().equals(")")) {
String[] paramData = new String[] { first.getToken(), null }; // 0 = type, 1 = value
while (tokenizer.hasNextToken()) {
Tok tok = tokenizer.nextTok();
if (tok.getToken().equals(")")) {
break;
}
if (paramData[0] == null) {
paramData[0] = tok.getToken();
}
else {
paramData[1] = tok.getToken();
params.add(new Parameter(BuiltInType.valueOf(paramData[0].toUpperCase()), paramData[1]));
paramData = new String[2];
}
}
}
tokenizer.nextTok(); // Skip the returns token.
String returnType = tokenizer.nextTok().getToken();
return new Method(superBlk, name, returnType, params.toArray(new Parameter[params.size()]));
}
}
package glenn.compiler.gh.parser;
import glenn.compiler.gh.lex.Tokenizer;
import glenn.compiler.gh.block.Blk;
/**
* Created by glennhealy on 29/02/2016.
*/
public abstract class Parser<T extends Blk> {
/**
* Takes a line and checks to see if it is for this parser by using regex.
*/
public abstract boolean shouldParse(String line);
/**
* Take the superBlock and the tokenizer for the line and return a block of this parser's type.
*/
public abstract T parse(Blk superBlk, Tokenizer tokenizer);
}
package glenn.compiler.gh.parser;
//import Type;
//import Variable;
import glenn.compiler.gh.block.Blk;
import glenn.compiler.gh.block.VariableBlk;
import glenn.compiler.gh.lex.Tok;
import glenn.compiler.gh.lex.TokType;
import glenn.compiler.gh.lex.Tokenizer;
/**
* Created by glennhealy on 02/03/2016.
*/public class VarPars extends Parser<Blk> {
@Override
public boolean shouldParse(String line) {
return line.matches("var [a-zA-Z]+ [a-zA-Z]+ = (\")?[a-zA-Z0-9]*(\")?");
}
@Override
public Blk parse(Blk superBlk, Tokenizer tokenizer) {
tokenizer.nextTok(); // Skip the var token.
String type = tokenizer.nextTok().getToken();
String name = tokenizer.nextTok().getToken();
tokenizer.nextTok(); // Skip the = token.
Tok v = tokenizer.nextTok();
Object value = null;
if (v.getType() == TokType.INTEGER_LITERAL) {
value = Integer.valueOf(v.getToken());
}
else if (v.getType() == TokType.FLOAT_LITERAL) {
value = Float.valueOf(v.getToken()); //token type check float
}
else if (v.getType() == TokType.STRING_LITERAL) {
value = v.getToken();
}
else /* if the token is a veriable itendifier */ {
value = superBlk.getVariable(v.getToken()).getValue();
}
return new VariableBlk(superBlk, type, name, value);
}
}
package glenn.compiler.gh;
import glenn.compiler.gh.block.Blk;
import glenn.compiler.gh.block.Method;
import glenn.compiler.gh.block.Class;
import glenn.compiler.gh.lex.Tokenizer;
import glenn.compiler.gh.parser.ClassPars;
import glenn.compiler.gh.parser.MethodPars;
import glenn.compiler.gh.parser.Parser;
import glenn.compiler.gh.parser.VarPars;
import java.awt.*;
import java.util.ArrayList;
////////import me.compiler.lex.*;
/**
* Created by glennhealy on 02/03/2016.
*/
public class Runtime {
private ArrayList<Class> classes;
public Runtime() {
this.classes = new ArrayList<Class>();
String code = "class Variables" + "\n" +
"method main requires () returns void" + "\n" +
"var string str = \"main\"" + "\n" +
"method printString requires (string str) returns void";
Parser<?>[] parsers = new Parser<?>[] { new ClassPars(), new MethodPars(), new VarPars() };
Class main = null;
Blk blk = null;
boolean succeed = false;
for (String line : code.split("\n")) {
succeed = false;
line = line.trim();
Tokenizer tokenizer = new Tokenizer(line);
for (Parser<?> parser : parsers) {
if (parser.shouldParse(line)) {
Blk newBlk = parser.parse(blk, tokenizer);
if (newBlk instanceof Class) {
classes.add((Class) newBlk);
}
else if (newBlk instanceof Method) {
blk.getBlockTree().get(0).addBlock(newBlk);
}
else {
blk.addBlock(newBlk);
}
blk = newBlk;
succeed = true;
break;
}
}
if (succeed != true) {
throw new IllegalArgumentException("Invalid arguments present at Line " + line);
}
}
for (Class c : classes) {
for (Blk b : c.getSubBlks()) {
if (b instanceof Method) {
Method method = (Method) b;
if (method.getName().equals("main must equal") && method.getType().equals("void") && method.getParameters().length == 0) {
main = c;
System.out.println("compiling correct" + getClass().getSimpleName());
}
}
}
}
if (main == null) {
throw new IllegalStateException("No main method could be found. please create a main method.");
}
main.run();
}
public static void main(String[] args) {
new Runtime();
}
}
package glenn.compiler.gh;
/**
* represents a value for a variable type.
*/
public class Value {
private Type type;
private Object value;
public Value(Type type, Object value) {
this.type = type;
this.value = value;
}
public Type getType() {
return type;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
<identifier>
First character is a letter, or any proceeding characters are letters or numbers.
<type>:
A primitive type: string, int, char, float, double boolean.
<value>:
Either an identifier (for a variable) or a literal (1, "Hello", true)
Class Declaration:
'class <identifier>'
Method Declaration:
'method <identifier = name> requires ([<type> <identifier = name>...]) returns <type>'
Variable Declaration:
'var <type> <identifier = name> [= <value>]'
Method Invocation:
'<identifier = name>([<value>...])'
Print Statement:
'Print <value>'
Return Statement:
'return <value>'
class HelloWorld
method main requires() returns void
print "HelloWorld"
package glenn.compiler.gh.parser;
import java.util.ArrayList;
import glenn.compiler.gh.BuiltInType;
import glenn.compiler.gh.block.Blk;
import glenn.compiler.gh.block.Method;
import glenn.compiler.gh.Parameter;
import glenn.compiler.gh.lex.Tok;
import glenn.compiler.gh.lex.Tokenizer;
/**
* Created by glennhealy on 01/03/2016.
*/
public class MethodPars extends Parser<Method> {
@Override
public boolean shouldParse(String line) {
return line.matches("method [a-zA-Z][a-zA-Z0-9]* requires \\(([a-zA-Z][a-zA-Z0-9]* [a-zA-Z][a-zA-Z0-9]*)*\\) returns [a-zA-Z][a-zA-Z0-9]*");
}
@Override
public Method parse(Blk superBlk, Tokenizer tokenizer) {
tokenizer.nextTok(); // Skip the method token.
String name = tokenizer.nextTok().getToken();
tokenizer.nextTok(); // Skip the requires token.
tokenizer.nextTok(); // Skip the ( token.
Tok first = tokenizer.nextTok();
ArrayList<Parameter> params = new ArrayList<>();
if (!first.getToken().equals(")")) {
String[] paramData = new String[] { first.getToken(), null }; // 0 = type, 1 = value
while (tokenizer.hasNextToken()) {
Tok tok = tokenizer.nextTok();
if (tok.getToken().equals(")")) {
break;
}
if (paramData[0] == null) {
paramData[0] = tok.getToken();
}
else {
paramData[1] = tok.getToken();
params.add(new Parameter(BuiltInType.valueOf(paramData[0].toUpperCase()), paramData[1]));
paramData = new String[2];
}
}
}
tokenizer.nextTok(); // Skip the returns token.
String returnType = tokenizer.nextTok().getToken();
return new Method(superBlk, name, returnType, params.toArray(new Parameter[params.size()]));
}
}
package glenn.compiler.gh;
/**
* Created by glennhealy on 01/03/2016.
*/
public class Parameter {
private String name;
private Type type;
public Parameter(Type type, String name){
this.type = type;
this.name = name;
}
public String getName(){
return name;
}
public Type getType(){
return type;
}
}
package glenn.compiler.gh.parser;
import glenn.compiler.gh.lex.Tokenizer;
import glenn.compiler.gh.block.Blk;
/**
* Created by glennhealy on 29/02/2016.
*/
public abstract class Parser<T extends Blk> {
/**
* Takes a line and checks to see if it is for this parser by using regex.
*/
public abstract boolean shouldParse(String line);
/**
* Take the superBlock and the tokenizer for the line and return a block of this parser's type.
*/
public abstract T parse(Blk superBlk, Tokenizer tokenizer);
}
package glenn.compiler.gh;
import glenn.compiler.gh.block.Blk;
import glenn.compiler.gh.block.Method;
import glenn.compiler.gh.block.Class;
import glenn.compiler.gh.lex.Tokenizer;
import glenn.compiler.gh.parser.ClassPars;
import glenn.compiler.gh.parser.MethodPars;
import glenn.compiler.gh.parser.Parser;
import glenn.compiler.gh.parser.VarPars;
import java.awt.*;
import java.util.ArrayList;
////////import me.compiler.lex.*;
/**
* Created by glennhealy on 02/03/2016.
*/
public class Runtime {
private ArrayList<Class> classes;
public Runtime() {
this.classes = new ArrayList<Class>();
String code = "class Variables" + "\n" +
"method main requires () returns void" + "\n" +
"var string str = \"main\"" + "\n" +
"method printString requires (string str) returns void";
Parser<?>[] parsers = new Parser<?>[] { new ClassPars(), new MethodPars(), new VarPars() };
Class main = null;
Blk blk = null;
boolean succeed = false;
for (String line : code.split("\n")) {
succeed = false;
line = line.trim();
Tokenizer tokenizer = new Tokenizer(line);
for (Parser<?> parser : parsers) {
if (parser.shouldParse(line)) {
Blk newBlk = parser.parse(blk, tokenizer);
if (newBlk instanceof Class) {
classes.add((Class) newBlk);
}
else if (newBlk instanceof Method) {
blk.getBlockTree().get(0).addBlock(newBlk);
}
else {
blk.addBlock(newBlk);
}
blk = newBlk;
succeed = true;
break;
}
}
if (succeed != true) {
throw new IllegalArgumentException("Invalid arguments present at Line " + line);
}
}
for (Class c : classes) {
for (Blk b : c.getSubBlks()) {
if (b instanceof Method) {
Method method = (Method) b;
if (method.getName().equals("main must equal") && method.getType().equals("void") && method.getParameters().length == 0) {
main = c;
System.out.println("compiling correct" + getClass().getSimpleName());
}
}
}
}
if (main == null) {
throw new IllegalStateException("No main method could be found. please create a main method.");
}
main.run();
}
public static void main(String[] args) {
new Runtime();
}
}
package glenn.compiler.gh.lex;
/**
* Created by glennhealy on 28/02/2016.
*/
public class Tok {
private String token;
private TokType type;
public Tok(String token, TokType type) {
this.token = token;
this.type = type;
}
public String getToken() {
return token;
}
public TokType getType() {
return type;
}
}
package glenn.compiler.gh.lex;
import java.util.regex.Pattern;
/**
* Created by glennhealy on 28/02/2016.
*/
public class TokData {
private Pattern pattern;
private TokType type;
public TokData(Pattern pattern, TokType type){
this.pattern = pattern;
this.type = type;
}
public Pattern getPattern() {
return pattern;
}
public TokType getType() {
return type;
}
}
package glenn.compiler.gh.lex;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by glennhealy on 28/02/2016.
*/
public class Tokenizer {
private ArrayList<TokData> tokDatas;
private String str;
private Tok lastToken;
private boolean pushBack;
public Tokenizer(String str) {
this.tokDatas = new ArrayList<TokData>();
this.str = str;
tokDatas.add(new TokData(Pattern.compile("^([a-zA-Z][a-zA-Z0-9]*)"), TokType.IDENTIFIER));
tokDatas.add(new TokData(Pattern.compile("^((-)?[0-9]+)"), TokType.INTEGER_LITERAL));
tokDatas.add(new TokData(Pattern.compile("^([+-]?\\d*\\.?\\d*)$"), TokType.FLOAT_LITERAL));
tokDatas.add(new TokData(Pattern.compile("^(\".*\")"), TokType.STRING_LITERAL));
for (String t : new String[] { "=", "\\(", "\\)", "\\.", "\\," }) {
tokDatas.add(new TokData(Pattern.compile("^(" + t + ")"), TokType.TOKEN));
}
}
public Tok nextTok() {
str = str.trim();
if (pushBack) {
pushBack = false;
return lastToken;
}
if (str.isEmpty()) {
return (lastToken = new Tok("", TokType.EMPTY));
}
for (TokData data : tokDatas) {
Matcher matcher = data.getPattern().matcher(str);
if (matcher.find()) {
String token = matcher.group().trim();
str = matcher.replaceFirst("");
if (data.getType() == TokType.STRING_LITERAL) {
return (lastToken = new Tok(token.substring(1, token.length() - 1), TokType.STRING_LITERAL));
}
else {
return (lastToken = new Tok(token, data.getType()));
}
}
}
throw new IllegalStateException("Could not parse " + str);
}
public boolean hasNextToken() {
return !str.isEmpty();
}
public void pushBack() {
if (lastToken != null) {
this.pushBack = true;
}
}
}
package glenn.compiler.gh.lex;
/**
* Created by glennhealy on 28/02/2016.
*/
public class tokenizerTest {
public static void main(String[] args) {
String code =
"class HelloWorld\n" +
"method main requires()\n" +
"print \"hello\""
;
Tokenizer tokenizer = new Tokenizer(code);
while (tokenizer.hasNextToken()) {
System.out.println(tokenizer.nextTok().getToken());
}
}
}
package glenn.compiler.gh.lex;
/**
* Created by glennhealy on 28/02/2016.
*/
public enum TokType {
EMPTY, //this is empty, absolutly nothing.
TOKEN, //this repersents a token e.g. (), =, */, ", +, -"
IDENTIFIER, // if first character is a letter, any proceeding characters are letters or numbers
INTEGER_LITERAL, //a number like 0, 1,2,3,4,5 etc.
FLOAT_LITERAL, // a IEEE floating point number such as 0.1, 0.02 or -1, -0.1, infinity, -infinity and NaN.
STRING_LITERAL, // anything encloses in double quotes ""
}
package glenn.compiler.gh;
/**
* Created by glennhealy on 02/03/2016.
*/
public interface Type {
public static Type match(String str) {
try {
return BuiltInType.valueOf(str.toUpperCase());
}
catch (Exception e) {
// TODO: Match str to a class.
return null;
}
}
}
package glenn.compiler.gh;
/**
* represents a value for a variable type.
*/
public class Value {
private Type type;
private Object value;
public Value(Type type, Object value) {
this.type = type;
this.value = value;
}
public Type getType() {
return type;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
package glenn.compiler.gh;
import glenn.compiler.gh.block.Blk;
/**
* Created by glennhealy on 02/03/2016.
*/
public class Variable extends Value {
private Blk blk;
private String name;
public Variable(Blk blk, Type type, String name, Object value) {
super(type, value);
this.blk = blk;
this.name = name;
}
public Blk getBlk() {
return blk;
}
public String getName() {
return name;
}
}
class variables
method main requires() returns void
var string str = getString()
printString(str)
method printString requires(string str) returns void
print str
method getString requires () returns string
return str()
package glenn.compiler.gh.parser;
//import Type;
//import Variable;
import glenn.compiler.gh.block.Blk;
import glenn.compiler.gh.block.VariableBlk;
import glenn.compiler.gh.lex.Tok;
import glenn.compiler.gh.lex.TokType;
import glenn.compiler.gh.lex.Tokenizer;
/**
* Created by glennhealy on 02/03/2016.
*/public class VarPars extends Parser<Blk> {
@Override
public boolean shouldParse(String line) {
return line.matches("var [a-zA-Z]+ [a-zA-Z]+ = (\")?[a-zA-Z0-9]*(\")?");
}
@Override
public Blk parse(Blk superBlk, Tokenizer tokenizer) {
tokenizer.nextTok(); // Skip the var token.
String type = tokenizer.nextTok().getToken();
String name = tokenizer.nextTok().getToken();
tokenizer.nextTok(); // Skip the = token.
Tok v = tokenizer.nextTok();
Object value = null;
if (v.getType() == TokType.INTEGER_LITERAL) {
value = Integer.valueOf(v.getToken());
}
else if (v.getType() == TokType.FLOAT_LITERAL) {
value = Float.valueOf(v.getToken()); //token type check float
}
else if (v.getType() == TokType.STRING_LITERAL) {
value = v.getToken();
}
else /* if the token is a veriable itendifier */ {
value = superBlk.getVariable(v.getToken()).getValue();
}
return new VariableBlk(superBlk, type, name, value);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment