語法分析實現

實現

  • 首先前面已經說過,語法分析根據每一行的第一個屬性字,然後對接下來的進行預測,如果符合預測,就是正確的指令
  • 那麼首先語法分析
Func
  • Func不能嵌套定義,首先判斷isFuncActive,如果是,則報錯,否則繼續讀取下一個屬性字是否是標識符,如果是標識符,那麼就在函數表中查找,是否重複定義過。如果沒有繼續再讀取下一個屬性字是否是“{”,如果是,就判斷函數名字是否是_Main,如果是就將MainHeader標記_Main已經出現過並且記錄其指令入口點。 然後就將該函數的名字和函數入口點加入函數表,並且標記當前isFuncActive,還要記錄當前函數的索引。函數信息的蒐集不是一次完成的。當遇到右“}”關閉括號時候,判斷當前函數是否是活躍的,如果是,就將統計的當前LocalSize和ParamCount放置進當前函數表中
  • 【當虛擬機真正運行的時候,他遇到一個函數,首先根據其localSize+ParamCount+1開拓堆棧空間,然後Push的時候將參數放置在空間的底部,然後放置返回地址,然後每遇到一個局部數據,就放置進堆棧中。所以對於局部數據來說,在運行的時候想支持前向引用,你可以先將函數遍歷然後將局部數據的定義一次性放入堆棧中。這樣前向引用的時候可以在堆棧中獲取到這個數據。不過這樣沒有必要,因爲會造成閱讀困難】
Param
  • 【作者的思路是,在第一次遍歷的時候我們需要首先統該函數計所有局部數據的大小iLoalSize並賦予其堆棧索引因爲局部數據是位於棧頂的,並且同時統計其ParamCount,但是沒有辦法賦予Param堆棧索引,因爲此時已經到達函數尾部了。當第二遍遍歷的時候,每遇到一個Param,就賦予其堆棧索引-(localSize+2+1+currParamCount)】
  • 因爲這個原因,Param不支持前向引用,因爲到第二遍遍歷的時候,我們才知道其堆棧索引,在第二遍同時也要進行指令解析。不過作者好像沒有注意到這個bug
  • 【爲什麼不在第一次遍歷的時候,對於Param和localVarible同時進行堆棧索引統計呢,因爲在調用函數的時候,參數是通過Push統一壓進去的,因此Param是一個連續的空間】
  • 因此對於Param的執行,就是判斷函數是否活躍,如果活躍,就緊接着判斷其下一個屬性字是否是標識符。如果是就獲取其堆棧索引,然後將其加入到符號表中
Var/Var[]
  • 首先判斷接下來的屬性字否是標識符,如果是標識符,就緊接着進行預讀取,判斷下一個是否是“【”,因爲有可能是數組,如果是數組,就判斷接下來是否是數字,如果是數字就將其保存到iSize,再判斷接下來是否是“】”,
  • 然後根據其是局部還是全局,獲得其堆棧索引,全局堆棧索引爲正,局部堆棧索引爲負【局部堆棧索引等於—(當前局部數據大小+2)】
  • 無論是全局變量還是局部變量,最後都要放進符號表裏面。【通過StackIndex是否大於0來判斷是局部還是全局】
  • 其實應該先判斷GetSymbol,如果可以獲取得到,那麼就直接報錯。不用繼續下去了
if(CurrNode.FuncIndex == FuncIndex | | CurrNode.StackIndex >= 0)
	return CurrNode;
SetStackSize
  • 如果是這個屬性字,首先判斷以前是否出現過,因爲他只能定義一次,然後判斷是否函數活躍的,因爲聲明堆棧大小只能在全局空間中。最後再獲取下一個屬性字,是否是一個整型變量,如果是,是否大於0,否則繼續報錯。如果將其轉換爲整數,保存到MainHeader結構體中,並且標識已經聲明過堆棧大小。這個是在第一次遍歷的時候就可以處理的指示符。
行標籤
  • 判斷當前函數是否活躍,因爲行標籤只可以定義在函數當中
  • 判斷接下來的屬性字是否是COMMA即冒號,如果是冒號,說明這就是一個行標籤
  • 然後將當前指令大小——即下一條指令的索引和該標籤加入到標籤表當中
指令解析
  • 對於指令解析,首先根據指令字符串查找LookUpTable查找到指令,然後獲取其iCount和iOpType
  • 並且在指令流數組中當前索引處存儲其iCount,並且給OpList分配空間
  • 根據其iCount進行循環,每循環一次就讀取其下一個屬性字並且獲取其操作數類型,然後將操作數類型和iOpType列表中對應操作數的類型掩碼取與,如果不爲零,則表明該操作數類型符合語法,並將其保存到OpList當中
  • Op有個字段是iType,然後是value
  • 對於指令來說,其操作數類型有以下幾種
  • 整型字面量
  • 字符串型字面量
  • 絕對堆棧索引
  • 相對堆棧索引 【需要先去堆棧獲取變量大小然後加上函數基址】
  • 標籤
  • 函數
  • 主應用程序API調用
  • 一個寄存器 _RetVal
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章