public double Calculate() { //изчиствам стека, защото ще го ползвам за пресмятането stack.Clear(); IEnumerator <Lexemе> iter = lexemesRPN.GetEnumerator(); while (iter.MoveNext()) { Lexemе lexeme = iter.Current; //ако поредния символ е операнд го пишем в стека if (!expressions.ContainsKey(lexeme.id)) { stack.Push(lexeme); } else { //това е оператор, може да е унарен или да работи с две стойности processSingleOperation(lexeme); } } return(stack.Pop().value); //TODO: провери дали стека е празен, защото ако не е празен и //израза не е бил само с постфиксни оператори значи има грешка //Console.WriteLine(" stack size: " + stack.Count); //Console.WriteLine("CODE FOR STATEMENT: " + this.ToString() + "\n" + asmCode + "\n"); }
//генерира асмеблерен код за целия израз (statement) public void generateAssembler(StringBuilder asmCode) { //изчиствам стека, защото ще го ползвам за генериране на асемблерния код stack.Clear(); IEnumerator <Lexemе> iter = lexemesRPN.GetEnumerator(); while (iter.MoveNext()) { Lexemе lexeme = iter.Current; //ако поредния символ е операнд го пишем в стека if (!expressions.ContainsKey(lexeme.id)) { stack.Push(lexeme); } //това е оператор, може да е унарен или да работи с две стойности Assembler.Result result = Assembler.processSingleOperation(lexeme, stack); if (result != null) { asmCode.Append(result.code); if (result.savedIn == Assembler.Result.IN_SAVE_PLACE) { //индикация, че на тази позиция има нещо, //чиято стойност е вече сметната //и трябва да се вземе например от програмния стек stack.Push(new Lexemе(intermediateLexemeSymbol, 0, 0, Assembler.getLastAddress(), Lexemе.NO_VALUE)); } } } //TODO: провери дали стека е празен, защото ако не е празен и //израза не е бил само с постфиксни оператори значи има грешка //Console.WriteLine(" stack size: " + stack.Count); Console.WriteLine("CODE FOR STATEMENT: " + this.ToString() + "\n" + asmCode + "\n"); }
//Парсерът приема всеки знак '-' за аритметична операция, затова тук се проверява //дали всъщност знакът е бил унарен оператор. //Замяната на знака се налага заради операциите със стека на ОПЗ, да се знае дали //да се прилага операцията върху един или два операнда. private void checkUnaryMinus(LexemеSequence input, Lexemе lexeme) { if (lexeme.id == Lexemе.MINUS) { bool unary_sign = false; if (input.GetPosition() > 1) { char symbol = input.getLexemе(input.GetPosition() - 2).id; if ((symbol == Lexemе.ASSIGNMENT) || (symbol == Lexemе.OPEN_BRACE) || (symbol == Lexemе.SEMICOLON) || (symbol == Lexemе.BITWISE_AND) || (symbol == Lexemе.BITWISE_OR) || (symbol == Lexemе.PLUS) || (symbol == Lexemе.MINUS) || (symbol == Lexemе.MULTUPLICATION) || (symbol == Lexemе.DIVISION) || (symbol == Lexemе.MODUL) || (symbol == Lexemе.BITWISE_INVERSION) || (symbol == Lexemе.BOOLEAN_INVERSION)) { unary_sign = true; } } else { unary_sign = true; } if (unary_sign) { lexeme.id = Lexemе.UNARY_MINUS; } } }
private void changeSymbol(LexemеSequence input, Lexemе lexeme, char search_symbol, char replace_symbol) { if (lexeme.id == search_symbol) { //проверка дали предходната лексема е идентификатор if (input.GetPosition() > 1) { if (input.getLexemе(input.GetPosition() - 2).id == Lexemе.IDENTIFIER) { lexeme.id = replace_symbol; return; } } //проверка дали следващата лексема е идентификатор if (input.GetPosition() < input.size()) { char symb = input.peekLexemе().id; if (input.peekLexemе().id == Lexemе.IDENTIFIER) { return; } else { throw new TranslatorException("Error 1: Expression " + search_symbol + " can be applyed only to identifier."); } } throw new TranslatorException("Error 2: Expression " + search_symbol + " can be applyed only to identifier."); } }
//Обработва Statement по Statement и генерира асемблерен код. public bool parseStatements(LexemеSequence input) { //входната поредица ще се обработва израз по израз (разделени са с ';') Lexemе lexemе = null; try { asmCode.Append(Assembler.asmHeader); input.rewind(); int input_size = input.size(); Statement stmt = new Statement(); //съдържа идентификаторите с постфиксни ++ и -- Statement postfixOperations = new Statement(); for (int i = 0; i < input_size; i++) { lexemе = input.getLexemе(); if (lexemе.id != Lexemе.SEMICOLON) { incAndDecOperatorDeal(input, lexemе); checkUnaryMinus(input, lexemе); checkUnaryPlus(input, lexemе); stmt.convertIntoRPN(lexemе, postfixOperations); } else { //прехвърля всичко от стека на изходната редица stmt.completeRPN(); //израза се преобразува в асемблерен код stmt.generateAssembler(asmCode); postfixOperations.generateAssembler(asmCode); stmt = new Statement(); postfixOperations = new Statement(); } } asmCode.Append(Assembler.returnDOS); asmCode.Append(Assembler.getIncludedProcsCode()); asmCode.Append(Assembler.asmFooter); Console.WriteLine("\nASSEMBLER CODE:\n" + asmCode); } catch (TranslatorException e) { if (lexemе != null) { Console.WriteLine(String.Format("Error at line {0}, position {1}: {2}", lexemе.row, lexemе.positionAtRow, e.Message)); } if (Startup.DEBUG) { Console.WriteLine(e.StackTrace); } return(false); } catch (Exception e) { Console.WriteLine(e.ToString()); return(false); } return(true); }
//Обработва Statement по Statement public bool parseStatements(LexemеSequence input) { //входната поредица ще се обработва израз по израз (разделени са с ';') Lexemе lexemе = null; try { input.Rewind(); int input_size = input.Size(); Statement stmt = new Statement(); //съдържа идентификаторите с постфиксни ++ и -- for (int i = 0; i < input_size; i++) { lexemе = input.GetLexemе(); if (lexemе.id != Lexemе.SEMICOLON) { checkUnaryMinus(input, lexemе); checkUnaryPlus(input, lexemе); stmt.convertIntoRPN(lexemе); } else { //вече е създаден ОПЗ, ще смятам резултата //прехвърля всичко от стека на изходната редица stmt.completeRPN(); //смятам резултата result = stmt.Calculate(); stmt = new Statement(); } } } catch (CalculatorException e) { if (lexemе != null) { Console.WriteLine(String.Format("Error at line {0}, position {1}: {2}", lexemе.row, lexemе.positionAtRow, e.Message)); } if (Startup.DEBUG) { Console.WriteLine(e.StackTrace); } return(false); } catch (Exception e) { Console.WriteLine(e.ToString()); return(false); } return(true); }
private static String getAddressOrValue(Lexemе lexeme) { if (lexeme.id == Statement.intermediateLexemeSymbol) { //това е on-the-fly стойност return(String.Format(savePlace, lexeme.address)); } else if (lexeme.id == Lexemе.IDENTIFIER) { return(String.Format("dword ptr [ebp+{0}]", lexeme.address)); } else if (lexeme.id == Lexemе.NUMBER) { return(lexeme.value.ToString()); } else { throw new TranslatorException("Error 1005: no match found for symbol: " + lexeme.id); } }
private void assignmentOperatorDeal() { //претърсват се символите от изходната редица и ако има различни //от идентификатор или знак '=' значи има семантична грешка //По този начин е възможен следния израз: //A = B = (C) = scanf(); //но не и например: //A = B + 2 = (C) = scanf(); IEnumerator <Lexemе> iter = lexemesRPN.GetEnumerator(); while (iter.MoveNext()) { Lexemе lexeme = iter.Current; if (lexeme.id != Lexemе.ASSIGNMENT && lexeme.id != Lexemе.IDENTIFIER && lexeme.id != Lexemе.OPEN_BRACE && lexeme.id != Lexemе.CLOSE_BRACE) { throw new CalculatorException("Left of assigment sign '=' can be only identifier."); } } }
public void convertIntoRPN(Lexemе lexeme) { Expression expression_sign = null; //ако поредния символ е операнд или константа го пишем направо на изходната редица if (expressions.TryGetValue(lexeme.id, out expression_sign) == false) { lexemesRPN.Add(lexeme); } else { //това е оператор if (expression_sign.id == Lexemе.CLOSE_BRACE) { //проверка дали има други оператори в стека if (stack.Count > 0) { //затварящата скоба предизвиква изхвърляне на символи от стека //докато се срещне отваряща скоба. Двете се унищожават. //взима се лексемата от върха на стека Lexemе TOS_lexeme = stack.Peek(); //стекът не е празен Expression TOS_expression_sign = expressions[TOS_lexeme.id]; while (TOS_expression_sign.id != Lexemе.OPEN_BRACE) { //предизвиква се изхвърляне на символи от стека към изходната редица TOS_lexeme = stack.Pop(); lexemesRPN.Add(TOS_lexeme); //поглежда се какъв е следващия символ от стека if (stack.Count > 0) { TOS_lexeme = stack.Peek(); TOS_expression_sign = expressions[TOS_lexeme.id]; } else { //стекът вече е празен throw new CalculatorException( "Error 1: Closing brace encountered with no corresponding open brace while converting to RPN."); } } //премахва се отварящата скоба от стека stack.Pop(); } else { throw new CalculatorException( "Error 2: Closing brace encountered with no corresponding open brace while converting to RPN."); } } else { //проверка за празен стек if (stack.Count > 0) { //обработват се останалите лексеми //взима се лексемата от върха на стека Lexemе TOS_lexeme = stack.Peek(); //стекът не е празен Expression TOS_expression_sign = expressions[TOS_lexeme.id]; while (expression_sign.outOfStackPriority <= TOS_expression_sign.inStackPriority) { //текущият символ е с по-нисък или равен приоритет и ще //предизвика изхвърляне на символи от стека към изходната редица TOS_lexeme = stack.Pop(); lexemesRPN.Add(TOS_lexeme); //поглежда се какъв е следващия символ от стека if (stack.Count > 0) { TOS_lexeme = stack.Peek(); TOS_expression_sign = expressions[TOS_lexeme.id]; } else { break; //стекът вече е празен } } } stack.Push(lexeme); } if (expression_sign.id == Lexemе.ASSIGNMENT) { assignmentOperatorDeal(); } } }
public void processSingleOperation(Lexemе lexeme) { switch (lexeme.id) { case Lexemе.PLUS: { Lexemе right_side_lexeme = stack.Pop(); Lexemе left_side_lexeme = stack.Pop(); stack.Push(new Lexemе(Lexemе.NUMBER, right_side_lexeme.value + left_side_lexeme.value)); break; } case Lexemе.ASSIGNMENT: { Lexemе right_side_lexeme = stack.Pop(); Lexemе left_side_lexeme = stack.Peek(); left_side_lexeme.value = right_side_lexeme.value; break; } case Lexemе.MINUS: { Lexemе right_side_lexeme = stack.Pop(); Lexemе left_side_lexeme = stack.Pop(); stack.Push(new Lexemе(Lexemе.NUMBER, left_side_lexeme.value - right_side_lexeme.value)); break; } case Lexemе.UNARY_MINUS: { Lexemе only_side_lexeme = stack.Pop(); stack.Push(new Lexemе(Lexemе.NUMBER, -only_side_lexeme.value)); break; } case Lexemе.MULTUPLICATION: { Lexemе right_side_lexeme = stack.Pop(); Lexemе left_side_lexeme = stack.Pop(); stack.Push(new Lexemе(Lexemе.NUMBER, right_side_lexeme.value * left_side_lexeme.value)); break; } case Lexemе.DIVISION: { Lexemе right_side_lexeme = stack.Pop(); Lexemе left_side_lexeme = stack.Pop(); stack.Push(new Lexemе(Lexemе.NUMBER, left_side_lexeme.value / right_side_lexeme.value)); break; } case Lexemе.MODUL: { Lexemе right_side_lexeme = stack.Pop(); Lexemе left_side_lexeme = stack.Pop(); stack.Push(new Lexemе(Lexemе.NUMBER, left_side_lexeme.value % right_side_lexeme.value)); break; } } }
//генерира асемблерен код за единичен оператор public static Result processSingleOperation(Lexemе lexeme, Stack <Lexemе> stack) { switch (lexeme.id) { case Lexemе.PLUS: { Lexemе right_side_lexeme = stack.Pop(); Lexemе left_side_lexeme = stack.Pop(); return(new Result(doPlus(getAddressOrValue(right_side_lexeme), getAddressOrValue(left_side_lexeme)), Result.IN_SAVE_PLACE)); } case Lexemе.ASSIGNMENT: { Lexemе right_side_lexeme = stack.Pop(); Lexemе left_side_lexeme = stack.Peek(); return(new Result(doAssignment(getAddressOrValue(right_side_lexeme), getAddressOrValue(left_side_lexeme)), Result.IN_MEMORY)); } case Lexemе.MINUS: { Lexemе right_side_lexeme = stack.Pop(); Lexemе left_side_lexeme = stack.Pop(); return(new Result(doMinus(getAddressOrValue(right_side_lexeme), getAddressOrValue(left_side_lexeme)), Result.IN_SAVE_PLACE)); } case Lexemе.PREFIX_INCREMENT: case Lexemе.POSTFIX_INCREMENT: { Lexemе only_side_lexeme = stack.Peek(); return(new Result(doIncrement(getAddressOrValue(only_side_lexeme)), Result.IN_MEMORY)); } case Lexemе.PREFIX_DECREMENT: case Lexemе.POSTFIX_DECREMENT: { Lexemе only_side_lexeme = stack.Peek(); return(new Result(doDecrement(getAddressOrValue(only_side_lexeme)), Result.IN_MEMORY)); } case Lexemе.BITWISE_INVERSION: { Lexemе only_side_lexeme = stack.Pop(); return(new Result(doBitwiseInversion(getAddressOrValue(only_side_lexeme)), Result.IN_SAVE_PLACE)); } case Lexemе.BITWISE_AND: { Lexemе right_side_lexeme = stack.Pop(); Lexemе left_side_lexeme = stack.Pop(); return(new Result(doBitwiseAnd(getAddressOrValue(right_side_lexeme), getAddressOrValue(left_side_lexeme)), Result.IN_SAVE_PLACE)); } case Lexemе.BITWISE_OR: { Lexemе right_side_lexeme = stack.Pop(); Lexemе left_side_lexeme = stack.Pop(); return(new Result(doBitwiseOr(getAddressOrValue(right_side_lexeme), getAddressOrValue(left_side_lexeme)), Result.IN_SAVE_PLACE)); } case Lexemе.BOOLEAN_INVERSION: { Lexemе only_side_lexeme = stack.Pop(); return(new Result(doBooleanInversion(getAddressOrValue(only_side_lexeme)), Result.IN_SAVE_PLACE)); } case Lexemе.UNARY_MINUS: { Lexemе only_side_lexeme = stack.Pop(); return(new Result(doUnaryMinus(getAddressOrValue(only_side_lexeme)), Result.IN_SAVE_PLACE)); } case Lexemе.MULTUPLICATION: { Lexemе right_side_lexeme = stack.Pop(); Lexemе left_side_lexeme = stack.Pop(); return(new Result(doMultiplication(getAddressOrValue(right_side_lexeme), getAddressOrValue(left_side_lexeme)), Result.IN_SAVE_PLACE)); } case Lexemе.DIVISION: { Lexemе right_side_lexeme = stack.Pop(); Lexemе left_side_lexeme = stack.Pop(); return(new Result(doDivision(getAddressOrValue(right_side_lexeme), getAddressOrValue(left_side_lexeme)), Result.IN_SAVE_PLACE)); } case Lexemе.MODUL: { Lexemе right_side_lexeme = stack.Pop(); Lexemе left_side_lexeme = stack.Pop(); return(new Result(doModul(getAddressOrValue(right_side_lexeme), getAddressOrValue(left_side_lexeme)), Result.IN_SAVE_PLACE)); } case Lexemе.PRINTF: { Lexemе only_side_lexeme = stack.Pop(); return(new Result(doPrintf(getAddressOrValue(only_side_lexeme)), Result.IN_MEMORY)); } case Lexemе.SCANF: { stack.Pop(); return(new Result(doScanf(), Result.IN_SAVE_PLACE)); } } return(null); }
//Открива и заменя постфиксни ++ и -- с префиксни при необходимост. //Парсерът приема тези оператори винаги за префиксни, затова тук се прави проверката дали //всъщност са суфиксни, при което идентификатора на лексемата ще се смени със съответния й. private void incAndDecOperatorDeal(LexemеSequence input, Lexemе lexeme) { changeSymbol(input, lexeme, Lexemе.PREFIX_INCREMENT, Lexemе.POSTFIX_INCREMENT); changeSymbol(input, lexeme, Lexemе.PREFIX_DECREMENT, Lexemе.POSTFIX_DECREMENT); }