String Ada如何逐个字符地获取输入字符

String Ada如何逐个字符地获取输入字符,string,ada,String,Ada,我是Ada新手,我正在尝试将递归体面解析器编译器教程中的代码转换为Ada。移植Jack W Crenshaw的教程“让我们构建一个编译器”是我学习许多语言的最喜欢的方式。在第三章之前,我一直在使用单字符标记。迁移到多字符令牌一直很麻烦 我有类似sudo的代码: procedure GetName is token: Ada.Strings.Unbounded; begin while IsAlNum(Look) loop Token := Token & Look;

我是Ada新手,我正在尝试将递归体面解析器编译器教程中的代码转换为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有点正式,只显示规范,不使用

再次感谢

Ada的单字符“get”方法是。文本IO包的这一部分还包括“向前看”和“立即获取”过程


Rosetta代码是许多已编制的Ada示例的良好来源。

如果您使用的是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;

在这个问题的最后,看起来您正在寻求Ada字符串处理方面的帮助

是的,Ada字符串确实最好作为静态字符串处理,而不是作为可调整大小的缓冲区处理。有三种典型的方法来处理这个问题

第一种方法是创建一个非常大的
字符串
缓冲区,使用一个单独的
自然
变量来保存字符串的逻辑长度。这是一种痛苦,并且有点容易出错,但至少比C在缓冲区末尾不断扫描空值的方法快

第二种方法是只划船并使用Ada.Strings.Unbounded.Unbounded_String。这是大多数人所做的,因为如果你习惯于以程序的方式思考问题,这是最简单的

第三个(如果可能的话,我更喜欢)是从功能上处理字符串。这里您需要了解的主要内容是Ada
String
s确实是静态的,但是您可以控制它们的生存期,并且您可以随时动态地生成静态字符串,只要您在功能上进行编程

例如,我可以创建一个新的
标记
字符串,其长度可以是我想要的(理论上是无限向前看的),方法如下:

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)和GOTO,这通常是可取的。

我编写了一个函数,将从输入中提取的每个新字符连接起来,并将其全部作为字符串返回。它可能适合做你需要的事情

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;

以防我的讲师或助教发现这与我提交的代码相匹配。我写的,所以我没有作弊。

谢谢,我还发现稍微改变一下思维,定义一个字符数组并强制限制输入长度给了我一个有效的解决方案。然而,在其他过程中,字符数组的使用引起了问题。Ada与C/C++非常不同,它强制类型和数据大小;事实上,我喜欢它——当然,它有时会有点挑战性,但它也确保了我不必调试程序的神秘和间歇性故障。作为最初编写OpenToken(Ada编译器构造工具包)的人,为了便于使用,我支持使用流输入而不是文本输入。但是,如果您想实际使用您的编译器,您可能会发现编写一个小程序包/类来尽可能多地将文件读入RAM,然后从该缓冲区中获取字符是很有帮助的。I/O越少越好。这里的目的不是为了实际使用而构建编译器。我已经很多年没有在任何地方使用68K了。。。其目的是尝试并复制Jack的原始编译器结构大纲,以便我可以学习Ada并将其与其他语言中的其他实现进行比较。在过去几年中,我在PHP、Python、Perl、Free Pascal C、C++、Stutic、java、GAMBAS等语言编写了相同的编译器。所以它只需要工作,而不是作为一个生产编译器。我会使用Flex/Bison作为真正的编译器。嘿,有Ada版本的Flex/Bison吗?在这里你可以看到Aflex和Ayacc的三个链接;gGenerator下还应该有Flex/Yacc在--Dmitri在这里有一个解析器包:--最后一个是OpenToken在这里:我已经可以得到一个字符了。我的问题是修改现有代码以接受多字符输入和令牌。我目前正在使用Ada.Text_IO.Get,它可以很好地处理单个字符。我发现,在Ada中从单字符标记到多字符标记的更改需要大量的工作,而在C/C++、Pascal、PHP、Python。。。这是一个容易的举动。但是Ada严格的类型检查意味着更改会在整个代码中传播。但是我想这就是这个练习的重点,学习一种新的语言。@user693336-这是关于Ada的一个非常基本的东西(这经常让C用户感到沮丧)。您仍然可以在Ada中“黑客”,但强大的类型系统迫使您在进行基本对象角色更改时停止并正确地重新设计事物。这实际上是该语言最棒的地方之一。一旦我有了几周的Ada,我就要玩这个了!听起来好棒!!!嗨,谢谢你提供的信息。移植这个编译器一直是我学习一门新语言最喜欢的方法之一。它似乎带来了许多在更简单的应用程序中通常不会出现的问题。这也给了我一个很好的语言基准。tut中的编译器