Every program needs some boiler plate … I/O routines, error message routines, etc. The programs we develop here will be no exceptions. I've tried to hold this stuff to an absolute minimum, however, so that we can concentrate on the important stuff without losing it among the trees. The code given below represents about the minimum that we need to get anything done. It consists of some I/O routines, an error-handling routine and a skeleton, null main program. I call it our cradle. As we develop other routines, we'll add them to the cradle, and add the calls to them as we need to. Make a copy of the cradle and save it, because we'll be using it more than once.
There are many different ways to organize the scanning activities of a parser. In Unix systems, authors tend to use getc and ungetc. I've had very good luck with the approach shown here, which is to use a single, global, lookahead character. Part of the initialization procedure (the only part, so far!) serves to “prime the pump” by reading the first character from the input stream. No other special techniques are required with Turbo 4.0 … each successive call to GetChar will read the next character in the stream.
Example 1.1. Cradle
program Cradle; { Constant Declarations } const TAB = ^I; { Variable Declarations } var Look: char; { Lookahead Character } { Read New Character From Input Stream } procedure GetChar; begin Read(Look); end; { Report an Error } procedure Error(s: string); begin WriteLn; WriteLn(^G, 'Error: ', s, '.'); end; { Report Error and Halt } procedure Abort(s: string); begin Error(s); Halt; end; { Report What Was Expected } procedure Expected(s: string); begin Abort(s + ' Expected'); end; { Match a Specific Input Character } procedure Match(x: char); begin if Look = x then GetChar else Expected('''' + x + ''''); end; { Recognize an Alpha Character } function IsAlpha(c: char): boolean; begin IsAlpha := upcase(c) in ['A'..'Z']; end; { Recognize a Decimal Digit } function IsDigit(c: char): boolean; begin IsDigit := c in ['0'..'9']; end; { Get an Identifier } function GetName: char; begin if not IsAlpha(Look) then Expected('Name'); GetName := UpCase(Look); GetChar; end; { Get a Number } function GetNum: char; begin if not IsDigit(Look) then Expected('Integer'); GetNum := Look; GetChar; end; { Output a String with Tab } procedure Emit(s: string); begin Write(TAB, s); end; { Output a String with Tab and CRLF } procedure EmitLn(s: string); begin Emit(s); WriteLn; end; { Initialize } procedure Init; begin GetChar end; { Main Program } begin Init; end. |
That's it for this introduction. Copy the code above into TP and compile it. Make sure that it compiles and runs correctly. Then proceed to the first lesson, which is on expression parsing.