292 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			D
		
	
	
	
	
	
			
		
		
	
	
			292 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			D
		
	
	
	
	
	
| 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;
 | |
|         }
 | |
| 
 | |
|     }
 | |
| 
 | |
| }
 |