Friday, November 22, 2013

Recreator – INPUT Statements

Like PRINT statements, INPUT statements contain several codes including the input parse item (double, integer or string), input begin, input begin with string prompt, input assign reference (double, integer or string), and the input or input prompt command code.  The input begin with string prompt and input command codes could also have the option sub-code set.  The separator of the recreator class will be used between these codes to keep track of the separators between the input reference items.

As the codes of the INPUT statement are processed, the resulting INPUT statement is built up by adding to the string on top of the holding stack.  The string of the current reference is added to the string being built with a separator in between.  After each reference or prompt string, the separator is set to a comma (or a semicolon after the prompt string without the option sub-code).  At the end of the statement, the INPUT or INPUT PROMPT keyword is added to the output string along with the built up string that is popped from the stack.

Implementation

The input begin string code follows the input prompt string expression, the string of which will be on top of the stack.  The input prompt begin recreate function for the input begin string code sets the separator to a comma if the option sub-code is set, otherwise sets it to a semicolon.

The input assign recreate function contains a local string.  If the separator is set, the string is set to the string of the reference that is popped from the stack.  The separator is added to the string on top of the stack followed by the string of the reference.  The separator is not set for the first reference of an INPUT statement, so no action is needed (the string of the reference is left on the stack).  The separator is set to a comma for the next reference.

The input recreate function for both the INPUT and INPUT PROMPT code adds the command keyword to the output string.  A space is added followed by the built up string that is popped from the stack.  If the command code has the option sub-code set (for keeping cursor on the same line), a semicolon is added to the output string.  The separator is cleared for the next statement.

The table class name access function with token pointer argument was modified to return the full name of the code.  This includes a space and the second word of a code that has the two word option set along with a second name.  This was needed for the INPUT PROMPT command that contains two words.

Pointers to the new input recreate functions were added to the table entries of the various input codes.  The input parse item and input begin codes do not produce anything during recreation and their table entries were set to the pointer of the blank recreate function.  The expected recreated outputs for translator test #12 (INPUT statements) were updated and are recreated correctly.

[commit 9c8631000f]

Saturday, November 16, 2013

Recreator – Unary Operator Problems

Many of the other translator tests were being recreated correctly including tests #7 (errors), #8 (more errors), #9 (semicolon errors), #10 (expression errors), #11 (temporary errors), and #14 (parser errors) once the expected results were updated as these did not have the not yet implemented INPUT and REM statements or colons.  However, tests #13 (negative constants) and #17 (constants) were not recreated correctly due to problems involving unary operators.

A problem occurred when a negate unary operator preceded a numeric constant.  When created, there was no space between the negate operator and the number.  If this statement is translated again, the negate operator and the number become a negative constant, which is not the same, through technically equivalent.  This will cause the line change detection in the program model to incorrectly detect a change.  The unary operator recreate function was modified to also add a space after the unary operator if the operand begins with a digit or decimal point.

A problem occurred with the negate integer operator.  The precedence of the negate integer was incorrectly set to 40 causing parentheses to be added incorrectly during recreation.  The precedence should have been 48, the same as the negate double operator, so the table entry for was corrected.

A problem occurred when a unary operator followed a power (exponential) operator, a higher precedence operator.  The operand was incorrectly surrounded with parentheses.  This binary operator recreate function was modified to also check if the second operand is a unary operator then the operand is not surrounded by parentheses.

These corrections allowed tests #13 and #17 to be recreated correctly.  The regression test script was also modified to not ignore white space when comparing to the expected results.  Without this change, the first problem above was not detected.  The memory test was already not ignoring white space.  I'm not sure what the reason was for making the regression test ignore white space.

[commit cf67d09f36]

Recreator – PRINT Statements

There are several codes that make up a PRINT statement including print item (double, integer or string), comma, print function (TAB and SPC), semicolon (only at the end of the statement) and the print command.  A recreate function was implemented for each of these codes.  Because the PRINT statement is composed of several codes, the separator member variable of the recreator instance is used between the processing of these codes to keep track of separators between the print items.

