System for ensuring the accuracy of file structures in a source-to-source computer program translator6317871Abstract A system for identifying the file structure of a computer program, preserving the file structure of the code after translation of source code from one high-level computer language to another, combining pieces of a source file that were generated in different translation sessions, and ensuring textual consistency of each piece of generated code in the resultant code files. Claims What is claimed is: Description BACKGROUND OF THE INVENTION
pTALCode C++ Code
define less(x) = <x #; #define less(x) < x
... ...
if a less(42) then if (a less (42))
... ...
FIG. 1: Parameterized Macro Definition and Invocation Notice that the macro illustrated in FIG. 1 is not a well-formed syntactic entity. That is, it contains part but not all of a relational operation. Concepts Virtual Source. A program's virtual source is a stream of tokens that a compiler parses to create a syntax tree representing that program. The virtual source is often the output of a preprocessor. Virtual source typically does not exist in textual form in any single source file; the token stream is created by a series of source file inclusions, macro expansions, and macro formal parameter substitutions. Virtual Source Production Mechanisms. Virtual source production mechanisms are used by a scanner or preprocessor to create virtual source. Virtual source production mechanisms available in pTAL and C++ are: source inclusion of files, macro expansion, and macro formal parameter substitution. A virtual source production mechanism can appear anywhere in a source file and its invocation can yield any portion of a syntactic construct; it need not honor syntactic construct boundaries. For example, a macro invocation can appear anywhere in a source file and the resulting macro expansion can yield a portion of a syntactic construct. Virtual Fragment. A virtual fragment contains the stream of tokens which result from invoking a virtual source production mechanism. Note that some sub-streams of these tokens may themselves represent invocations of virtual source production mechanisms. Fragment Tree. A fragment tree represents every virtual source production mechanism that was employed to create the virtual source. The leaves of the fragment tree are the tokens of the virtual source. The root of the fragment tree is the source file that a compiler starts reading to perform a compilation. This is treated as a source file "inclusion." Invocation Syntax. When a text preprocessor recognizes a reference to a macro, for example "mac(5)," it substitutes text from the body of the macro at that point. The tokens representing "mac(5)" compose the invocation syntax for that macro. Macro formal parameters and source file inclusion behave like parameterless macro invocations. The invocation syntax for a macro formal parameter is the name of the formal parameter referenced in the macro body. The invocation syntax for source file inclusion is a preprocessor directive. Virtual Partition: A virtual fragment contains one or more virtual partitions. A virtual partition is bounded by the beginning or end of a virtual fragment and by directives which control conditional compilation or file sectioning (a feature available in the pTAL language). Fragment Template: A fragment template is a sequence of tokens that reside in a file, in a macro body, in a macro actual parameter, etc. A virtual fragment is an instance of a fragment template. The pTAL language contains restrictions which allow a fragment template to always be extracted from a text file. This restriction is in principle unnecessary; the current invention covers languages, such as Burroughs ALGOL, which do not have such restrictions and allow, for example, a define expansion to define a new define. Partition Template: A partition template is a sequence of tokens bounded by fragment template bounds and by directives which control conditional compilation or file sectioning. A virtual partition is an instance of a partition template. Translator Overview FIG. 8A is an illustration of computer system 200 suitable for performing the processing steps of the present invention. Computer system 200 includes display 202 having display screen 204. Cabinet 206 houses standard computer components (not shown) such as a disk drive, CDROM drive, display adapter, network card, random access memory (RAM), central processing unit (CPU), and other components, subsystems and devices. User input devices such as mouse 208 having buttons 210, and keyboard 212 are shown. Other user input devices such as a trackball, touch-screen, digitizing tablet, etc. can be used. In general, the computer system is illustrative of but one type of computer system, such as a desktop computer, suitable for use with the present invention. Computers can be configured with many different hardware components and can be made in many dimensions and styles (e.g., laptop, palmtop, pentop, server, workstation, mainframe). Any hardware platform suitable for performing the processing described herein is suitable for use with the present invention. FIG. 8B illustrates subsystems that might typically be found in a computer such as computer 200. In FIG. 8B, subsystems within box 220 are directly interfaced to internal bus 228. Such subsystems typically are contained within the computer system such as within cabinet 206 of FIG. 8A. Subsystems include input/output (I/O) controller 222, System Memory (or "RAM") 224, CPU 226, Display Adapter 230, Serial Port 240, Fixed Disk 242, Network Interface Adapter 244. The use of bus 228 allows each of the subsystems to transfer data among subsystems and, most importantly, with the CPU. External devices can communicate with the CPU or other subsystems via bus 228 by interfacing with a subsystem on the bus. Thus, Monitor 246 connects with Display Adapter 230, a relative pointing device (e.g. a mouse) connects through Serial Port 240. Some devices such as Keyboard 250 can communicate with the CPU by direct means without using the main data bus as, for example, via an interrupt controller and associated registers. As with the external physical configuration shown in FIG. 8A, many subsystem configurations are possible. FIG. 8B is illustrative of but one suitable configuration. Subsystems, components or devices other than those shown in FIG. 8B can be added. A suitable computer system can be achieved without using all of the subsystems shown in FIG. 8B. For example, a standalone computer need not be coupled to a network so Network Interface 244 would not be required. Other subsystems such as a CDROM drive, graphics accelerator, etc. can be included in the configuration without affecting the performance of the system of the present invention. The present invention is embodied in a software system for translating source code to target code where the target code is a different computer language from the source code. The software system is referred to as the "Rosetta Translator" made by Tandem Computers, Inc. In FIG. 2, A source language syntax tree represents the syntactic structure of the virtual source. A source language fragment tree represents the virtual source production mechanisms that were employed to create the virtual source. Explicit tokens appear on the leaves of the otherwise traditional syntax tree. Each of these tokens is also a leaf of the fragment tree, indicating which virtual source production mechanism brought it into the virtual source. The syntax tree and the fragment tree are said to be "joined at the tokens." The following sections of the above-referenced, incorporated patent applications should be consulted: Andrews, K., Del Vigna, P., and Molloy, M., "Macro and File Structure Preservation in Source-to-source Translation", Software--Practice and Experience, 26(3), March 1996, describes the fragment translator algorithm. Aho, Sethi, and Ullman, Compilers: Principles, Techniques, and Tools, Addison-Wesley, 1985, describes compiler construction and principles. Andrews, K., Del Vigna, P., and Molloy, M., "Macro and File Structure Preservation in Source-to-source Translation", Software--Practice and Experience, 26(3), March 1996, provides a description of source-to-source translation. FIG. 2: Rosetta Translator Overview Novel Features The novel features that this invention disclosure is intended to describe include: the extraction of fragment templates and partition templates from a source language text file the checking of textual consistency of the target language code generated for each partition template the piecing together of a target language code file from partition templates the combining of pieces of a target language code file that were generated in different translation sessions Identifying fragment templates and partition templates takes place in the scanner; the rest of this work takes place in the source generator. Properties of Partitions This section describes some interesting properties of partitions. The discussion focuses on macros, but the ideas apply as well to macro actual parameters, included files, and conditionally complied regions of code. A source language partition is semantically equivalent to the target language partition to which it translates. For a macro to "work", it must expand to a meaningful token stream in every context of use in the generated code. For a macro to be readable and maintainable, it must be invoked for the same purposes in the generated code as in the source code; it must provide the same benefit by encapsulating equivalent target language text. Tokens in a source language virtual partition must be translated in their context or contexts of use. Macros cannot be translated at their point of definition because, even if the text could be parsed, semantic analysis would not be possible. Only when the macro is expanded is the semantic information necessary for translation available. Macros are, for example, translated after they are expanded. Conditionally compiled regions of code are, for example, only translated when the surrounding toggles allow them to be scanned. An important implication of this property is that shared interface files tend to be translated incrementally, as a side effect of translating the modules that use them. Every instance of a source language partition template should translate to the same target language text. A macro body is translated once for every expansion in the virtual source. The Rosetta Translator chooses to produce exactly one target language macro for each source language macro; this design decision requires that the translation of every instance of a macro expansion be textually identical. The Rosetta Translator can only be sure that the translation of a macro "works" in every context of use if every instance of the macro expansion translates to textually identical generated code. A textual mismatch might occur, for example, when the syntax expressing two distinct operations is the same in the source language but different in the target language. The pun (one phrase with two distinct meanings) does not translate. Construct translations should not blur partition boundaries. Each source language syntactic construct is mapped to a corresponding target language syntactic construct, and source language tokens within that construct are mapped to corresponding target language tokens within the corresponding target language construct. While the tokens in the resultant token stream need not maintain the same relative ordering as the source language tokens that generated them, virtual partition boundaries are points of ordering enforcement. Each token in a given target language virtual partition is generated from some token in the same source language virtual partition. Extracting Partition Templates From a Source File The Rosetta Translator extracts source language partition templates from a source language code file and assembles target language partition templates into a target language code file. The target language syntax tree can be different from the source language syntax tree, and the target language fragment tree can be different from the source language fragment tree, but the partition template structure visible in a generated source file is exactly the same as that visible in the corresponding input source file. Recall that partition templates are bounded by: compiler directives which control conditional compilation or file sectioning beginning and end of macro bodies in a macro definition beginning and end of a macro actual parameter beginning and end of a file Macro actual parameters behave exactly like macro bodies, except that the scope in which actual parameters can be expanded is limited to the body of the macro. Because the translation of a macro body (with actual parameter substitutions replaced by formal parameters, of course) must be textually identical for all contexts of use, and a macro definition can appear in an interface file that is included in the translation of many modules, the Rosetta Translator must perform a consistency check between the translation produced by the first expansion of the macro and the translation produced by each subsequent expansion of the macro. The scope of a macro actual parameter is limited to the macro body itself, so the Rosetta Translator need only perform a consistency check during any particular translation session to ensure that all expansions of a formal parameter within one particular define expansion are textually identical. It need never perform a consistency check between translation sessions. This property allows replication or reordering of virtual source production mechanism invocation syntax when the encapsulated code is replicated or reordered during syntax translation. Invocation syntax need not have a one-to-one correspondence between the input source file and the output source file. The Rosetta Translator preserves the define encapsulation when the entire contents of the define is replicated during translation. For example, all uses of the index variable in the translation of the following FOR loop are encapsulated in define invocations.
pTAL Code Rosetta-Generated C++ Code
DEFINE id = s.a[7]# #define id s.a[7]
...
FOR id := 0 TO 9 DO for(id = 0; id <= 9; ++id)
BEGIN {
a[id] := id; a[id] id;
END; }
FIG. 3: Replicated Code Encapsulated By a Macro When piecing together partition templates to create a target language code file, the source generator embeds the macro actual parameters in the partition that contains the invocation syntax for the macro. The fragment tree is flattened at macro actual substitution points in creating the text of partition templates. The following example illustrates the extraction of partition templates from a source language code file. FIG. 4: Static Partitions in a Source Language Code File The scanner extracts partition templates from the source language code file. Instances of these partition templates populate the fragment tree. The following two figures illustrate the pTAL fragment tree that the Rosetta Translator builds after scanning the source file shown above. The sequence of tokens that makes up the leaves of the fragment tree is the fully expanded virtual source. Notice that the beginning and end of each define body forms a partition boundary, as do the ?IF and ?ENDIF compiler directives. The contents of a macro body (a+13 in this example) reside in a macro invocation virtual fragment, and its invocation syntax (stuff () in this example) resides in the invoking virtual fragment. Partition templates that are not used do not appear in the fragment tree. Assume for this example that the toggle 15 is not set. The conditionally compiled region of code does not appear in the fragment tree, and the body of define junk does not appear in the fragment tree. FIG. 6: Second Half of the Fragment Tree Building an Output File The Rosetta Translator pieces together textual representations of instances of target language partition templates to form target language output files, fitting a textual representation of a macro body, for example, into its definition. It also pieces together partitions translated only in previous runs with partitions whose translations have just been completed. As previously discussed, the text of macro actual parameter fragment templates is collapsed into the invoking partition just before the file is pieced together. The following example illustrates the assembling of a target language code file. The source generator obtains an instance of each partition template from the target language fragment tree and commits it to text, then writes it to the target language code file. It fits the text representing the body of the macro stuff into the macro definition. Notice that there was no macro invocation fragment for the macro junk, so the resultant code file contains no text for that partition template. FIG. 7: Static Partitions in a Target Language Code File The translator must perform consistency checks between newly-generated partitions and previously-generated partitions if the source language text has not changed. Inconsistently translated code can appear in any partition, not just in macro bodies. The translator must discard previously-generated partitions if the source language text has changed since they were generated. Partition Template Map A partition template map is an ordered list of partition templates as they would appear in a code file. A partition template map assumes that macro actual parameters are collapsed into the partition in which the macro invocation appears. Each partition template in the partition template map is associated with a source language textual rendering of the partition and a target language textual rendering of the partition. Writing the target language textual rendering of each partition template in the order in which they appear in the partition template map creates a target language code file. A partition template map can describe the partition structure of a file as revealed to the translator in one translation session. A partition template map describing the partition structure of a file for one translation session does not necessarily describe the partition structure of the same file for another translation session, because the toggle settings might be different, exposing different code (which might contain macro definitions) and directives to the translator. Notice that one cannot scan the contents of conditionally compiled regions of code that are not exposed to the translator because the text might not make sense programmatically; there must be a separate translation session for each meaningful set of toggle settings. Code generated in different translation sessions can be accumulated into one target language file by merging the partition template maps for different translation sessions and merging the corresponding text for each partition. In this way, the Rosetta Translator can build up target language code files incrementally, as their contents are used. The partition template map for a target language code file might not correspond to any single translation session. This partition template map might not be derivable from the target language code itself, so the partition template map corresponding to each file must be saved in some retrievable place. The partition template map keeps the following information: A means of identifying the source language text in the partition template (location and size in the file is fine) A means of identifying the target language text in the partition template (location and size in the file is fine once the text is written to a file; a buffer of text is fine before the output file is built) An indication of whether or not virtual partition instances exist for the partition template (an untranslated partition has not been scanned during the current translation session, if this partition template map represents the current session, or during any of the accumulated translation sessions that this partition template map represents) Additional information in the partition template map can be used to improve the performance of the comparisons. The Rosetta Translator stores partition template map information as text at the end of each generated C++ file protected by toggles to keep it from being compiled. This information could be stored in a database separate from the generated target language text files. The scanner stores conditional compilation and file sectioning directives as partition boundaries even if they guard text from being scanned. An ?IF directive with a toggle setting that forbids scanning the text that follows is translated even though the partition that it bounds is not. Which partition templates are translated might differ from translation session to translation session, depending on which defines are used, etc. Include files are normally built up incrementally as the partition templates in them are referenced. Merging Partition Template Maps The following algorithm merges two partition template maps, one from the current translation session (currSessionPartMap), and one from a previous translation session (prevSessionPartMap). The main file undergoing translation together with all of the files that it includes and all of the files that the include files include all participate in a translation session. Operations are as Follows GetCurrentPartitionMap (file): Returns the current partition template map for file file. GetPrevPartitionmap (file): Returns the previous translation session's partition template map for file file. IsCodeFromPrevSession(): TRUE if a previous translation session has generated some target language code for this file. GetNextPart (pmap): Returns the next partition in the partition template map pmap. For purposes of presentation of this algorithm: implicit in the partition template map is an iterator. DescribeSamePartition (partA, partB): Returns TRUE if partA and partB were describing the same partition template. WasTranslated (part): Returns TRUE if an instance of partition template part exists in the target language fragment tree. InsertAfter (partA, partB): Insert partAba in the same partition map as partB, inserting immediately after partB. MergePartitionso
FOR (file =
each file participating in this translation session) BEGIN
currSessionPartMap = GetCurrentPartitionMap(file)
prevSessionPartMap = GetPrevPartitionMap(file)
IF (IsCodeFromPrevSession( )) THEN BEGIN
currSessionPart = GetNextPart(currSessionPartMap)
prevSessionPart = GetNextPart(prevSessionPartMap)
WHILE (prevSessionPart != NULL) BEGIN
IF (currSessionPart == NULL) THEN BEGIN
/* Partition map from current session ran dry */
Append(prevSessionPart,currSessionPartMap)
END
ELSE IF (DescribeSamePartition(
currSessionPart,prevSessionPart)) THEN BEGIN
IF (WasTranslated(currSessionPart) AND
NOT WasTranslated(prevSessionPart))
THEN BEGIN
prevSessionPart = GetNextPart(prevSessionPartMap)
WHILE (NOT DescribeSamePartition(
currSessionPart,prevSessionPart))
currSessionPart = GetNextPart(currSessionPartMap)
END ELSE IF (NOT WasTranslated(currSessionPart) AND
WasTranslated(prevSessionPart))THEN
BEGIN
/* might be multiple Partitions guarded by IF */
markerPart = currSessionPart
currSessionPart = GetNextPart(currSessionPartMap)
WHILE (NOT DescribeSamePartition(currSessionPart,
prevSessionPart)) BEGIN
InsetAfter(prevSessionPart,markerSessionPart)
prevSessionPart = GetNextPart(prevSessionPartMap)
/* markerPart gets newly inserted partition */
markerPart = GetNextPart(currSessionPartMap)
END
END ELSE BEGIN
currSessionPart = GetNextPart(currSessionPartMap)
prevSessionPart = GetNextPart(prevSessionPartMap)
END
END ELSE BEGIN /* don't describe the same Partition */
/* A partition has been added or deleted from the */
/* source language file. Discard the previously /*
/* generated file and remove the partitions added /*
/* from that file. */
END
END
END
END
The merged partition template map is used to build the source file containing the accumulation of all partitions translated in any translation session so far. The merged partition template map information is saved for use in the next translation session. The algorithm given here assumes that the source language text does not change between the previous translation session and the current translation session. Heuristics can be applied to cope with new or changed partitions. Consistency of Target Language Virtual Partitions The Rosetta Translator's design requires that it must check the textual consistency of every instance of each partition template. Every target language virtual partition created during the current session must be consistent. A textual rendering of a target language virtual partition created during the current translation session must be consistent with the target language text generated for the same partition template in previous translation sessions, if any. If inconsistent text is generated for different contexts of use, then that code will not be correct for all contexts of use. Such code is unlikely to compile and execute correctly. Serious mismatches can arise in included files or in define bodies. Any time one source language textual sequence can translate to different C-language text in different contexts, there is a danger of generating code that does not compile or execute correctly in every context of use. Untranslated Define Actual Parameters Because a define actual parameter must be translated in its context of use, no translation is possible if there is no use of the formal parameter in the define. For example, consider the following code:
?if fast
define d(x) = 7#; ! <--this is define d when settog fast !
?endif fast
?ifnot fast
define d(x) = x * 2#;
?endif fast
proc p;
begin
int a := 4;
int b := 5;
a := d(b);
end;
Suppose the code were translated with the option "SETTOG FAST" set. The code is expanded as follows:
define d(x) ...
proc p;
begin
int a := 4;
int b := 5;
a := 7;!Wow!! There's no use of the formal "b"!
end;
The expanded pTAL code is translated to the following expanded C++ code: The resultant C++ code appears as follows:
#define d(x) 7
void p() {
int 16 a = 4;
int 16 b = 5;
a = d(/*UA:x*/);
The Rosetta Translator emits a special comment "/*UA:x*/" that indicates that no use of the formal parameter x was translated; it holds the place of an untranslated actual parameter corresponding to the formal x. It attaches the special comment to the representation in the fragment tree of the pTAL define actual parameter. The comment is translated to C++ when the define invocation and its attendant actual parameter is translated. In this case, there is no instance (notice that the reference partition is null) of the C++ define actual parameter, so the comment holds its place. When this code is translated again with the "fast" toggle reset, the fragment subtree does contain a define actual parameter. Suppose the code were translated with the option "RESETTOG FAST" set. The code is expanded as follows:
define d(x) ...
proc p;
begin
int a := 4;
int b := 5;
a := b * 2; !There is a use of the actual param "b"!
end;
The expanded pTAL code is translated to the following expanded C++ code:
void p () {
int_16 a = 4;
int_16 b = 5;
a = b * 2;
The resultant C++ code appears as follows:
#define d(x) x * 2
void p() {
int_16 a = 4;
int_16 b = 5;
a = d(b);
};
The Rosetta Translator performs a consistency check between the fragment containing the invocation of the macro d generated during the current translation session (with the "fast" toggle reset) and the corresponding fragment generated during the previous translation session (with the "fast" toggle set). One translation has an actual parameter in the macro invocation, and one has a special comment holding the place of an untranslated actual parameter ("/*UA:x*/"). The consistency check notices the special comment and replaces it with copies of the actual parameter tokens. This situation differs from translating a define with no actual parameter provided. For example, consider the following code:
define e(x) = 7 x + #;
proc p;
begin
int a := 4;
a := e() 7;
end;
The reference partition is empty, not null. The Rosetta Translator emits a warning when it encounters an actual parameter that is empty, because it cannot decide where in the target language define body partition to place the formal parameter associated with the empty actual. Checking Textual Consistency The following algorithm compares two virtual partitions token by token. Both of these virtual partitions are instances of the same partition template. This algorithm walks the sequence of tokens in the first virtual partition, comparing each with a token from the second virtual partition. It does not climb the fragment tree, it strictly examines tokens in the given virtual partitions. Note that in order to merge the fragment representing a macro actual parameter that is missing, the algorithm must rise above the textual level. Operations are as Follows GetNextToken (virtualPart): Returns a token from the virtual partition virtualPart. This operation is used to iterate over all of the tokens in the virtual partition. Returns NULL when the tokens are exhausted. This operation does not climb the fragment tree; for example, if iterating over the tokens in the partition in the macro invocation fragment shown in FIG. 6, it would return a, then +, then 13. RepresentsUntranslatedActual (token): Returns TRUE if the token token represents an untranslated define actual parameter in a macro invocation. RepresentsActualParamDelimiter (token): Returns TRUE if the token token represents a comma or close (right) parenthesis that completes a macro actual parameter. Notice that the actual parameter may contain a parenthesized list. Copy (token): Returns a copy of the token token. InsertAfter (token, virtualPart, otherToken): Insert the token othertoken into the virtual partition virtualpart after the token token. RemoveToken (token): Removes the token token from the virtual partition virtualPart. Same (token, otherToken): Return TRUE if the tokens represented by token and otherToken have the same image. Compare(firstlnstance.secondlnstance)
WHILE (token = GetNextToken(firstInstance)) BEGIN
IF ((otherToken = GetNextToken(secondInstance)) == NULL)
RETURN FALSE
IF (RepresentsUntranslatedActual(token)) THEN BEGIN
marker = token
WHILE (NOT RepresentsActualParamDelimiter(otherToken))
BEGIN
InsertAfter(token,firstInstance,Copy(otherToken))
/* token points to inserted token */
token = GetNextToken(firstInstance)
otherToken = GetNexttoken(secondInstance)
END
/* token points to delimiter */
token = GetNextToken(firstInstance)
/* remove the untranslated actual indicator */
RemoveToken(marker,firstInstance)
END ELSE
IF (RepresentsUntranslatedActual(otherToken)) THEN BEGIN
marker = otherToken
WHILE (NOT RepresentsActualParamDelimiter(token)) BEGIN
InsertAfter(otherToken,secondInstance,Copy(token))
/* otherToken points to inserted token */
otherToken = GetNextToken(secondInstance)
token = GetNextToken(firstInstance)
END
/* otherToken points to delimiter */
otherToken = GetNextToken(secondInstance)
/* remove the untranslated actual indicator */
RemoveToken(marker,secondInstance)
END
IF (NOT Same(token,otherToken)) THEN BEGIN
RETURN FALSE
END
END
RETURN TRUE
The following algorithm checks the consistency of all instances of each partition template in each file that participates in a translation session. Operations are as follows GetInstance (part): Returns a virtual partition that is an instance of the partition template part. This routine is used to iterate over all of the virtual partitions in the fragment tree that are instances of the given partition template. Returns NULL when the virtual partitions are exhausted. TranslatedInPrevSession (part): Returns TRUE if the partition template part was translated in a previous translation session. ScanTextFromOutputFile (part): Scans the text generated in the output file corresponding to the partition template part, if that partition was translated in a previous translation session. If part was not previously translated, scan nothing. It is useful to scan tokens, so whitespace can be easily ignored during a comparison. PrevTranslation (part): Returns a virtual partition representing a previous translation of the partition template part. Assuming that ScanTextFromOutputFile tokenized the text, the partition contains a sequence of tokens; fragment invocations are NOT represented. ReportError (): Reports an error condition. CheckConsistenc()
MergePartitions( )
FOR (file =
each file participating in this translation session) BEGIN
PartMap = GetCurrentPartitionMap(file)
WHILE (part = GetNextPart(partMap)) BEGIN
referenceInstance = GetInstance(Part)
WHILE (instance = GetInstance(part)) BEGIN
Compare( instance, referenceinstance)
END
IF (TranlatedInPrevSession(part)) THEN BEGIN
ScanTextFromOutputFile(part)
IF (NOT Compare(PrevTranslation(part), referenceInstance))
THEN ReportError( )
END
END
END
It is useful to compare tokens, so whitespace is ignored and the comparison can take place before the stream of tokens is committed to text in case a transformation is necessary. If a mismatch occurs, it is appropriate to issue an error message, or attempt to manipulate the fragment tree to encapsulate the difference in a new macro formal parameter. The fragment tree transformations necessary to do the latter are described in a previous patent application. Although the present invention has been discussed with respect to a particular embodiment thereof, it should be understood that the embodiment is but illustrative of one way to practice the present invention, the scope of which is determined solely by the appended claims.
|
Same subclass Same class Consider this |
||||||||||
