summaryrefslogtreecommitdiff
path: root/dice-lang/src
diff options
context:
space:
mode:
Diffstat (limited to 'dice-lang/src')
-rw-r--r--dice-lang/src/bjc/dicelang/v2/DiceBox.java102
-rw-r--r--dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java112
-rw-r--r--dice-lang/src/bjc/dicelang/v2/DoubleMatcher.java58
-rw-r--r--dice-lang/src/bjc/dicelang/v2/Shunter.java59
-rw-r--r--dice-lang/src/bjc/dicelang/v2/Token.java74
5 files changed, 398 insertions, 7 deletions
diff --git a/dice-lang/src/bjc/dicelang/v2/DiceBox.java b/dice-lang/src/bjc/dicelang/v2/DiceBox.java
new file mode 100644
index 0000000..86bce4d
--- /dev/null
+++ b/dice-lang/src/bjc/dicelang/v2/DiceBox.java
@@ -0,0 +1,102 @@
+package bjc.dicelang.v2;
+
+import java.util.Random;
+
+public class DiceBox {
+ private static final Random rng = new Random();
+
+ public interface Die {
+ boolean canOptimize();
+ int optimize();
+
+ int roll();
+ }
+
+ private static class ScalarDie implements Die {
+ private int val;
+
+ public ScalarDie(int vl) {
+ val = vl;
+ }
+
+ public boolean canOptimize() {
+ return true;
+ }
+
+ public int optimize() {
+ return val;
+ }
+
+ public int roll() {
+ return val;
+ }
+
+ public String toString() {
+ return Integer.toString(val);
+ }
+ }
+
+ private static class SimpleDie implements Die {
+ private int numDice;
+ private int diceSize;
+
+ public SimpleDie(int nDice, int size) {
+ numDice = nDice;
+ diceSize = size;
+ }
+
+ public boolean canOptimize() {
+ if(diceSize == 1) return true;
+ else return false;
+ }
+
+ public int optimize() {
+ return numDice;
+ }
+
+ public int roll() {
+ int total = 0;
+
+ for(int i = 0; i < numDice; i++) {
+ total += rng.nextInt(i) + 1;
+ }
+
+ return total;
+ }
+
+ public String toString() {
+ return numDice + "d" + diceSize;
+ }
+ }
+
+ public static Die parseExpression(String exp) {
+ if(!isValidExpression(exp)) return null;
+
+ if(exp.matches(scalarDiePattern)) {
+ return new ScalarDie(Integer.parseInt(exp));
+ } else if(exp.matches(simpleDiePattern)) {
+ String[] dieParts = exp.split("d");
+
+ if(dieParts[0].equals("")) {
+ return new SimpleDie(1, Integer.parseInt(dieParts[1]));
+ } else {
+ return new SimpleDie(Integer.parseInt(dieParts[0]), Integer.parseInt(dieParts[1]));
+ }
+ }
+
+ return null;
+ }
+
+ private static final String scalarDiePattern = "[\\+\\-]?\\d+";
+ private static final String simpleDiePattern = "(?:\\d+)?d\\d+";
+
+ public static boolean isValidExpression(String exp) {
+ if(exp.matches(scalarDiePattern)) {
+ return true;
+ } else if(exp.matches(simpleDiePattern)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java b/dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java
index 51006d7..d8a43c5 100644
--- a/dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java
+++ b/dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java
@@ -12,6 +12,9 @@ import bjc.utils.funcutils.ListUtils;
import java.util.Arrays;
import java.util.Deque;
import java.util.LinkedList;
+import java.util.regex.Pattern;
+
+import static bjc.dicelang.v2.Token.Type.*;
public class DiceLangEngine {
// Input rules for processing tokens
@@ -24,12 +27,17 @@ public class DiceLangEngine {
// Debug indicator
private boolean debugMode;
+ private final int MATH_PREC = 20;
+ private final int DICE_PREC = 10;
+ private final int EXPR_PREC = 0;
+
public DiceLangEngine() {
opExpansionTokens = new LinkedList<>();
opExpansionTokens.add(new Pair<>("+", "\\+"));
opExpansionTokens.add(new Pair<>("-", "-"));
opExpansionTokens.add(new Pair<>("*", "\\*"));
+ opExpansionTokens.add(new Pair<>("//", "//"));
opExpansionTokens.add(new Pair<>("/", "/"));
opExpansionTokens.add(new Pair<>(":=", ":="));
opExpansionTokens.add(new Pair<>("=>", "=>"));
@@ -37,12 +45,12 @@ public class DiceLangEngine {
deaffixationTokens = new LinkedList<>();
deaffixationTokens.add(new Pair<>("(", "\\("));
- deaffixationTokens.add(new Pair<>(")", "\\("));
+ deaffixationTokens.add(new Pair<>(")", "\\)"));
deaffixationTokens.add(new Pair<>("[", "\\["));
deaffixationTokens.add(new Pair<>("]", "\\]"));
nextLiteral = 1;
-
+
// @TODO make configurable
debugMode = true;
}
@@ -77,9 +85,99 @@ public class DiceLangEngine {
});
}
+ IList<String> semiExpandedTokens =
+ ListUtils.deAffixTokens(
+ destringed, deaffixationTokens);
+
+ IList<String> fullyExpandedTokens =
+ ListUtils.splitTokens(
+ semiExpandedTokens, opExpansionTokens);
+
+ if(debugMode)
+ System.out.printf("\tCommand after token"
+ + " expansion: "
+ + fullyExpandedTokens.toString()
+ + "\n");
+
+ IList<Token> lexedTokens = new FunctionalList<>();
+
+ for(String token : fullyExpandedTokens.toIterable()) {
+ Token tk = lexToken(token);
+
+ if(tk == null) continue;
+ else if(tk == Token.NIL_TOKEN) return false;
+ else lexedTokens.add(tk);
+ }
+
+ if(debugMode)
+ System.out.printf("\tCommand after tokenization: %s\n", lexedTokens.toString());
+
return true;
}
+ private Token lexToken(String token) {
+ if(token.equals("")) return null;
+
+ Token tk = Token.NIL_TOKEN;
+
+ switch(token) {
+ case "+":
+ tk = new Token(ADD);
+ break;
+ case "-":
+ tk = new Token(SUBTRACT);
+ break;
+ case "*":
+ tk = new Token(MULTIPLY);
+ break;
+ case "/":
+ tk = new Token(DIVIDE);
+ break;
+ case "//":
+ tk = new Token(IDIVIDE);
+ break;
+ case "(":
+ tk = new Token(OPAREN);
+ break;
+ case ")":
+ tk = new Token(CPAREN);
+ break;
+ case "[":
+ tk = new Token(OBRACKET);
+ break;
+ case "]":
+ tk = new Token(CBRACKET);
+ break;
+ default:
+
+ tk = tokenizeLiteral(token);
+ }
+
+ return tk;
+ }
+
+ private Pattern intMatcher = Pattern.compile(
+ "[\\-\\+]?\\d+");
+
+ private Token tokenizeLiteral(String token) {
+ Token tk = Token.NIL_TOKEN;
+
+ if(DoubleMatcher.floatingLiteral.matcher(token).matches()) {
+ tk = new Token(FLOAT_LIT, Double.parseDouble(token));
+ } else if(intMatcher.matcher(token).matches()) {
+ tk = new Token(INT_LIT, Integer.parseInt(token));
+ } else if(DiceBox.isValidExpression(token)) {
+ tk = new Token(DICE_LIT, DiceBox.parseExpression(token));
+ } else {
+ System.out.printf("\tERROR: Unrecognized token:"
+ + "%s\n", token);
+
+ return tk;
+ }
+
+ return tk;
+ }
+
private boolean destringTokens(IList<String> tokens,
IMap<String, String> stringLiterals,
IList<String> destringed) {
@@ -96,7 +194,7 @@ public class DiceLangEngine {
String litName = literalName + nextLiteral++;
stringLiterals.put(litName,
- token.substring(1, token.length() - 1));
+ token.substring(1, token.length() - 1));
destringed.add(litName);
continue;
@@ -105,7 +203,7 @@ public class DiceLangEngine {
if(stringMode) {
// @TODO make this not an error
System.out.printf("\tPARSER ERROR: Initial"
- +" quotes can only start strings\n");
+ +" quotes can only start strings\n");
} else {
currentLiteral.append(token.substring(1) + " ");
@@ -115,11 +213,11 @@ public class DiceLangEngine {
if(!stringMode) {
// @TODO make this not an error
System.out.printf("\tPARSER ERROR: Terminal"
- +" quotes can only end strings\n");
+ +" quotes can only end strings\n");
return false;
} else {
currentLiteral.append(
- token.substring(0, token.length() - 1));
+ token.substring(0, token.length() - 1));
String litName = literalName + nextLiteral++;
@@ -137,7 +235,7 @@ public class DiceLangEngine {
currentLiteral.append(token + " ");
} else {
System.out.printf("\tERROR: Escaped quote "
- + " outside of string literal\n");
+ + " outside of string literal\n");
return false;
}
} else {
diff --git a/dice-lang/src/bjc/dicelang/v2/DoubleMatcher.java b/dice-lang/src/bjc/dicelang/v2/DoubleMatcher.java
new file mode 100644
index 0000000..3c6f6c5
--- /dev/null
+++ b/dice-lang/src/bjc/dicelang/v2/DoubleMatcher.java
@@ -0,0 +1,58 @@
+package bjc.dicelang.v2;
+
+import java.util.regex.Pattern;
+
+/**
+ * Checks if a string would pass Double.parseDouble.
+ *
+ * Uses a regex from the javadoc for Double.valueOf()
+ */
+public class DoubleMatcher {
+ private static final String Digits =
+ "(\\p{Digit}+)";
+ private static final String HexDigits =
+ "(\\p{XDigit}+)";
+
+ // an exponent is 'e' or 'E' followed by an optionally
+ // signed decimal integer.
+ private static final String Exp =
+ "[eE][+-]?" + Digits;
+
+ private static final String fpRegex =
+ ("[\\x00-\\x20]*" +
+ // Optional leading "whitespace"
+ "[+-]?(" + // Optional sign character
+ "NaN|" + // "NaN" string
+ "Infinity|" + // "Infinity" string
+
+ // A decimal floating-point string representing a finite positive
+ // number without a leading sign has at most five basic pieces:
+ // Digits . Digits ExponentPart FloatTypeSuffix
+ //
+ // Since this method allows integer-only strings as input
+ // in addition to strings of floating-point literals, the
+ // two sub-patterns below are simplifications of the grammar
+ // productions from section 3.10.2 of
+ // The Java™ Language Specification.
+
+ // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
+ "((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+
+
+ // . Digits ExponentPart_opt FloatTypeSuffix_opt
+ "(\\.("+Digits+")("+Exp+")?)|"+
+
+ // Hexadecimal strings
+ "((" +
+ // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
+ "(0[xX]" + HexDigits + "(\\.)?)|" +
+
+ // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
+ "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +
+
+ ")[pP][+-]?" + Digits + "))" +
+ "[fFdD]?))" +
+ "[\\x00-\\x20]*");// Optional trailing "whitespace"
+
+ public static final Pattern floatingLiteral = Pattern.compile(fpRegex);
+
+}
diff --git a/dice-lang/src/bjc/dicelang/v2/Shunter.java b/dice-lang/src/bjc/dicelang/v2/Shunter.java
new file mode 100644
index 0000000..bca08eb
--- /dev/null
+++ b/dice-lang/src/bjc/dicelang/v2/Shunter.java
@@ -0,0 +1,59 @@
+package bjc.dicelang.v2;
+
+import bjc.utils.funcdata.FunctionalList;
+import bjc.utils.funcdata.FunctionalMap;
+import bjc.utils.funcdata.IList;
+import bjc.utils.funcdata.IMap;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import static bjc.dicelang.v2.Token.Type.*;
+
+public class Shunter {
+ // The binary operators and their
+ // priorities
+ private IMap<Token.Type, Integer> ops;
+
+ // Unary operators that can only be
+ // applied to non-operator tokens
+ private Set<Token.Type> unaryAdjectives;
+
+ // Unary operators that con only be
+ // applied to operator tokens
+ private Set<Token.Type> unaryAdverbs;
+
+ private final int MATH_PREC = 20;
+ private final int DICE_PREC = 10;
+ private final int EXPR_PREC = 0;
+
+ public Shunter() {
+ ops = new FunctionalMap<>();
+
+ unaryAdjectives = new HashSet<>();
+ unaryAdverbs = new HashSet<>();
+
+ ops.put(ADD, 0 + MATH_PREC);
+ ops.put(SUBTRACT, 0 + MATH_PREC);
+
+ ops.put(MULTIPLY, 1 + MATH_PREC);
+ ops.put(IDIVIDE, 1 + MATH_PREC);
+ ops.put(DIVIDE, 1 + MATH_PREC);
+
+ ops.put(DICEGROUP, 0 + DICE_PREC);
+ ops.put(DICECONCAT, 1 + DICE_PREC);
+
+ ops.put(LET, 0 + EXPR_PREC);
+ ops.put(BIND, 1 + EXPR_PREC);
+ }
+
+ public IList<Token> shuntTokens(IList<Token> tks) {
+ IList<Token> returned = new FunctionalList<>();
+
+ for(Token tk : tks.toIterable()) {
+
+ }
+
+ return returned;
+ }
+}
diff --git a/dice-lang/src/bjc/dicelang/v2/Token.java b/dice-lang/src/bjc/dicelang/v2/Token.java
new file mode 100644
index 0000000..471832e
--- /dev/null
+++ b/dice-lang/src/bjc/dicelang/v2/Token.java
@@ -0,0 +1,74 @@
+package bjc.dicelang.v2;
+
+import bjc.dicelang.IDiceExpression;
+
+/**
+ * Lexer token
+ */
+public class Token {
+ public final static Token NIL_TOKEN = new Token(Type.NIL);
+
+ /**
+ * Possible token types
+ */
+ public static enum Type {
+ ADD, SUBTRACT,
+ MULTIPLY,
+ DIVIDE, IDIVIDE,
+ INT_LIT, FLOAT_LIT, STRING_LIT,
+ VREF,
+ DICE_LIT, DICEGROUP, DICECONCAT,
+ LET, BIND,
+ OPAREN, CPAREN,
+ OBRACKET, CBRACKET,
+ NIL,
+ }
+
+ public final Type type;
+
+ // At most one of these is valid
+ // based on the token type
+ public int intValue;
+ public double floatValue;
+ public DiceBox.Die diceValue;
+
+ public Token(Type typ) {
+ type = typ;
+ }
+
+ public Token(Type typ, int val) {
+ this(typ);
+
+ intValue = val;
+ }
+
+ public Token(Type typ, double val) {
+ this(typ);
+
+ floatValue = val;
+ }
+
+ public Token(Type typ, DiceBox.Die val) {
+ this(typ);
+
+ diceValue = val;
+ }
+
+ public String toString() {
+ switch(type) {
+ case INT_LIT:
+ case STRING_LIT:
+ case VREF:
+ return type.toString() + "("
+ + intValue + ")";
+ case FLOAT_LIT:
+ return type.toString() + "("
+ + floatValue + ")";
+ case DICE_LIT:
+ return type.toString() + "("
+ + diceValue + ")";
+ default:
+ return type.toString();
+ }
+ }
+}