/// <summary> /// Parse Loop statement /// </summary> private void LOOP() { if (c_bParserASMDebug) m_Em.asm(";;;;;; LOOP statement begin ;;;;;;"); // Labels string sBeginLabel = m_LABEL_BASE + m_iLabelLevel++; string sEndLabel = m_LABEL_BASE + m_iLabelLevel++; // consume LOOP token m_tok = m_Tknzr.NextToken(); // Beginning of loop m_Em.Label(sBeginLabel); // Parse until IF ParseLoop(Token.TOKENTYPE.IF); // IF Match(Token.TOKENTYPE.IF); List<Token> inFix = new List<Token>(); for (; m_tok.m_tokType != Token.TOKENTYPE.THEN; m_tok = m_Tknzr.NextToken()) inFix.Add(m_tok); //// LOOP instantiation // Match tokens Match(Token.TOKENTYPE.THEN); // parse after condition ParseLoop(); Match(Token.TOKENTYPE.SEMI_COLON); Match(Token.TOKENTYPE.END); Match(Token.TOKENTYPE.SEMI_COLON); // eval conditional expression EvalPostFix(InFixToPostFix(inFix)); // if EAX is one then statement is true and jump to IF m_Em.Compare("EAX", "1"); m_Em.Jump("jge", sEndLabel); //// evaluate inside loop ParseLoop(); //m_Em.RDINT(); // trace // jump to top of loop m_Em.Jump("jmp", sBeginLabel); // label if condition fails jump over m_Em.Label(sEndLabel); // consume remaining "END;" Match(Token.TOKENTYPE.END); Match(Token.TOKENTYPE.SEMI_COLON); if (c_bParserASMDebug) m_Em.asm(";;;;;; end LOOP statement ;;;;;;"); }
/// <summary> /// Returns true if type is one of: (, AND, OR, =, !=, >, >=, <, <= /// </summary> /// <param name="type"></param> /// <returns></returns> private bool InfixPlusMinusCondition(Token.TOKENTYPE type) { return (type == Token.TOKENTYPE.AND || type == Token.TOKENTYPE.OR || type == Token.TOKENTYPE.EQUAL || type == Token.TOKENTYPE.NOT_EQ || type == Token.TOKENTYPE.GRTR_THAN || type == Token.TOKENTYPE.GRTR_THAN_EQ || type == Token.TOKENTYPE.LESS_THAN || type == Token.TOKENTYPE.LESS_THAN_EQ); }
/// <summary> /// Parse tokens from infix to postfix, including conditionals and logical operators /// </summary> private List<Token> InFixToPostFix(List<Token> tokList = null) { // InFix to PostFix Stack<Token> stkInToPost = new Stack<Token>(); // infix to postfix stack List<Token> lsExpression = new List<Token>(); // get the whole expression as seperate list List<Token> lsPostFix = new List<Token>(); // postfix statement Token tok; // temp // get expression into list // Use passed in list if possible if (tokList == null) for (; m_tok.m_tokType != Token.TOKENTYPE.SEMI_COLON; m_tok = m_Tknzr.NextToken()) lsExpression.Add(m_tok); else lsExpression = tokList; // loop through expression for (int j = 0; j < lsExpression.Count; ++j) { switch (lsExpression[j].m_tokType) { case Token.TOKENTYPE.RIGHT_PAREN: // Pop elements until '(' is found if (stkInToPost.Count > 0) { tok = stkInToPost.Pop(); while (stkInToPost.Count > 0 && tok.m_tokType != Token.TOKENTYPE.LEFT_PAREN) { lsPostFix.Add(tok); tok = stkInToPost.Pop(); } // while not '(' } // if stack no empty break; //** HIGHEST PRECEDENCE case Token.TOKENTYPE.MOD: case Token.TOKENTYPE.MULT: case Token.TOKENTYPE.DIV: case Token.TOKENTYPE.LEFT_PAREN: // Highest precedence, push onto stack if (!checkNeg(ref lsPostFix, ref lsExpression, ref j)) stkInToPost.Push(lsExpression[j]); // push onto stack break; //** MIDDLE PRECEDENCE case Token.TOKENTYPE.AND: case Token.TOKENTYPE.OR: case Token.TOKENTYPE.NOT: case Token.TOKENTYPE.EQUAL: case Token.TOKENTYPE.NOT_EQ: case Token.TOKENTYPE.GRTR_THAN: case Token.TOKENTYPE.GRTR_THAN_EQ: case Token.TOKENTYPE.LESS_THAN: case Token.TOKENTYPE.LESS_THAN_EQ: // if previous token was operator then check if number should be negative if (!checkNeg(ref lsPostFix, ref lsExpression, ref j)) { if (stkInToPost.Count > 0) { tok = stkInToPost.Peek(); // check top of stack and compare precedence while (true) { // left paren on top is like having an empty stack if (tok.m_tokType == Token.TOKENTYPE.LEFT_PAREN) { stkInToPost.Push(lsExpression[j]); // push onto stack break; } // if '(' // Current lower / top higher if (tok.m_tokType == Token.TOKENTYPE.MULT || tok.m_tokType == Token.TOKENTYPE.DIV || tok.m_tokType == Token.TOKENTYPE.MOD) { tok = stkInToPost.Pop(); lsPostFix.Add(tok); if (stkInToPost.Count > 0) tok = stkInToPost.Peek(); else // stack empty push { stkInToPost.Push(lsExpression[j]); // push onto stack break; } // else continue; // not needed, but kept for readability } // Higher // equal if (InfixPlusMinusCondition(tok.m_tokType)) { tok = stkInToPost.Pop(); lsPostFix.Add(tok); stkInToPost.Push(lsExpression[j]); // push onto stack break; } // Equal // Current higher / top lower if (tok.m_tokType == Token.TOKENTYPE.PLUS || tok.m_tokType == Token.TOKENTYPE.MINUS) { stkInToPost.Push(lsExpression[j]); // push onto stack break; } // Lower } // while } // if stack not empty else // stack empty stkInToPost.Push(lsExpression[j]); // push onto stack } // if not neg break; //** LOWEST PRECEDENCE case Token.TOKENTYPE.PLUS: case Token.TOKENTYPE.MINUS: // if previous token was operator then check if number should be negative if (!checkNeg(ref lsPostFix, ref lsExpression, ref j)) { if (stkInToPost.Count > 0) { tok = stkInToPost.Peek(); // check top of stack and compare precedence while (true) { // left paren on top is like having an empty stack if (tok.m_tokType == Token.TOKENTYPE.LEFT_PAREN) { stkInToPost.Push(lsExpression[j]); // push onto stack break; } // Current lower / top higher if (InfixPlusMinusCondition(tok.m_tokType) || tok.m_tokType == Token.TOKENTYPE.MULT || tok.m_tokType == Token.TOKENTYPE.DIV || tok.m_tokType == Token.TOKENTYPE.MOD) { tok = stkInToPost.Pop(); lsPostFix.Add(tok); // check stack if (stkInToPost.Count > 0) tok = stkInToPost.Peek(); else // stack empty push { stkInToPost.Push(lsExpression[j]); // push onto stack break; } // else continue; // not needed, but kept for readability } // Top higher // equal if (tok.m_tokType == Token.TOKENTYPE.PLUS || tok.m_tokType == Token.TOKENTYPE.MINUS) { tok = stkInToPost.Pop(); lsPostFix.Add(tok); stkInToPost.Push(lsExpression[j]); // push onto stack break; } // Equal / Lower } // while } // if stack not empty else // stack empty stkInToPost.Push(lsExpression[j]); // push onto stack } // if not neg break; case Token.TOKENTYPE.ID: // Check if ARRAY if (j + 1 < lsExpression.Count && lsExpression[j + 1].m_tokType /*m_Tknzr.PeekToken().m_tokType*/ == Token.TOKENTYPE.LEFT_BRACK) { lsPostFix.Add(lsExpression[j]); // add ID ++j; // only skip over ID, [ is current token lsPostFix.Add(lsExpression[j]); // add [ ++j; // move to next // Add array as ID [ postfix index exp ] // ex: list[23*] List<Token> ltTemp = new List<Token>(); // Add everything in brackets and convert to postfix for (; lsExpression[j].m_tokType != Token.TOKENTYPE.RIGHT_BRACK; ++j) ltTemp.Add(lsExpression[j]); lsPostFix.AddRange(InFixToPostFix(ltTemp)); // add post fix expression lsPostFix.Add(lsExpression[j]); // add ] break; } goto case Token.TOKENTYPE.INT_NUM; case Token.TOKENTYPE.INT_NUM: lsPostFix.Add(lsExpression[j]); break; default: ErrorHandler.Error(ERROR_CODE.TOKEN_INVALID, lsExpression[j].m_iLineNum, "Expected (,),+,-,*,/,MOD,INT_NUM, or ID token"); break; } // switch } // for all tokens in lsExpression while (stkInToPost.Count > 0) lsPostFix.Add(stkInToPost.Pop()); // get last element out return lsPostFix; }
/// <summary> /// Parse Assignment function /// ex. ID := Expression ; /// </summary> private void ID() { // lookup in symbol table Symbol sym = FindSymbol(m_tok.m_strName); switch (sym.SymType) { case Symbol.SYMBOL_TYPE.TYPE_CONST: ErrorHandler.Error(ERROR_CODE.CONST_REDEFINITION, m_tok.m_iLineNum, "Cannot redefine a CONST value"); return; // get out of function case Symbol.SYMBOL_TYPE.TYPE_REFPROC: case Symbol.SYMBOL_TYPE.TYPE_PROC: ProcID(sym); return; default: break; } // SymType // consume token m_tok = m_Tknzr.NextToken(); // ID // Check if ARRAY, get proper offset if (m_tok.m_tokType == Token.TOKENTYPE.LEFT_BRACK) ArrayID(sym); else // type INT { m_Em.CalcIntAddress(sym.Offset.ToString(), sym.ParamType); m_Em.pushReg("EAX"); } Match(Token.TOKENTYPE.ASSIGN); // := // Get value to be stored if (m_tok.m_tokType == Token.TOKENTYPE.RDINT) { m_Em.RDINT(); m_tok = m_Tknzr.NextToken(); Match(Token.TOKENTYPE.LEFT_PAREN); Match(Token.TOKENTYPE.RIGHT_PAREN); } // RDINT else EvalPostFix(InFixToPostFix()); // evaluate expression, emit asm in process // Value to be stored should be in EAX // store the value at proper place: m_Em.popReg("EDI"); m_Em.movReg("[EDI]", "EAX"); Match(Token.TOKENTYPE.SEMI_COLON); }
/// <summary> /// Parse IF statement /// </summary> private void IF() { if (c_bParserASMDebug) m_Em.asm(";;;;;; IF statement begin ;;;;;;"); // labels string sIfLabel = m_LABEL_BASE + m_iLabelLevel++; string sElseLabel = m_LABEL_BASE + m_iLabelLevel++; string sEndLabel = m_LABEL_BASE + m_iLabelLevel++; // consume token (IF) m_tok = m_Tknzr.NextToken(); List<Token> inFix = new List<Token>(); for (; m_tok.m_tokType != Token.TOKENTYPE.THEN; m_tok = m_Tknzr.NextToken()) inFix.Add(m_tok); // eval conditional expression EvalPostFix(InFixToPostFix(inFix)); // if EAX is one then statement is true and jump to IF m_Em.Compare("EAX", "1"); m_Em.Jump("je", sIfLabel); // Force jump to else m_Em.Jump("jmp", sElseLabel); // consume token (THEN) m_tok = m_Tknzr.NextToken(); ///// run code in IF section if (c_bParserASMDebug) m_Em.asm(";;; IF"); m_Em.Label(sIfLabel); // IF Label ParseLoop(); // Parse inside of IF until ELSE or END is reached m_Em.Jump("jmp", sEndLabel); // jump around else code // Else label, put even if no ELSE token m_Em.Label(sElseLabel); // ELSE Label if (m_tok.m_tokType == Token.TOKENTYPE.ELSE) // if END then there is no ELSE section { // consume token (ELSE) m_tok = m_Tknzr.NextToken(); //// else code if (c_bParserASMDebug) m_Em.asm(";;; ELSE"); ParseLoop(Token.TOKENTYPE.ELSE); // Parse inside of ELSE until END token } // ELSE m_Em.Label(sEndLabel); // END Label // consume remaining "END;" Match(Token.TOKENTYPE.END); Match(Token.TOKENTYPE.SEMI_COLON); if (c_bParserASMDebug) m_Em.asm(";;;;;; end IF statement ;;;;;;"); }
/// <summary> /// Parses a modula-2 file. File must be open. /// </summary> public void ParseFile() { // make sure tokenizer is reset m_Tknzr.Reset(); // reset emitter m_Em.Reset(); // reset symbol table m_SymTable.Reset(); // reset offset and label count m_iOff = 4; m_iLabelLevel = 0; m_iArithmeticLevel = 0; m_tok = m_Tknzr.NextToken(); // Force jump to main when first run m_Em.Jump("jmp", "__MAIN"); // Loop through file while (m_tok.m_tokType != Token.TOKENTYPE.EOF || m_tok == null) { Module(); while (m_tok.m_tokType != Token.TOKENTYPE.BEGIN) { switch (m_tok.m_tokType) { case Token.TOKENTYPE.CONST: Const(); break; case Token.TOKENTYPE.TYPE: Type(); break; case Token.TOKENTYPE.VAR: Vars(); break; case Token.TOKENTYPE.PROCEDURE: Procedure(); break; default: //error break; } } // print symbol table Function(); } // while }
/// <summary> /// Parse array on left side of :=. Address is pushed onto the stack /// </summary> /// <param name="sym"></param> private void ArrayID(Symbol sym) { // ***** ARRAY ID() ***** // if (c_bParserASMDebug) m_Em.asm(";;;; ARRAY Assignment ;;;;"); m_tok = m_Tknzr.NextToken(); List<Token> lsIndex = new List<Token>(); // get index expression (contents between [ ] ) for (; m_tok.m_tokType != Token.TOKENTYPE.RIGHT_BRACK; m_tok = m_Tknzr.NextToken()) lsIndex.Add(m_tok); // get index value EvalPostFix(InFixToPostFix(lsIndex)); // calculate address m_Em.CalcArrayAddress(sym.ArrayEnd.ToString(), sym.Offset.ToString(), sym.ParamType, "ID() ADDRESS: "); // push for assignment m_Em.pushReg("EAX"); Match(Token.TOKENTYPE.RIGHT_BRACK); }
/// <summary> /// Parse and emit WRINT module keyword /// ex. WRINT(42); /// </summary> private void WRINT() { // consume token m_tok = m_Tknzr.NextToken(); // eat '(' Match(Token.TOKENTYPE.LEFT_PAREN); // evaluate expression // consumes RIGHT_PAREN and SEMICOLON tokens List<Token> exp = new List<Token>(); for (; m_tok.m_tokType != Token.TOKENTYPE.SEMI_COLON; m_tok = m_Tknzr.NextToken()) exp.Add(m_tok); exp.RemoveAt(exp.Count - 1); // remove ')' in WRINT(exp) // Get value of INT EvalPostFix(InFixToPostFix(exp)); // write to console // - int to print should be in EAX m_Em.WRINT(); // prints what is in EAX Match(Token.TOKENTYPE.SEMI_COLON); // consume token //m_tok = m_Tknzr.NextToken(); }
/// <summary> /// Parse and emit WRLN modula keyword /// ex. WRLN; /// </summary> private void WRLN() { // consume token m_tok = m_Tknzr.NextToken(); m_Em.WRLN(); Match(Token.TOKENTYPE.SEMI_COLON); }
/// <summary> /// Parses the TYPE section /// </summary> private void Type() { Match(Token.TOKENTYPE.TYPE); List<int> intList = new List<int>(); // type values List<string> lsIDs = new List<string>(); // type IDs // ID, Equal, ARRAY, LEFT_BRACK, INT, .., INT, RIGHT_BRACK, OF, INTEGER, ; // prListType = ARRAY [11 .. 30] OF INTEGER ; while (m_tok.m_tokType != Token.TOKENTYPE.CONST && m_tok.m_tokType != Token.TOKENTYPE.VAR) { // ID = ARRAY if (m_tok.m_tokType == Token.TOKENTYPE.ID) { // check if it exists already if (lsIDs.Contains(m_tok.m_strName)) { ErrorHandler.Error(ERROR_CODE.TYPE_REDECLARATION, m_tok.m_iLineNum, "TYPE ID already exists"); break; } // store ID in temp string lsIDs.Add(m_tok.m_strName); Match(Token.TOKENTYPE.ID); Match(Token.TOKENTYPE.EQUAL); // Determine which type being defined (Eventually refactor cases into separate functions) switch (m_tok.m_tokType) { case Token.TOKENTYPE.ARRAY: m_tok = m_Tknzr.NextToken(); // eat ARRAY if (m_tok.m_tokType == Token.TOKENTYPE.LEFT_BRACK) { m_tok = m_Tknzr.NextToken(); // eat '[' // Add ARRAY bounds to intlist -> [INT .. INT] intList.Add(int.Parse(m_tok.m_strName)); m_tok = m_Tknzr.NextToken(); Match(Token.TOKENTYPE.DOT_DOT); // .. intList.Add(int.Parse(m_tok.m_strName)); m_tok = m_Tknzr.NextToken(); Match(Token.TOKENTYPE.RIGHT_BRACK); // ] Match(Token.TOKENTYPE.OF); // Match type switch (m_tok.m_tokType) { case Token.TOKENTYPE.INTEGER: m_tok = m_Tknzr.NextToken(); // eat token break; default: ErrorHandler.Error(ERROR_CODE.INVALID_TYPE, m_tok.m_iLineNum, string.Format("Invalid type:{0}, should be INTEGER", m_tok.m_tokType)); break; } // ARRAY data type Match(Token.TOKENTYPE.SEMI_COLON); } // If LEFT_BRACK // Add "template" to symbol table foreach (string id in lsIDs) m_SymTable.AddSymbol(new Symbol(id, 0, Symbol.SYMBOL_TYPE.TYPE_ARRAY, Symbol.STORAGE_TYPE.TYPE_INT, Symbol.PARAMETER_TYPE.LOCAL_VAR, 0, 0, intList[intList.Count - 2], intList[intList.Count - 1])); break; default: ErrorHandler.Error(ERROR_CODE.INVALID_TYPE, m_tok.m_iLineNum, string.Format("Invalid type:{0}, should be ARRAY", m_tok.m_tokType)); break; } // switch TYPE } // ID = } // != CONST }
/// <summary> /// Parses: /// ID : TYPE /// and adds the appropriate symbols to the table at scope. /// NOTE: m_tok is now the token after TYPE /// </summary> /// <param name="scope"></param> private void VarDef(int scope = 0, int baseoffset = -1, Symbol.PARAMETER_TYPE Paramater_Type = Symbol.PARAMETER_TYPE.LOCAL_VAR) { List<string> lsIDs = new List<string>(); // stack offset to access variable // check if using local or global offset int iOffset = (baseoffset < 0) ? m_iOff : baseoffset; // loop through all var definitions (ex. i, k, j : INTEGER) while (m_tok.m_tokType != Token.TOKENTYPE.COLON) { // check for identifier if (m_tok.m_tokType == Token.TOKENTYPE.ID) { // check if it exists if (lsIDs.Contains(m_tok.m_strName)) { ErrorHandler.Error(ERROR_CODE.VAR_REDECLARATION, m_tok.m_iLineNum, "VAR ID already exists"); break; } // store ID in temp string lsIDs.Add(m_tok.m_strName); } // If ID // consume ID token Match(Token.TOKENTYPE.ID); // check if last VAR to be declared if (m_tok.m_tokType == Token.TOKENTYPE.COMMA) // consume token m_tok = m_Tknzr.NextToken(); } // while not COLON Match(Token.TOKENTYPE.COLON); // add symbol for each var to symbol table // - probably not the best way to implement the loop and switch foreach (string s in lsIDs) { switch (m_tok.m_tokType) { case Token.TOKENTYPE.INTEGER: // Add symbol m_SymTable.AddSymbol(new Symbol(s, scope, Symbol.SYMBOL_TYPE.TYPE_SIMPLE, Symbol.STORAGE_TYPE.TYPE_INT, Paramater_Type, iOffset)); iOffset += 4; // inc offset by 32bits break; case Token.TOKENTYPE.CARDINAL: // not implemented break; case Token.TOKENTYPE.REAL: // not implemented break; default: // Look for user defined type in symbol type Symbol sym = m_SymTable.FindSymbol(m_tok.m_strName); if (sym == null) ErrorHandler.Error(ERROR_CODE.TOKEN_INVALID, m_tok.m_iLineNum, "Expecting INTEGER, CARDINAL, or REAL token"); else // ARRAY m_SymTable.AddSymbol(new Symbol(s, scope, Symbol.SYMBOL_TYPE.TYPE_ARRAY, Symbol.STORAGE_TYPE.TYPE_INT, Paramater_Type, iOffset, 0, sym.BaseOffset, sym.ArrayEnd)); iOffset += (sym.ArrayEnd - sym.BaseOffset) * 4; // memory offset of array-> sizeof(int)*(EndIndex - BeginIndex) break; } // switch } // foreach // update m_iOff if using global scope if (baseoffset < 0) m_iOff = iOffset; // consume token m_tok = m_Tknzr.NextToken(); }
/// <summary> /// Parse/emit procedure call /// </summary> /// <param name="sym"></param> private void ProcID(Symbol sym) { // ***** PROCEDURE ***** // // Parse argument list, pushing each value onto the stack // little ( k ) ; int iArgCount = 0; m_tok = m_Tknzr.NextToken(); Match(Token.TOKENTYPE.LEFT_PAREN); // Parse arguments into list of token lists // each list in the token list is an argument for the function being parsed List<List<Token>> lslsArgs = new List<List<Token>>(); // hold the arguments, list of token (expression) lists for (; m_tok.m_tokType != Token.TOKENTYPE.SEMI_COLON; m_tok = m_Tknzr.NextToken()) { // parse argument into EAX List<Token> lsArg = new List<Token>(); for (; m_tok.m_tokType != Token.TOKENTYPE.COMMA && m_tok.m_tokType != Token.TOKENTYPE.RIGHT_PAREN; m_tok = m_Tknzr.NextToken()) lsArg.Add(m_tok); lslsArgs.Add(lsArg); // add argument expression to list of arg expressions ++iArgCount; // used when restoring the stack } // Get arguments // Must push arguments in reverse order for (int i = iArgCount; i > 0; --i) { // if proc is reference then push pointer to variable if (sym.SymType == Symbol.SYMBOL_TYPE.TYPE_REFPROC) { Symbol symRefArg = m_SymTable.FindSymbol(lslsArgs[i - 1][0].m_strName); m_Em.asm(";// Push REF addresses for: " + symRefArg.Name + " in PROCEDURE: " + sym.Name); m_Em.asm(";// PARAM: " + symRefArg.ParamType.ToString()); // int if (lslsArgs[i - 1].Count == 1) m_Em.CalcIntAddress(symRefArg.Offset.ToString(), symRefArg.ParamType); // array else { // Evaluate index List<Token> ltIndex = lslsArgs[i - 1].GetRange(2, lslsArgs[i - 1].Count - 3); EvalPostFix(InFixToPostFix(ltIndex)); m_Em.CalcArrayAddress(symRefArg.BaseOffset.ToString(), symRefArg.Offset.ToString(), symRefArg.ParamType, ";///ProcID Offset: "); } m_Em.pushReg("EAX"); continue; } // Get value into EAX then push onto stack EvalPostFix(InFixToPostFix(lslsArgs[i - 1])); m_Em.pushReg("EAX"); } // Push parameters for function Match(Token.TOKENTYPE.SEMI_COLON); // Call function m_Em.asm(string.Format("call {0} ; PROCEDURE {0}", sym.Name)); m_Em.Add("SP", (lslsArgs.Count * 4).ToString()); }
private void ProcFunction(int callingscope, string procname) { // ********************* // ***** PROCEDURE ***** // skip BEGIN m_tok = m_Tknzr.NextToken(); // Find PROCEDURE symbol in one below top scope Scope scpActive = m_SymTable.GetCurrentScope(); Scope scpCalling = m_SymTable.GetScope(callingscope); Symbol symProc = null; foreach (Symbol sym in scpCalling.Symbols) if (sym.Name == procname) { symProc = sym; break; } // get procedure symbol // error if (symProc == null) ErrorHandler.Error(ERROR_CODE.SYMBOL_UNDEFINED, m_tok.m_iLineNum, "Expecting PROCEDURE name"); // procedure header if (c_bParserASMDebug) m_Em.asm(string.Format(";======= PROCEDURE: {0} =======", symProc.Name)); // Print jump label m_Em.Label(symProc.Name); // Prep procedure stack, save old stack info m_Em.pushReg("BP"); // save old stack base m_Em.movReg("BP", "SP"); // stack pointer now points to "bottom" of procedure stack // Make room for local variables // Get number of local variables if (c_bParserASMDebug) m_Em.asm("; Make room for local variables ;;;;;;;;"); int iArg = 0, iLocalVarSpace = 0; foreach (Symbol sym in scpActive.Symbols) if (sym.ParamType == Symbol.PARAMETER_TYPE.LOCAL_VAR && sym.SymType == Symbol.SYMBOL_TYPE.TYPE_SIMPLE) ++iArg; iLocalVarSpace = 4 + (4 * (iArg)); // integer variables List<int> liArraySizes = new List<int>(); List<Symbol> lsArrays = new List<Symbol>(); ///// // If array is REF_PARM only needs 4 bytes of space // Just the address of the lowest is passed // if VAL_PARM // WOOH LAMBDAS! // Get all Array symbols into a list lsArrays.AddRange(scpActive.Symbols.ToList().FindAll(sym => sym.SymType.Equals(Symbol.SYMBOL_TYPE.TYPE_ARRAY))); // Get all offsets lsArrays.ForEach(sym => { if (sym.ParamType == Symbol.PARAMETER_TYPE.LOCAL_VAR) iLocalVarSpace += (sym.ArrayEnd - sym.BaseOffset) * 4; ; }); // space for local variables m_Em.Sub("SP", iLocalVarSpace.ToString()); if (c_bParserASMDebug) m_Em.asm("; Function Body ;;;;;;;;"); // Parse/Emit until END ParseLoop(); if (c_bParserASMDebug) m_Em.asm("; Epilogue ;;;;;;;;"); // Deallocate variables (readjust stack) //m_Em.movReg("SP", "BP"); m_Em.Add("SP", (iLocalVarSpace).ToString()); // Restore old basepointer m_Em.popReg("BP"); //// restore calling stack //int iOffset = 0; //scpActive.Symbols.ToList().ForEach(s => //{ // if (s.ParamType != Symbol.PARAMETER_TYPE.LOCAL_VAR) // iOffset += 4;//(s.ArrayEnd - s.BaseOffset) * 4; // //else // // iOffset += 4; //}); //m_Em.Add("SP", (iLocalVarSpace).ToString()); // Print return instruction m_Em.asm("ret ; Return to calling code"); // procedure footer if (c_bParserASMDebug) m_Em.asm(string.Format(";======= END PROCEDURE: {0} =======", symProc.Name)); // match end Match(Token.TOKENTYPE.END); Match(Token.TOKENTYPE.ID); Match(Token.TOKENTYPE.SEMI_COLON); // remove active scope, set next active m_SymTable.RemoveScope(); }
/// <summary> /// Parses the PROCEDURE header of a modula-2 file /// EX: /// PROCEDURE ID ( ID : TYPE ) ; /// </summary> private void Procedure() { // PROCEDURE little //( i : INTEGER ) ; // store calling scope int iCallScope = m_SymTable.ActiveScope; // consume PROCEDURE token m_tok = m_Tknzr.NextToken(); // look up proc ID, check for redeclaration Symbol procSym = m_SymTable.FindSymbol(m_tok.m_strName); if (procSym != null) ErrorHandler.Error(ERROR_CODE.PROC_REDECLARATION, m_tok.m_iLineNum, "PROCEDURE already declared"); Token tkProcID = m_tok; // save proc ID // Consume ID token m_tok = m_Tknzr.NextToken(); // Parse arguments if any if (m_tok.m_tokType == Token.TOKENTYPE.LEFT_PAREN) { m_tok = m_Tknzr.NextToken(); // check for passed by reference // if VAR token exists then parameters are reference types if (m_tok.m_tokType == Token.TOKENTYPE.VAR) { // Add PROC to symbol table to calling scope m_SymTable.AddSymbol(new Symbol(tkProcID.m_strName, iCallScope, Symbol.SYMBOL_TYPE.TYPE_REFPROC, Symbol.STORAGE_TYPE.STORE_NONE, Symbol.PARAMETER_TYPE.LOCAL_VAR, 0)); // Create new scope for procedure m_SymTable.AddScope(); m_tok = m_Tknzr.NextToken(); // consume VAR token while (m_tok.m_tokType != Token.TOKENTYPE.RIGHT_PAREN) VarDef(m_SymTable.ActiveScope, 4, Symbol.PARAMETER_TYPE.REF_PARM); // Add Proc sym with TYPE_REFPROC so that we know the parameters are of reference type // in the ID() function. Do so by overwriting the symbol } // Pass by value else { // Add PROC to symbol table to calling scope m_SymTable.AddSymbol(new Symbol(tkProcID.m_strName, iCallScope, Symbol.SYMBOL_TYPE.TYPE_PROC, Symbol.STORAGE_TYPE.STORE_NONE, Symbol.PARAMETER_TYPE.LOCAL_VAR, 0)); // Create new scope for procedure m_SymTable.AddScope(); // Parse procedure paramaters (arguments) while (m_tok.m_tokType != Token.TOKENTYPE.RIGHT_PAREN) // while not ) VarDef(m_SymTable.ActiveScope, 4, Symbol.PARAMETER_TYPE.VAL_PARM); // baseoffset for scope starts at 4 } m_tok = m_Tknzr.NextToken(); // Consume ) } Match(Token.TOKENTYPE.SEMI_COLON); while (m_tok.m_tokType != Token.TOKENTYPE.BEGIN) { switch (m_tok.m_tokType) { // CONST case Token.TOKENTYPE.CONST: Const(m_SymTable.ActiveScope); break; // VAR Parse PROCEDURE's local vars case Token.TOKENTYPE.VAR: Vars(m_SymTable.ActiveScope, 4); break; } } // Parse PROCEDURE's contents m_Em.asm(string.Format("\r\n\r\n;// START Procedure: {0}", tkProcID.m_strName)); ProcFunction(iCallScope, tkProcID.m_strName); m_Em.asm(string.Format(";// END Procedure: {0}\r\n\r\n", tkProcID.m_strName)); }
/// <summary> /// True has been returned if tokType matches the current token, false if not. /// One token has been consumed. /// </summary> /// <param name="tokType"></param> /// <returns></returns> private bool Match(Token.TOKENTYPE tokType) { bool b = (m_tok.m_tokType == tokType); // Throw error if not expected token if (!b) ErrorHandler.Error(ERROR_CODE.TOKEN_INVALID, m_tok.m_iLineNum, string.Format("Expected token: {0}", tokType.ToString())); m_tok = m_Tknzr.NextToken(); return b; }
// ********************************************************************************* // ********************************************************************************* // K E Y W O R D H E L P E R F U N C T I O N S // ********************************************************************************* /// <summary> /// Parse and emit WRSTR modula keyword /// ex. WRSTR("string contents"); /// </summary> private void WRSTR() { // consume token m_tok = m_Tknzr.NextToken(); Match(Token.TOKENTYPE.LEFT_PAREN); // Check for parse error if (m_tok.m_tokType != Token.TOKENTYPE.STRING) ErrorHandler.Error(ERROR_CODE.TOKEN_INVALID, m_tok.m_iLineNum, "Expected STRING token"); m_Em.WRSTR(m_tok.m_strName); Match(Token.TOKENTYPE.STRING); Match(Token.TOKENTYPE.RIGHT_PAREN); Match(Token.TOKENTYPE.SEMI_COLON); }
/// <summary> /// Loops and parses keywords of functions /// </summary> private void ParseLoop(Token.TOKENTYPE endType = Token.TOKENTYPE.END) { bool runloop = true; // While not endType and no error while (m_tok.m_tokType != endType && ErrorHandler.LastError == (ERROR_CODE)0 && runloop) { switch (m_tok.m_tokType) { case Token.TOKENTYPE.WRSTR: WRSTR(); break; case Token.TOKENTYPE.WRLN: WRLN(); break; case Token.TOKENTYPE.WRINT: WRINT(); break; case Token.TOKENTYPE.ID: ID(); break; case Token.TOKENTYPE.IF: IF(); break; case Token.TOKENTYPE.LOOP: LOOP(); break; case Token.TOKENTYPE.EXIT: m_tok = m_Tknzr.NextToken(); // consume token goto case Token.TOKENTYPE.END; case Token.TOKENTYPE.ELSE: case Token.TOKENTYPE.END: runloop = false; break; // exit default: // Invalid token ErrorHandler.Error(ERROR_CODE.TOKEN_INVALID, m_tok.m_iLineNum, string.Format("Token {0} invalid\r\nExpected a proper keyword", m_tok.m_tokType)); break; } // switch } // while }
/// <summary> /// normal constructor with tokentype, lexeme and line number /// </summary> /// <param name="tok"></param> /// <param name="inName"></param> /// <param name="inLine"></param> public Token(Token.TOKENTYPE tok, string inName, int inLine) { m_tokType = tok; m_strName = inName; m_iLineNum = inLine; }