/// <summary> /// Constructor. iScope is the scope level, 0 being the lowest. symFirst is the first symbol /// in the Scope. /// </summary> /// <param name="iScope"></param> /// <param name="symFirst"></param> public Scope(int iScope, Symbol symFirst) { m_iScope = iScope; m_llSymbols = new LinkedList<Symbol>(); m_llCurNode = new LinkedListNode<Symbol>(symFirst); m_llSymbols.AddFirst(m_llCurNode); }
/// <summary> /// symbol has been added to the internal list. /// </summary> /// <param name="symbol"></param> public void AddSymbol(Symbol symbol) { // Check if first in list if (m_llSymbols.Count == 0) m_llSymbols.AddFirst(symbol); else m_llSymbols.AddAfter(m_llCurNode, symbol); // Update active node m_llCurNode = m_llSymbols.Last; }
/// <summary> /// Add symbol to given scope /// </summary> /// <param name="symbol"></param> /// <param name="scope"></param> public void AddSymbol(Symbol symbol, int scope) { if (scope < 0) return; if (c_iCurScope == scope) { AddSymbol(symbol); return; } // stack to hold popped scopes Stack<Scope> stkTemp = new Stack<Scope>(); // get scope requested Scope scp = c_stkScope.Pop(); while (scp.CurrentScope != scope) { stkTemp.Push(scp); scp = c_stkScope.Pop(); } // push proper scope back on c_stkScope.Push(scp); // Add symbol to now current scope AddSymbol(symbol); // restore stack while (stkTemp.Count > 0) c_stkScope.Push(stkTemp.Pop()); }
/// <summary> /// Add Symbol to active scope /// </summary> /// <param name="symbol"></param> public void AddSymbol(Symbol symbol) { // check if any scope exists if (c_stkScope.Count == 0) AddScope(); // add first scope // get last scope Scope scope = c_stkScope.Pop(); // check if symbol is in scope if (scope.Contains(symbol.Name)) // remove symbol scope.RemoveSymbol(symbol); // update symbol scope level symbol.Scope = c_iCurScope; // add symbol scope.AddSymbol(symbol); // push back c_stkScope.Push(scope); }
/// <summary> /// true has been returned if symbol exists in class list, false if not. /// </summary> /// <param name="symbol"></param> /// <returns></returns> public bool Contains(Symbol symbol) { return m_llSymbols.Contains(symbol); }
/// <summary> /// symbol has been removed from the internal list if it exists in the list. /// </summary> /// <param name="symbol"></param> public void RemoveSymbol(Symbol symbol) { if (m_llSymbols.Contains(symbol)) m_llSymbols.Remove(symbol); }
/// <summary> /// Puts the proper address for int symbol in EAX. offset is the symbol offset, /// and Param_Type is the parameter type. /// </summary> /// <param name="offset"></param> /// <param name="Param_Type"></param> public void CalcIntAddress(string offset, Symbol.PARAMETER_TYPE Param_Type) { asm(" movzx EDI, BP"); switch (Param_Type) { case Symbol.PARAMETER_TYPE.LOCAL_VAR: Sub("EDI", offset); break; case Symbol.PARAMETER_TYPE.REF_PARM: //Add("EDI", offset); movReg("EAX", "[EDI+" + offset + "]"); return; case Symbol.PARAMETER_TYPE.VAL_PARM: Add("EDI", offset); break; } movReg("EAX", "EDI"); }
/// <summary> /// Puts the proper address for array[index] in EAX. Value of index must be in /// EAX. end is the end of the array, offset is the symbol offset. local /// determines if array is a reference or local var. Base offset is the base (so Arr[2..5] /// it would be 2 ] /// </summary> public void CalcArrayAddress(string end, string offset, Symbol.PARAMETER_TYPE Param_Type, string comment = "") { // (BP~offset) - ((ArrayEnd - Index) * 4) movReg("EBX", "EAX"); movReg("EAX", end); Sub("EAX", "EBX"); iMul("EAX", "4"); asm(" movzx EDI, BP"); // Get offset switch (Param_Type) { case Symbol.PARAMETER_TYPE.LOCAL_VAR: Sub("EDI", offset); movReg("EBX", "EDI"); break; case Symbol.PARAMETER_TYPE.REF_PARM: // Get address of whole array movReg("EBX", "[EDI+" + offset + "]"); break; case Symbol.PARAMETER_TYPE.VAL_PARM: default: break; } // Calculate final offset from BP Sub("EBX", "EAX"); movReg("EAX", "EBX"); //WRSTR(comment); //WRINT(); //WRLN(); }
/// <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> /// 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()); }