Add existing files

This commit is contained in:
2022-07-25 22:07:11 +02:00
parent 51b4289c74
commit 0f35a253a9
9 changed files with 1232 additions and 0 deletions
+41
View File
@@ -0,0 +1,41 @@
import std.stdio;
import ast;
import parser;
import runtimedata;
void main()
{
Parser par;
EvalReturn ret;
Expr expr;
Variable[string] varStack;
writeln("The SNOL environment is now active, you may proceed with giving your commands.");
do
{
write("Command: ");
try
{
par = Parser(readln());
expr = par.parse();
if (expr !is null)
{
ret = expr.evaluate(varStack);
}
}
catch(ParseException e)
{
writeln(e.msg);
}
catch(RunException e)
{
writeln(e.msg);
}
}
while (ret.type != EVAL_TYPE.EXIT);
writeln("Interpreter is now terminated...");
}
+366
View File
@@ -0,0 +1,366 @@
module ast;
import std.stdio;
import runtimedata;
import std.string;
import std.conv;
abstract class Expr
{
Expr masterExpr = null;
EvalReturn evaluate(ref Variable[string] varStack);
}
class FloatExpr : Expr
{
this(float val)
{
value = val;
}
float value;
override EvalReturn evaluate(ref Variable[string] varStack)
{
return EvalReturn(EVAL_TYPE.NUMBER, DATA_TYPE.FLOAT, value);
}
}
class IntExpr : Expr
{
this(int val)
{
value = val;
}
int value;
override EvalReturn evaluate(ref Variable[string] varStack)
{
return EvalReturn(EVAL_TYPE.NUMBER, DATA_TYPE.INTEGER, value);
}
}
class VarExpr : Expr
{
this(string var)
{
varName = var;
}
string varName;
override EvalReturn evaluate(ref Variable[string] varStack)
{
const Variable* varPtr = (varName in varStack);
if (varPtr is null)
{
return EvalReturn(EVAL_TYPE.UNDEFINED_VAR, DATA_TYPE.NONE, varName);
}
else
{
return EvalReturn(EVAL_TYPE.VAR, DATA_TYPE.VAR_POINTER, varName);
}
}
}
class OpExpr : Expr
{
this(char op, bool unary = false)
{
this.op = op;
this.unary = unary;
}
bool unary;
char op;
Expr RHE;
Expr LHE;
override EvalReturn evaluate(ref Variable[string] varStack)
{
EvalReturn left = void;
if (!unary)
{
left = LHE.evaluate(varStack);
}
EvalReturn right = RHE.evaluate(varStack);
if (op == '=') //ASSIGN
{
if (right.type == EVAL_TYPE.UNDEFINED_VAR)
throw new RunException("Error! ["~right.sVar ~ "] is not defined!");
if (left.type == EVAL_TYPE.UNDEFINED_VAR)
varStack[left.sVar] = Variable();
if (right.type == EVAL_TYPE.VAR)
{
varStack[left.sVar].dataType = varStack[right.sVar].dataType;
if (varStack[left.sVar].dataType == DATA_TYPE.INTEGER)
varStack[left.sVar].iVal = varStack[right.sVar].iVal;
else
varStack[left.sVar].fVal = varStack[right.sVar].fVal;
}
else
{
if (right.dataType == DATA_TYPE.INTEGER)
{
varStack[left.sVar].iVal = right.iVal;
varStack[left.sVar].dataType = right.dataType;
}
else if (right.dataType == DATA_TYPE.FLOAT)
{
varStack[left.sVar].fVal = right.fVal;
varStack[left.sVar].dataType = right.dataType;
}
}
return EvalReturn(EVAL_TYPE.ASSIGN, DATA_TYPE.NONE, 0);
}
else if (op == '-' && unary) //UNARY -
{
if (right.type == EVAL_TYPE.UNDEFINED_VAR)
throw new RunException("Error! ["~right.sVar ~ "] is not defined!");
if (right.type == EVAL_TYPE.VAR)
{
if (varStack[right.sVar].dataType == DATA_TYPE.INTEGER)
{
return EvalReturn(EVAL_TYPE.NUMBER, DATA_TYPE.INTEGER, -varStack[right.sVar]
.iVal);
}
else if (varStack[right.sVar].dataType == DATA_TYPE.FLOAT)
{
return EvalReturn(EVAL_TYPE.NUMBER, DATA_TYPE.FLOAT, -varStack[right.sVar].fVal);
}
}
else if (right.type == EVAL_TYPE.NUMBER)
{
if (right.dataType == DATA_TYPE.INTEGER)
return EvalReturn(EVAL_TYPE.NUMBER, DATA_TYPE.INTEGER, -right.iVal);
else if (right.dataType == DATA_TYPE.FLOAT)
return EvalReturn(EVAL_TYPE.NUMBER, DATA_TYPE.FLOAT, -right.fVal);
}
}
else if (op == '+' && unary) //UNARY +
{
if (right.type == EVAL_TYPE.UNDEFINED_VAR)
throw new RunException("Error! ["~right.sVar ~ "] is not defined!");
if (right.type == EVAL_TYPE.VAR)
{
if (varStack[right.sVar].dataType == DATA_TYPE.INTEGER)
{
return EvalReturn(EVAL_TYPE.NUMBER, DATA_TYPE.INTEGER, varStack[right.sVar]
.iVal);
}
else if (varStack[right.sVar].dataType == DATA_TYPE.FLOAT)
{
return EvalReturn(EVAL_TYPE.NUMBER, DATA_TYPE.FLOAT, varStack[right.sVar].fVal);
}
}
else if (right.type == EVAL_TYPE.NUMBER)
{
if (right.dataType == DATA_TYPE.INTEGER)
return EvalReturn(EVAL_TYPE.NUMBER, DATA_TYPE.INTEGER, right.iVal);
else if (right.dataType == DATA_TYPE.FLOAT)
return EvalReturn(EVAL_TYPE.NUMBER, DATA_TYPE.FLOAT, right.fVal);
}
}
else if (indexOf("*/+-%", op) > -1) // rest
{
if (right.type == EVAL_TYPE.UNDEFINED_VAR)
throw new RunException("Error! ["~ right.sVar ~ "] is not defined!");
if (left.type == EVAL_TYPE.UNDEFINED_VAR)
throw new RunException("Error! ["~right.sVar ~ "] is not defined!");
DATA_TYPE r;
DATA_TYPE l;
union Data
{
int Int;
float Float;
}
Data leftData,rightData;
if (right.type == EVAL_TYPE.VAR)
{
if (varStack[right.sVar].dataType == DATA_TYPE.INTEGER)
{
r = varStack[right.sVar].dataType;
rightData.Int = varStack[right.sVar].iVal;
}
else if (varStack[right.sVar].dataType == DATA_TYPE.FLOAT)
{
r = varStack[right.sVar].dataType;
rightData.Float = varStack[right.sVar].fVal;
}
}
else if (right.type == EVAL_TYPE.NUMBER)
{
if (right.dataType == DATA_TYPE.INTEGER)
{
r = right.dataType;
rightData.Int = right.iVal;
}
else if (right.dataType == DATA_TYPE.FLOAT)
{
r = right.dataType;
rightData.Float = right.fVal;
}
}
if (left.type == EVAL_TYPE.VAR)
{
if (varStack[left.sVar].dataType == DATA_TYPE.INTEGER)
{
l = varStack[left.sVar].dataType;
leftData.Int = varStack[left.sVar].iVal;
}
else if (varStack[left.sVar].dataType == DATA_TYPE.FLOAT)
{
l = varStack[left.sVar].dataType;
leftData.Float = varStack[left.sVar].fVal;
}
}
else if (left.type == EVAL_TYPE.NUMBER)
{
if (left.dataType == DATA_TYPE.INTEGER)
{
l = right.dataType;
leftData.Int = left.iVal;
}
else if (left.dataType == DATA_TYPE.FLOAT)
{
l = left.dataType;
leftData.Float = left.fVal;
}
}
if (l != r)
throw new RunException("Error! Operands must be of the same type in an arithmetic operation!");
if (l == DATA_TYPE.INTEGER)
{
switch (op)
{
case '+':
return EvalReturn(EVAL_TYPE.NUMBER, l, leftData.Int + rightData.Int);
case '-':
return EvalReturn(EVAL_TYPE.NUMBER, l, leftData.Int - rightData.Int);
case '*':
return EvalReturn(EVAL_TYPE.NUMBER, l, leftData.Int * rightData.Int);
case '/':
return EvalReturn(EVAL_TYPE.NUMBER, l, leftData.Int / rightData.Int);
case '%':
return EvalReturn(EVAL_TYPE.NUMBER, l, leftData.Int % rightData.Int);
default: break;
}
}
else {
switch (op)
{
case '+':
return EvalReturn(EVAL_TYPE.NUMBER, l, leftData.Float + rightData.Float);
case '-':
return EvalReturn(EVAL_TYPE.NUMBER, l, leftData.Float - rightData.Float);
case '*':
return EvalReturn(EVAL_TYPE.NUMBER, l, leftData.Float * rightData.Float);
case '/':
return EvalReturn(EVAL_TYPE.NUMBER, l, leftData.Float / rightData.Float);
case '%':
return EvalReturn(EVAL_TYPE.NUMBER, l, leftData.Float % rightData.Float);
default: break;
}
}
}
return EvalReturn(EVAL_TYPE.NUMBER, DATA_TYPE.NONE, 0);
}
}
class BEGExpr : Expr
{
VarExpr RHE;
override EvalReturn evaluate(ref Variable[string] varStack)
{
EvalReturn r = RHE.evaluate(varStack);
write("Input: ");
string input = strip(readln());
if (isNumeric(input))
{
if (r.type == EVAL_TYPE.UNDEFINED_VAR)
varStack[r.sVar] = Variable();
try
{
varStack[r.sVar].iVal = to!int(input);
varStack[r.sVar].dataType = DATA_TYPE.INTEGER;
}
catch (ConvException e)
{
varStack[r.sVar].fVal = to!float(input);
varStack[r.sVar].dataType = DATA_TYPE.FLOAT;
}
}
else
{
throw new RunException("Error! Cannot convert input");
}
return EvalReturn(EVAL_TYPE.BEG, DATA_TYPE.NONE, 0);
}
}
class PRINTExpr : Expr
{
VarExpr RHE;
override EvalReturn evaluate(ref Variable[string] varStack)
{
EvalReturn r = RHE.evaluate(varStack);
if (r.type == EVAL_TYPE.UNDEFINED_VAR)
{
writeln("SNOL> Error! [" ~ r.sVar ~ "] is not defined!");
}
else if (r.type == EVAL_TYPE.VAR)
{
Variable* v = (r.sVar in varStack);
if (v.dataType == DATA_TYPE.INTEGER)
writeln("SNOL> [" ~ r.sVar ~ "] = ", v.iVal);
else
writeln("SNOL> [" ~ r.sVar ~ "] = ", v.fVal);
}
return EvalReturn(EVAL_TYPE.PRINT, DATA_TYPE.NONE, 0);
}
}
class EXITExpr : Expr
{
override EvalReturn evaluate(ref Variable[string] varStack)
{
return EvalReturn(EVAL_TYPE.EXIT, DATA_TYPE.NONE, 0);
}
}
+152
View File
@@ -0,0 +1,152 @@
module lexer;
import std.stdio;
import core.stdc.ctype;
import std.string;
enum TOKEN_TYPE
{
OPERATOR,
INTEGER,
FLOAT,
VARIABLE,
PROCEDURE,
UNKNOWN,
END_OF_TEXT
}
struct Token
{
TOKEN_TYPE type;
string data;
}
const string OPERATORS = "=+-*/%";
struct Lexer
{
long position = 0;
private string textToTokenize;
this(string textToTokenize)
{
this.textToTokenize = textToTokenize;
}
Token getNextToken()
{
if (position >= textToTokenize.length)
return Token(TOKEN_TYPE.END_OF_TEXT, null);
string dataStr;
char lastChar = textToTokenize[position];
while (isspace(lastChar))
{
position++;
if (position >= textToTokenize.length)
return Token(TOKEN_TYPE.END_OF_TEXT, null);
lastChar = textToTokenize[position];
}
if (isalpha(lastChar))
{
dataStr ~= lastChar;
lastChar = textToTokenize[++position];
while (isalnum(lastChar))
{
dataStr ~= lastChar;
position++;
if (position >= textToTokenize.length)
break;
else
lastChar = textToTokenize[position];
}
if (dataStr == "BEG")
return Token(TOKEN_TYPE.PROCEDURE, dataStr);
else if (dataStr == "PRINT")
{
return Token(TOKEN_TYPE.PROCEDURE, dataStr);
}
else if (dataStr == "EXIT" && lastChar == '!')
{
position++;
return Token(TOKEN_TYPE.PROCEDURE, dataStr);
}
else
{
return Token(TOKEN_TYPE.VARIABLE, dataStr);
}
}
if (indexOf(OPERATORS, lastChar) > -1)
{
dataStr ~= lastChar;
position++;
return Token(TOKEN_TYPE.OPERATOR, dataStr);
}
if (isdigit(lastChar))
{
dataStr ~= lastChar;
position++;
if (position >= textToTokenize.length)
return Token(TOKEN_TYPE.INTEGER, dataStr);
lastChar = textToTokenize[position];
while (isdigit(lastChar))
{
dataStr ~= lastChar;
position++;
if (position >= textToTokenize.length)
return Token(TOKEN_TYPE.INTEGER, dataStr);
lastChar = textToTokenize[position];
}
if (lastChar == '.')
{
dataStr ~= lastChar;
position++;
if (position >= textToTokenize.length)
{
position--;
return Token(TOKEN_TYPE.INTEGER, dataStr);
}
lastChar = textToTokenize[position];
while (isdigit(lastChar))
{
dataStr ~= lastChar;
position++;
if (position >= textToTokenize.length)
return Token(TOKEN_TYPE.FLOAT, dataStr);
lastChar = textToTokenize[position];
}
if(dataStr[$-1] == '.')
{
position--;
return Token(TOKEN_TYPE.INTEGER, dataStr[0..$-1]);
}
return Token(TOKEN_TYPE.FLOAT, dataStr);
}
else
{
return Token(TOKEN_TYPE.INTEGER, dataStr);
}
}
dataStr ~= lastChar;
position++;
return Token(TOKEN_TYPE.UNKNOWN, dataStr);
}
}
+291
View File
@@ -0,0 +1,291 @@
module parser;
import lexer;
import ast;
import std.stdio;
import std.conv;
import std.string;
class ParseException : Exception
{
this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null) pure nothrow @nogc @safe
{
super(msg, file, line, nextInChain);
}
}
struct Parser
{
Lexer lex;
Token[] tokens = [];
Expr[] expr = [];
this(string textToParse)
{
lex = Lexer(textToParse);
}
Expr parse()
{
syntaxSanityCheck();
buildAST();
Expr topExpr = null;
if(expr.length < 1)
return null;
foreach (Expr key; expr)
{
if (key.masterExpr is null)
{
topExpr = key;
break;
}
}
return topExpr;
}
private void syntaxSanityCheck()
{
Token currentToken = lex.getNextToken();
tokens ~= currentToken;
while (currentToken.type != TOKEN_TYPE.END_OF_TEXT)
{
//writeln(currentToken);
if (currentToken.type == TOKEN_TYPE.PROCEDURE && currentToken.data == "BEG")
{
currentToken = lex.getNextToken();
tokens ~= currentToken;
if (currentToken.type != TOKEN_TYPE.VARIABLE)
{
throw new ParseException("Unknown command! Does not match any valid command of the language.");
}
currentToken = lex.getNextToken();
tokens ~= currentToken;
if (currentToken.type != TOKEN_TYPE.END_OF_TEXT)
{
throw new ParseException("Unknown command! Does not match any valid command of the language.");
}
}
if (currentToken.type == TOKEN_TYPE.PROCEDURE && currentToken.data == "EXIT")
{
currentToken = lex.getNextToken();
tokens ~= currentToken;
if (currentToken.type != TOKEN_TYPE.END_OF_TEXT)
{
throw new ParseException("Unknown command! Does not match any valid command of the language.");
}
}
if (currentToken.type == TOKEN_TYPE.PROCEDURE && currentToken.data == "PRINT")
{
currentToken = lex.getNextToken();
tokens ~= currentToken;
if (currentToken.type != TOKEN_TYPE.VARIABLE)
{
throw new ParseException("Unknown command! Does not match any valid command of the language.");
}
currentToken = lex.getNextToken();
tokens ~= currentToken;
if (currentToken.type != TOKEN_TYPE.END_OF_TEXT)
{
throw new ParseException("Unknown command! Does not match any valid command of the language.");
}
}
else if (currentToken.type == TOKEN_TYPE.OPERATOR)
{
if (currentToken.data == "=")
{
if ((tokens.length > 1 || tokens.length == 0) && tokens[0].type != TOKEN_TYPE
.VARIABLE)
{
throw new ParseException("Unknown command! Does not match any valid command of the language.");
}
currentToken = lex.getNextToken();
tokens ~= currentToken;
}
else if (currentToken.data == "-")
{
currentToken = lex.getNextToken();
tokens ~= currentToken;
if (currentToken.type != TOKEN_TYPE.VARIABLE && currentToken.type != TOKEN_TYPE.INTEGER && currentToken
.type != TOKEN_TYPE.FLOAT)
throw new ParseException("Unknown command! Does not match any valid command of the language.");
if (tokens.length <= 2 || (tokens[$ - 3].type != TOKEN_TYPE.VARIABLE && tokens[$ - 3].type != TOKEN_TYPE
.INTEGER && tokens[$ - 3].type != TOKEN_TYPE.FLOAT))
{
tokens[$ - 2].data = 'u' ~ tokens[$ - 2].data;
}
}
else if (currentToken.data == "+")
{
currentToken = lex.getNextToken();
tokens ~= currentToken;
if (currentToken.type != TOKEN_TYPE.VARIABLE && currentToken.type != TOKEN_TYPE.INTEGER && currentToken
.type != TOKEN_TYPE.FLOAT)
throw new ParseException("Unknown command! Does not match any valid command of the language.");
if (tokens.length <= 2 || (tokens[$ - 3].type != TOKEN_TYPE.VARIABLE && tokens[$ - 3].type != TOKEN_TYPE
.INTEGER && tokens[$ - 3].type != TOKEN_TYPE.FLOAT))
{
tokens[$ - 2].data = 'u' ~ tokens[$ - 2].data;
}
}
else
{
if (tokens[$ - 2].type != TOKEN_TYPE.VARIABLE && tokens[$ - 2].type != TOKEN_TYPE.INTEGER && tokens[$ - 2]
.type != TOKEN_TYPE.FLOAT)
throw new ParseException(
"Unknown command! Does not match any valid");
currentToken = lex.getNextToken();
tokens ~= currentToken;
/*if(currentToken.type!=TOKEN_TYPE.VARIABLE && currentToken.type!=TOKEN_TYPE.INTEGER && currentToken.type!=TOKEN_TYPE.FLOAT)
throw new ParseException("Wrong usage of '"~tokens[$-1].data~"' operator");*/
}
}
else if (currentToken.type == TOKEN_TYPE.FLOAT || currentToken.type == TOKEN_TYPE.INTEGER || currentToken
.type == TOKEN_TYPE.VARIABLE)
{
currentToken = lex.getNextToken();
tokens ~= currentToken;
if (currentToken.type != TOKEN_TYPE.OPERATOR && currentToken.type != TOKEN_TYPE
.END_OF_TEXT)
{
throw new ParseException("Unknown command! Does not match any valid command of the language.");
}
}
else if( currentToken.type == TOKEN_TYPE.UNKNOWN)
{
throw new ParseException("Unexpected token: " ~ currentToken.data);
}
else
{
currentToken = lex.getNextToken();
tokens ~= currentToken;
}
}
}
private void opMaker(int id)
{
OpExpr opExpr = cast(OpExpr) expr[id];
if (!opExpr.unary)
{
Expr leftExpr = expr[id - 1];
while (leftExpr.masterExpr !is null)
{
leftExpr = leftExpr.masterExpr;
}
leftExpr.masterExpr = opExpr;
opExpr.LHE = leftExpr;
}
Expr rightExpr = expr[id + 1];
while (rightExpr.masterExpr !is null)
{
rightExpr = rightExpr.masterExpr;
}
rightExpr.masterExpr = opExpr;
opExpr.RHE = rightExpr;
}
private void buildAST()
{
for (int i = 0; i < tokens.length; i++)
{
if (tokens[i].type == TOKEN_TYPE.END_OF_TEXT)
break;
else if (tokens[i].type == TOKEN_TYPE.FLOAT)
expr ~= new FloatExpr(to!float(tokens[i].data));
else if (tokens[i].type == TOKEN_TYPE.INTEGER)
expr ~= new IntExpr(to!int(tokens[i].data));
else if (tokens[i].type == TOKEN_TYPE.OPERATOR && tokens[i].data[0] == 'u')
expr ~= new OpExpr(to!char(tokens[i].data[1]), true);
else if (tokens[i].type == TOKEN_TYPE.OPERATOR)
expr ~= new OpExpr(to!char(tokens[i].data));
else if (tokens[i].type == TOKEN_TYPE.VARIABLE)
expr ~= new VarExpr(to!string(tokens[i].data));
else if (tokens[i].type == TOKEN_TYPE.PROCEDURE && tokens[i].data == "BEG")
expr ~= new BEGExpr();
else if (tokens[i].type == TOKEN_TYPE.PROCEDURE && tokens[i].data == "PRINT")
expr ~= new PRINTExpr();
else if (tokens[i].type == TOKEN_TYPE.PROCEDURE && tokens[i].data == "EXIT")
expr ~= new EXITExpr();
}
if(expr.length < 1)
return;
for (int i = 0; i < expr.length; i++) // unary
{
if (typeid(expr[i]) == typeid(OpExpr) && (cast(OpExpr) expr[i]).unary)
{
opMaker(i);
}
}
for (int i = 0; i < expr.length; i++) // * / %
{
if (typeid(expr[i]) == typeid(OpExpr) && indexOf("*/%", (cast(OpExpr) expr[i]).op) > -1 && !(
cast(OpExpr) expr[i]).unary)
{
opMaker(i);
}
}
for (int i = 0; i < expr.length; i++) // + -
{
if (typeid(expr[i]) == typeid(OpExpr) && indexOf("+-", (cast(OpExpr) expr[i]).op) > -1 && !(
cast(OpExpr) expr[i]).unary)
{
opMaker(i);
}
}
for (int i = 0; i < expr.length; i++) // =
{
if (typeid(expr[i]) == typeid(OpExpr) && indexOf("=", (cast(OpExpr) expr[i]).op) > -1 && !(
cast(OpExpr) expr[i]).unary)
{
opMaker(i);
}
}
//PROCEDURES expr
if (typeid(expr[0]) == typeid(BEGExpr))
{
BEGExpr begExpr = (cast(BEGExpr) expr[0]);
VarExpr rightExpr = cast(VarExpr) expr[1];
rightExpr.masterExpr = begExpr;
begExpr.RHE = rightExpr;
}
else if (typeid(expr[0]) == typeid(PRINTExpr))
{
PRINTExpr printExpr = (cast(PRINTExpr) expr[0]);
VarExpr rightExpr = cast(VarExpr) expr[1];
rightExpr.masterExpr = printExpr;
printExpr.RHE = rightExpr;
}
}
}
+76
View File
@@ -0,0 +1,76 @@
module runtimedata;
enum DEBUG = true;
class RunException : Exception
{
this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null) pure nothrow @nogc @safe
{
super(msg, file, line, nextInChain);
}
}
enum DATA_TYPE
{
FLOAT,
INTEGER,
VAR_POINTER,
NONE
}
enum EVAL_TYPE
{
NUMBER,
UNDEFINED_VAR,
VAR,
PRINT,
BEG,
ASSIGN,
EXIT
}
struct EvalReturn
{
this(EVAL_TYPE type,DATA_TYPE dataType, float fVal )
{
this.type=type;
this.dataType = dataType;
this.fVal = fVal;
}
this(EVAL_TYPE type,DATA_TYPE dataType, int iVal)
{
this.type=type;
this.dataType = dataType;
this.iVal = iVal;
}
this(EVAL_TYPE type,DATA_TYPE dataType, string sVar)
{
this.type=type;
this.dataType = dataType;
this.sVar = sVar;
}
EVAL_TYPE type;
DATA_TYPE dataType;
union
{
float fVal;
int iVal;
string sVar;
}
}
struct Variable
{
DATA_TYPE dataType;
union
{
float fVal;
int iVal;
}
}