As the codes of the PRINT statement are processed, the resulting PRINT statement is built up by adding to the string on top of the holding stack.  Generally, the string for the current item is popped from the stack, a separator is added to the string on top of the stack, which contains previous items and the string of the current item is added to the string of the previous items that is on top of the stack.  At the end of the statement, the PRINT keyword is added to the output string along with the built up string of the print items and separators that is popped from the stack.

Implementation

The print item recreate function contains a local string variable.  If the separator is set from a previous print code, the string is set to it.  If this separator is not a space, then a space is added after the separator.  The separator is a space if the last print code was a comma (see below).  The string on top of the stack is popped and added to the string.  If the stack is now empty, then the string is pushed to the stack, otherwise the string is added to the string on top of the stack.  The separator is set to a semicolon for the next item if there is one.

Spaces are normally added after a comma like a semicolon, but spaces are not added between multiple commas.  The print comma recreate function contains a local string variable.  If the holding stack is not empty, the string on top of the stack is popped into the local string.  A comma is added to the string (which is empty if the stack was empty, like when there is a comma directly after the PRINT keyword).  The local string is pushed to the stack.  The separator is set to a space.  A space is only added after the last consecutive comma.

The print function recreate function first calls the internal function recreate function (since print functions are translated the same as other internal functions), which will process the print function and its operand and leave the result on top of the stack.  The print item recreate function is called to process the print function like any other item.

The semicolon code is only found at the end of a PRINT statement and replaces the print command code.  The print semicolon recreate function pops the string from the holding stack, adds a semicolon, and pushes it back to the stack.  The print recreate function is called to complete the PRINT statement.

The print recreate function adds the PRINT keyword to the output string.  If the holding stack is not empty, a space is added to the output string, and the string is popped from the stack and added to the output string.

A new separator is set access function was added to the recreator to a specific character, which is used by the print item recreate function.  Pointers to the new print recreate functions were added to the table entries of the various codes.  The expected recreated outputs for translator test #6 (PRINT statements) were updated and now recreated correctly.

[commit 1d3a05f610]

Recreator – Interactive Testing

Up to now, the only way to test the recreator was by using the expression and translator test files with the batch test mode.  An interactive recreator mode was not implemented since the recreator only supported expressions and creating separate modes for both expressions and commands was unnecessary.  With support for commands (just assignments at the moment), an interactive mode for the recreator could be added.

Before implementing the interactive recreator mode, the translator, program unit and recreator instances (which were local variable in the tester class run routine), were changed to the member variables of the tester class.  As local variables, it was necessary to pass references to them between the various tester routines, which defeated the purpose of having a class.  The output stream is now given to the tester constructor, which is stored in a member variable so that it can be shared by all the class routines, instead of being an argument to the run routine and passed to the other routines.

The tester class was modified to support the new interactive recreator test mode, which is activated with the new "-tr" command line option.

The translate input routine was modified to accept a header string for the list of translated token output.  If this header string is not used, then "Output:" is used as before.  This routine was also modified to return the pointer to the RPN list if the header string is used.  Otherwise, the RPN list is deleted as before and a null pointer is returned, which is also returned when the input line has an error.

The new recreate input routine was added, which starts be calling the translate input routine with the header set to the "Token:" string.  If an RPN list is returned (no error detected), the RPN list is recreated and deleted.  The recreated output is prefixed with the "Output:" string as its header.

[commit 2dc4b17e97] [commit 0ccfb105e7]

Monday, November 11, 2013

Recreator – Sub-String Assignments

Translated sub-string assignments (previously described on July 14) consist of the string reference, followed by the expressions of the arguments of the sub-string function with the assign sub-string code.  This is the same form as when these functions appear in expressions, so sub-strings can be recreated the same way.  This is not the case with multiple sub-string assignments where the sub-string assign codes are all at the end of the translated statement with special assign keep codes except for the final code.

At run time, after popping the value to assign and assignment the value, the assign keep codes push the value back to the stack for the next assignment.  The final non-keep assignment just pops the value off of the stack.  The recreation of multiple sub-string assignments works similarly.  The assign keep code will pop the recreated string of the value expression to assign.  A sub-string assign keep code recreates the sub-string as a function and push the result back to the stack.  For all assign keep codes, the reference string is popped, the current separator is added followed by the value string.  This string is pushed back to the stack.

