2012-06-11 66 views
2

我是Ada的新手,我試圖將編譯器教程中遞歸體面解析器中的代碼轉換爲Ada。移植Jack W Crenshaw的教程「Let's Build a Compiler」是我學習多種語言的最佳途徑。我已經完成了第三章的所有工作,使用單個字符標記。向多字符標記的轉移一直很麻煩。Ada如何按字符獲取輸入字符

我的代碼是這樣的須藤代碼:

procedure GetName is 
    token: Ada.Strings.Unbounded; 
begin 
    while IsAlNum(Look) loop 
    Token := Token & Look; 
    GetChar; 
    end loop 
end GetName; 

現在我知道阿達用於字符串是靜態的。但我需要能夠將從輸入中獲取的每個新字符連接到Token中的字符集合。 Look是全局預見值(輸入的最後一個字符)。

感謝您的幫助。另外,網絡上有沒有好的Ada教程或食譜網站?我爲C程序員閱讀了Lovelace和Ada。該Ada RMs是有點正式,只顯示規格不使用...

再次感謝!

+0

「sudo」還是僞? – Coffee

+0

IsAlNumOrUnderscore! –

回答

2

在這個問題的結束,它看起來像你所要求的在Ada的字符串處理幫助。

是的,Ada字符串確實最好作爲靜態字符串處理,而不是調整大小的緩衝區。有三種典型的方法來解決這個問題。

第一個是製作一個非常大的String緩衝區,使用單獨的Natural變量來保存字符串的邏輯長度。這是一種痛苦,並且有點容易出錯,但是至少比C的方法在緩衝區末尾持續掃描null值的方法快。

第二個是隻是踢和使用Ada.Strings.Unbounded.Unbounded_String。這是大多數人所做的事情,因爲如果你習慣以程序的方式來思考事情,那麼這是最容易的。

第三,(我更喜歡的時候可能)是處理你的字符串功能。您需要的主要洞察是Ada String確實是靜態的,但是您可以控制它們的生命週期,並且如果您在功能上編程,則可以隨時動態創建靜態字符串。

function Matches_Token (Scanned : String) return boolean; --// Returns true if the given string is a token 
function Could_Match_Longer (Scanned : String) return boolean; --// Returns true if the given string could be part of a larger token. 
function Get_Next_Char return Character; --// Returns the next character from the stream 
procedure Unget; --// Puts the last character back onto the stream 
procedure Advance (Amount : Natural); --// Advance the stream pointer the given amount 
function Longest_Matching_Token (Scanned : String) return String is 
    New_Token : constant String := Scanned & Get_Next_Char; 
begin 
    --// Find the longest token a further scan can match 
    if Could_Match_Longer(New_Token) then 
     declare 
      LMT : constant String := Longest_Matching_Token (New_Token); 
     begin 
      if LMT /= "" then 
       unget; 
       return LMT; 
      end if; 
     end; 
    end if; 

    --// See if this string at least matches. 
    if Matches_Token(New_Token) then 
     unget; 
     return New_Token; 
    else 
     unget; 
     return ""; 
    end if; 
end Build_Token; 

function Get_Next_Token return String is 
    Next_Token : constant String := Build_Token(""); 
