DataMuseum.dk

Presents historical artifacts from the history of:

Rational R1000/400 Tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Rational R1000/400 Tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: B T

⟦c13e4659a⟧ TextFile

    Length: 68178 (0x10a52)
    Types: TextFile
    Names: »B«

Derivation

└─⟦180fe333a⟧ Bits:30000405 8mm tape, Rational 1000, SW CATALOG, 10_20_0
└─⟦180fe333a⟧ Bits:30000537 8mm tape, Rational 1000, SW Catalog 10_20_0
    └─⟦5cb1d1d7f⟧ »DATA« 
        └─⟦3b1ee7bd8⟧ 
            └─⟦this⟧ 

TextFile

with Host_Dependencies;  -- Host dependents constants
with Lex_Identifier_Token_Value;
-- contains data structures and subprogram
--    to distinguish identifiers from
--    reserved words
with Lexical_Error_Message;  -- outputs error messages.
with Parsetables;  -- tables from parser generator
use Parsetables;
with Grammar_Constants;  -- constants from the parser generator
use Grammar_Constants;
with Text_Io;


package body Lex is

    --| Overview
    --|
    --| Package Lex is implemented as a state machine via case statements.
    --| The implementation is optimized to minimize the number of times
    --| each character is handled.  Each character is handled twice: once
    --| on input and once on lexing based on the character.
    --|
    --| The algorithm depends on having an End_Of_Line_Character
    --| terminate each source file line.  This concludes the final token
    --| on the line for the case statement scanners.

    --| Notes
    --|
    --| Abbreviations Used:
    --|
    --| Char : Character
    --| CST  : Current_Source_Token
    --| gram : grammar
    --| sym  : symbol
    --| val  : value
    --| RW   : Reserved Word
    --|

    use Parserdeclarations;
    package Lem renames Lexical_Error_Message;
    package Pt renames Parsetables;
    package Gc renames Grammar_Constants;
    -- other package renames are in the package spec

    ------------------------------------------------------------------
    -- Character Types
    ------------------------------------------------------------------

    subtype Graphic_Character is Character range ' ' .. Ascii.Tilde;

    subtype Upper_Case_Letter is Character range 'A' .. 'Z';

    subtype Lower_Case_Letter is Character range Ascii.Lc_A .. Ascii.Lc_Z;

    subtype Digit is Character range '0' .. '9';

    subtype Valid_Base_Range is Gc.Parserinteger range 2 .. 16;

    subtype End_Of_Line_Character is Character range Ascii.Lf .. Ascii.Cr;

    ------------------------------------------------------------------
    -- Source position management
    ------------------------------------------------------------------

    Current_Column : Hd.Source_Column := 1;
    Current_Line : Hd.Source_Line := 1;
    --| the position of Next_Char in the source file.
    --| Visible so the Lexical_Error_message package can use them.

    ------------------------------------------------------------------
    -- Source Input Buffers and their Management
    ------------------------------------------------------------------

    Next_Char : Character := ' ';  --| input buffer for next character
    --| to scan from source file

    End_Of_Line_Buffer : constant      --| character that signals end of
                                  --| line buffer
                                  Character :=
       End_Of_Line_Character'First;

    subtype Line_Buffer_Range is Positive
                                    range 1 .. ((Hd.Source_Column'Last) + 2);
    --| The first extra element is needed to hold the End_Of_Line_Buffer
    --| character. The second extra element allows Line_Buffer_Index
    --| to exceed Line_Buffer_Last.

    Line_Buffer : String (Line_Buffer_Range) := ( -- 1 =>
                                                 End_Of_Line_Buffer,
                                                 others => ' ');
    --| input buffer containing source file line being lexed.

    Line_Buffer_Last : Hd.Source_Column := Line_Buffer'First;
    --| length of source file line being lexed.

    Line_Buffer_Index : Line_Buffer_Range := Line_Buffer_Range'First;
    --| index of character being lexed.

    End_Of_File_Reached : Boolean := False;
    --| true when end of the input source has been reached

    ------------------------------------------------------------------
    -- Token to be Returned and its Management
    ------------------------------------------------------------------

    Cst : Pd.Parsestackelement;
    --| token being assembled for return by
    --| subprogram GetNextSourceToken

    subtype Cst_Initialization_Type is Pd.Parsestackelement;

    Cst_Initializer : Cst_Initialization_Type;
    --| short cut to initializing discriminants properly

    End_Of_File_Token : Cst_Initialization_Type;

    ------------------------------------------------------------------
    -- Other objects
    ------------------------------------------------------------------

    Exit_After_Get_Next_Char : Boolean := False;
    --| true; call Get_Next_Char before exiting, so that
    --| Next_Char contains the next character to be scanned.
    --| This object is not located in subprogram GetNextSourceToken,
    --| to save the time of re-elaboration on each call.

    Previous_Token_Value : Pt.Tokenrange := Pt.Stringtokenvalue;
    --| used to resolve tick use as a token in T'('a') versus
    --| use as a delimiter in a character literal.

    Source_File : Text_Io.File_Type;

    ------------------------------------------------------------------
    -- Declarations for Scan_Numeric_Literal and Scan_Comment
    ------------------------------------------------------------------

    Temp_Source_Text : Pd.Source_Text;  --| temporary to hold value of
    --| Source_Text

    ------------------------------------------------------------------

    subtype Work_String_Range_Plus_Zero is
       Natural range 0 .. Natural (Hd.Source_Column'Last);

    Work_String : String (1 .. Work_String_Range_Plus_Zero'Last);

    Work_String_Length : Work_String_Range_Plus_Zero;
    -- Must initialize to 0 before each use.

    ------------------------------------------------------------------
    -- Declarations for Procedures:
    --
    -- Scan_Exponent, Scan_Based_Integer, Scan_Integer,
    -- and Scan_Numeric_Literal
    ------------------------------------------------------------------

    Seen_Radix_Point : Boolean := False;
    --| true  : real
    --| false : integer

    ------------------------------------------------------------------
    -- Subprogram Specifications Local to Package Lex
    ------------------------------------------------------------------

    procedure Get_Next_Char;  --| Obtains next character

    --| Requires
    --|
    --| This subprogram requires an opened source file, and
    --| Current Column > Line_Buffer_Last on its first call to initialize
    --| the input buffers Next_Char and Line_Buffer correctly.
    --|

    --| Effects
    --|
    --| This subprogram places the next character from the source file
    --| in Next_Char and updates the source file position.
    --| Subprogram Get_Next_Line sets End_Of_File_Reached true, and causes
    --| Next_Char to be set to the last character in Line_Buffer.
    --|

    --| Modifies
    --|
    --| Current_Column
    --| Current_Line
    --| Next_Char
    --| Line_Buffer
    --| Line_Buffer_Last
    --| Line_Buffer_Index
    --| End_Of_File_Reached
    --|

    ------------------------------------------------------------------

    procedure Get_Next_Line;  --| gets next source file line to lex

    --| Requires
    --|
    --| This subprogram requires the source file to be open.
    --|

    --| Effects
    --|
    --| This subprogram gets next source line from input file.
    --| Sets Current_Column and Line_Buffer_Index to 1, and
    --| increments Current_Line.
    --| If the End of File is detected,
    --| End_Of_File_Reached is set true,
    --| End_Of_File_Token is set up,
    --| and Next_Char is set to End_Of_Line_Buffer.
    --|

    --| Modifies
    --|
    --| Current_Line
    --| End_Of_File_Reached
    --| End_Of_File_Token - only when the end of file is reached.
    --| Line_Buffer
    --| Line_Buffer_Last
    --|

    ------------------------------------------------------------------

    function Look_Ahead ( --| Return character n columns ahead
                         --| in current in current line.
                         In_Columns_Ahead : in      --| Number of columns ahead to get
                         Hd.Source_Column --| return character from.
                         ) return Character;

    --| Requires
    --|
    --| Line_Buffer
    --| Line_Buffer_Last
    --|

    --| Effects
    --|
    --| Return character In_Columns_Ahead in Line_Buffer.
    --| If this character is off the end of Line_Buffer,
    --| End_Of_Line_Buffer character is returned.
    --|

    ------------------------------------------------------------------

    procedure Set_Cst_Gram_Sym_Val ( --| Sets gram_sym_val for current
                                    --| token.
                                    In_Token_Value : in Pt.Tokenrange);
    --| value of token

    --| Effects
    --|
    --| This subprogram fills in gram_sym_val for the current token.
    --|

    ------------------------------------------------------------------

    procedure Set_Cst_Source_Rep ( --| Saves the symbol representation
                                  --| in the current token.
                                  In_String : in String);
    --| string holding symbol.

    --| Effects
    --|
    --| This subprogram fills in lexed_token.symrep for the current token.
    --|

    ------------------------------------------------------------------

    procedure Initialize_Cst;  --| Sets lx_srcpos for current token.

    --| Requires
    --|
    --| This subprogram requires Current_Column and Current_Line.
    --|

    --| Effects
    --|
    --| This subprogram sets common fields in CST.
    --|

    ------------------------------------------------------------------

    procedure Add_Next_Char_To_Source_Rep;
    --| appends Next_Char to growing
    --| source representation

    --| Requires
    --|
    --| Next_Char
    --|

    --| Effects
    --|
    --| This subprogram appends Next_Char to the growing source
    --| representation.
    --|

    --| Modifies
    --|
    --| Work_String
    --| Work_String_Length
    --|

    ------------------------------------------------------------------

    procedure Check_For_Consecutive_Underlines;
    --| Issues an error message if
    --| consecutive underlines occur.

    --| Requires
    --|
    --| Work_String
    --| Work_String_Length
    --|

    --| Effects
    --|
    --| Issues an error message if consecutive underlines occur.
    --|

    ------------------------------------------------------------------

    procedure Check_For_Terminal_Underline;
    --| Issues an error message if
    --| a terminal underline occurs.

    --| Requires
    --|
    --| Work_String
    --| Work_String_Length
    --|

    --| Effects
    --|
    --| This subprogram issues an error message if a terminal underline
    --| occurs.

    ------------------------------------------------------------------

    procedure Scan_Comment;  --| Scans comments.

    --| Requires
    --|
    --| This subprogram requires an opened source file.
    --|

    --| Effects
    --|
    --| This subprogram scans the rest of a comment.
    --|

    --| Modifies
    --|
    --| CST
    --|

    ------------------------------------------------------------------

    procedure Scan_Identifier_Including_Rw;
    --| Scans identifiers including
    --| reserved words

    --| Requires
    --|
    --| This subprogram requires an opened source file.
    --|

    --| Effects
    --|
    --| This subprogram scans the rest of the identifier,
    --| and determines if its a reserved word.
    --|

    --| Modifies
    --|
    --| CST
    --|

    ------------------------------------------------------------------

    procedure Scan_Exponent;  --| Scans exponent field in
    --| appropriate numeric_literals

    --| Requires
    --|
    --| This subprogram requires an opened source file.
    --|

    --| Effects
    --|
    --| This subprogram scans the end of numeric_literals which
    --| contain exponents.
    --|

    --| Modifies
    --|
    --| Work_String
    --| Work_String_Length
    --|

    ------------------------------------------------------------------

    procedure Scan_Based_Integer
                 ( --| scans a based integer field of
                  --| a numeric literal
                  In_Base_To_Use : in      --| the base to use for lexing.
                  Valid_Base_Range);

    --| Requires
    --|
    --| This subprogram requires an opened source file.

    --| Effects
    --|
    --| This subprogram scans a based integer field in a numeric literal,
    --| verifying that is lexically correct.
    --|

    --| Modifies
    --|
    --| Work_String
    --| Work_String_Length
    --|

    --| Notes
    --|
    --| This subprogram and Scan_Integer are nearly identical.
    --| They are separate to save the overhead of:
    --|
    --| - passing a base in for decimal literals; and
    --|
    --| - distinguishing the extended digit 'E' from the exponent
    --| delimiter 'E'.
    --|

    ------------------------------------------------------------------

    procedure Scan_Integer;  --| scans an integer field of
    --|  a numeric literal

    --| Requires
    --|
    --| This subprogram requires an opened source file.
    --|

    --| Effects
    --|
    --| This subprogram scans an integer field in a numeric literal,
    --| verifying it is lexically correct.
    --|

    --| Modifies
    --|
    --| Work_String
    --| Work_String_Length
    --|

    --| Notes
    --|
    --| This subprogram and Scan_Based_Integer are nearly identical.
    --| They are separate to save the overhead of:
    --|
    --| - passing a base in for decimal literals; and
    --|
    --| - distinguishing the extended digit 'E' from the exponent
    --| delimiter 'E'.
    --|

    ------------------------------------------------------------------

    procedure Scan_Numeric_Literal;  --| Scans numbers

    --| Requires
    --|
    --| This subprogram requires an opened source file, and the
    --| Universal Arithmetic package to handle conversions.
    --|

    --| Effects
    --|
    --| This subprogram scans the rest of the numeric literal and converts
    --| it to internal universal number format.
    --|

    --| Modifies
    --|
    --| CST
    --|

    -------------------------------------------------------------------

    procedure Scan_String_Literal;  --| Scans string literals

    --| Requires
    --|
    --| This subprogram requires an opened source file.
    --|

    --| Effects
    --|
    --| This subprogram scans the rest of the string literal.
    --|

    --| Modifies
    --|
    --| CST
    --|

    ------------------------------------------------------------------
    -- Subprogram Bodies Global to Package Lex
    -- (declared in package specification).
    ------------------------------------------------------------------

    procedure Initialization is

    begin

        End_Of_File_Reached := False;

        -- forces Get_Next_Char to call Get_Next_Line
        Current_Column := Line_Buffer_Last + 1;
        Get_Next_Char;

    end Initialization;

    ------------------------------------------------------------------

    function Getnextnoncommenttoken return Pd.Parsestackelement is separate;

    ------------------------------------------------------------------

    function Getnextsourcetoken return Pd.Parsestackelement is

        --| Overview
        --|
        --| Note the following LRM Sections:
        --|     LRM Section 2.2  - Lexical Elements, Separators and Delimiters
        --|     LRM Section 2.2  - Notes
        --|     LRM Section 2.5  - Character Literals
        --|     LRM Section 2.7  - Comments
        --|     LRM Section 2.7  - Note
        --|     LRM Section 2.10 - Allowed Replacements of Characters
        --|

    begin

        if (End_Of_File_Reached) then
            Cst := End_Of_File_Token;
        else

            -- this else terminates
            -- shortly before the return statement

            -- This loop performs the following functions:
            --
            -- 1) It scans for and ignores repeated separators.
            -- 2) It reports illegal characters between tokens.
            -- 3) It identifies and lexes tokens.
            --    Delimiters and character literals are handled
            --    by code inside this loop.
            --    Complex tokens: identifiers, string and
            --    numeric literals are lexed by called
            --    subprograms.
            -- 4) It recognizes and processes comments that
            --    occur before the first token found.  Comments
            --    after tokens are processed by a separate loop
            --    after this one.
            Scan_For_Token:
                loop
                    case Next_Char is
                        when Upper_Case_Letter | Lower_Case_Letter =>
                            Initialize_Cst;
                            Scan_Identifier_Including_Rw;
                            exit Scan_For_Token;

                            -- Next_Char already updated
                        when Digit =>
                            Initialize_Cst;
                            Scan_Numeric_Literal;
                            exit Scan_For_Token;

                            -- Next_Char already updated
                        when Ascii.Quotation |

                             -- '"'
                             Ascii.Percent =>

                            -- '%'
                            Initialize_Cst;
                            Scan_String_Literal;
                            exit Scan_For_Token;

                            -- Next_Char already updated
                        when ''' =>
                            Initialize_Cst;

                            if ((Gc."=" (Previous_Token_Value,
                                         Pt.Identifiertokenvalue)) or else
                                (Gc."=" (Previous_Token_Value,
                                         Pt.Alltokenvalue)) or else
                                (Gc."=" (Previous_Token_Value,
                                         Pt.Stringtokenvalue)) or else
                                (Gc."=" (Previous_Token_Value,
                                         Pt.Charactertokenvalue)) or else
                                (Gc."=" (Previous_Token_Value,
                                         Pt.Rightparen_Tokenvalue))) then

                                --  CST is a ' delimiter
                                Set_Cst_Gram_Sym_Val (Pt.Apostrophe_Tokenvalue);
                            elsif (Look_Ahead (2) = ''') then

                                -- CST is a character literal
                                Cst.Gram_Sym_Val := Pt.Charactertokenvalue;
                                Get_Next_Char;

                                if not (Next_Char in Graphic_Character) then

                                    -- flag as an error
                                    Lem.Output_Message
                                       (Current_Line, Current_Column,
                                        Integer'Image
                                           (Character'Pos (Next_Char))

                                        -- convert to string
                                        , Lem.Character_Is_Non_Graphic);
                                end if;

                                -- save the source representation.
                                Set_Cst_Source_Rep ("'" & Next_Char);
                                Get_Next_Char;

                                -- pass by the closing
                                -- single quote
                            else

                                -- flag single quote use as illegal
                                Lem.Output_Message
                                   (Current_Line, Current_Column,
                                    Lem.Illegal_Use_Of_Single_Quote);

                                --  assume CST is a ' delimiter;
                                Set_Cst_Gram_Sym_Val (Pt.Apostrophe_Tokenvalue);
                            end if;

                            Exit_After_Get_Next_Char := True;


                        when Ascii.Ampersand =>

                            -- '&'
                            Initialize_Cst;
                            Set_Cst_Gram_Sym_Val (Pt.Ampersand_Tokenvalue);
                            Exit_After_Get_Next_Char := True;

                        when '(' =>
                            Initialize_Cst;
                            Set_Cst_Gram_Sym_Val (Pt.Leftparen_Tokenvalue);
                            Exit_After_Get_Next_Char := True;

                        when ')' =>
                            Initialize_Cst;
                            Set_Cst_Gram_Sym_Val (Pt.Rightparen_Tokenvalue);
                            Exit_After_Get_Next_Char := True;

                        when '*' =>
                            Initialize_Cst;
                            Get_Next_Char;

                            case Next_Char is
                                when '*' =>
                                    Set_Cst_Gram_Sym_Val
                                       (Pd.Exponentiation_Tokenvalue);
                                    Exit_After_Get_Next_Char := True;
                                when others =>
                                    Set_Cst_Gram_Sym_Val (Pt.Star_Tokenvalue);
                                    exit Scan_For_Token;

                                    -- Next_Char already updated
                            end case;

                        when '+' =>
                            Initialize_Cst;
                            Set_Cst_Gram_Sym_Val (Pt.Plus_Tokenvalue);
                            Exit_After_Get_Next_Char := True;

                        when ',' =>
                            Initialize_Cst;
                            Set_Cst_Gram_Sym_Val (Pt.Comma_Tokenvalue);
                            Exit_After_Get_Next_Char := True;

                        when '-' =>

                            -- Minus_Sign or Hyphen
                            Initialize_Cst;
                            Get_Next_Char;

                            case Next_Char is
                                when '-' =>

                                    -- Minus_Sign or Hyphen
                                    -- two hyphens indicate a comment
                                    Set_Cst_Gram_Sym_Val
                                       (Pt.Comment_Tokenvalue);
                                    Scan_Comment;
                                    Exit_After_Get_Next_Char := True;
                                when others =>
                                    Set_Cst_Gram_Sym_Val (Pt.Minus_Tokenvalue);
                                    exit Scan_For_Token;

                                    -- Next_Char already updated
                            end case;

                        when '.' =>
                            Initialize_Cst;
                            Get_Next_Char;

                            case Next_Char is
                                when '.' =>
                                    Set_Cst_Gram_Sym_Val (Pt.Dotdot_Tokenvalue);
                                    Exit_After_Get_Next_Char := True;
                                when others =>
                                    Set_Cst_Gram_Sym_Val (Pt.Dot_Tokenvalue);
                                    exit Scan_For_Token;

                                    -- Next_Char already updated
                            end case;

                        when '/' =>
                            Initialize_Cst;
                            Get_Next_Char;

                            case Next_Char is
                                when '=' =>
                                    Set_Cst_Gram_Sym_Val (Pd.
                                                          Notequals_Tokenvalue);
                                    Exit_After_Get_Next_Char := True;
                                when others =>
                                    Set_Cst_Gram_Sym_Val (Pt.Slash_Tokenvalue);
                                    exit Scan_For_Token;

                                    -- Next_Char already updated
                            end case;

                        when Ascii.Colon =>

                            -- ':'
                            Initialize_Cst;
                            Get_Next_Char;

                            case Next_Char is
                                when '=' =>
                                    Set_Cst_Gram_Sym_Val
                                       (Pd.Assignment_Tokenvalue);
                                    Exit_After_Get_Next_Char := True;
                                when others =>
                                    Set_Cst_Gram_Sym_Val (Pt.Colon_Tokenvalue);
                                    exit Scan_For_Token;

                                    -- Next_Char already updated
                            end case;

                        when Ascii.Semicolon =>

                            -- ';'
                            Initialize_Cst;
                            Set_Cst_Gram_Sym_Val (Pt.Semicolon_Tokenvalue);
                            Exit_After_Get_Next_Char := True;

                        when '<' =>
                            Initialize_Cst;
                            Get_Next_Char;

                            case Next_Char is
                                when '=' =>
                                    Set_Cst_Gram_Sym_Val (Pt.Lteq_Tokenvalue);
                                    Exit_After_Get_Next_Char := True;
                                when '<' =>
                                    Set_Cst_Gram_Sym_Val
                                       (Pd.Startlabel_Tokenvalue);
                                    Exit_After_Get_Next_Char := True;
                                when '>' =>
                                    Set_Cst_Gram_Sym_Val (Pd.Box_Tokenvalue);
                                    Exit_After_Get_Next_Char := True;
                                when others =>
                                    Set_Cst_Gram_Sym_Val (Pt.Lt_Tokenvalue);
                                    exit Scan_For_Token;

                                    -- Next_Char already updated
                            end case;

                        when '=' =>
                            Initialize_Cst;
                            Get_Next_Char;

                            case Next_Char is
                                when '>' =>
                                    Set_Cst_Gram_Sym_Val (Pd.Arrow_Tokenvalue);
                                    Exit_After_Get_Next_Char := True;
                                when others =>
                                    Set_Cst_Gram_Sym_Val (Pt.Eq_Tokenvalue);
                                    exit Scan_For_Token;

                                    -- Next_Char already updated
                            end case;

                        when '>' =>
                            Initialize_Cst;
                            Get_Next_Char;

                            case Next_Char is
                                when '=' =>
                                    Set_Cst_Gram_Sym_Val (Pt.Gteq_Tokenvalue);
                                    Exit_After_Get_Next_Char := True;
                                when '>' =>
                                    Set_Cst_Gram_Sym_Val (Pd.
                                                          Endlabel_Tokenvalue);
                                    Exit_After_Get_Next_Char := True;
                                when others =>
                                    Set_Cst_Gram_Sym_Val (Pt.Gt_Tokenvalue);
                                    exit Scan_For_Token;

                                    -- Next_Char already updated
                            end case;

                        when Ascii.Bar |

                             -- '|'
                             Ascii.Exclam =>

                            -- '!'
                            -- vertical bar and its alternative
                            Initialize_Cst;
                            Set_Cst_Gram_Sym_Val (Pt.Bar_Tokenvalue);
                            Exit_After_Get_Next_Char := True;

                        when Ascii.Ht =>

                            -- Horizontal Tab
                            -- a lexical unit separator - skip it.
                            -- position Current_Column properly. This is done
                            --     here to save the cost of a test on every
                            --     character in Get_Next_Char.
                            Current_Column := Hd.Findtabcolumn (Current_Column);

                        when ' ' | End_Of_Line_Character =>

                            -- rest of the lexical unit separators
                            if (End_Of_File_Reached) then
                                return End_Of_File_Token;
                            end if;


                        when Ascii.Underline =>

                            -- '_'
                            case Look_Ahead (1) is
                                when Upper_Case_Letter | Lower_Case_Letter =>

                                    -- flag illegal leading under line
                                    Lem.Output_Message
                                       (Current_Line, Current_Column,
                                        Lem.Leading_Underline);
                                    Initialize_Cst;
                                    Scan_Identifier_Including_Rw;
                                    exit Scan_For_Token;

                                    -- Next_Char already updated
                                when Digit =>

                                    -- flag illegal leading under line
                                    Lem.Output_Message
                                       (Current_Line, Current_Column,
                                        Lem.Leading_Underline);
                                    Initialize_Cst;
                                    Scan_Numeric_Literal;
                                    exit Scan_For_Token;

                                    -- Next_Char already updated
                                when others =>

                                    -- flag illegal character for start
                                    -- of token
                                    Lem.Output_Message
                                       (Current_Line, Current_Column, "_",
                                        Lem.Character_Can_Not_Start_Token);
                            end case;


                        when Ascii.Sharp |

                             -- '#'
                             Ascii.Dollar |

                             -- '$'
                             Ascii.Query |

                             -- '?'
                             Ascii.At_Sign |

                             -- '@'
                             Ascii.L_Bracket |

                             -- '['
                             Ascii.Back_Slash |

                             -- '\'
                             Ascii.R_Bracket |

                             -- ']'
                             Ascii.Circumflex |

                             -- '^'
                             Ascii.Grave |

                             -- '`'
                             Ascii.L_Brace |

                             -- '{'
                             Ascii.R_Brace |

                             -- '}'
                             Ascii.Tilde =>

                            -- '~'
                            -- flag illegal character for start of token
                            Lem.Output_Message
                               (Current_Line, Current_Column, Next_Char & ""

                                -- convert to string
                                , Lem.Character_Can_Not_Start_Token);

                        when Ascii.Nul ..

                                -- Null to
                                Ascii.Bs |

                             --  Back Space
                             Ascii.So ..

                                -- Shift Out to
                                Ascii.Us |

                             --  Unit Separator
                             Ascii.Del =>

                            -- Delete
                            -- flag as non-graphic ASCII control character
                            Lem.Output_Message
                               (Current_Line, Current_Column,
                                Integer'Image (Character'Pos (Next_Char))

                                -- convert to string
                                , Lem.Character_Is_Non_Graphic);

                        when others =>

                            -- should never happen due to 's
                            -- definition of CHARACTER. flag as illegal anyhow
                            Lem.Output_Message (Current_Line, Current_Column,
                                                Lem.Character_Is_Non_Ascii);
                    end case;

                    Get_Next_Char;

                    -- for next time through loop.
                    if (Exit_After_Get_Next_Char) then
                        Exit_After_Get_Next_Char := False;
                        exit Scan_For_Token;
                    end if;

                end loop Scan_For_Token;

            -- Next_Char already updated
            Previous_Token_Value := Cst.Gram_Sym_Val;

            -- for resolving T'('c')
        end if;

        -- (End_Of_File_Reached)
        return Cst;

        -- On leaving: object Next_Char should contain character
        -- to scan on next call of this function.
    end Getnextsourcetoken;

    ------------------------------------------------------------------
    -- Subprogram Bodies Local to Package Lex
    ------------------------------------------------------------------

    procedure Get_Next_Char is

    begin

        --| Algorithm
        --|
        --| Source File is scanned returning each character until the
        --| end of the file is found. Proper column positioning for a tab
        --| character is done in GetNextSourceToken for speed.
        --|

        -- The End_Of_Line_Character that Get_Next_Line
        -- inserts needs to be seen by the scanning
        -- case statements to terminate tokens correctly.
        Current_Column := Current_Column + 1;
        Line_Buffer_Index := Line_Buffer_Index + 1;
        Next_Char := Line_Buffer (Line_Buffer_Index);

        if (Line_Buffer_Index > Line_Buffer_Last) then
            Get_Next_Line;

            -- Current_Column and Line_Buffer_Index are handled there.
            Next_Char := Line_Buffer (Line_Buffer_Index);
        end if;

    end Get_Next_Char;  -- procedure

    ------------------------------------------------------------------

    procedure Get_Next_Line is

    begin

        -- Get next source line from CURRENT_INPUT. Update column and
        -- line counts
        Current_Column := 1;
        Line_Buffer_Index := 1;

        Ignore_Null_Line:
            loop

                -- do NOT move next statement out of loop
                if (Current_Line < Hd.Source_Line'Last) then
                    begin
                        -- block
                        Current_Line :=
                           Hd.Source_Line -- type conversion
                              (Text_Io.Line (File => Text_Io.Current_Input));

                        if (Current_Line >= Hd.Source_Line'Last) then
                            raise Constraint_Error;
                        end if;
                    exception
                        when others =>
                            Current_Line := Hd.Source_Line'Last;
                            Lem.Output_Message
                               (Current_Line, Current_Column,
                                Hd.Source_Line'Image (Hd.Source_Line'Last),
                                Lem.Source_Line_Maximum_Exceeded);
                    end;  -- block
                end if;

                Text_Io.Get_Line (File => Text_Io.Current_Input,
                                  Item => Line_Buffer
                                             (1 .. (Line_Buffer'Last - 1)),
                                  Last => Line_Buffer_Last);
                -- flag a line that is too long as an error

                if (Line_Buffer_Last >= Line_Buffer'Last - 1) and then
                   (Text_Io.End_Of_Line (File => Text_Io.Current_Input)) then
                    Lem.Output_Message (Current_Line, Current_Column,
                                        Lem.Source_Line_Too_Long);
                end if;

                exit Ignore_Null_Line when
                   (Line_Buffer_Last /= (Line_Buffer'First - 1));
            end loop Ignore_Null_Line;

        Line_Buffer_Last := Line_Buffer_Last + 1;
        Line_Buffer (Line_Buffer_Last) := End_Of_Line_Buffer;

    exception
        -- when end of file is reached
        when Text_Io.End_Error =>
            -- save that state for GetNextSourceToken
            End_Of_File_Reached := True;

            -- update column and line counts
            Line_Buffer_Last := 1;
            Line_Buffer (Line_Buffer_Last) := End_Of_Line_Buffer;
            Line_Buffer_Index := 1;
            Current_Column := 1;
            -- Current_Line is ok.
            -- Last call to GET_LINE advanced it one.

            -- set the value of End_Of_File_Token
            -- the discriminants were set up by the object declaration
            End_Of_File_Token.Gram_Sym_Val := Pt.Eof_Tokenvalue;
            End_Of_File_Token.Lexed_Token := (Srcpos_Line => Current_Line,
                                              Srcpos_Column => Current_Column,
                                              Text => Pd.Null_Source_Text);

    end Get_Next_Line;

    ------------------------------------------------------------------
    function Look_Ahead
                (In_Columns_Ahead : in Hd.Source_Column) return Character is

        ------------------------------------------------------------------
        -- Declarations for subprogram Look_Ahead
        ------------------------------------------------------------------
        Position_To_Try : Integer := Integer

                                        --type conversion
                                        (Line_Buffer_Index + In_Columns_Ahead);

        ------------------------------------------------------------------
    begin

        -- if request is past the end of line
        if (Position_To_Try > Integer (Line_Buffer_Last)) then
            -- type conversion
            -- return the end_of_line character
            return End_Of_Line_Buffer;
        else
            -- else return the requested character
            return Line_Buffer (Position_To_Try);
        end if;

    end Look_Ahead;

    -- function

    ------------------------------------------------------------------
    procedure Set_Cst_Gram_Sym_Val (In_Token_Value : in Pt.Tokenrange) is

    begin

        Cst.Gram_Sym_Val := In_Token_Value;

    end Set_Cst_Gram_Sym_Val;

    ----------------------------------------------------------------------
    procedure Set_Cst_Source_Rep (In_String : in String) is

    begin

        -- store the representation
        Pd.Put_Source_Text (In_String, Cst.Lexed_Token.Text);

    end Set_Cst_Source_Rep;

    ------------------------------------------------------------------
    procedure Initialize_Cst is

    begin

        -- Set up discriminants, and source position properly
        -- Set other CST fields to null values
        Cst := Cst_Initializer;

        Cst.Lexed_Token := (Srcpos_Line => Current_Line,
                            Srcpos_Column => Current_Column,
                            Text => Pd.Null_Source_Text);

    end Initialize_Cst;

    ------------------------------------------------------------------
    procedure Add_Next_Char_To_Source_Rep is

    begin

        -- append the character to growing source representation
        Work_String_Length := Work_String_Length + 1;
        Work_String (Work_String_Length) := Next_Char;

    end Add_Next_Char_To_Source_Rep;

    ------------------------------------------------------------------
    procedure Check_For_Consecutive_Underlines is

    begin

        -- flag consecutive underlines as an error (leading
        -- underlines are handled in GetNextSourceToken).
        if (Work_String (Work_String_Length) = Ascii.Underline) then
            Lem.Output_Message (Current_Line, Current_Column,
                                Lem.Consecutive_Underlines);
        end if;

    end Check_For_Consecutive_Underlines;

    -- procedure

    ------------------------------------------------------------------
    procedure Check_For_Terminal_Underline is

    begin

        -- flag a trailing underline as an error.
        -- trailing underlines are saved for the same
        -- reason as leading ones.
        -- See comment in GetNextSourceToken.

        if (Work_String (Work_String_Length) = Ascii.Underline)
           -- check the preceeding character
            then
            Lem.Output_Message (Current_Line, Current_Column,
                                Lem.Terminal_Underline);
        end if;

    end Check_For_Terminal_Underline;

    ------------------------------------------------------------------
    procedure Scan_Comment is

        --| Overview
        --|
        --| Note the following LRM Sections:
        --|     LRM Section 2.7  - Comments
        --|     LRM Section 2.7  - Note
        --|
    begin

        -- get to the beginning of the comment
        Get_Next_Char;
        Set_Cst_Source_Rep (Line_Buffer
                               (Line_Buffer_Index .. Line_Buffer_Last - 1));
        -- subtract 1 so that the carridge return is not also returned.

        Line_Buffer_Index := Line_Buffer_Last + 1;
        -- force next call to Get_Next_Char to call Get_Next_Line

    end Scan_Comment;

    ------------------------------------------------------------------
    procedure Scan_Identifier_Including_Rw is

        --| Overview
        --|
        --| Note the following LRM Sections:
        --|     LRM Section 2.3 - Identifiers
        --|     LRM Section 2.3 - Note
        --|     LRM Section 2.9 - Reserved Words
        --|     LRM Section 2.9 - Notes
        --|

        ------------------------------------------------------------------
    begin

        Work_String_Length := 0;

        -- scan source file for rest of token
        -- note that first character of the token is stored first
        Scan_For_Identifier_Including_Rw:
            loop
                Add_Next_Char_To_Source_Rep;

                -- set up for processing next characte
                Get_Next_Char;

                case Next_Char is
                    when Upper_Case_Letter | Lower_Case_Letter | Digit =>
                        -- action is at start of next loop cycle
                        null;
                    when Ascii.Underline =>
                        -- '_'
                        Check_For_Consecutive_Underlines;
                    when others =>
                        Check_For_Terminal_Underline;

                        -- token is terminated by any character except letter
                        --     digit, or underline;
                        exit Scan_For_Identifier_Including_Rw;  -- this loop
                end case;

            end loop Scan_For_Identifier_Including_Rw;

        -- find out what kind of token it is
        Lex_Identifier_Token_Value.Find
           (In_Identifier => Work_String (1 .. Work_String_Length),
            Out_Token_Value => Cst.Gram_Sym_Val);

        -- store the source representation of the token found
        Set_Cst_Source_Rep (Work_String (1 .. Work_String_Length));

    end Scan_Identifier_Including_Rw;

    ------------------------------------------------------------------
    procedure Scan_Exponent is

        --| Overview
        --|
        --| Note the following LRM Sections:
        --|     LRM Section 2.4.1 - Decimal Literals
        --|     LRM Section 2.4.1 - Notes
        --|     LRM Section 2.4.2 - Based Literals
        --|
    begin

        -- Check for missing 'E' or 'e',
        -- and for existence of the exponent
        case Next_Char is
            when 'E' | 'e' =>
                null;  -- normal case
            when others =>
                return;  -- no exponent to process
        end case;
        -- add first character to growing literal

        Add_Next_Char_To_Source_Rep;


        -- scan source file for rest of the exponent
        -- verify that next character is legal for an integer field
        Get_Next_Char;

        case Next_Char is
            when '+' =>
                -- add sign character to growing literal
                Add_Next_Char_To_Source_Rep;

                Get_Next_Char;
            when '-' =>
                -- Minus_Sign
                if not (Seen_Radix_Point) then
                    -- flag negative exponent as illegal in an integer
                    Lem.Output_Message
                       (Current_Line, Current_Column,
                        Lem.Negative_Exponent_Illegal_In_Integer);
                end if;

                -- add sign character to growing literal
                Add_Next_Char_To_Source_Rep;

                Get_Next_Char;
            when others =>
                null;
        end case;

        case Next_Char is
            when Digit =>
                -- scan the integer field of the exponent
                Scan_Integer;
            when Ascii.Underline =>
                -- '_'
                if (Look_Ahead (1) in Digit) then
                    -- flag illegal leading under line
                    Lem.Output_Message (Current_Line, Current_Column,
                                        Lem.Leading_Underline);
                    -- scan the integer field of the exponent
                    Scan_Integer;
                else
                    -- issue error message that integer field is missing
                    Lem.Output_Message (Current_Line, Current_Column,
                                        Lem.Exponent_Missing_Integer_Field);
                end if;
            when others =>
                -- issue an error message that integer field is missing
                Lem.Output_Message (Current_Line, Current_Column,
                                    Lem.Exponent_Missing_Integer_Field);
        end case;

    end Scan_Exponent;

    ------------------------------------------------------------------
    procedure Scan_Based_Integer (In_Base_To_Use : in Valid_Base_Range) is

        --| Overview
        --|
        --| Note the following LRM Sections:
        --|     LRM Section 2.4   - Numeric Literals
        --|     LRM Section 2.4.2 - Based Literals
        --|

        ------------------------------------------------------------------
        -- Declarations for Procedure Scan_Based_Integer
        ------------------------------------------------------------------
        Bad : constant Gc.Parserinteger := Gc.Parserinteger'Last;

        --| an integer value greater than 15 to use as a flag to indicate
        --| illegal values.
        Transform : constant array (Character) of Gc.Parserinteger :=

           -------- ( nul,  soh,  stx,  etx,     eot,  enq,  ack,  bel,
           (Bad, Bad, Bad, Bad, Bad, Bad, Bad, Bad,

            --------   bs,   ht,   lf,   vt,      ff,   cr,   so,   si,
            Bad, Bad, Bad, Bad, Bad, Bad, Bad, Bad,

            --------   dle,  dc1,  dc2,  dc3,     dc4,  nak,  syn,  etb,
            Bad, Bad, Bad, Bad, Bad, Bad, Bad, Bad,

            --------   can,  em,   sub,  esc,     fs,   gs,   rs,   us,
            Bad, Bad, Bad, Bad, Bad, Bad, Bad, Bad,

            --------   ' ',  '!',  '"',  '#',     '$',  '%',  '&',  ''',
            Bad, Bad, Bad, Bad, Bad, Bad, Bad, Bad,

            --------   '(',  ')',  '*',  '+',     ',',  '-',  '.',  '/',
            Bad, Bad, Bad, Bad, Bad, Bad, Bad, Bad,

            --------   '0',  '1',  '2',  '3',     '4',  '5',  '6',  '7',
            0, 1, 2, 3, 4, 5, 6, 7,

            --------   '8',  '9',  ':',  ';',     '<',  '=',  '>',  '?',
            8, 9, Bad, Bad, Bad, Bad, Bad, Bad,

            --------   '@',  'A',  'B',  'C',     'D',  'E',  'F',  'G',
            Bad, 10, 11, 12, 13, 14, 15, Bad,

            --------   'H',  'I',  'J',  'K',     'L',  'M',  'N',  'O',
            Bad, Bad, Bad, Bad, Bad, Bad, Bad, Bad,

            --------   'P',  'Q',  'R',  'S',     'T',  'U',  'V',  'W',
            Bad, Bad, Bad, Bad, Bad, Bad, Bad, Bad,

            --------   'X',  'Y',  'Z',  '[',     '\',  ']',  '^',  '_',
            Bad, Bad, Bad, Bad, Bad, Bad, Bad, Bad,

            --------   '`',  'a',  'b',  'c',     'd',  'e',  'f',  'g',
            Bad, 10, 11, 12, 13, 14, 15, Bad,

            --------   'h',  'i',  'j',  'k',     'l',  'm',  'n',  'o',
            Bad, Bad, Bad, Bad, Bad, Bad, Bad, Bad,

            --------   'p',  'q',  'r',  's',     't',  'u',  'v',  'w',
            Bad, Bad, Bad, Bad, Bad, Bad, Bad, Bad,

            --------   'x',  'y',  'z',  '{',     '|',  '}',  '~',   del);
            Bad, Bad, Bad, Bad, Bad, Bad, Bad, Bad);

        --| used to transform a character value to an integer value for
        --| purpose of checking that a digit is within the legal range
        --| for the base passed in via In_Base_To_Use.

        ------------------------------------------------------------------
    begin

        -- check that first character, if not an under line,
        -- is a valid digit for base being used.
        if (Next_Char /= Ascii.Underline) and then
           (Transform (Next_Char) >= In_Base_To_Use) then
            -- flag digit as invalid for base
            Lem.Output_Message (Current_Line, Current_Column, Next_Char & ""
                                -- convert to string
                                , Lem.Digit_Invalid_For_Base);
        end if;

        -- scan source file for rest of the field
        -- note that first character of the field is stored first
        Scan_For_Based_Integer:
            loop

                Add_Next_Char_To_Source_Rep;

                -- set up for processing next character
                Get_Next_Char;

                case Next_Char is
                    when 'A' .. 'F' | 'a' .. 'f' | Digit =>
                        -- check if Next_Char is in valid base range
                        if (Transform (Next_Char) >= In_Base_To_Use) then
                            -- flag digit as invalid for base
                            Lem.Output_Message
                               (Current_Line, Current_Column, Next_Char & ""
                                -- convert to string
                                , Lem.Digit_Invalid_For_Base);
                        end if;
                        -- rest of action is at start of next loop cycle
                    when Ascii.Underline =>
                        -- '_'
                        Check_For_Consecutive_Underlines;
                    when others =>
                        Check_For_Terminal_Underline;
                        -- field is terminated by any character except
                        -- extended digit (letters a to f and digits),
                        -- or underline
                        exit Scan_For_Based_Integer;  -- this loop
                end case;

            end loop Scan_For_Based_Integer;
        -- Next_Char already updated

    end Scan_Based_Integer;

    ------------------------------------------------------------------
    procedure Scan_Integer is

        --| Overview
        --|
        --| Note the following LRM Sections:
        --|     LRM Section 2.4   - Numeric Literals
        --|     LRM Section 2.4.1 - Decimal Literals
        --|     LRM Section 2.4.1 - Notes
        --|
    begin

        -- scan source file for rest of the field
        -- note that first character of the field is stored first
        Scan_For_Integer:
            loop

                Add_Next_Char_To_Source_Rep;

                -- set up for processing next character
                Get_Next_Char;

                case Next_Char is
                    when Digit =>
                        -- rest of action is at start of next loop cycle
                        null;
                    when Ascii.Underline =>
                        -- '_'
                        Check_For_Consecutive_Underlines;
                    when others =>
                        Check_For_Terminal_Underline;

                        -- field is terminated by any character except
                        --     digit, or underline
                        exit Scan_For_Integer;  -- this loop
                end case;

            end loop Scan_For_Integer;  -- Next_Char already updated

    end Scan_Integer;

    ------------------------------------------------------------------
    procedure Scan_Numeric_Literal is

        --| Overview
        --|
        --| Note the following LRM Sections:
        --|     LRM Section 2.4   - Numeric Literals
        --|     LRM Section 2.4.1 - Decimal Literals
        --|     LRM Section 2.4.1 - Notes
        --|     LRM Section 2.4.2 - Based Literals
        --|     LRM Section 2.10  - Allowed Replacements of Characters
        --|

        ------------------------------------------------------------------
        -- Declarations for Scan_Numeric_Literal
        ------------------------------------------------------------------
        Based_Literal_Delimiter : Character;

        --| holds value of first based_literal delimeter:
        --| ASCII.COLON (':') or ASCII.SHARP ('#');
        --| so the second one can be checked to be identical.
        Base_Being_Used : Gc.Parserinteger;

        --| base value to be passed to Scan_Based_Literal.

        ------------------------------------------------------------------
    begin

        Cst.Gram_Sym_Val := Pt.Numerictokenvalue;

        Work_String_Length := 0;
        -- also used by sub-scanners called from this subprogram.

        -- Scan first field
        Scan_Integer;

        -- Now, scan rest of literal dependent on what Next_char is
        case Next_Char is

            -- have a decimal_literal
            when '.' =>
                if (Look_Ahead (1) = '.') then
                    -- next token is a range double delimiter.
                    -- finished with numeric_literal.
                    Seen_Radix_Point := False;  -- have an integer_literal
                    -- already set_up for next scanner,
                    -- no call to Get_Next_Char.
                else
                    Seen_Radix_Point := True;
                    Add_Next_Char_To_Source_Rep;
                    Get_Next_Char;

                    case Next_Char is
                        when Digit =>
                            Scan_Integer;
                            -- check and flag multiple radix points

                            while (Next_Char = '.') and then
                                     (Look_Ahead (1) in Digit) loop
                                Lem.Output_Message
                                   (Current_Line, Current_Column,
                                    Lem.Too_Many_Radix_Points);
                                Add_Next_Char_To_Source_Rep;
                                Get_Next_Char;
                                Scan_Integer;
                            end loop;
                        when Ascii.Underline =>
                            -- '_'
                            -- flag illegal leading under line
                            Lem.Output_Message (Current_Line, Current_Column,
                                                Lem.Leading_Underline);
                            Scan_Integer;
                            -- not flagging an integer consisting of a
                            -- single underline as a trailing radix
                            -- point case.  Check and flag multiple radix
                            -- points.

                            while (Next_Char = '.') and then
                                     (Look_Ahead (1) in Digit) loop
                                Lem.Output_Message
                                   (Current_Line, Current_Column,
                                    Lem.Too_Many_Radix_Points);
                                Add_Next_Char_To_Source_Rep;
                                Get_Next_Char;
                                Scan_Integer;
                            end loop;
                        when others =>
                            -- flag trailing radix point as an error
                            Lem.Output_Message
                               (Current_Line, Current_Column,
                                Lem.Digit_Needed_After_Radix_Point);
                    end case;

                    Scan_Exponent;  -- check for and process exponent

                end if;

                -- have a based_literal
            when Ascii.Sharp |      -- '#'
                 Ascii.Colon =>
                -- ':'
                Based_Literal_Delimiter := Next_Char;
                Base_Being_Used := Gc.Parserinteger'Value
                                      (Work_String (1 .. Work_String_Length));

                if (Base_Being_Used not in Valid_Base_Range) then
                    -- flag illegal bases as errors
                    Lem.Output_Message (Current_Line, Current_Column,
                                        Work_String (1 .. Work_String_Length),
                                        Lem.Base_Out_Of_Legal_Range_Use_16);
                    Base_Being_Used := 16;
                    -- we use the maximum base to pass all the
                    -- extended_digits as legal.
                end if;

                Add_Next_Char_To_Source_Rep;  -- save the base delimiter
                Get_Next_Char;

                case Next_Char is
                    when 'A' .. 'F' | 'a' .. 'f' | Digit =>
                        Scan_Based_Integer (Base_Being_Used);
                    when Ascii.Underline =>
                        -- '_'
                        -- flag illegal leading under line
                        Lem.Output_Message (Current_Line, Current_Column,
                                            Lem.Leading_Underline);
                        -- not flagging an integer consisting of a single
                        -- under line as a trailing radix point case.
                        Scan_Based_Integer (Base_Being_Used);
                    when '.' =>
                        -- flag leading radix point as an error
                        Lem.Output_Message
                           (Current_Line, Current_Column,
                            Lem.Digit_Needed_Before_Radix_Point);
                    when Ascii.Sharp |      -- '#'
                         Ascii.Colon =>
                        -- ':'
                        -- flag missing field as an error
                        Lem.Output_Message (Current_Line, Current_Column,
                                            Lem.No_Integer_In_Based_Number);

                        -- based_literal_delimiter_mismatch handled in
                        -- next case statement.
                    when others =>
                        -- flag missing field as an error
                        Lem.Output_Message (Current_Line, Current_Column,
                                            Lem.No_Integer_In_Based_Number);
                end case;

                case Next_Char is
                    when '.' =>
                        Seen_Radix_Point := True;  -- have a real_literal
                        Add_Next_Char_To_Source_Rep;

                        Get_Next_Char;

                        case Next_Char is
                            when 'A' .. 'F' | 'a' .. 'f' | Digit =>
                                Scan_Based_Integer (Base_Being_Used);
                                -- check and flag multiple radix points

                                while (Next_Char = '.') and then
                                         ((Look_Ahead (1) in Digit) or
                                          (Look_Ahead (1) in 'A' .. 'F') or
                                          (Look_Ahead (1) in 'a' .. 'f')) loop
                                    Lem.Output_Message
                                       (Current_Line, Current_Column,
                                        Lem.Too_Many_Radix_Points);
                                    Add_Next_Char_To_Source_Rep;
                                    Get_Next_Char;
                                    Scan_Based_Integer (Base_Being_Used);
                                end loop;
                            when Ascii.Underline =>
                                -- '_'
                                -- flag illegal leading under lined
                                Lem.Output_Message
                                   (Current_Line, Current_Column,
                                    Lem.Leading_Underline);
                                -- not flagging an integer consisting of
                                -- a single underline as a trailing
                                -- radix point case.
                                Scan_Based_Integer (Base_Being_Used);
                            when others =>
                                -- flag trailing radix point as an error
                                Lem.Output_Message
                                   (Current_Line, Current_Column,
                                    Lem.Digit_Needed_After_Radix_Point);
                        end case;

                        case Next_Char is
                            when Ascii.Sharp |      -- '#'
                                 Ascii.Colon =>
                                -- ':'

                                Add_Next_Char_To_Source_Rep;
                                -- save the base delimiter

                                if (Next_Char /= Based_Literal_Delimiter) then
                                    -- flag based_literal delimiter
                                    -- mismatch as an error
                                    Lem.Output_Message
                                       (Current_Line, Current_Column,
                                        "Opener: " & Based_Literal_Delimiter &
                                           " Closer: " & Next_Char,
                                        Lem.Based_Literal_Delimiter_Mismatch);
                                end if;

                                Get_Next_Char;  -- after base delimiter
                                -- check for and process exponent
                                Scan_Exponent;

                            when others =>
                                -- flag missing second
                                -- based_literal delimiter as an error
                                Lem.Output_Message
                                   (Current_Line, Current_Column,
                                    Lem.Missing_Second_Based_Literal_Delimiter);
                        end case;

                    when Ascii.Sharp |      -- '#'
                         Ascii.Colon =>
                        -- ':'
                        -- have an integer_literal
                        Seen_Radix_Point := False;
                        -- save the base delimiter
                        Add_Next_Char_To_Source_Rep;

                        if (Next_Char /= Based_Literal_Delimiter) then
                            -- flag based_literal delimiter mismatch error
                            Lem.Output_Message
                               (Current_Line, Current_Column,
                                "Opener: " & Based_Literal_Delimiter &
                                   " Closer: " & Next_Char,
                                Lem.Based_Literal_Delimiter_Mismatch);
                        end if;

                        Get_Next_Char;  -- get character after base delimiter
                        Scan_Exponent;  -- check for and process exponent

                    when others =>
                        -- assume an integer_literal
                        Seen_Radix_Point := False;
                        -- flag missing second
                        -- based_literal delimiter as an error
                        Lem.Output_Message
                           (Current_Line, Current_Column,
                            Lem.Missing_Second_Based_Literal_Delimiter);
                end case;

                --we have an integer_literal
            when others =>
                Seen_Radix_Point := False;  -- have an integer_literal
                Scan_Exponent;  -- check for and process exponent
        end case;

        -- one last error check
        if (Next_Char in Upper_Case_Letter) or
           (Next_Char in Lower_Case_Letter) then
            -- flag missing space between numeric_literal and
            -- identifier (including RW) as an error.
            Lem.Output_Message (Current_Line, Current_Column,
                                Lem.Space_Must_Separate_Num_And_Ids);
        end if;

        -- now store the source representation of the token found.
        Set_Cst_Source_Rep (Work_String (1 .. Work_String_Length));

    end Scan_Numeric_Literal;

    ------------------------------------------------------------------
    procedure Scan_String_Literal is

        --| Overview
        --|
        --| Note the following LRM Sections:
        --|     LRM Section 2.6  - String Literals
        --|     LRM Section 2.6  - Note
        --|     LRM Section 2.10 - Allowed Replacements of Characters
        --|
        String_Delimiter : Character := Next_Char;

    begin

        Work_String_Length := 0;

        Cst.Gram_Sym_Val := Pt.Stringtokenvalue;

        -- scan until matching string delimiter or end of line is found
        Scan_For_String:
            loop
                Get_Next_Char;

                if (Next_Char = String_Delimiter) then
                    Get_Next_Char;

                    if (Next_Char = String_Delimiter) then
                        -- add one string delimiter to growing string
                        Add_Next_Char_To_Source_Rep;
                    else
                        -- string is ended
                        exit Scan_For_String;
                    end if;
                elsif (Next_Char in Graphic_Character) then
                    -- add graphic character to growing string
                    Add_Next_Char_To_Source_Rep;
                elsif (Next_Char in End_Of_Line_Character) then
                    -- string is ended. flag the error.
                    Lem.Output_Message (Current_Line, Current_Column,
                                        Lem.No_Ending_String_Delimiter);
                    exit Scan_For_String;
                else
                    -- flag non-graphic characters as errors
                    Lem.Output_Message
                       (Current_Line, Current_Column,
                        Integer'Image (Character'Pos (Next_Char))
                        -- convert to string
                        , Lem.Only_Graphic_Characters_In_Strings);
                end if;

            end loop Scan_For_String;  -- Next_Char already updated

        -- now store the source representation found without the
        -- string delimiters
        Set_Cst_Source_Rep (Work_String (1 .. Work_String_Length));

        return;

    end Scan_String_Literal;

    ------------------------------------------------------------------
    function Show_Current_Line return Hd.Source_Line is

        --| Overview
        --| Return current line number
    begin

        return Current_Line;

    end Show_Current_Line;
end Lex;