For the final non-keep assign code, the LET keyword is appended to the output string if the assign code has the option sub-code.  The value string is popped from the stack, which will also contain the other references in a multiple assignment statement.  The string of the final reference is popped and appended to the output string.  Finally the value string is appended to the output string.

Implementation

A separator character member variable was added to the recreator class with access functions for getting the separator character, checking if it is set (not the null character), clearing it (setting it to the null character), and setting it.

The new assign string recreate function contains a local string variable and starts by checking if the separator character is not set.  An unset separator indicates the first and maybe only reference. For the first reference, the string is set to the assignment operator (an equal) surrounded by spaces and the separator is set to a comma.  If the separator is set, then the string is set to it (which is a comma) plus a space.  The string on top of the holding stack is popped and appended to the string.

If the assignment token has the sub-string flag set, then the code of the original sub-string function is obtained.  This was accomplished by making the original sub-string function code the second associated code in all the table entries of the assign keep and non-keep sub-string codes.  The name and the operand count is obtained for the original sub-string function code and the push with operands routine is called to process the arguments of the sub-string function.  The resulting string is left on top of the holding stack.

If the assignment code is a keep code (determined if the second associated code index is zero, which is only the case for the keep codes), the value string with the separator and other references prefixed is appended to the string on top of the holding stack.  Otherwise the assignment code is the end of the statement.  The let recreate function is called to append the LET keyword if the option sub-code is set.  The last reference is popped from the holding stack, appended to the output string, and the string with the rest of the references, separators and value is appended to the output string.  The separator is cleared for the next command.

