symbolrule ::= identifier := outexpression
Strings, identifiers and numbers in a source program are normally recognised by the basic types in Syntax Rules and stored as leaves in the tree currently being built. The generated code may use these strings by calling the relevant output command as the tree is being processed. In most computer languages, identifiers and numbers tend to have properties associated with them which influence the form of the code generated. These properties are sometimes defined explicitly while others may have implicit declarations. For example, an Algol program requires every identifier to have its type declared explicitly. This declaration also defines the scope of the identifier - that is, the part of the program in which the identifier may be used. In order to generate code which depends on information supplied by earlier statements, there is a need to provide a Symbol Table which can be used to store strings, together with certain properties associated with them. Routines must be provided to access this table and interrogate it.
The TREE-META Symbol Table provides the user with storage for up to 400 strings. These strings will usually be identifiers recognised in the source program. However, there is no reason why numbers or strings appearing in a tree should not also be added to the Symbol Table. Each Symbol Table entry has associated with it three values which have names TYPE, LEVEL and VALUE. Whereas TYPE and VALUE may be used for any purpose, LEVEL is primarily used to differentiate between the same name declared at different block levels in an Algol-like language. Thus, the name, together with the contents of LEVEL, uniquely define a Symbol Table entry. The properties of these three values are as follows:
The three global variables TYPE, LEVEL and VALUE need to have the necessary values associated with them before a Symbol Table entry is made. This is done using the standard arithmetic statements defined in Chapter 6. For example:
< TYPE<-1 ; LEVEL<-0 ; VALUE<-3 >
is a possible arithmetic list appearing in a Code Rule. Similarly, routines which look up entries in the Symbol Table, will often reset the value of these variables. The new values can be checked using the standard comparison tests allowed in arithmetic lists. For example:
< TYPE=1 > ....... / .........
might appear in a Code Rule to define different actions depending on the TYPE value for a Symbol Table entry.
A number of routines are defined for manipulating Symbol Table entries. They may appear in arithmetic lists in the same way as the routines defined in Section 6.5. The routines are:
DEC[-,-]=> < TYPE<-1 ; VALUE<-3 ; LEVEL<-2 ; ENTER[*2] >might be called with a pointer to the tree:
ADR[-] => < LOOK[*1] > < OUT [VALUE] > / 'ERROR' ;If this rule is called with the node ADR having the string ABC as the only branch, the name ABC will be looked up in the Symbol Table and, if it exists, the corresponding VALUE will be printed. If an entry with name ABC does not exist, the message ERROR is printed. The function LOOK should always be the last item in an arithmetic list, otherwise the Boolean result will have no effect.
END[] => < T<-CLEAR[0] ; OUT[T] > ;will remove all the entries from the Symbol Table, set T to the number of entries removed and print its value. In a compiler for a block-structured language, the entries for a particular block LEVEL value will be removed when the end of the block is reached. This ensures that only those variables which still have the correct scope can be accessed. By always choosing the entry with the highest LEVEL found on look-up, the correct variable is chosen if several nested blocks have declarations involving variables with the same name.
A special output rule, the Symbol Rule, allows the same operation to be performed on every entry in the Symbol Table. An example is:
SC := 'DEFINE ' *1 ' EQU ' < OUT[VALUE] > % ;
The action of the rule is as follows:
Thus, *1 on the right hand side of the rule will output the name of the Symbol Table entry being considered. No other nodename is allowed in a Symbol Rule. This is the only limitation. There is no reason why, for example, the Symbol Rule should not call other Code Rules. However, it must not call another Symbol Rule.
A Symbol Rule is executed by calling it from a Code Rule as though it were a Code Rule with no arguments. For example:
ENDP[] => SC[] 'END' % ;
would call the Symbol Rule defined above. The result would be a set of lines of the form:
DEFINE FRED EQU 27
where FRED is the name of a Symbol Table entry and the number 27 is the VALUE entry for FRED.