
with INTEGER_TEXT_IO, TEXT_IO;
use INTEGER_TEXT_IO, TEXT_IO;

procedure PRETTY_PRINTER is
    type SYMBOL is (LITERAL, --  
    -- reserved words  
    --  
    ABORT_SY, ABS_SY, ACCEPT_SY, ACCESS_SY, ALL_SY, AND_SY, ARRAY_SY, AT_SY, BEGIN_SY, BODY_SY,
            CASE_SY, CONST_SY, DECLARE_SY, DELAY_SY, DELTA_SY, DIGITS_SY, DO_SY, ELSE_SY, ELSIF_SY,
            END_SY, ENTRY_SY, EXCEPT_SY, EXIT_SY, FOR_SY, FUNCTION_SY, GENERIC_SY, GOTO_SY,
            IF_SY, IN_SY, IS_SY, LIMITED_SY, LOOP_SY, MOD_SY, NEW_SY, NOT_SY, NULL_SY, OF_SY,
            OR_SY, OTHERS_SY, OUT_SY, PACKAGE_SY, PRAGMA_SY, PRIVATE_SY, PROC_SY, RAISE_SY,
            RANGE_SY, RECORD_SY, REM_SY, RENAMES_SY, RETURN_SY, REVERSE_SY, SELECT_SY, SEPARATE_SY,
            SUBTYPE_SY, TASK_SY, TERMINATE_SY, THEN_SY, TYPE_SY, USE_SY, WHEN_SY, WHILE_SY,
            WITH_SY, XOR_SY, --  
    -- special symbols  
    --  
    QUOTE, LEFT_PAREN, RIGHT_PAREN, PERIOD, ELLIPSIS, OPEN_LABEL, CLOSE_LABEL, BOX, --  
    -- symbols which require spaces before and after  
    --  
    EQUAL_ARROW, EXPONENTIATE, REPLACEMENT, NOT_EQUAL_TO, GR_EQ_TO, LS_EQ_TO, SPLAT, PLUS,
            DASH, SLASH, LESS_THAN, GREATER_THAN, EQUAL_SIGN, BAR, COLON, AMPERSAND, --  
    -- symbols which require spaces after  
    --  
    SEMICOLON, COMMA, --  
    -- other tokens  
    --  
    IDENTIFIER, NEWLINE, COMMENT, EOF);
    MAX_ID_LEN : constant INTEGER := 31;
    subtype IDENT is STRING(1..MAX_ID_LEN);
    subtype SPECIAL is STRING(1..2);
    OUTPUT_NEST : BOOLEAN := FALSE;
    -- output lexical level  
    TAB_LENGTH : INTEGER := 4;
    -- user-defined tab length  
    RESULT : BOOLEAN := TRUE;
    -- global file processing  
    WORD : array(SYMBOL) of IDENT;
    -- reserved word list  
    SPEC_SYM : array(QUOTE..COMMA) of CHARACTER;
    -- special symbol list  
    COMP_SYM : array(ELLIPSIS..LS_EQ_TO) of SPECIAL;
    -- composite symbol list  
    LENGTH : INTEGER;
    -- length of literal string  
    LITERAL_STRING : STRING(1..128);
    -- literal string  
    QUIT : exception;
    -- general error  
    --  
    -- process fatal errors  
    --  

    procedure FATAL(ERROR_NUMBER : INTEGER) is
    begin
        case ERROR_NUMBER is
            when 0 =>
                PUT("Unexpected end of file");
            when 1 =>
                PUT("FILE not found");
            when 2 =>
                PUT("Invalid option");
            when 3 =>
                PUT("Invalid character(s) found");
            when others =>
                null;
        end case;
        NEW_LINE;
        PUT("Reformatting aborted");
        NEW_LINE;
        raise QUIT;
    end FATAL;

    procedure PROCESS is
        --  
        -- mode_type is an indication of the state of the prettyprinter  
        -- when processing Ada source programs.  It is used to make  
        -- reformatting decisions on questionable tokens such as  
        -- "else"   
        --  
        type MODE_TYPE is (NORMAL, END_TOKEN, EXIT_TOKEN, END_SPEC, IN_SPEC, IN_WHEN, COLON_TOKEN,
                CASE_TOKEN, ACCEPT_MODE, OR_IN_SELECT, SHORT_CIRCUIT);
        MODE : MODE_TYPE := NORMAL;
        CH : CHARACTER := ' ';
        CHAR_COUNT : INTEGER := 0;
        LINE_LENGTH : INTEGER := 0;
        MAX_LINE_LENGTH : constant INTEGER := 256;
        LINE : STRING(1..MAX_LINE_LENGTH) := (1..MAX_LINE_LENGTH => ' ');
        ID : IDENT;
        TOKEN, LAST_TOKEN : SYMBOL;
        NEWLINE_FLAG : BOOLEAN := TRUE;
        TABS : INTEGER := 0;
        -- lexical level  
        TEMP_TABS : INTEGER := 0;
        -- temporary indent for continuation  

        procedure LEX is
            H, J, K : INTEGER;
            --  
            -- convert to upper case  
            --  

            function UPPER(CH : CHARACTER) return CHARACTER is
            begin
                if CH < 'a' or else CH > 'z' then
                    return CH;
                else
                    return CHARACTER'VAL(CHARACTER'POS(CH) - 32);
                end if;
            end UPPER;
            --  
            -- backup input one character  
            --  

            procedure BACKUP is
            begin
                CHAR_COUNT := CHAR_COUNT - 1;
                CH := LINE(CHAR_COUNT);
            end BACKUP;
            --  
            -- fetch a character from the input stream  
            --  

            procedure NEXT_CHARACTER is
            begin
                if CHAR_COUNT = LINE_LENGTH then
                    LINE_LENGTH := 0;
                    CHAR_COUNT := 0;
                    if END_OF_FILE then
                        LINE(1) := ASCII.SUB;
                        CH := ASCII.SUB;
                    else
                        -- loop to input characters  
                        while not END_OF_LINE and then not END_OF_FILE loop
                            LINE_LENGTH := LINE_LENGTH + 1;
                            GET(CH);
                            LINE(LINE_LENGTH) := CH;
                        end loop;
                    end if;
                    if CH /= ASCII.SUB then
                        -- skip line feed, set new line flag  
                        LINE_LENGTH := LINE_LENGTH + 1;
                        LINE(LINE_LENGTH) := ' ';
                        SKIP_LINE;
                    end if;
                end if;
                CHAR_COUNT := CHAR_COUNT + 1;
                CH := LINE(CHAR_COUNT);
            end NEXT_CHARACTER;

            procedure NEXT_CH is
            begin
                NEXT_CHARACTER;
                if CH = ASCII.SUB then
                    FATAL(0);
                end if;
            end NEXT_CH;
            --  
            -- functions to check the nature of the input character  
            --  

            function DIGIT(CH : CHARACTER) return BOOLEAN is
            begin
                return CH >= '0' and then CH <= '9';
            end DIGIT;

            function LETTER(CH : CHARACTER) return BOOLEAN is
            begin
                return UPPER(CH) >= 'A' and then UPPER(CH) <= 'Z';
            end LETTER;

            function LETTER_OR_DIGIT(CH : CHARACTER) return BOOLEAN is
            begin
                return LETTER(CH) or else DIGIT(CH);
            end LETTER_OR_DIGIT;

            function HEX(CH : CHARACTER) return BOOLEAN is
            begin
                return UPPER(CH) >= 'A' and then UPPER(CH) <= 'F';
            end HEX;
        begin
            -- lex  
            LAST_TOKEN := TOKEN;
            SKIP_SPACES : while CH = ' ' or else CH = ASCII.HT or else CH = ASCII.LF loop
                NEXT_CHARACTER;
            end loop SKIP_SPACES;
            --  
            -- process identifiers, reserved words  
            --  
            if LETTER(UPPER(CH)) then
                K := 1;
                for I in 1..MAX_ID_LEN loop
                    ID(I) := ' ';
                end loop;
                while LETTER_OR_DIGIT(CH) or else CH = '_' loop
                    if K <= MAX_ID_LEN then
                        ID(K) := UPPER(CH);
                        K := K + 1;
                    end if;
                    declare
                        OCH : CHARACTER := CH;
                    begin
                        NEXT_CH;
                        if OCH = '_' then
                            if not LETTER_OR_DIGIT(CH) then
                                exit;
                            end if;
                        end if;
                    end;
                end loop;
                -- perform binary search for reserved word  
                H := SYMBOL'POS(ABORT_SY);
                J := SYMBOL'POS(XOR_SY);
                loop
                    K := (H + J) / 2;
                    if ID <= WORD(SYMBOL'VAL(K)) then
                        J := K - 1;
                    end if;
                    if ID >= WORD(SYMBOL'VAL(K)) then
                        H := K + 1;
                    end if;
                    exit when H > J;
                end loop;
                if H - 1 > J then
                    TOKEN := SYMBOL'VAL(K);
                else
                    TOKEN := IDENTIFIER;
                end if;
                --  
                -- process numbers  
                --  
            elsif DIGIT(CH) then
                NUMBER_CRUNCHER : declare

                    function IN_BASE(CH : CHARACTER) return BOOLEAN is
                    begin
                        return DIGIT(CH) or HEX(CH);
                    end IN_BASE;

                    procedure STUFF_CH is
                    begin
                        LENGTH := LENGTH + 1;
                        LITERAL_STRING(LENGTH) := CH;
                    end STUFF_CH;

                    procedure GET_INTEGER is
                    begin
                        while IN_BASE(CH) loop
                            STUFF_CH;
                            NEXT_CH;
                            if CH = '_' then
                                STUFF_CH;
                                NEXT_CH;
                                STUFF_CH;
                                if not IN_BASE(CH) then
                                    exit;
                                end if;
                            end if;
                        end loop;
                    end GET_INTEGER;
                begin
                    -- number cruncher  
                    LENGTH := 0;
                    GET_INTEGER;
                    TOKEN := LITERAL;
                    if CH = '#' or else CH = ':' then
                        -- process based number  
                        STUFF_CH;
                        NEXT_CH;
                        GET_INTEGER;
                        if CH = '#' or CH = ':' then
                            STUFF_CH;
                            NEXT_CH;
                        elsif CH = '.' then
                            NEXT_CH;
                            if CH = '.' then
                                BACKUP;
                            else
                                if CH = '#' or CH = ':' then
                                    STUFF_CH;
                                    NEXT_CH;
                                end if;
                            end if;
                        end if;
                        --------------  elsif ch = '.' then  
                        ------------------  next_ch;  
                        --------------------if ch = '.' then  
                        ------------------------backup;  
                        ------------------------get_integer;  
                        --------------------end if;  
                    end if;
                    ----------------if upper(ch) = 'E' then  
                    --------------------stuff_ch;  
                    --------------------next_ch;  
                    --------------------if ch = '-' or else ch = '+' then  
                    ------------------------stuff_ch;  
                    ------------------------next_ch;  
                    --------------------end if;  
                    --------------------get_integer;  
                    ----------------end if;  
                end NUMBER_CRUNCHER;
                --  
                -- process other tokens  
                --  
            else
                case CH is
                        --  
                        -- single quote could be character literal  
                        --  
                    when ''' =>
                        LITERAL_STRING(1) := ''';
                        LITERAL_STRING(3) := ''';
                        LENGTH := 3;
                        NEXT_CH;
                        LITERAL_STRING(2) := CH;
                        if CH = '(' or else LETTER(CH) then
                            NEXT_CH;
                            if CH = ''' then
                                TOKEN := LITERAL;
                                NEXT_CH;
                            else
                                TOKEN := QUOTE;
                                BACKUP;
                            end if;
                        else
                            NEXT_CH;
                            TOKEN := LITERAL;
                            if CH = ''' then
                                NEXT_CH;
                            end if;
                        end if;
                    when '<' =>
                        NEXT_CH;
                        case CH is
                            when '=' =>
                                TOKEN := LS_EQ_TO;
                                NEXT_CH;
                            when '>' =>
                                TOKEN := BOX;
                                NEXT_CH;
                            when '<' =>
                                TOKEN := OPEN_LABEL;
                                NEXT_CH;
                            when others =>
                                TOKEN := LESS_THAN;
                        end case;
                    when '>' =>
                        NEXT_CH;
                        case CH is
                            when '=' =>
                                TOKEN := GR_EQ_TO;
                                NEXT_CH;
                            when '>' =>
                                TOKEN := CLOSE_LABEL;
                                NEXT_CH;
                            when others =>
                                TOKEN := GREATER_THAN;
                        end case;
                    when '-' =>
                        NEXT_CH;
                        if CH = '-' then
                            -- process comments  
                            LITERAL_STRING(1) := '-';
                            LITERAL_STRING(2) := '-';
                            LENGTH := 2;
                            loop
                                NEXT_CH;
                                LENGTH := LENGTH + 1;
                                LITERAL_STRING(LENGTH) := CH;
                                exit when CHAR_COUNT = LINE_LENGTH;
                            end loop;
                            TOKEN := COMMENT;
                        else
                            TOKEN := DASH;
                        end if;
                        --  
                        -- process string literals  
                        --  
                    when '"' | '%' =>
                        declare
                            STRCH : CHARACTER := CH;
                        begin
                            LENGTH := 1;
                            LITERAL_STRING(1) := '"';
                            loop
                                NEXT_CH;
                                if CH = STRCH then
                                    NEXT_CH;
                                    exit when CH /= STRCH;
                                end if;
                                LENGTH := LENGTH + 1;
                                LITERAL_STRING(LENGTH) := CH;
                            end loop;
                            LENGTH := LENGTH + 1;
                            LITERAL_STRING(LENGTH) := '"';
                            TOKEN := LITERAL;
                        end;
                    when '=' =>
                        NEXT_CH;
                        if CH = '>' then
                            TOKEN := EQUAL_ARROW;
                            NEXT_CH;
                        else
                            TOKEN := EQUAL_SIGN;
                        end if;
                    when '*' =>
                        NEXT_CH;
                        if CH = '*' then
                            TOKEN := EXPONENTIATE;
                            NEXT_CH;
                        else
                            TOKEN := SPLAT;
                        end if;
                    when '.' =>
                        NEXT_CH;
                        if CH = '.' then
                            TOKEN := ELLIPSIS;
                            NEXT_CH;
                        else
                            TOKEN := PERIOD;
                        end if;
                    when '/' =>
                        NEXT_CH;
                        if CH = '=' then
                            TOKEN := NOT_EQUAL_TO;
                            NEXT_CH;
                        else
                            TOKEN := SLASH;
                        end if;
                    when ':' =>
                        NEXT_CH;
                        if CH = '=' then
                            TOKEN := REPLACEMENT;
                            NEXT_CH;
                        else
                            TOKEN := COLON;
                        end if;
                    when '+' =>
                        TOKEN := PLUS;
                        NEXT_CH;
                    when ',' =>
                        TOKEN := COMMA;
                        NEXT_CH;
                    when ';' =>
                        TOKEN := SEMICOLON;
                        NEXT_CHARACTER;
                    when '|' | '!' =>
                        TOKEN := BAR;
                        NEXT_CH;
                    when '&' =>
                        TOKEN := AMPERSAND;
                        NEXT_CH;
                    when '(' =>
                        TOKEN := LEFT_PAREN;
                        NEXT_CH;
                    when ')' =>
                        TOKEN := RIGHT_PAREN;
                        NEXT_CH;
                    when ASCII.SUB =>
                        TOKEN := EOF;
                    when others =>
                        FATAL(3);
                end case;
            end if;
        end LEX;

        procedure PRINT_TOKEN is

            procedure PUT_STRING(STR : STRING; UPPER_CASE : BOOLEAN) is
            begin
                for I in 1..STR'LAST loop
                    exit when STR(I) = ' ';
                    if UPPER_CASE then
                        -- print in upper case  
                        if STR(I) in 'a'..'z' then
                            -- convert to upper case  
                            PUT(CHARACTER'VAL(CHARACTER'POS(STR(I)) - 32));
                        else
                            PUT(STR(I));
                        end if;
                    else
                        -- print in lower case  
                        if STR(I) in 'A'..'Z' then
                            -- convert to lower case  
                            PUT(CHARACTER'VAL(CHARACTER'POS(STR(I)) + 32));
                        else
                            PUT(STR(I));
                        end if;
                    end if;
                end loop;
            end PUT_STRING;
        begin
            -- print_token  
            -- put in an extra newline for subprogram headers  
            if TOKEN = PROC_SY or else TOKEN = FUNCTION_SY or else TOKEN = PACKAGE_SY or else TOKEN = TASK_SY then
                        NEW_LINE;
                if OUTPUT_NEST then
                    PUT(TABS);
                    PUT(": ");
                end if;
            end if;
            -- check to see if new line is required  
            if NEWLINE_FLAG then
                NEWLINE_FLAG := FALSE;
                NEW_LINE;
                if OUTPUT_NEST then
                    PUT(TABS);
                    PUT(": ");
                end if;
                for I in 1..(TABS + TEMP_TABS) loop
                    for J in 1..TAB_LENGTH loop
                        PUT(' ');
                    end loop;
                end loop;
                TEMP_TABS := 0;
                -- space needed before some special symbols, all reserved  
                -- words (except "not")  
            elsif TOKEN in EQUAL_ARROW..AMPERSAND or else (TOKEN in ABORT_SY..XOR_SY and LAST_TOKEN /= LEFT_PAREN
                    ) or else -- after some special symbols  
            LAST_TOKEN in EQUAL_ARROW..COMMA or else -- after reserved words (except "if;", "abs(", "array(")  
            (LAST_TOKEN in ABORT_SY..XOR_SY and then TOKEN /= SEMICOLON and then not ((LAST_TOKEN = ABS_SY
                    or else LAST_TOKEN = ARRAY_SY) and then TOKEN = LEFT_PAREN)) then
                PUT(' ');
            end if;
            case TOKEN is
                when ABORT_SY..XOR_SY =>
                    PUT_STRING(WORD(TOKEN), FALSE);
                when QUOTE..PERIOD | SPLAT..COMMA =>
                    PUT(SPEC_SYM(TOKEN));
                when ELLIPSIS..LS_EQ_TO =>
                    PUT(COMP_SYM(TOKEN));
                when IDENTIFIER =>
                    PUT_STRING(ID, TRUE);
                when COMMENT | LITERAL =>
                    for I in 1..LENGTH loop
                        PUT(LITERAL_STRING(I));
                    end loop;
                when others =>
                    null;
            end case;
        end PRINT_TOKEN;

        procedure PRE_PROCESS is
            --  
            -- "is" requires special processing  
            --  

            procedure ANOMALIES is
            begin
                if MODE = END_SPEC then
                    MODE := NORMAL;
                    if (TOKEN /= SEPARATE_SY) and then (TOKEN /= NEW_SY) then
                        TABS := TABS + 1;
                        NEWLINE_FLAG := TRUE;
                    end if;
                end if;
            end ANOMALIES;
            --  
            -- process tokens which end a sequence  
            --  

            procedure END_POSTS is
            begin
                if TOKEN = END_SY then
                    TABS := TABS - 1;
                    LEX;
                    -- end case does tabs -= 2  
                    if TOKEN = CASE_SY then
                        TABS := TABS - 1;
                    end if;
                    -- print "end", save next token  
                    PRINT_END : declare
                        TEMP : SYMBOL := TOKEN;
                    begin
                        TOKEN := END_SY;
                        PRINT_TOKEN;
                        TOKEN := TEMP;
                    end PRINT_END;
                    MODE := END_TOKEN;
                    -- end record does --tabs after printing  
                    if TOKEN = RECORD_SY then
                        TABS := TABS - 1;
                    end if;
                elsif (TOKEN = ELSE_SY and then MODE /= SHORT_CIRCUIT) or else (TOKEN = OR_SY
                        and then LAST_TOKEN = SEMICOLON) or else TOKEN = BEGIN_SY or else TOKEN = ELSIF_SY
                        or else -- exception, if not used in exception declaration  
                (TOKEN = EXCEPT_SY and then MODE /= COLON_TOKEN) or else -- when, if arm of case (not "exit when...")  
                (TOKEN = WHEN_SY and then MODE /= EXIT_TOKEN) then
                    TABS := TABS - 1;
                elsif TOKEN = RECORD_SY then
                    NEWLINE_FLAG := TRUE;
                    TABS := TABS + 1;
                end if;
            end END_POSTS;
            --  
            -- set mode for future reference  
            --  

            procedure SET_MODE is
            begin
                case TOKEN is
                    when END_SY =>
                        MODE := END_TOKEN;
                    when EXIT_SY =>
                        MODE := EXIT_TOKEN;
                    when CASE_SY =>
                        MODE := CASE_TOKEN;
                    when PROC_SY | FUNCTION_SY | PACKAGE_SY | TASK_SY =>
                        MODE := IN_SPEC;
                    when WHEN_SY =>
                        MODE := IN_WHEN;
                    when ACCEPT_SY =>
                        MODE := ACCEPT_MODE;
                    when AND_SY =>
                        MODE := SHORT_CIRCUIT;
                    when OR_SY =>
                        if LAST_TOKEN = SEMICOLON then
                            MODE := OR_IN_SELECT;
                        else
                            MODE := SHORT_CIRCUIT;
                        end if;
                    when COLON =>
                        if MODE /= IN_SPEC and then MODE /= ACCEPT_MODE then
                            MODE := COLON_TOKEN;
                        end if;
                    when SEMICOLON =>
                        if MODE /= IN_SPEC then
                            MODE := NORMAL;
                        end if;
                    when IS_SY =>
                        if MODE = IN_SPEC then
                            MODE := END_SPEC;
                        end if;
                    when DO_SY =>
                        if MODE = ACCEPT_MODE then
                            MODE := END_SPEC;
                        end if;
                    when ELSE_SY | THEN_SY =>
                        null;
                    when others =>
                        if MODE = SHORT_CIRCUIT then
                            MODE := NORMAL;
                        end if;
                end case;
            end SET_MODE;
        begin
            ANOMALIES;
            END_POSTS;
            SET_MODE;
            -- process end posts that start a new line  
            if TOKEN = BEGIN_SY or else (TOKEN = EXCEPT_SY and then MODE /= COLON_TOKEN) then
                NEWLINE_FLAG := TRUE;
            elsif ((TOKEN = OR_SY) or else (TOKEN = AND_SY)) and then (COL > 90) then
                NEWLINE_FLAG := TRUE;
                TEMP_TABS := 2;
            end if;
        end PRE_PROCESS;

        procedure POST_PROCESS is

            procedure START_POSTS is
            begin
                -- process start posts  
                if TOKEN = DECLARE_SY or else TOKEN = BEGIN_SY or else (TOKEN = EXCEPT_SY and then MODE /= COLON_TOKEN
                        ) or else (TOKEN = ELSE_SY and then MODE /= SHORT_CIRCUIT) or else (TOKEN = OR_SY
                        and then MODE = OR_IN_SELECT) or else (TOKEN = LOOP_SY and then MODE /= END_TOKEN)
                        or else (TOKEN = SELECT_SY and then MODE /= END_TOKEN) or else (TOKEN = RECORD_SY
                        and then MODE /= END_TOKEN) or else (TOKEN = THEN_SY and then MODE /= SHORT_CIRCUIT)
                        or else (TOKEN = EQUAL_ARROW and then MODE = IN_WHEN) then
                    TABS := TABS + 1;
                    NEWLINE_FLAG := TRUE;
                elsif TOKEN = IS_SY then
                    case MODE is
                        when IN_SPEC =>
                            MODE := END_SPEC;
                        when CASE_TOKEN =>
                            TABS := TABS + 2;
                            NEWLINE_FLAG := TRUE;
                        when others =>
                            null;
                    end case;
                elsif TOKEN = DO_SY then
                    if MODE = ACCEPT_MODE then
                        MODE := END_SPEC;
                    end if;
                end if;
            end START_POSTS;
        begin
            START_POSTS;
            -- process start tokens that require a new line  
            if (TOKEN = SEMICOLON and then MODE /= IN_SPEC) or else (TOKEN = COMMENT) then
                NEWLINE_FLAG := TRUE;
            elsif ((COL > 90) and then (TOKEN = COMMA)) or else (COL > 110) or else (TOKEN = SEMICOLON
                    and then MODE = IN_SPEC) then
                NEWLINE_FLAG := TRUE;
                TEMP_TABS := 2;
            end if;
        end POST_PROCESS;
    begin
        -- process  
        loop
            -- get a token  
            LEX;
            -- process end of file  
            if TOKEN = EOF then
                exit;
            end if;
            -- pre process  
            PRE_PROCESS;
            -- output token (newline, tabs if required)  
            PRINT_TOKEN;
            -- post process  
            POST_PROCESS;
        end loop;
    end PROCESS;
    --  
    -- process options  
    --  

    procedure PROCESS_OPTIONS is
        --        pointer : integer := where;  
    begin
        null;
        --    GET_FOREIGN;  
        --    for i in 1..input_length loop  
        --        if input(i) = '$' then  
        --            process_options(i+1);  
        --            exit;  
        --        end if;  
        --    end loop;  
        --        options: loop  
        --            case input(pointer) is  
        --                -- process tab length  
        --                when 'T' | 't' =>  
        --                    pointer := pointer + 1;  
        --                    if input(pointer) in '0'..'9' then  
        --                        tab_length := character'pos(input(pointer)) - 16#30#;  
        --                    else  
        --                        fatal(2);  
        --                        exit options;  
        --                    end if;  
        --                    pointer := pointer + 1;  
        --                -- process nesting level output  
        --                when 'N' | 'n' =>  
        --                    pointer := pointer + 1;  
        --                    output_nest := true;  
        --                -- skip all spaces  
        --                when ' ' =>  
        --                    loop  
        --                        pointer := pointer + 1;  
        --                        exit when input(pointer) /= ' ';  
        --                    end loop;  
        --                -- end of input  
        --                when nul =>  
        --                    exit;  
        --                -- otherwise, its a mistake  
        --                when others =>  
        --                    exit options;  
        --            end case;  
        --        end loop options;  
    end PROCESS_OPTIONS;
begin
    -- pretty_printer  
    WORD(ABORT_SY) := "ABORT                          ";
    WORD(ABS_SY) := "ABS                            ";
    WORD(ACCEPT_SY) := "ACCEPT                         ";
    WORD(ACCESS_SY) := "ACCESS                         ";
    WORD(ALL_SY) := "ALL                            ";
    WORD(AND_SY) := "AND                            ";
    WORD(ARRAY_SY) := "ARRAY                          ";
    WORD(AT_SY) := "AT                             ";
    WORD(BEGIN_SY) := "BEGIN                          ";
    WORD(BODY_SY) := "BODY                           ";
    WORD(CASE_SY) := "CASE                           ";
    WORD(CONST_SY) := "CONSTANT                       ";
    WORD(DECLARE_SY) := "DECLARE                        ";
    WORD(DELAY_SY) := "DELAY                          ";
    WORD(DELTA_SY) := "DELTA                          ";
    WORD(DIGITS_SY) := "DIGITS                         ";
    WORD(DO_SY) := "DO                             ";
    WORD(ELSE_SY) := "ELSE                           ";
    WORD(ELSIF_SY) := "ELSIF                          ";
    WORD(END_SY) := "END                            ";
    WORD(ENTRY_SY) := "ENTRY                          ";
    WORD(EXCEPT_SY) := "EXCEPTION                      ";
    WORD(EXIT_SY) := "EXIT                           ";
    WORD(FOR_SY) := "FOR                            ";
    WORD(FUNCTION_SY) := "FUNCTION                       ";
    WORD(GENERIC_SY) := "GENERIC                        ";
    WORD(GOTO_SY) := "GOTO                           ";
    WORD(IF_SY) := "IF                             ";
    WORD(IN_SY) := "IN                             ";
    WORD(IS_SY) := "IS                             ";
    WORD(LIMITED_SY) := "LIMITED                        ";
    WORD(LOOP_SY) := "LOOP                           ";
    WORD(MOD_SY) := "MOD                            ";
    WORD(NEW_SY) := "NEW                            ";
    WORD(NOT_SY) := "NOT                            ";
    WORD(NULL_SY) := "NULL                           ";
    WORD(OF_SY) := "OF                             ";
    WORD(OR_SY) := "OR                             ";
    WORD(OTHERS_SY) := "OTHERS                         ";
    WORD(OUT_SY) := "OUT                            ";
    WORD(PACKAGE_SY) := "PACKAGE                        ";
    WORD(PRAGMA_SY) := "PRAGMA                         ";
    WORD(PRIVATE_SY) := "PRIVATE                        ";
    WORD(PROC_SY) := "PROCEDURE                      ";
    WORD(RAISE_SY) := "RAISE                          ";
    WORD(RANGE_SY) := "RANGE                          ";
    WORD(RECORD_SY) := "RECORD                         ";
    WORD(REM_SY) := "REM                            ";
    WORD(RENAMES_SY) := "RENAMES                        ";
    WORD(RETURN_SY) := "RETURN                         ";
    WORD(REVERSE_SY) := "REVERSE                        ";
    WORD(SELECT_SY) := "SELECT                         ";
    WORD(SEPARATE_SY) := "SEPARATE                       ";
    WORD(SUBTYPE_SY) := "SUBTYPE                        ";
    WORD(TASK_SY) := "TASK                           ";
    WORD(TERMINATE_SY) := "TERMINATE                      ";
    WORD(THEN_SY) := "THEN                           ";
    WORD(TYPE_SY) := "TYPE                           ";
    WORD(USE_SY) := "USE                            ";
    WORD(WHEN_SY) := "WHEN                           ";
    WORD(WHILE_SY) := "WHILE                          ";
    WORD(WITH_SY) := "WITH                           ";
    WORD(XOR_SY) := "XOR                            ";
    SPEC_SYM(AMPERSAND) := '&';
    SPEC_SYM(QUOTE) := ''';
    SPEC_SYM(LEFT_PAREN) := '(';
    SPEC_SYM(RIGHT_PAREN) := ')';
    SPEC_SYM(SPLAT) := '*';
    SPEC_SYM(PLUS) := '+';
    SPEC_SYM(COMMA) := ',';
    SPEC_SYM(DASH) := '-';
    SPEC_SYM(PERIOD) := '.';
    SPEC_SYM(SLASH) := '/';
    SPEC_SYM(COLON) := ':';
    SPEC_SYM(SEMICOLON) := ';';
    SPEC_SYM(LESS_THAN) := '<';
    SPEC_SYM(EQUAL_SIGN) := '=';
    SPEC_SYM(GREATER_THAN) := '>';
    SPEC_SYM(BAR) := '|';
    COMP_SYM(EQUAL_ARROW) := "=>";
    COMP_SYM(ELLIPSIS) := "..";
    COMP_SYM(EXPONENTIATE) := "**";
    COMP_SYM(REPLACEMENT) := ":=";
    COMP_SYM(NOT_EQUAL_TO) := "/=";
    COMP_SYM(GR_EQ_TO) := ">=";
    COMP_SYM(LS_EQ_TO) := "<=";
    COMP_SYM(OPEN_LABEL) := "<<";
    COMP_SYM(CLOSE_LABEL) := ">>";
    COMP_SYM(BOX) := "<>";
    PROCESS_OPTIONS;
    -- reformat  
    PROCESS;
    NEW_LINE;
exception
when QUIT =>
    null;
end PRETTY_PRINTER;