begin 
    Advance (Next_Token'length); 
    return Next_Token; 
end Get_Next_Token; 

這並不總是字符串的最有效的方法:

舉例來說,我可以做一些像下面創建一個新的Token字符串的任何長度我想(與理論上無限前瞻)處理(太多的堆棧使用),但它通常是最簡單的。

實際上,掃描和解析實際上是一種特殊情況的應用程序,其中通常避免的醜陋的東西,如緩衝區(方法1)和gotos通常是可取的。

+0

嗨,謝謝你的信息。移植這種編譯器一直是我學習一種新語言的最佳方式之一。它似乎帶來了許多通常不會在簡單應用程序中出現的問題。這也給了我一個用語言工作的好標準。本教程中的編譯器適用於68K機器,但我過去已成功將其轉換爲8051,6811,8086甚至C,以用作交叉編譯器。現在我正在努力學習Ada,並且只有一小時實際工作時間。我發現信息很難找到。 – user693336

+0

@ user693336 - Certianly我發現學習語言的最佳方式是嘗試在其中編程。 Strings的這個問題是他們是任何Ada學習者嘗試使用的第一個東西,而Ada數組規則具有微妙(但影響深遠)的含義。除非你習慣於函數式語言,否則第一種方法通常是嘗試使用C字符串處理方法,這總會導致大量的挫敗感(除非你放棄並使用'Ada.Strings.Unbounded')。不幸的是,Ada最奇怪的黑客是大多數新手試圖做的第一件事,但它就是這樣。 –

2

Ada的單個字符「get」方法是Ada.Text_IO.Get。在Text_IO包的那一部分還有Look_Ahead和Get_Immediate過程。

很多制定Ada示例的好資源是Rosetta Code的Ada Category

+0

我已經可以獲得單個字符。我的問題是修改現有代碼以接受多字符輸入和令牌。我目前正在使用Ada.Text_IO.Get,它適用於單個字符。我發現在Ada中從單個字符標記變爲多字符標記需要很多工作,在C/C++,Pascal,PHP,Python中......這是一個簡單的舉措。但是Ada的嚴格類型檢查意味着更改會在整個代碼中傳播。但我想這是練習的要點,要學習一門新的語言。 – user693336

+1

@ user693336 - 這是關於Ada的一個非常基本的東西(經常讓C用戶感到沮喪)。您仍然可以在Ada中「破解」,但強類型系統會強制您在進行基本的對象角色更改時停止並*正確地重新設計*事物。這實際上是關於該語言的最好的事情之一。 –

+0

剛剛看了OpenToken。一旦我在我的腰帶上得到幾個星期的阿達,我將不得不玩這個遊戲!聽起來不錯!!! – user693336

2

如果你打算使用Ada 2005或更高版本(實際上95可能有它,不完全確定),你可以使用Streams。事情是這樣的:

With Ada.Text_IO; 

With 
Ada.Streams.Stream_IO, 
Ada.Text_IO.Text_Streams, 
Ada.IO_Exceptions; 


Procedure IO is 
    Use Ada.Text_IO; 

    -- Get the Standard_Input. 
    Input_File : Ada.Text_IO.File_Type:= Ada.Text_IO.Standard_Input; 

    -- Create a stream from the Standard Input. 
    Input_Stream : Access Ada.Streams.Root_Stream_Type'Class:= 
     Ada.Text_IO.Text_Streams.Stream(File => Input_File); 

Begin 

    GET_USER_INPUT: 
    declare 
    C: Character; 
    begin 
    loop 
     Character'Read(Input_Stream, C); 
     exit when C = '*'; 
     -- Build your string here. 
    end loop; 
    -- THIS IS AN ALTERNATE WAY FOR EXITING THE ABOVE LOOP. 
    Exception 
    When ADA.IO_EXCEPTIONS.END_ERROR => Null; -- Raised normally at EOF. 
    end GET_USER_INPUT; 
    -- Suggested, refactoring GET_USER_INPUT into a function. 

    Put_Line("Testing."); 

End IO; 
+0

謝謝,我還發現改變我的想法和定義一個字符數組並強制限制輸入長度給了我一個工作解決方案。然而,字符數組的使用引起了其他程序中的問題。 Ada與C/C++非常不同,它強制類型和數據大小。 – user693336

+0

我知道;我真的很喜歡它 - 當然,它有時可能會有點挑戰,但它也確保我不會需要調試那些神祕和間歇性故障的程序。 – Shark8

+0

作爲最初編寫OpenToken(Ada編譯器構建工具包)的人,我第二次使用流輸入而不是Text_IO以便於使用。但是,如果你想實際使用你的這個編譯器,你可能會發現編寫一個小包/類來儘可能多地讀取文件到RAM中是有幫助的,然後從緩衝區中獲取字符。你做的I/O越少越好。 –

2

我寫了一個函數來連接從輸入中獲取的每個新字符並將其全部作爲字符串返回。它可能適合做你需要的東西。

FUNCTION get_a_string (ch : IN Character) RETURN String IS 
----------------------------------------------------------------- 
--| Recursively hack out a string from a stream of single 
--| character input. Starting with an ESC sentinel and ending 
--| with an EOL sentinel. 
--| ESC is the ESC character and EOL is a space. 
---------------------------------------------------------------- 
    next : Character; 
    ch2s : String(1..1); 
BEGIN -- get_a_string 
    Ada.Text_IO.Put("Waiting: ");--BARF 
    Ada.Text_IO.Get(Item => next); 

    IF ch = ESC THEN -- start 
     RETURN get_a_string(next); 
    ELSIF next = EOL THEN --Escape Case 
     ch2s(1) := ch; 
     RETURN ch2s; 
    ELSE -- Keep getting input 
     RETURN ch & get_a_string(next); 
    END IF; 
END get_a_string; 

如果我的導師或TA發現這是與我轉入的代碼的匹配項,我寫了它,所以我沒有作弊。