assignment parsing works

This commit is contained in:
nora 2021-01-16 18:11:18 +01:00
parent 9de19a993e
commit 313a584631
12 changed files with 424 additions and 108 deletions

2
.idea/.gitignore generated vendored
View file

@ -2,4 +2,4 @@
/shelf/
/workspace.xml
out\
.class
*.class

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.github.nilstrieb.hunterlang.editor.EditorView">
<grid id="27dc6" binding="panel1" default-binding="true" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="500" height="400"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="beb13" class="javax.swing.JEditorPane" binding="editorPane1" default-binding="true">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false">
<preferred-size width="150" height="50"/>
</grid>
</constraints>
<properties/>
</component>
</children>
</grid>
</form>

View file

@ -1,8 +0,0 @@
package com.github.nilstrieb.hunterlang.editor;
import javax.swing.*;
public class EditorView {
private JEditorPane editorPane1;
private JPanel panel1;
}

View file

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

View file

@ -1,6 +1,7 @@
package com.github.nilstrieb.hunterlang.lexer;
import com.github.nilstrieb.hunterlang.lib.ConsoleColors;
import com.github.nilstrieb.hunterlang.parser.ParseTreeNode;
public class LexToken {
WordType key;
@ -11,11 +12,34 @@ public class LexToken {
this.value = value;
}
public LexToken(WordType key) {
this(key, "");
}
public int expectsPostArgCount() {
return key.expectsPostArg();
}
public boolean expectsPreArg() {
return key.expectsPreArg() > 0;
}
public ParseTreeNode toNode(){
return new ParseTreeNode(key, value);
}
@Override
public String toString() {
return ConsoleColors.BLUE_BOLD + "{Key=" +
return ConsoleColors.PURPLE_BOLD + "T" + ConsoleColors.BLUE_BOLD + "{Key=" +
ConsoleColors.RED_BOLD_BRIGHT + key +
ConsoleColors.BLUE_BOLD + ", value=" +
ConsoleColors.YELLOW + value + ConsoleColors.BLUE_BOLD + "}";
ConsoleColors.YELLOW + value + ConsoleColors.BLUE_BOLD + "}" + ConsoleColors.RESET;
}
public WordType getKey() {
return key;
}
public String getValue() {
return value;
}
}

View file

@ -1,27 +0,0 @@
package com.github.nilstrieb.hunterlang.lexer;
import java.util.ArrayList;
public class LexedList {
private ArrayList<ArrayList<LexToken>> list;
public LexedList() {
list = new ArrayList<>();
}
public void newLine(){
list.add(new ArrayList<>());
}
public void add(int line, WordType type, String value) {
list.get(line).add(new LexToken(type, value));
}
public void add(int line, WordType type){
add(line, type, "");
}
public ArrayList<LexToken> get(int i) {
return list.get(i);
}
}

View file