All of the translator assignment tests (#1 through #5) are all now recreated corrected except for a single PRINT statement in test #5 (since the PRINT recreation has not been implemented yet).

[commit b1c7dc5bce]

Sunday, November 10, 2013

Recreator – Assignments

Translated assignment statements consists of one (single assignment) or more (list assignment) variables or arrays (references) followed by the expression of the value to assign with an assignment code at the end, which may have the option sub-code indicating the optional LET keyword was entered at the beginning of the statement.  When these statement are being recreated upon reaching the assignment code at the end, the strings of the references will be on the string holding stack (the first or only variable at the bottom) along with the string of the value expression (at the top of the stack).

The new assign recreate function handles the assign double, assign integer, assign double list, assign integer list and assign string list codes.  The assign string code could be at the end of a mixed sub-string assignment statement and these will be handled differently (see July 14).  The strings on the holding stack need to be appended to the output string in reverse order with the necessary separators between them (a comma between the references when there are more than one, and an equal between the last or only reference and the value expression).

To reverse the strings, the assign recreate function contains a local string stack and starts by popping the value expression string from the holding stack and pushing it to this local stack.  A local separator string is set to the assignment operator (an equal) with surrounding spaces.  The routine loops until the holding stack is empty.  For each reference, the separator string is appended and the popped string is pushed to the local stack.  The separator string is set to the comma with a space for the next reference.

A new let recreator support function was also added that checks if the assignment token has the option sub-code set and appends the LET keyword with a space to the output string if it does.  This function will also be used for multiple mixed sub-string assignment statements.  The assign recreate function calls this function and then loops until the local stack is empty appending each string popped to the output string.

A new recreator stack is empty access function was needed to determine if the holding stack is empty.  This was implemented in the recreator class header file since it was only one line of code.  Since the recreator top, top append, and append access functions are also only one line of code, their definitions were also moved to the header file.  Finally, the pointer to the assign recreate function was added to the table entries of the above mentioned assignment codes.

The results for translator tests #1 to #5 (various assignment tests) were changed to the expected results (inputs with spaces added and upper case keywords).  The statements in tests #1 (assignment tests) and #3 (data type assignments) are recreated correctly.  Many of the statements in the other tests are also recreated correctly, but the ones that are not contain string and sub-string list assignments yet to be implemented.

[commit 97c666a9d3]

Saturday, November 9, 2013

Recreator – Expressions (Tagged)

Expressions are now fully supported by the recreator.  All the expressions test recreate the original source correctly.  The next step is to add support for the first round of commands (LET, PRINT, INPUT and REM).  The first tag of the 0.6 development series was added, v0.6.0.

[commit 0dc1f0ebf5]

Recreator – Arrays and Functions

Supporting arrays and functions in the recreator is only necessary for the translator tests.  So that arrays and functions are recreated properly for these tests, preliminary recreate functions were created for arrays, defined functions and user functions.

The array and function recreate functions get the name from the string of the token.  An open parentheses is added to the name since it is not stored in the token.  The name and the attached count in the RPN item is passed to the push with operands routine.  The define function recreate function handles both define function with and without tokens, so an open parentheses is only added to the name if the attached count is not zero.  Pointers to these functions were added to the preliminary table entries for the codes of these tokens.

All the expressions in expression test #3 (parenthetical tokens) now recreate the correct output. 

[commit b6e8973352]

Translator – Arrays and Functions

A problem with recreating arrays and functions (user and define) is that the translator was not setting a code in these tokens.  Preliminary table entries were added for the codes needed.  These codes include an array, a define function with no parentheses, a define function with parentheses and a function.  There will eventually be codes for each data type, but these four codes are sufficient for now.

In the get operand routine, for the define function with and with no parentheses token types, the appropriate token code is assigned.  Since there is only a single code for each of these, the data type of the token is preserved because the table set token routine sets the data type of the token to the one in the table entry for the code.

The process parentheses token routine was modified to set the code of the token to the array code or the function code if the identifier starts with an 'F' character.  This routine also processes define functions with parentheses tokens, so the code is not set for these tokens.  Later in the routine when the RPN item is created, the attached count is no longer set to zero for array tokens.

The attached count of the RPN item can no longer be used to detect if there are attached tokens.  The attached array pointer will instead be used for this detection by checking if the pointer is set to null.  The RPN item text routine was updated to use the attached array pointer to detect attached tokens instead of the attached count.  This routine was also changed to use member variables directly instead of using the access functions.

[commit e1919952fa]

Recreator – Internal Functions

The arguments (operands) of internal functions precede the code of the internal functions, so the strings of the operands will be on the string holding stack in reverse order when the internal function token is processed.  The arguments of define and user functions work the same way as do the subscripts of arrays.

A generic push with operands routine was implemented taking the name string of the function or array and the count of operands, and contains a local string stack and a separator string initialized to a closing parentheses (the string on top of the stack will be the last operand).  Looping to the count, the string of an operand is popped from the holding stack, the separator string is appended, this string is pushed to the local stack and the separator string is set to a comma and a space for the next operand (if there is one).  The strings are popped from the local stack until empty and appended to the name.  The name is pushed to the holding stack.

The push with operands routine also works with functions with no arguments (nothing is pushed to the local stack when the count is zero, so only the name is pushed to the holding stack).  An internal function recreate function was added that gets the name and the operand count of the internal function code from the table and calls the push with operands routine.  A pointer to this function was added to all of the internal function code table entries.

While trying expression test #3 (parenthetical tokens), there were blank invalid tokens.  These occurred from the hidden conversion codes that were present in the first test expression.  A blank recreate function was added that does nothing.  A pointer to this function was added to the hidden integer and double conversion codes.  Eventually, all codes will have a recreate function.

The expected results for expression test #3 and test #4 (internal functions) were set to the correct expected results (with appropriate spacing).  All of the expressions in test #4 produce the correct output.  Some of the expressions in test #3 do not produce the correct output because they contain arrays, define functions or user functions, which are not being handled yet.

[commit ac9ab4774d]

Recreator – Operand Recreate Function

The method of using an unset (null) recreate function pointer to indicate an operand is problematic during development.  It is also possible that the recreate function for code is not yet implemented.  Further, using a blank token string to indicate an unimplemented code is also a problem since this also could mean that the code does not produce any output (take for example the hidden conversion codes).

Therefore, an operand recreate function was implemented, which simply pushes the string of the token to the string holding stack.  A pointer to this function was added to the constant and variable code table entries.  The main recreate routine was modified to surround the string of a token code with no recreate function with question marks.  A check was also needed for whether the code in the token is valid before retrieving its recreate function.

[commit 9734165b8b]

Recreator – Error Checks / Expression Mode

Some error checks were added to the recreator along with an expression test mode.  The first check is to make sure the string holding stack is empty upon returning from the main recreate routine.  Any items left on the stack are popped and appended to the output string prefixed by "NotEmpty" to indicate an error before returning.

However,  the expression test mode left the resulting string on the holding stack.  Therefore, a check was required for the expression test mode.  An expression mode flag argument was added to the recreate routine.  When set, the string on top of the holding stack is popped and appended to the output string.  This is followed by the check for an empty stack.

An error check was also added to the pop routine to make sure the holding stack is not empty.  If the stack is empty, the "<Empty>" string is returned to indicate an error.

The tester  translate input routine was modified to pass the expression mode flag to the recreate routine and to just use the output string returned (it is no longer necessary to pop from the holding stack of the recreator for expression mode).

[commit 2980b89a24]

Thursday, November 7, 2013

Recreator – Unnecessary Parentheses

Parentheses in an expression control order of evaluation of the expression and are removed during the translation process.  The parentheses are recreated by looking at the precedences of the operators.  However, parentheses can be added to an expression that are not required, take the expression A+(B*C).  The multiply has higher precedence than add, so the translation becomes A B C * +, which is the same as the expression A+B*C.

So that these unnecessary parentheses are recreated, the translator adds the parentheses sub-code of tokens.  The above example expression is translated as A B C *')' +.  The translator also allows for extra sets of parentheses; the expression A+((B*C)) is translated to A B C *')' ) +.  A closing parentheses code is added when the previous token already has the parentheses sub-code.  For a third pair of parentheses, the closing parentheses token gets the parentheses sub-code.  And so on.  At run-time, parentheses codes and sub-codes are ignored.

