56 lines
1.3 KiB
C#
56 lines
1.3 KiB
C#
using System;
|
|
|
|
using Dungeoneer.Error;
|
|
|
|
namespace Dungeoneer.Interpreter {
|
|
|
|
public static class Parser {
|
|
|
|
public static int ParseRoll(string text) { return ParseRoll(Lexer.Tokenize(text)); }
|
|
public static int ParseRoll(TokenSet tokens) {
|
|
int result = 0;
|
|
bool wasValue = false;
|
|
char operation = '+';
|
|
int? rollDc = null;
|
|
foreach(Token token in tokens) {
|
|
switch(token) {
|
|
case ValueToken value:
|
|
if(wasValue)
|
|
throw new SyntaxException("Value followed by value");
|
|
result = Operate(result, value.Value, operation);
|
|
wasValue = true;
|
|
break;
|
|
case OperatorToken op:
|
|
if(!wasValue)
|
|
throw new SyntaxException("Operator followed by operator");
|
|
operation = op.Value;
|
|
wasValue = false;
|
|
break;
|
|
case DcToken dc:
|
|
if(rollDc.HasValue)
|
|
throw new SyntaxException("Duplicate element: DC");
|
|
rollDc = dc.Value;
|
|
break;
|
|
default:
|
|
throw new SyntaxException($"invalid token: {token.GetType()}");
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static int Operate(int a, int b, char op) {
|
|
switch(op) {
|
|
case '+': return (a + b);
|
|
case '-': return (a - b);
|
|
case '*': return (a * b);
|
|
case '/': return (a / b);
|
|
case '%': return (a % b);
|
|
case '^': return (int)Math.Pow(a, b);
|
|
default: throw new SyntaxException("unmatched operator");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|