@ -1,6 +1,9 @@
package com.github.nilstrieb.hunterlang.lexer;
import com.github.nilstrieb.hunterlang.lib.ConsoleColors;
import com.github.nilstrieb.hunterlang.parser.ParseException;
import com.github.nilstrieb.hunterlang.parser.ParseTreeNode;
import com.github.nilstrieb.hunterlang.parser.Parser;
import java.util.ArrayList;
@ -31,15 +34,16 @@ public class Lexer {
public static final String STRING_REGEX = "^\"(.*)\".*";
public static final String NUMBER_REGEX = "^(-?\\d+.?\\d*).*";
private LexedList tokens;
private ArrayList<LexToken> tokens;
private ArrayList<LexToken> temp;
public ArrayList<LexToken> lex(String code) {
tokens = new ArrayList<>();
temp = new ArrayList<>();
public LexedList lex(String code) {
tokens = new LexedList();
ArrayList<LexToken> tempList = new ArrayList<>();
String[] lines = code.split("\\r\\n|\\n");
for (int i = 0; i < lines.length; i++) {
tokens.newLine();
String line = lines[i];
for (int j = 0; j < line.length(); j++) {
String sub = line.substring(j);
@ -53,103 +57,127 @@ public class Lexer {
//FIXED KEYWORDS
else if (sub.startsWith(MEMCALL)) {
tokens.add(i, WordType.MEMCALL);
addToken(WordType.MEMCALL);
j += MEMCALL.length() - 1;
} else if (sub.startsWith(ASSIGNMENT)) {
tokens.add(i, WordType.ASSIGNMENT);
addToken(WordType.ASSIGNMENT);
j += ASSIGNMENT.length() - 1;
} else if (sub.startsWith(IF)) {
tokens.add(i, WordType.IF);
addToken(WordType.IF);
j += IF.length() - 1;
} else if (sub.startsWith(WANTS)){
tokens.add(i, WordType.WANTS);
} else if (sub.startsWith(WANTS)) {
addToken(WordType.WANTS);
j += WANTS.length() - 1;
} else if (sub.startsWith(ELSE)){
tokens.add(i, WordType.ELSE);
} else if (sub.startsWith(ELSE)) {
addToken(WordType.ELSE);
j += ELSE.length() - 1;
}
//CONDITIONS
else if (sub.startsWith(GTHAN)){
tokens.add(i, WordType.GTHAN);
else if (sub.startsWith(GTHAN)) {
addToken(WordType.GTHAN);
j += GTHAN.length() - 1;
} else if (sub.startsWith(LTHAN)){
tokens.add(i, WordType.LTHAN);
} else if (sub.startsWith(LTHAN)) {
addToken(WordType.LTHAN);
j += LTHAN.length() - 1;
} else if (sub.startsWith(EQUALS)){
tokens.add(i, WordType.EQUALS);
} else if (sub.startsWith(EQUALS)) {
addToken(WordType.EQUALS);
j += EQUALS.length() - 1;
}
//OPERATORS
else if (sub.startsWith(PLUS)){
tokens.add(i, WordType.PLUS);
} else if (sub.startsWith(MINUS)){
tokens.add(i, WordType.MINUS);
} else if (sub.startsWith(MULTIPLY)){
tokens.add(i, WordType.MULTIPLY);
}else if (sub.startsWith(DIVIDE)){
tokens.add(i, WordType.DIVIDE);
} else if (sub.startsWith(MOD)){
tokens.add(i, WordType.MOD);
else if (sub.startsWith(PLUS)) {
addToken(WordType.PLUS);
} else if (sub.startsWith(MINUS)) {
addToken(WordType.MINUS);
} else if (sub.startsWith(MULTIPLY)) {
addToken(WordType.MULTIPLY);
} else if (sub.startsWith(DIVIDE)) {
addToken(WordType.DIVIDE);
} else if (sub.startsWith(MOD)) {
addToken(WordType.MOD);
}
// BRACKETS
else if (sub.startsWith(BOPEN)){
tokens.add(i, WordType.BOPEN);
} else if (sub.startsWith(BCLOSE)){
tokens.add(i, WordType.BCLOSE);
else if (sub.startsWith(BOPEN)) {
addToken(WordType.BOPEN);
} else if (sub.startsWith(BCLOSE)) {
addToken(WordType.BCLOSE);
}
//VALUES
else if (sub.matches(STRING_REGEX)) {
String string = sub.replaceAll(STRING_REGEX, "$1");
tokens.add(i, WordType.STRING, string);
addToken(WordType.STRING, string);
j += string.length() + 1;
} else if (sub.matches(NUMBER_REGEX)) {
String number = sub.replaceAll(NUMBER_REGEX, "$1");
tokens.add(i, WordType.NUMBER, number);
addToken(WordType.NUMBER, number);
j += number.length() - 1;
} else if (sub.matches(BOOL_REGEX)){
} else if (sub.matches(BOOL_REGEX)) {
String bool = sub.replaceAll(BOOL_REGEX, "$1");
tokens.add(i, WordType.BOOL, bool);
addToken(WordType.BOOL, bool);
j += bool.length() - 1;
}
//Calls
else if(sub.matches(LIBFUNCCALL_REGEX)){
else if (sub.matches(LIBFUNCCALL_REGEX)) {
String libName = sub.replaceAll(LIBFUNCCALL_REGEX, "$1");
String funcName = sub.replaceAll(LIBFUNCCALL_REGEX, "$2");
tokens.add(i, WordType.LIB, libName);
tokens.add(i, WordType.FUNCCALL, funcName);
addToken(WordType.LIB, libName);
addToken(WordType.FUNCCALL, funcName);
j += libName.length(); //lib name
j += 1 + 4 + 1; // space + does + space
j += funcName.length() - 1; //func name
}
}
System.out.println(ConsoleColors.GREEN_BOLD + line);
System.out.println(ConsoleColors.BLUE_BOLD + tokens.get(i));
System.out.println(ConsoleColors.BLUE_BOLD + temp);
tokens.addAll(temp);
temp.clear();
}
return tokens;
}
private void addToken(WordType type, String value) {
temp.add(new LexToken(type, value));
}
private void addToken(WordType type) {
temp.add(new LexToken(type));
}
public static void main(String[] args) {
Lexer l = new Lexer();
LexedList tokens = l.lex("""
String assign = """
killua0 hunts 3
killua0 hunts -3.4 #hunts nothing
killua0 hunts 4
killua1 hunts "hallo"
#comment
#comment""";
String ifs = """
Gon wants false {
Leorio does say "false"
} wants killua0 > 3 {
}
wants killua0 > 3 {
Leorio does say "big killua"
} got {
Leorio does say "small killua"
}
""");
""";
ArrayList<LexToken> tokens = l.lex(ifs);
Parser p = new Parser();
try {
ArrayList<ParseTreeNode> nodes = p.parse(tokens);
for (ParseTreeNode node : nodes) {
System.out.println(node);
}
} catch (ParseException e) {
e.printStackTrace();
}
}
}

View file

@ -1,5 +1,49 @@
package com.github.nilstrieb.hunterlang.lexer;
public enum WordType {
ASSIGNMENT, MEMCALL, STRING, NUMBER, BOOL, IF, WANTS, ELSE, BOPEN, BCLOSE, GTHAN, LTHAN, EQUALS, FUNCNAME, FUNCARGS, FUNCRETURN, IOCALL, FUNCCALL, OPERATOR, LIB, MINUS, DEFAULT, PLUS, MULTIPLY, DIVIDE, MOD;
ASSIGNMENT(1, 1), //memory, value
MEMCALL(1), //adress
STRING,
NUMBER,
BOOL,
IF(1), //wants
WANTS(2), //condition, body
ELSE(1), //body
BOPEN(-1), //body, close
BCLOSE,
GTHAN(1, 1),
LTHAN(1, 1),
EQUALS(1, 1),
FUNCCALL(-1), //args
LIB(1), //function
MINUS(1, 1),
PLUS(1, 1),
MULTIPLY(1, 1),
DIVIDE(1, 1),
MOD(1, 1),
NEGATIVE(1),
EMPTY;
private int postArgAmount;
private int preArgAmount;
WordType(int postArgAmount, int preArgAmount) {
this.postArgAmount = postArgAmount;
this.preArgAmount = preArgAmount;
}
WordType(int postArgAmount) {
this(postArgAmount, 0);
}
WordType() {
this(0, 0);
}
public int expectsPostArg() {
return postArgAmount;
}
public int expectsPreArg() {
return preArgAmount;
}
}

View file

@ -0,0 +1,7 @@
package com.github.nilstrieb.hunterlang.parser;
public class ParseException extends Exception{
public ParseException(String message) {
super(message);
}
}

View file

@ -0,0 +1,44 @@
package com.github.nilstrieb.hunterlang.parser;
import com.github.nilstrieb.hunterlang.lexer.LexToken;
import com.github.nilstrieb.hunterlang.lexer.WordType;
import java.util.ArrayList;
public class ParseTreeBodyNode extends ParseTreeNode{
private ArrayList<ParseTreeNode> statements;
private ArrayList<LexToken> tokens;
public ParseTreeBodyNode(WordType key, String value) {
super(key, value);
this.statements = new ArrayList<>();
this.tokens = new ArrayList<>();
}
public ParseTreeBodyNode(ParseTreeNode node) {
this(node.key, node.value);
}
public ArrayList<ParseTreeNode> getStatements() {
return statements;
}
public void addToken(LexToken currentToken) {
tokens.add(currentToken);
}
@Override
public String toString() {
return super.toString() + statements;
}
@Override
public String toString(String indent) {
return super.toString(indent) + statements;
}
public void parse() throws ParseException {
Parser p = new Parser();
statements = p.parse(tokens);
}
}

View file

@ -0,0 +1,99 @@
package com.github.nilstrieb.hunterlang.parser;
import com.github.nilstrieb.hunterlang.lexer.WordType;
import com.github.nilstrieb.hunterlang.lib.ConsoleColors;
import java.util.ArrayList;
public class ParseTreeNode {
WordType key;
String value;
ArrayList<ParseTreeNode> children;
int remainingPreArgs;
int remainingPostArgs;
public ParseTreeNode(WordType key, String value) {
this.key = key;
this.value = value;
children = new ArrayList<>();
remainingPostArgs = key.expectsPostArg();
remainingPreArgs = key.expectsPreArg();
}
public ParseTreeNode() {
this(WordType.EMPTY, "");
}
public ArrayList<ParseTreeNode> getChildren() {
return children;
}
public void addChild(ParseTreeNode n, boolean pre) {
children.add(n);
if (pre) {
remainingPreArgs--;
}
}
public void addChild(ParseTreeNode n) {
addChild(n, false);
}
public int expectsPostArgCount() {
return remainingPostArgs;
}
public boolean expectsPreArg() {
return remainingPreArgs > 0;
}
public void setKey(WordType key) {
this.key = key;
remainingPostArgs = key.expectsPostArg();
remainingPreArgs = key.expectsPreArg();
}
@Override
public String toString() {
return ConsoleColors.PURPLE_BOLD + "N" + ConsoleColors.BLUE_BOLD + "{name=" +
ConsoleColors.RED_BOLD_BRIGHT + key +
ConsoleColors.BLUE_BOLD + ", value=" +
ConsoleColors.YELLOW + value +
ConsoleColors.BLUE_BOLD + ", children=" + printList(children, "") +
ConsoleColors.BLUE_BOLD + "}" + ConsoleColors.RESET;
}
public String toString(String indent) {
return ConsoleColors.PURPLE_BOLD + indent + "N" + ConsoleColors.BLUE_BOLD + "{name=" +
ConsoleColors.RED_BOLD_BRIGHT + key +
ConsoleColors.BLUE_BOLD + ", value=" +
ConsoleColors.YELLOW + value +
ConsoleColors.BLUE_BOLD + ", children=" + printList(children, indent + " ") +
ConsoleColors.BLUE_BOLD + "}" + ConsoleColors.RESET;
}
public String printList(ArrayList<ParseTreeNode> list, String indent) {
if(list.size() == 0){
return "[]";
}
String indentHigher = indent + " ";
StringBuilder sb = new StringBuilder();
for (ParseTreeNode node : list) {
sb.append("[\n");
sb.append(node.toString(indentHigher));
}
sb.append("]");
return sb.toString();
}
public WordType getKey() {
return key;
}
public String getValue() {
return value;
}
}

View file

@ -1,7 +1,118 @@
package com.github.nilstrieb.hunterlang.parser;
public class Parser {
}
import com.github.nilstrieb.hunterlang.hllibrary.FunctionArgLookup;
import com.github.nilstrieb.hunterlang.lexer.LexToken;
import com.github.nilstrieb.hunterlang.lexer.WordType;
import com.github.nilstrieb.hunterlang.lib.ConsoleColors;
class ParseTreeNode {
import java.util.ArrayList;
import java.util.ListIterator;
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 {
System.out.println(ConsoleColors.GREEN_BACKGROUND + ConsoleColors.BLACK_BOLD + "------START PARSER------" + ConsoleColors.RESET);
ArrayList<ParseTreeNode> statements = new ArrayList<>();
iterator = tokens.listIterator();
currentToken = iterator.next();
if (iterator.hasNext()) {
nextToken = iterator.next();
}
//goes through each statement. On pass -> one statement
do {
System.out.println(ConsoleColors.GREEN_BRIGHT + "NEXT STATEMENT");
prevNode = new ParseTreeNode();
//start with first token
ParseTreeNode startNode = currentToken.toNode();
//if it wants a pre argument theres an error
if (currentToken.expectsPreArg()) {
throw new ParseException("previous expression expected, doesn't exist");
}
//calculate the arguments of the start node, parsing the whole statement
getArguments(startNode, true);
System.out.println(prevNode);
statements.add(prevNode);
} while (iterator.hasNext());
System.out.println(ConsoleColors.GREEN_BACKGROUND + ConsoleColors.BLACK_BOLD + "------STOP PARSER------" + ConsoleColors.RESET);
return statements;
}
private void getArguments(ParseTreeNode node, boolean isParent) throws ParseException {
if (node.getKey() == WordType.MINUS && prevNode.getKey() != WordType.NUMBER) {
node.setKey(WordType.NEGATIVE);
}
if (node.expectsPreArg()) {
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;
}
if (expectedArg == 0) {
nextToken();
} else {
nextToken();
for (int i = 0; i < expectedArg; i++) {
ParseTreeNode child = currentToken.toNode();
getArguments(child, false);
node.addChild(child);
}
}
if (currentToken != null && currentToken.expectsPreArg()) {
getArguments(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()) {
nextToken = iterator.next();
}
}
}