parser rewrite wip

This commit is contained in:
nora 2021-01-16 23:33:16 +01:00
parent d7c9aeb127
commit 7d72665c74
5 changed files with 192 additions and 107 deletions

View file

@ -2,13 +2,10 @@ package com.github.nilstrieb.hunterlang.hllibrary;
public class FunctionArgLookup { public class FunctionArgLookup {
public static int argLookup(String lib, String name){ public static int argLookup(String name) {
return switch (lib){ return switch (name) {
case "Leorio" -> switch (name){ case "Leorio.say" -> 1;
case "say" -> 1; case "Leorio.listen" -> 0;
case "listen" -> 0;
default -> 0;
};
default -> 0; default -> 0;
}; };
} }

View file

@ -1,29 +1,46 @@
package com.github.nilstrieb.hunterlang.lexer; package com.github.nilstrieb.hunterlang.lexer;
import com.github.nilstrieb.hunterlang.hllibrary.FunctionArgLookup;
import com.github.nilstrieb.hunterlang.lib.ConsoleColors; import com.github.nilstrieb.hunterlang.lib.ConsoleColors;
import com.github.nilstrieb.hunterlang.parser.ParseTreeBodyNode;
import com.github.nilstrieb.hunterlang.parser.ParseTreeNode; import com.github.nilstrieb.hunterlang.parser.ParseTreeNode;
public class LexToken { public class LexToken {
WordType key; WordType key;
String value; String value;
private int argOverrideValue = -1;
public LexToken(WordType key, String value) { public LexToken(WordType key, String value) {
this.key = key; this.key = key;
this.value = value; this.value = value;
if (key.expectsPostArg() == -1) {
if (key == WordType.LIBFUNCCALL) {
//a function. will only support lib functions
argOverrideValue = FunctionArgLookup.argLookup(value);
}
}
} }
public LexToken(WordType key) { public LexToken(WordType key) {
this(key, ""); this(key, "");
} }
public int expectsPostArgCount() { public boolean hasPostfix() {
return key.expectsPostArg(); if(argOverrideValue == -1){
return key.expectsPostArg() > 0;
} else {
return argOverrideValue > 0;
} }
public boolean expectsPreArg() {
}
public boolean hasPrefix() {
return key.expectsPreArg() > 0; return key.expectsPreArg() > 0;
} }
public ParseTreeNode toNode(){ public ParseTreeNode toNode() {
return new ParseTreeNode(key, value); return new ParseTreeNode(key, value);
} }
@ -42,4 +59,12 @@ public class LexToken {
public String getValue() { public String getValue() {
return value; return value;
} }
public int postfixCount() {
if(argOverrideValue == -1){
return key.expectsPostArg();
} else {
return argOverrideValue;
}
}
} }

View file

@ -13,7 +13,7 @@ public class Lexer {
private static final String MEMCALL = "killua"; private static final String MEMCALL = "killua";
public static final String ASSIGNMENT = "hunts"; public static final String ASSIGNMENT = "hunts";
public static final String IF = "Gon"; public static final String IF = "Gon wants";
public static final String WANTS = "wants"; public static final String WANTS = "wants";
public static final String ELSE = "got"; public static final String ELSE = "got";
public static final String BOPEN = "{"; public static final String BOPEN = "{";
@ -38,6 +38,7 @@ public class Lexer {
private ArrayList<LexToken> temp; private ArrayList<LexToken> temp;
public ArrayList<LexToken> lex(String code) { public ArrayList<LexToken> lex(String code) {
System.out.println(ConsoleColors.GREEN_BACKGROUND + ConsoleColors.BLACK_BOLD + "------START LEXER------" + ConsoleColors.RESET);
tokens = new ArrayList<>(); tokens = new ArrayList<>();
temp = new ArrayList<>(); temp = new ArrayList<>();
@ -124,8 +125,7 @@ public class Lexer {
else if (sub.matches(LIBFUNCCALL_REGEX)) { else if (sub.matches(LIBFUNCCALL_REGEX)) {
String libName = sub.replaceAll(LIBFUNCCALL_REGEX, "$1"); String libName = sub.replaceAll(LIBFUNCCALL_REGEX, "$1");
String funcName = sub.replaceAll(LIBFUNCCALL_REGEX, "$2"); String funcName = sub.replaceAll(LIBFUNCCALL_REGEX, "$2");
addToken(WordType.LIB, libName); addToken(WordType.LIBFUNCCALL, libName + "." + funcName);
addToken(WordType.FUNCCALL, funcName);
j += libName.length(); //lib name j += libName.length(); //lib name
j += 1 + 4 + 1; // space + does + space j += 1 + 4 + 1; // space + does + space
j += funcName.length() - 1; //func name j += funcName.length() - 1; //func name
@ -137,6 +137,7 @@ public class Lexer {
temp.clear(); temp.clear();
} }
System.out.println(ConsoleColors.GREEN_BACKGROUND + ConsoleColors.BLACK_BOLD + "------STOP LEXER------" + ConsoleColors.RESET);
return tokens; return tokens;
} }
@ -152,11 +153,13 @@ public class Lexer {
Lexer l = new Lexer(); Lexer l = new Lexer();
String assign = """ String assign = """
killua70 hunts 3 > 0
killua0 hunts 3 killua0 hunts 3
killua0 hunts -3.4 #hunts nothing killua0 hunts -3.4 #hunts nothing
killua1 hunts "hallo" killua1 hunts "hallo"
#comment"""; #comment""";
String ifs = """ String ifs = """
killua0 hunts 3 > 0
Gon wants false { Gon wants false {
Leorio does say "false" Leorio does say "false"
} }
@ -165,19 +168,29 @@ public class Lexer {
} got { } got {
Leorio does say "small killua" Leorio does say "small killua"
} }
Gon wants true {
Gon wants true {
1
}
}
""";
String sif = """
Gon wants true {
Leorio does say "false"
"""; """;
String hierarchy = """ String hierarchy = """
killua0 hunts 3 > 3 killua0 hunts 3 > 3
"""; """;
ArrayList<LexToken> tokens = l.lex(hierarchy); ArrayList<LexToken> tokens = l.lex(sif);
Parser p = new Parser(); Parser p = new Parser();
try { try {
ArrayList<ParseTreeNode> nodes = p.parse(tokens); ArrayList<ParseTreeNode> nodes = p.parse(tokens);
for (ParseTreeNode node : nodes) { for (ParseTreeNode parseTreeNode : nodes) {
System.out.println(node); System.out.println(parseTreeNode);
} }
} catch (ParseException e) { } catch (ParseException e) {
e.printStackTrace(); e.printStackTrace();

View file

@ -1,5 +1,7 @@
package com.github.nilstrieb.hunterlang.lexer; package com.github.nilstrieb.hunterlang.lexer;
import com.github.nilstrieb.hunterlang.hllibrary.FunctionArgLookup;
public enum WordType { public enum WordType {
ASSIGNMENT(1, 1), //memory, value ASSIGNMENT(1, 1), //memory, value
MEMCALL(1), //adress MEMCALL(1), //adress
@ -14,15 +16,13 @@ public enum WordType {
GTHAN(1, 1), GTHAN(1, 1),
LTHAN(1, 1), LTHAN(1, 1),
EQUALS(1, 1), EQUALS(1, 1),
FUNCCALL(-1), //args
LIB(1), //function
MINUS(1, 1), MINUS(1, 1),
PLUS(1, 1), PLUS(1, 1),
MULTIPLY(1, 1), MULTIPLY(1, 1),
DIVIDE(1, 1), DIVIDE(1, 1),
MOD(1, 1), MOD(1, 1),
NEGATIVE(1), NEGATIVE(1),
EMPTY; EMPTY, LIBFUNCCALL(-1);
private int postArgAmount; private int postArgAmount;
private int preArgAmount; private int preArgAmount;

View file

@ -1,116 +1,166 @@
package com.github.nilstrieb.hunterlang.parser; package com.github.nilstrieb.hunterlang.parser;
import com.github.nilstrieb.hunterlang.hllibrary.FunctionArgLookup;
import com.github.nilstrieb.hunterlang.lexer.LexToken; import com.github.nilstrieb.hunterlang.lexer.LexToken;
import com.github.nilstrieb.hunterlang.lexer.WordType; import com.github.nilstrieb.hunterlang.lexer.WordType;
import com.github.nilstrieb.hunterlang.lib.ConsoleColors; import com.github.nilstrieb.hunterlang.lib.ConsoleColors;
import com.sun.source.tree.LambdaExpressionTree;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.ListIterator; import java.util.ListIterator;
public class Parser { public class Parser {
private ListIterator<LexToken> iterator;
private LexToken currentToken = null;
private LexToken prevToken = null;
private LexToken nextToken = null;
private ParseTreeNode prevNode;
public ArrayList<ParseTreeNode> parse(ArrayList<LexToken> tokens) throws ParseException { public ArrayList<ParseTreeNode> parse(ArrayList<LexToken> tokens) throws ParseException {
System.out.println(ConsoleColors.GREEN_BACKGROUND + ConsoleColors.BLACK_BOLD + "------START PARSER------" + ConsoleColors.RESET); System.out.println(ConsoleColors.GREEN_BACKGROUND + ConsoleColors.BLACK_BOLD + "------START PARSER------" + ConsoleColors.RESET);
ArrayList<ParseTreeNode> statements = new ArrayList<>(); ArrayList<ArrayList<LexToken>> split = splitStatements(tokens);
for (ArrayList<LexToken> lexTokens : split) {
iterator = tokens.listIterator(); System.out.println(lexTokens);
currentToken = iterator.next();
if (iterator.hasNext()) {
nextToken = iterator.next();
} }
//goes through each statement. On pass -> one statement ArrayList<ParseTreeNode> list = new ArrayList<>();
do {
System.out.println(ConsoleColors.GREEN_BRIGHT + "NEXT STATEMENT");
prevNode = new ParseTreeNode(); ParseTreeNode parent = null;
for (ArrayList<LexToken> statement : split) {
ListIterator<LexToken> iterator = statement.listIterator();
//start with first token LexToken current = iterator.next();
ParseTreeNode startNode = currentToken.toNode();
//if it wants a pre argument theres an error switch (current.getKey()) {
if (currentToken.expectsPreArg()) { case MEMCALL -> {
throw new ParseException("previous expression expected, doesn't exist"); //assignment
int assignmentIndex = 0;
while (iterator.hasNext()) {
assignmentIndex++;
current = iterator.next();
if (current.getKey() == WordType.ASSIGNMENT) {
break;
}
} }
//calculate the arguments of the start node, parsing the whole statement parent = current.toNode();
doStatement(startNode, true); parent.addChild(evaluate(new ArrayList<>(statement.subList(0, assignmentIndex))));
System.out.println(prevNode); parent.addChild(evaluate(new ArrayList<>(statement.subList(assignmentIndex + 1, statement.size()))));
statements.add(prevNode); }
} while (iterator.hasNext()); case IF, WANTS -> {
parent = new ParseTreeBodyNode(current.toNode());
ParseTreeBodyNode parentBN = (ParseTreeBodyNode) parent;
while (current.getKey() != WordType.BOPEN) {
current = iterator.next();
parent.addChild(current.toNode());
}
int brackets = 0;
while ((brackets != 0 || current.getKey() != WordType.BCLOSE) && iterator.hasNext()) {
current = iterator.next();
parentBN.addToken(current);
if (current.getKey() == WordType.BOPEN) {
brackets++;
} else if (current.getKey() == WordType.BCLOSE) {
brackets--;
}
}
parentBN.parse();
}
case ELSE -> {
}
case LIBFUNCCALL -> {
}
case BCLOSE -> {
}
default -> throw new ParseException("Unexpected value at start of statement: " + current.getKey());
}
list.add(parent);
}
System.out.println(ConsoleColors.GREEN_BACKGROUND + ConsoleColors.BLACK_BOLD + "------STOP PARSER------" + ConsoleColors.RESET); System.out.println(ConsoleColors.GREEN_BACKGROUND + ConsoleColors.BLACK_BOLD + "------STOP PARSER------" + ConsoleColors.RESET);
return statements; return list;
} }
private void doStatement(ParseTreeNode node, boolean isParent) throws ParseException { /**
if (node.getKey() == WordType.MINUS && prevNode.getKey() != WordType.NUMBER) { * Evalues an expression. For example something like killuakillua3+4 > 6
node.setKey(WordType.NEGATIVE); *
} * @param tokens The tokens
* @return The parent node
*/
private ParseTreeNode evaluate(ArrayList<LexToken> tokens) throws ParseException {
ListIterator<LexToken> iterator = tokens.listIterator();
LexToken prev;
LexToken curr;
LexToken next;
ParseTreeNode currentParent;
if (node.expectsPreArg()) { prev = iterator.next();
node.addChild(prevNode, true);
}
int expectedArg = node.expectsPostArgCount();
if (expectedArg == -1) {
if (node.getKey() == WordType.FUNCCALL) {
//a function. will only support lib functions
System.out.println(currentToken);
expectedArg = FunctionArgLookup.argLookup(prevToken.getValue(), currentToken.getValue());
} else {
ParseTreeBodyNode bNode = new ParseTreeBodyNode(node);
node = bNode;
fillBody(bNode);
}
}
if (isParent) {
prevNode = node;
}
nextToken();
if (expectedArg != 0) {
for (int i = 0; i < expectedArg; i++) {
ParseTreeNode child = currentToken.toNode();
doStatement(child, false);
node.addChild(child);
}
}
if (currentToken != null && currentToken.expectsPreArg()) {
doStatement(currentToken.toNode(), true);
}
}
private void fillBody(ParseTreeBodyNode node) throws ParseException {
int level = 0;
nextToken();
while (currentToken.getKey() != WordType.BCLOSE || level != 0) {
if (currentToken.getKey() == WordType.BOPEN) {
level++;
} else if (currentToken.getKey() == WordType.BCLOSE) {
level--;
}
node.addToken(currentToken);
nextToken();
}
node.parse();
}
private void nextToken() {
prevToken = currentToken;
currentToken = nextToken;
if (iterator.hasNext()) { if (iterator.hasNext()) {
nextToken = iterator.next(); curr = iterator.next();
} else {
//1 token
return prev.toNode();
} }
if (iterator.hasNext()) {
next = iterator.next();
} else {
//2 tokens
currentParent = prev.toNode();
currentParent.addChild(curr.toNode());
return currentParent;
}
if (curr.hasPrefix()) {
currentParent = curr.toNode();
currentParent.addChild(prev.toNode(), true);
currentParent.addChild(evaluate(new ArrayList<>(tokens.subList(2, tokens.size()))));
} else if (prev.postfixCount() == 1) {
currentParent = prev.toNode();
currentParent.addChild(evaluate(new ArrayList<>(tokens.subList(1, tokens.size()))));
} else {
throw new ParseException("more than one arg: " + prev.postfixCount() + " thrown on: " + prev + " all: " + tokens);
}
return currentParent;
}
private ArrayList<ArrayList<LexToken>> splitStatements(ArrayList<LexToken> tokens) throws ParseException {
System.out.println(ConsoleColors.YELLOW_BACKGROUND_BRIGHT + ConsoleColors.BLACK_BOLD + "SPLITTER" + ConsoleColors.RESET);
ArrayList<ArrayList<LexToken>> tokensSplit = new ArrayList<>();
tokensSplit.add(new ArrayList<>());
ListIterator<LexToken> iterator = tokens.listIterator();
if (tokens.size() < 2) {
throw new ParseException("code has to consist of at least 2 tokens");
}
LexToken prev;
LexToken curr = iterator.next();
tokensSplit.get(0).add(curr);
int i = 0;
int brackets = 0;
while (iterator.hasNext()) {
prev = curr;
curr = iterator.next();
if (curr.getKey() == WordType.BOPEN) {
brackets++;
}
if (brackets == 0 && !prev.hasPostfix() && !curr.hasPrefix()) {
//when there is no connection between two tokens, they are part of seperate statements
tokensSplit.add(new ArrayList<>());
i++;
}
tokensSplit.get(i).add(curr);
if (curr.getKey() == WordType.BCLOSE) {
brackets--;
}
}
return tokensSplit;
} }
} }