趙強把分號檢測的最終版又跑了一遍,二十個邊界用例全部通過。他滿意地點了點頭,翻到筆記本的第三條。
"變量未使用檢測。"
他盯著這七個字看了十幾秒,然後轉頭對林遠說:"這個比分號檢測難多了。"
"難在哪?"
"分號檢測是逐行判斷——當前行在什麼狀態、要不要檢查分號,一行一行過就行。但變量檢測得跨行追蹤——一個變量在第5行聲明,可能在第30行用了,也可能從頭到尾沒用過。得記錄所有聲明過的變量,再掃描所有使用位置,最後比對。"
他越說越興奮:"而且最麻煩的是作用域——函數裡有個name,結構體裡也有個name,這兩個不是同一個變量。我的程序得分清楚哪個name屬於哪個作用域。"
"思路是什麼?"
"先用哈希表記錄所有聲明的變量名和行號,再掃一遍代碼看哪些沒用過。但最麻煩的是同名變量——函數裡有個name,結構體裡也有個name,這兩個不是同一個東西。"
他想了想,在白板上畫了一個結構:
Scope {
variables: [變量列表]
parent: 指向上一層
}
"遇到{就創建新的Scope,繼承上一層的所有變量。遇到}就銷毀當前Scope,退回上一層。查找變量的時候,從當前Scope開始,沿parent指針往上找——找到了就是'已聲明',一路找到根還沒找到就是'未聲明'。"
林遠看著他畫的這個結構,嘴角微微上揚。
"作用域樹。"
"什麼?"
"你畫的東西叫作用域樹。每個節點是一個作用域,存著這一層聲明的變量,parent指針連著外層。查找的時候從葉子往根遍歷。"
趙強愣了一下,然後笑了:"我發明的?"
"你畫的,理論上沒毛病。"林遠說,"但實現的時候有個細節——變量使用記錄也得帶上作用域信息。同一個名字在不同作用域是不同的變量,你不能只用變量名做key,得用'變量名+作用域層級'做key。"
趙強點頭,已經在筆記本上開始寫代碼結構了。
回到電腦前,他先定義了一個結構體來表示作用域節點,每個節點包含一個哈希表(變量名→聲明行號)和一個指向父節點的指針。然後寫了三個核心函數:進入作用域(創建子節點)、退出作用域(銷毀子節點)、查找變量(從當前節點沿父指針往上找)。
代碼量比分號檢測大了不少,但趙強的思路很清晰——他在寫每個函數之前,先在紙上把輸入輸出和邊界情況列出來,然後再動手。這是他從分號檢測那裡學到的習慣。
大約五十分鐘,初版寫完。
他跑了一個測試——二十行代碼,第5行聲明了temp,後面沒用過。
輸出:Line 5: variable 'temp' declared but never used.
沒有誤報。
他又跑了嵌套三層同名變量的用例。
輸出準確——三個temp被正確區分為三個不同的變量,只在各自作用域內有效。
"基礎功能跑通了。"趙強說。然後他開始自己加測試用例——全局變量、static變量、函數參數、循環變量、宏定義里的變量、結構體成員……
一口氣寫了十五個邊界用例。
跑了三個,有兩個出了問題:
第一個:函數參數和局部變量同名。他的程序把函數參數當成了普通局部變量,導致參數被標記為"未使用"——實際上它在函數體內被使用了,只是作用域層級不同。
第二個:for循環的循環變量。for(int i=0; ...) 里的i應該在循環體作用域內,但他的程序把for語句本身和循環體當成了兩個獨立作用域。
"都是作用域邊界的問題。"趙強自言自語。十分鐘修函數參數作用域,五分鐘修for循環作用域。
重新跑十五個用例。全部通過。
趙強靠在椅背上,長出了一口氣。
"什麼感覺?"林遠問。
"比狀態機有意思。"趙強說,"狀態機是一個變量跟蹤五種狀態,作用域樹是一個結構管理無數變量。複雜度完全不是一個級別的。"
"第三條打算做什麼?"
"括號匹配。你上次說我先把一條規則做到極致——分號檢測我覺得差不多了,變量檢測也搞定了。第三條換個方向,做括號匹配。"
"思路有了?"
"棧。"趙強只說了兩個字,"左括號入棧,右括號彈棧,最後棧空了就匹配。遇到類型不匹配或者多出來少出來的,都能檢查出來。"
"去做吧。"
趙強已經轉回屏幕,手指開始敲鍵盤。
蘇明遠今天出去跑了一趟客戶。回來手裡拎著一袋子白菜和豆腐,還有一疊列印紙。
"超市只剩這些了。"他把菜扔在桌上,又把列印紙攤開,"不過今天不是去超市——是給海淀的一家網絡公司送WatchGuard案例。他們技術總監看了我們的方案,想了解一下實際部署效果。"
"結果呢?"
"他們暫時沒預算,但答應把案例庫拿給管理層看。"蘇明遠坐下來,開始整理那疊列印紙,"回來的路上我想了想——案例庫五十多個客戶全堆在一起,找起來太慢。我想按行業分,每個行業挑三到五個標杆案例,做一份一頁紙的簡報。以後去談客戶,直接帶著對應行業的簡報去。"
"為什麼想到這個?"
"今天那家公司的技術總監跟我說了一句話——'技術指標我看得多了,但我更想知道你的同行用了效果怎麼樣'。客戶不關心你的產品有多厲害,他們關心的是跟自己情況類似的人用了之後怎麼樣。"
"那就做。"林遠說,"每個行業挑最核心的三個案例,寫清楚三件事:客戶面臨什麼問題、怎麼部署的、效果怎麼樣。別超過一頁紙。"
蘇明遠重重點頭,坐下開始整理。
傍晚,林遠打開郵箱。
百都回信了。
"林遠先生:您的安全架構方案經團隊評審後獲得高度認可。商務條款方面,我們建議:年度合作金額10.7萬美元,附加0.15%期權,三年歸屬,每季度一次評審費用。如無異議,我們將起草正式協議。"
林遠看著這封郵件,沒有立刻回復。
0.15%。比之前的報價高了一截,但離他的目標還差一點——他要的是0.18%。
差距不算大。但談判就是這樣——你越急著答應,對方越覺得還有空間。你不急,對方反而會想"是不是已經接近他的底線了"。
他關上郵箱。先不急回。等想清楚反建議怎麼寫再說。
窗外的雨不知道什麼時候停了。
蘇明遠在整理案例簡報,桌上鋪了一桌子列印紙。趙強在敲鍵盤——括號匹配,棧結構,嘴裡偶爾蹦出一個詞:"入棧……彈棧……類型檢查……"
三個人,各忙各的,互不打擾。
林遠站在窗前看了一會兒外面的夜色。封校第三十五天。一切都在往前走,只是走得沒有想像中那麼快。
但方向是對的。