(*****************************************************}
{}
{ * PROJECT:       BBB interpreter}
{}
{ * ORGANIZATION:  Microfluffy Corp.}
{}
{ * LANGUAGE:      Turbo Pascal}
{}
{ * FILE:          symtab.pas}
{}
{ * DESCRIPTION:   This file implements the symbol table}
{}
{ * VERSION:       1.0}
{}
{ *****************************************************)



unit SymTab;



interface



	uses
		Scan;



{ This procedure initializes the symbol table.  Call it at the}
{}
{  beginning of the program.                                     }

	procedure InitSymtab;



{ This function tests whether a variable name refers to a string}
{}
{  variable or not.  It returns true if the variable is a string}
{}
{  (ie, if it has a '$' on the end                                }

	function IsStrVar (var name: string): boolean;



{ These procedures set the value of a variable.  If the variable}
{}
{  is not in the symbol table, it is created.                     }

	procedure SetIntVal (var name: string; var value: integer);

	procedure SetStrVal (var name: string; var value: string);



{ These procedures lookup the value of a variable.  The value is}
{}
{  returned in the value parameter.  If the variable is not in the}
{}
{  symbol table, it is created and initialized to zero/empty.     }

	procedure GetIntVal (var name: string; var value: integer);

	procedure GetStrVal (var name: string; var value: string);





{ prints out an error message of the form "Error: (line <num>) <message>".}
{}
{   ErrStr contains the message to display, and LineNum the line number}
{}
{   that the error occurred on.  If LineNum nonpositive, then the error}
{}
{   message will not include a line number.  After printing out the error}
{}
{   message, the program ends.}
{}
{ }

	procedure PrintError (ErrStr: string; LineNum: integer);





implementation





{data types that the symbol table needs}

	type

  { record that contains the value of a string variable }

		strvarrec = record

				name: VarStr;

				value: StrVarStr;

			end;



  { record that contains the value of an integer variable }

		intvarrec = record

				name: VarStr;

				value: integer;

			end;





{ variables that actually contain the symbols }

	var

  { these contain the actual variable values }

		StrTable: array[1..MAX_STRVAR] of strvarrec;

		IntTable: array[1..MAX_INTVAR] of intvarrec;

  { these mark which entries in the table have been used }

		StrIdx: integer;

		IntIdx: integer;





{ prints out an error message of the form "Error: (line <num>) <message>".}
{}
{   ErrStr contains the message to display, and LineNum the line number}
{}
{   that the error occurred on.  If LineNum nonpositive, then the error}
{}
{   message will not include a line number.  After printing out the error}
{}
{   message, the program ends.}
{}
{ }

	procedure PrintError (ErrStr: string; LineNum: integer);

	begin {PrintError}

		if (LineNum <= 0) then
			begin

				writeln('Error: ', ErrStr);

				halt;

			end

		else

			begin
				writeln;
				write('Error: (line ');

				write(LineNum);

				writeln(') ', ErrStr);

				writeln('Press any key to exit.');
				readln;
				halt;

			end;

	end;  {PrintError}



{ initialization }

	procedure InitSymtab;

	begin {InitSymtab}

		StrIdx := 0;         {set table sizes to zero}

		IntIdx := 0;

	end;  {InitSymtab}



{ figure out if <name> is referring to a string variable }

	function IsStrVar (var name: string): boolean;

		var

			i: integer;

	begin {IsStrVar}

		IsStrVar := (name[length(name)] = '$');

	end;  {IsStrVar}



{ integer variable lookup }

	procedure GetIntVal (var name: string; var value: integer);

		var

			i: integer;

	begin {GetIntVal}

  { search through the integer table for the variable }

  { named <name>, and if it is found, put it's value }

  { in <value> and return.}

		for i := 1 to IntIdx do
			begin

				if (name = IntTable[i].name) then
					begin

						value := IntTable[i].value;

					end;

			end; {for}



  { if the variable isn't there, then add it }

		i := 0;

		SetIntVal(name, i);

		value := 0;

	end;  {GetIntVal}



{ string variable lookup }

	procedure GetStrVal (var name: string; var value: string);

		var

			i: integer;

			s: string;

	begin {GetStrVal}

  { search through the string table for the variable }

  { named <name>, and if it is found, put it's value }

  { in <value> and return }

		for i := 1 to StrIdx do
			begin

				if (name = StrTable[i].name) then
					begin

						value := StrTable[i].value;

					end;

			end; {for}



  { if the variable isn't there, then add it }

		s := '';

		SetStrVal(name, s);

		value := s;

	end;  {GetStrVal}



{ set the value of an integer variable }

	procedure SetIntVal (var name: string; var value: integer);

		var

			i: integer;

	begin {SetIntVal}

  { try to lookup the variable <name>, and set it's value }

		for i := 1 to IntIdx do
			begin

				if (name = IntTable[i].name) then
					begin

						IntTable[i].value := value;


					end;

			end; {for}



  { don't allow the add if the table is full or if the }

  { variable name is too long }

		if (IntIdx = MAX_INTVAR) then

			PrintError(e_nomem, 0);

		if (Length(name) > MAX_VAR) then

			PrintError(e_varlen, 0);



  { increment the table size and record the variable }

		IntIdx := IntIdx + 1;

		IntTable[IntIdx].name := name;

		IntTable[IntIdx].value := value;

	end;  {SetIntVal}



{ set the value of a string variable }

	procedure SetStrVal (var name: string; var value: string);

		var

			i: integer;

	begin {SetStrVal}

  { try to lookup the variable <name>, and set it's value }

		for i := 1 to StrIdx do
			begin

				if (name = StrTable[i].name) then
					begin

						StrTable[i].value := value;

					end;

			end; {for}



  { don't allow the add if the table is full or if the }

  { variable name is too long }

		if (StrIdx = MAX_STRVAR) then

			PrintError(e_nomem, 0);

		if (Length(name) > MAX_VAR) then

			PrintError(e_varlen, 0);



  { increment the table size and record the variable }

		StrIdx := StrIdx + 1;

		StrTable[StrIdx].name := name;

		StrTable[StrIdx].value := value;

	end;  {SetStrVal}



end.
