如何A掉未來程序改


話說有這樣一道神題:【集訓隊互測2015】未來程序·改

大意是要求寫一個簡單的C++解釋器!這里去掉了C++的許多特性,連簡單的breakcontinue都沒有了!

話說NOI被屠了之后,一時心血來潮,打算A了這道題。最近的一個星期閑着無聊(其實還是很多事要做),在歷經險阻之后,終於A掉這道喪心病狂的OI題。

雖然我沒有看過任何關於解釋器的理論,但我覺得好像還是可以憑自己亂搞出來的,於是便開始了這長達一周的旅程。估計寫了4h的代碼,調試2h。

聽說可以用語言分析樹這樣高大的東西來做,我看到其他A了的3個人就是用這樣的東西的。Orz,以后有機會找來學學。

我認為我的代碼有三個最主要的部分,實現了之后發現寫掉這題也不算太難。

變量儲存

就是將單個的變量和數組儲存起來的一個東西。最最困難的一個地方是有些變量重名,但是不是同一個量,比如:

int i;
i = 10;
if (i) {
  int i;
  i = 0;
  if (i) {
    cout << 1;
  }
  else cout << 0;
}

這里的i就是不一樣的,運行后輸出0

我是用了map<string, stack<Variable> >,來保存的,每次遇到左大括號時標記一下,遇到右大括號就清理一下。由於變量的讀寫是非常普遍的,而在這里由使用了map,所以導致了程序運行速度慢,不管啦,反正可以過就可以了,其實可以用hash代替。

語句執行

主要的思想是維護一些光標(我管它叫光標),光標就是一個變量,保存着程序運行到哪里。

首先要把所有的函數都預先找到它們的位置,然后寫兩個函數:

  • Return runStatement(int startPosition);
  • Return runFunction(int startPosition, const vector<int> &params);

這里Return是一個結構體,記錄返回的值、返回的命令(return,continue,break,雖說這里沒有后面兩個)以及運行完這個語句/函數后到哪個位置。

至於怎么寫runStatement,就主要靠下面的了。

表達式計算

一個經典的方法就是運用棧,一個符號棧,一個變量棧。

下面是一些主要的問題和解決方法:

  • 正號和負號怎么處理?
  • 預處理下,把+(正號,不是加號)變為$+。並且注意它們是右結合的。
  • 有右結合的運算符,比如=
  • 當有一個新符號加入時,我們通過這樣的判斷就能解決這個問題:while (levelCur < levelTop || (levelCur == levelTop && ! rightCombine(opt))) ...
  • cout這些特殊的怎么處理?
  • 我們只需要標記一下就可以了(把它作為一個特殊變量)。
  • 數組和函數的參數怎么處理?
  • 比如f(1, 3, 2, 5),我們把f當作一個右結合的四目運算符就可以了。

然后寫好了這些我們就可以快樂地AC了!

代碼鏈接。感覺用C++寫C++解釋器有點逗呢。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM