WITH Ada.Text_IO, VStrings; USE Ada.Text_IO, VStrings; PACKAGE BODY English_Lexer IS ------------------------------------------------------------------------ --| Ada 95 version of lexical scanner for simple English. --| This version uses procedure pointers for the actions --| of the finite-state machine. The FSM executes the actions --| directly instead of using a CASE statement. --| Author: Michael B. Feldman, The George Washington University --| Last Modified: January 1996 ------------------------------------------------------------------------ TYPE State IS (Start, Build, Finish); TYPE InputClass IS (Letter, CR, AnythingElse); -- Ada 95 feature: access-to-procedure type TYPE Action IS ACCESS PROCEDURE; TYPE LexicalEntry IS RECORD NewState : State; ThisAction : Action; END RECORD; TYPE FSM_Table IS ARRAY (State, InputClass) OF LexicalEntry; FUNCTION Classify (Ch: Character) RETURN InputClass IS BEGIN CASE Ch IS WHEN 'A'..'Z' | 'a'..'z' | '0'..'9' => RETURN Letter; WHEN OTHERS => RETURN AnythingElse; END CASE; END Classify; PROCEDURE GetWord (F : IN File_Type; Word : OUT WordType; Success: OUT Boolean; EOL : OUT Boolean; EOF : OUT Boolean) IS Char : character; ThisClass : InputClass; PresentState : State; ThisEntry : LexicalEntry; NewAction : Action; TempWord : WordType; -- Action procedures - will be designated in the lexical table, -- then dereferenced to dispatch the appropriate action PROCEDURE Nothing IS BEGIN NULL; END Nothing; PROCEDURE StartWord IS BEGIN TempWord := TempWord & Char; END StartWord; PROCEDURE AddLetter IS BEGIN TempWord := TempWord & Char; END AddLetter; PROCEDURE BumpLine IS BEGIN EOL := True; END BumpLine; -- Lexical table for simplified English text. -- Note values like StartWord'Access, etc., in the action fields EnglishText : CONSTANT FSM_Table := ( -- entries for current state = Start, current input = ((Build, StartWord'Access), -- Letter (Finish, BumpLine'Access), -- CR (Start, Nothing'Access)), -- AnythingElse -- entries for current state = Build, current input = ((Build, AddLetter'Access), -- Letter (Finish, BumpLine'Access), -- CR (Finish, Nothing'Access)), -- AnythingElse -- entries for current state = Finish, current input = ((Finish, Nothing'Access), -- Letter (Finish, Nothing'Access), -- CR (Finish, Nothing'Access))); -- AnythingElse -- End of lexical table for simple English BEGIN --- body of GetWord EOL := false; EOF := false; PresentState := Start; LOOP IF PresentState = Finish THEN EXIT; END IF; IF End_of_File (F) THEN EOF := true; EXIT; ELSIF End_of_Line (F) THEN Skip_Line (F); ThisClass := CR; ELSE Get (F, Char); Put(Char); ThisClass := Classify (Char); END IF; -- Dereference the appropriate action, which causes it to -- be dispatched (called). EnglishText (PresentState, ThisClass).ThisAction.ALL; -- Just get new state from the table. PresentState := EnglishText(PresentState,ThisClass).NewState; END LOOP; Word := TempWord; Success := NOT VStrings.IsEmpty(Word); END GetWord; END English_Lexer;