mirror of
https://github.com/Noratrieb/Hunterlang.git
synced 2026-01-14 20:45:00 +01:00
parser rewrite wip
This commit is contained in:
parent
d7c9aeb127
commit
7d72665c74
5 changed files with 192 additions and 107 deletions
|
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue