14.9. Literal Arguments

Sharp-eyed readers might have noticed, though, that we don't even have a proper form of a simple factor yet, because we don't allow for loading literal constants, only variables. Let's fix that now.

To begin with, we'll need a GetNum function. We've seen several versions of this, some returning only a single character, some a string, and some an integer. The one needed here will return a LongInt, so that it can handle anything we throw at it. Note that no type information is returned here: GetNum doesn't concern itself with how the number will be used:

{ Get a Number }
function GetNum: LongInt;
var Val: LongInt;
   if not IsDigit(Look) then Expected('Integer');
   Val := 0;
   while IsDigit(Look) do begin
      Val := 10 * Val + Ord(Look) - Ord('0');
   GetNum := Val;

Now, when dealing with literal data, we have one little small problem. With variables, we know what type things should be because they've been declared to be that type. We have no such type information for literals. When the programmer says, "-1," does that mean a byte, word, or longword version? We have no clue. The obvious thing to do would be to use the largest type possible, i.e. a longword. But that's a bad idea, because when we get to more complex expressions, we'll find that it will cause every expression involving literals to be promoted to long, as well.

A better approach is to select a type based upon the value of the literal, as shown next:

{ Load a Constant to the Primary Register }
function LoadNum(N: LongInt): char;
var Typ : char;
   if abs(N) <= 127 then
      Typ := 'B'
   else if abs(N) <= 32767 then
      Typ := 'W'
   else Typ := 'L';
   LoadConst(N, Typ);
   LoadNum := Typ;


I know, I know, the number base isn't really symmetric. You can store -128 in a single byte, and -32768 in a word. But that's easily fixed, and not worth the time or the added complexity to fool with it here. It's the thought that counts.

Note that LoadNum calls a new version of the code generator routine LoadConst, which has an added argument to define the type:

{ Load a Constant to the Primary Register }
procedure LoadConst(N: LongInt; Typ: char);
var temp:string;
   Str(N, temp);
   Move(Typ, '#' + temp, 'D0');

Now we can modify procedure Expression to accomodate the two possible kinds of factors:

{ Parse and Translate an Expression }
function Expression: char;
   if IsAlpha(Look) then
      Expression := Load(GetName)
      Expression := LoadNum(GetNum);


Wow, that sure didn't hurt too bad! Just a few extra lines do the job.

OK, compile this code into your program and give it a try. You'll see that it now works for either variables or constants as valid expressions.