2009-05-31 19 views
5

我用Lex和YACC(實際上是Flex和Bison)創建了一個編譯器。該語言允許對任何符號(如C#)的無限前向引用。問題是如果不知道標識符是什麼,就不可能解析語言。如何在編譯器中實現前向引用?

我所知道的唯一的解決辦法是LEX整個源,然後做一個「廣度優先」解析,例如類的聲明和函數聲明,以更高層次的東西得到使用它們的函數之前解析。然而,這對於大文件需要大量內存,並且使用YACC很難處理(我將不得不爲每種類型的聲明/正文創建單獨的語法)。我還必須手動編寫詞法分析器(這不是什麼大問題)。

我並不關心效率的一大部分(雖然它仍然很重要),因爲一旦我完成它就會重寫本身的編譯器,但我希望該版本速度更快(所以如果有的話是Lex/YACC無法完成的快速通用技術,但可以通過手工完成,也請提示他們)。所以現在,開發的便利是最重要的因素。

有沒有解決這個問題的好方法?這通常在C#或Java等語言的編譯器中如何實現?

回答

7

完全有可能解析它。儘管標識符和關鍵字之間存在不明確的地方,但lex會很高興地通過賦予關鍵字優先級來應對這種情況。

我不明白有什麼其他問題。在解析階段,您不需要確定標識符是否有效。您正在構建解析樹或抽象語法樹(差別很小,但與本討論無關)。之後,通過執行解析過程中生成的AST來構建嵌套符號表結構。然後你再次通過AST來檢查使用的標識符是否有效。通過對AST進行一個或多個附加分析來生成輸出代碼或其他中間數據結構,然後完成!

編輯:如果你想看看它是如何完成的,請檢查Mono C#編譯器的源代碼。這實際上是用C#編寫的,而不是C或C++,但它確實使用了與yacc非常相似的Jay的.NET端口。

+0

它無關的關鍵字。它更像這樣:是ABC(包裝AB),(C類),(包裝A),(B類),(C領域)或(Fieled A)(B領域)。(C領域)等等。 – Zifre 2009-05-31 18:35:57

+1

然後我的答案的第二段適用。你不需要知道解析。對待 '。'作爲語法中的一個操作符。在您的AST通行證中,您可以根據符號表檢查它們。 – U62 2009-05-31 18:44:47

1

一種選擇是通過掃描和緩存令牌來處理前向引用,直到你遇到某種你知道如何實現(有點像「恐慌模式」錯誤恢復)。一旦你想完整的文件,回去嘗試重新解析之前未解析的位。對於不得不手寫詞法分析器;不要,使用lex來生成一個普通的解析器,並通過一個手寫的shim來讀取它,這樣可以讓你從緩存中回溯並提供解析器,以及lex所做的。

至於做一些語法,一點樂趣與對YACC文件的預處理器,你應該能夠讓他們都出相同的原始源