Implementation

A new parentheses recreate function was added, which calls the pop with parentheses function with true as the argument to add parentheses when popping the top string.  The pop with parentheses was modified to optionally return the precedence value and unary operator flag from the item popped from the holding stack.  The string with parentheses along with the precedence value and unary operator flag are then pushed back to the holding stack.

In the recreate routine after processing an item in the RPN list, a check was added for the parentheses sub-code and if set, calls the parentheses recreate function.  The parentheses recreate function was also added to the table entry of the closing parentheses code.

During the testing these changes, a problem was found in the translator where the parentheses sub-code was not being added to a closing parentheses token (it incorrectly added another closing parentheses token to the output list).  This was due to translator check pending parentheses routine checking if the top item of the done stack (the last item added to the output list) to see if it already had a parentheses sub-code.  It should have been checking the last item in the output list instead (the closing parentheses tokens are not pushed to the done stack) .

A few additional expressions were added to expression test #2 (parentheses tests) for testing extra parentheses.  Both  the expected translated and recreated results were updated.  All of the expressions in test #2 are now being recreated correctly.

[commit 385cc5925d]

Wednesday, November 6, 2013

Recreator – Parentheses (Unary Operators)

Handling the recreation of parentheses with unary operators is similar to that of binary operators except there is only one operand with another issue.  As with binary operators, if the precedence of the unary operator is higher than the operand on top of the stack, parentheses should be added around the operand.  However, parentheses should only be added if the operand on top of the holding stack is not another unary operator.  Consider the expression and its translation:
-NOT A%            A% NOT Neg%
When the Neg% operator is being processed, its precedence is higher than the NOT on top of the stack (actually the top contains the string "NOT A%" with the precedence of the NOT operator).  With just the precedence check, parentheses would be added around the "NOT A%" expression, which is not correct.  There needs to be an additional check to not add parentheses if the top item is a unary operator expression.

Implementation

A unary operator flag variable was added to the stack item to indicate if the holding stack item is a unary operator sub-expression.  The push access function was modified to take an optional unary operator flag value that is pushed with the string and precedence.  The default flag is set to false and is only set to true by the unary operator recreate function.

The unary operator recreate function was modified to get the precedence of the operator being processed from the table.  The pop call of the operand was changed to call the new pop with parentheses with the argument set to whether the top stack item is not a unary operator and the operator precedence is higher than the precedence of the top stack item.

There were insufficient expressions in expression test #2 (parenthetical expressions) to test the various situations with unary operators, so several were added.  The translated test expected results were also updated for the new expressions.  The expressions that still do not match are due to unnecessary entered parentheses.

