我是Ada的新手,我正在尝试将Recursive Decent Parser的编译器教程中的代码转换为Ada。移植教程“让我们构建一个编译器”由Jack W Crenshaw一直是我学习多种语言的最佳方式。我使用单字符令牌完成了第三章的所有工作。转向多字符令牌很麻烦。
我的代码类似于这个sudo代码:
procedure GetName is
token: Ada.Strings.Unbounded;
begin
while IsAlNum(Look) loop
Token := Token & Look;
GetChar;
end loop
end GetName;
现在我知道Ada希望字符串是静态的。但我需要能够将从输入中获取的每个新字符连接到令牌中的字符集合。 Look是全局预见值(输入的最后一个字符)。
谢谢你的帮助。另外,网上有没有好的Ada教程或食谱网站?我已经为C程序员阅读了Lovelace和Ada。 Ada RMs有点正式,只显示规格不使用......
再次感谢!
答案 0 :(得分:3)
如果您要使用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;
答案 1 :(得分:3)
在这个问题的最后,看起来你在Ada字符串处理中寻求帮助。
是的,Ada字符串确实最好作为静态字符串处理,而不是可调整大小的缓冲区。有三种方法可以解决这个问题。
第一个是创建一个非常大的String
缓冲区,使用一个单独的Natural
变量来保存字符串的逻辑长度。这是一种痛苦,并且有点容易出错,但至少比C在缓冲区末端不断扫描空值的方法更快。
第二种方法是直接使用Ada.Strings.Unbounded.Unbounded_String。这是大多数人所做的事情,因为如果你习惯于以程序的方式思考问题,这是最简单的。
第三个(我希望在可能的情况下)是处理你的字符串功能。这里你需要的主要见解是Ada String
确实是静态的,但你可以控制它们的生命周期,如果你在功能上编程,你可以随时动态地创建静态字符串。
例如,我可以通过执行以下操作来创建一个新的Token
字符串,其长度与我想要的长度(理论上无限前瞻):
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;
这并不总是最有效的字符串处理方法(堆栈使用过多),但它通常是最简单的。
在实践中,扫描和解析实际上是一种特殊情况的应用程序,通常建议通常避免使用缓冲区(方法1)和gotos等丑陋的东西。
答案 2 :(得分:2)
Ada的单字符“get”方法是Ada.Text_IO.Get。同样在Text_IO包的那一部分是Look_Ahead和Get_Immediate过程。
许多成功的Ada示例的一个很好的来源是Rosetta Code的Ada Category。
答案 3 :(得分: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认为这与我上交的代码匹配。我写了它,所以我不是在作弊。