[commit a5951ecfc3]

Tuesday, November 5, 2013

Recreator – Parentheses (Binary Operators)

Parentheses are removed from expressions during translation.  The binary operator recreate function needs to recreate the parentheses for operators depending on their precedences.  Consider these expressions with their translations:
A * B + C * D          (A + B) * (C + D)
A B * C D * +          A B + C D + *
The translations of these two expressions have a similar form.  The first expression will be recreated correctly since multiply is higher precedence than add.  However the second expression without parentheses "A + B * C + D" does not mean the same thing since add is lower precedence than multiply making the parentheses required.

Parentheses are required around an operand if the precedence of the operator is higher than the operand. Parentheses are also required around the second operand if the precedence of the operator is the same as the operand since operators of the same precedence are processed from left to right.

Implementation

A precedence variable was added the stack item to hold the precedence of an operator sub-expression.  The push access function was modified to take an optional precedence value that is pushed with the string.  The default precedence is set to the highest precedence for when operands like constants and variables are pushed.  A top access function was added so that the item on top of the string holding stack can be accessed.
A new pop with parentheses access function was added that takes a flag argument, which when set will surround the string operand popped from the string holding stack with parentheses when set.

The binary operator recreate function was modified to get the precedence of the operator being processed from the table.  The pop call of the second operand was replaced with a call to the new pop with parentheses with the argument set to whether the operator precedence is higher than or the same as the precedence of the item on top of the stack.  Similarly the first operand is popped with parentheses if the operator precedence is higher than the top item.

Instead of using the top append access function, the string of the operator expression is built in a local string.  The string is first set to the second operand with parentheses if needed.  The string is then set to first operand with parentheses if needed, plus a space, plus the operator name, plus another space plus the current value of the string with the second operand.  Finally this string is pushed to the string holding stack with the precedence of the operator.

The expected outputs for expression test #2 (parenthetical expressions) were set to the inputs.  Many of these expressions match the inputs since the precedence for binary operator is now being handled.  The expressions that don't match involve unary operators (no precedence checking yet) and unnecessary entered parentheses.

[commit 694e224aee]

Sunday, November 3, 2013

Recreator – Simple Expressions (Implementation)

The recreator is a separate new class since the RPN list will already have been decoded from the program model (with dictionary lookups to change indexes back into there original names), so there is no need to access neither the program model or the dictionaries.  The constructor does nothing more than set the member table instance reference.  There are only two additional member variables, the string holding stack and the output string.

The output string will contain the recreated text of a program line and will be appended to as the RPN list is processed.  Since the various recreate functions are outside of the recreator class, there is a single append access function for appending a string to the output string.

The holding stack temporarily contains strings as the RPN list is processed and is used to reverse the RPN list.  It is defined as a QStack of the StackItem structure, which contains a string.  The holding stack was not defined directly as a stack of strings because an additional item will be needed.  There are several access functions including a push function to push a string onto the stack, a pop function to pop a string from the stack, and a top append function to append a string to the top string on the stack.

Besides the class member functions, the recreator source file also contains several general recreate functions which are outside the class so that their pointer can be put into in the table entries.  These include the unary operator and binary operator recreate functions, which work as described in the previous post.

A recreate function type was added to the table entry structure with an access function.  The recreate functions arguments include a reference to the recreator instance and a pointer to the RPN item from the RPN list.  Recreate functions were added to all of the operator, constant, and variable codes.  A constant string recreate function was implemented for the constant string code that adds the necessary double quotes.

A recreator instance reference argument was added to the tester class translate input routine.  For expressions, the recreator does not return an output string (there is no command to pop the string of the final expression from the holding stack and append it to the output string.  Instead of adding a special expression mode to the recreator to do this, and since the pop access function is public (for the recreate functions), the translate input routine gets the output string using this function.

The expressions in expression test #1 (simple expressions) are properly recreated and match the inputs except expectedly for spacing and case (lower case word operators are output in upper case).  While the other expressions produce recreated output, the output is not correct because parentheses, internal functions, etc. are not yet supported.

[commit 4bdd513c2c]