Wednesday, June 2, 2010

Translator – Semicolons with PRINT

Up to now, the Semicolon (an operator) has not been implemented (in fact, causes the program to crash if entered in an expression because its table entry has no expression information structure). The semicolon will have a low precedence, the same as the comma since it is also an expression separator, so it will empty all other operators from the hold stack. No lower precedence tokens will be on the hold stack except for an open parentheses, identifier with parentheses (function or array), function (internal or defined), or an assignment operator.

The Semicolon will have a token handler function, which is called after the hold stack is processed.   The handler will check the command on top of the command stack. If the command stack is empty, then an “unexpected semicolon” error will occur. For now, only a PRINT command needs to be processed. Any other command will also cause an “unexpected semicolon” error to occur. The hold stack needs to be checked to make sure it is empty (has the initial Null token on top), otherwise a “missing closing parentheses” error occurs. An assignment won't be on the hold stack if there is a PRINT on the command stack.

For a PRINT command, the handler needs to process any expression on top of the done stack. If the done stack is empty, then there was no expression before the semicolon (allowed). In this case, a dummy semicolon token is appended to the output so that it can be reproduced. Adding a sub-code for this situation is a wasted effort (because there may be no token before the semicolon in the output, which would complicate matters in using a sub-code).

The expression on the done stack will be handled by the find code function as previously described. The flag for the PRINT command item on top of the done stack needs to be set in case this is the last semicolon in the PRINT statement – to tell the PRINT command not to append the Print code to the output (to keep the cursor on the same line).

The PrintTmpStr (which will be named PrintTmp to stick with the 3 character data type naming convention for code names) is not being added at this time. PrintStr is a code that takes a string operand, and as such, whether it's operand is a String or a TmpStr can't be determined by the Translator, so it will have it's operand saved for later determination by the Encoder.

Tuesday, June 1, 2010

Translator – Print-Only Functions

There are currently two print-only functions, SPC and TAB. Both functions may only be used in a PRINT statement and are not valid in any other expression. There needs to be a new table entry Print flag that will be used for these print-only functions, which are defined as internal functions.

When internal functions are processed (arguments checked and necessary hidden conversion codes inserted), a check is needed that if a function has the Print flag, then the current command on top of the command stack must be a PRINT command otherwise an “invalid use of print function” error occurs. In additional, print-only functions do not have return values, so no result value is pushed onto the done stack. These print-only functions also need to set the flag in the PRINT command item on top of the command stack in case these are the last item in the PRINT statement (to prevent the PRINT code from being appended to the output, which will keep the cursor on the same line at run-time).

During execution at run-time, these functions perform their action directly to the output, which is the reason no result needs to be pushed back on the evaluation stack (the result is outputted instead).

Bug Fix:Upon making the changes for print-only functions, I realized there was an unrelated bug where a command would be accepted after receiving an operand (for example: A LET ...) because the mode was still set to Command. Therefore, when an operand token is processed, if the mode is Command then the mode is set to Assignment – this will prevent a command token from being accepted after an operand.

Monday, May 31, 2010

Translator – PRINT Command (Translating)

Currently, command tokens are pushed onto the command stack, so will a PRINT command token when it is received. The PRINT's next token mode value will be set to Expression. The Semicolon, Comma and End-of-statement will trigger the insertion of the value specific print code.

The existing find code function can be used to determine which specific print value code to append to the output. The PrintDbl code will serve as the main code, which will have PrintInt, PrintStr and PrintTmpStr as associated codes, each with one operand of the appropriate data type. A new token will be created with the PrintDbl code and passed to the find code function, which will return the correct code for the expression. The token is then be appended to the output.

At the end of the statement, the PRINT command token will be on top of the command stack. The end of statement processing needs to pop this token off from the stack and perform whatever handling is necessary. There needs to be a command handler that performs a command's specific needs. For reasons that will be clear later, the token handler function cannot be used for this purpose, so a new command handler function pointer is required in the table entries.

The PRINT command handler needs to determine when the PRINT token should be appended to the output (to go to a new line), or not (stay on the same line). If the done stack is not empty, then there is an unprocessed expression that needs a specific print value code. This means there was no semicolon or comma at the end of the statement, so the PRINT token can be appended. However, an empty done stack does not indicate no PRINT token is needed, consider the PRINT command by itself.

Therefore, a flag is needed, to be set when an print-only internal function, semicolon or comma is processed. If the done stack was empty, the command handler will check if this flag is set, to determine not to append the PRINT command token (in which case the PRINT token is deleted). This flag will be added to the command stack's item structure item, which is cleared when the command is initially pushed onto the stack.

Translator – PRINT Command (Translation)

The translated statement PRINT will consist of a number of different printing codes, which include PrintDbl, PrintInt, PrintStr, PrintTmpStr, Comma, Semicolon, and Print. The print only Spc and Tab internal function codes will also print. Before explaining further, here are some examples with their translations:
PRINT  Print
PRINT A;B%  A PrintDbl B PrintInt Print
PRINT A$+B$,C$;  A$ B$ + PrintTmpStr Comma C$ PrintStr
PRINT TAB(A+1);"Hello"  A 1 + Tab "Hello" PrintStr Print
PRINT "Start";SPC(10)  "Start" PrintStr 10 Spc
PRINT ,,A  Comma Comma A PrintDbl Print
PRINT ;  Semicolon
Note that when the cursor is to go to a new line, there is a Print code at the end of the translation, otherwise it is absent. The Print code at run-time preforms the new line action, so in it's absence, the cursor remains on the same line. The PrintDbl, PrintInt, PrintStr and PrintTmpStr will output the value that is on top of the evaluation stack, with PrintTmpStr deleting the temporary string when done.

At run-time, the Comma code will advance the cursor to the next column by outputting spaces. The Tab and Spc codes perform there action by outputting spaces. The Semicolon code does not perform any action during run-time, it is there only so that it can't reproduced during recreation of the source. Next, how the PRINT statement will be translated...

Translator – PRINT Command

It is necessary to look at how PRINT statements will be executed to determine how they need to be encoded and thus translated. But first, here is the general syntax of the PRINT statement:
PRINT [<expression>][;|, [<expression>]...]
Zero or more expressions may be included. The expressions can result with a double, integer or string value. Numbers are output with a trailing space. The expression may be one of print only functions SPC and TAB, both taking an integer expression. After the expressions are output, the PRINT will move to a new line unless the line ends with a semicolon, comma, SPC or TAB. (More options will be added later like PRINT USING and PRINT to a file.)

The SPC function outputs the number of spaces of the integer expression (less than 1 outputs no spaces). The TAB function advances the cursor to the column of the integer expression, where the first column is defined as column 1 (less than 1 is taken as column 1). If the cursor is already beyond the column specified, then PRINT goes to the next line, and then to the specified column. Using TAB(1) in the middle of a PRINT statement has the effect of doing a new line (an '\n' in C).

A semicolon is used to separate expressions, but does not affect what is output. The syntax above implies multiple semicolons may be entered. This is allowed, but will cause dummy semicolon tokens to be inserted into the code. A comma advances to the next column. A column will initially be defined as one-fifth of the screen width (at 80 columns, this is 5 columns of 16 characters). Eventually there will be a way for this width to be defined to any value.

Sunday, May 30, 2010

Translator – LET Command (Release)

The LET command is implemented and working. A new set of translator test inputs were added for commands, with LET statements for each possible assignment (each data type, non-list and list) with the LET keyword were included. Three error test inputs were added also, one with a two LET keywords, one with a LET keyword in the middle, and a PRINT (to test the “not yet implemented” error).

The plan was to release a whole series of development releases (0.1.12-dev-X) starting with the LET command, but some many changes were made to the code (including the parser correction, parser test updates, token handlers, etc.) from the 0.1.11 release, that this release will be an official Translator development release (0.1.12). This will probably continue for each command added to the Translator.  Sub-developmental releases may still be used for the more complex commands.

This release also contains regression test scripts that were used during the latest round of changes. The scripts saved a lot of command line typing due to all the reorganization of the code (token handlers, token status and token mode changes). A Windows batch file equivalent is also included, but does not work near as nice because of the limitations of the Window compare utility. Both scripts delete any current output files, runs the tests and then compares to the files in the test directory.

The Translator now has initial support for commands with just the LET/Assignment statement supported and ibcp_0.1.12-src.zip has been uploaded at Sourceforge IBCP Project along with the binary for the program. Next, implementing the PRINT command...

Translator – LET Command (Implementation)

The SimpleStack class is used for the new command stack, which will hold a CmdItem structure consisting of a token pointer and a code. The code will initially be set from the token's index, but may be changed to other associated codes as commands are processed by the Translator. Since the hold and done stacks are also simple stacks, these were changed from the List class to the SimpleStack class. This only required minor changes to push and pop calls for these stacks.

As previously hinted, the Translator status enumeration needed to be moved outside the Translator class before the TableEntry structure. The enumeration was renamed TokenStatus as that seemed appropriate for the return value of the Translator's add token function. Each of the enumeration values were also renamed except for the BUG statuses, which were left alone.

A previously mentioned, the mode must be changed from Command to Assignment upon receiving the LET command token. Some commands will need to change the mode from Command to Expression (PRINT, IF, WHILE, etc.). Some commands will need to change the mode from Command to a new End-of-Statement mode, since nothing is expected after command keyword (END IF, DO, LOOP, etc.).

Having an every growing switch statement of the command code is not efficient. Therefore, a next token mode value was added to the TableEntry structure. When a command token is received, if the mode is currently Command, then the mode will be changed to the command's table entry next token mode value. The command will be pushed onto the command stack along with it's current code. No further action needs to be taken until the rest of the statement is processed.

Since there will be mode values in the TableEntry structure, the Translator mode enumeration was also moved before TableEntry and renamed TokenMode (again an appropriate name). The enumeration values were also renamed to reflect this. For now, if the next token mode is not set for a command (a new Null token mode value), then a “not yet implemented” bug error occurs. If the current mode is not Command, then a new “unexpected command” message occurs.

For the LET command, the next token mode value is Assignment. When an assignment operator is added to the output list, if there is a LET command on the command stack, it is popped and the assignment operator's token's LET sub-code flag is set. For now, since the command stack should be empty, the end-of-line processing only needs to check if the command stack is empty. Later it will need to process commands on the stack.

Saturday, May 29, 2010

Parser – Bug / Test Updates

During the testing of the LET command implementation, some problems were discovered. The first problem was in the Parser's get number token function. The simple single 0 digit caused an “invalid leading zero in number constant” error. This error check was to prevent a constant like 01 from being accepted, but it did allow a leading zero when followed by a decimal point like in 0.1. This fix was to check if the next character is a digit, and if it's not, then it terminates looking for more characters, and then otherwise cause the error.

Due to this error, it was a good idea to re-run all of the parser tests since it has been a while since these were checked. Low and behold, they all failed or miscompared. The print token function used by these tests hadn't been updated for the changes to the code and data type enumerations, so these were updated. Once corrected, there were still miscompares, but these were due to either the decimal code values changing (because of all the new codes that have been added) or because the data type of many operators and internal functions were changed from None to their appropriate data type. Additional 0 constant test inputs were added to the Parser number test inputs.

The regression test scripts were updated to also include the parser tests. The Windows batch file uses the comp command, which has a nice feature that a wild card can be used for both files names and it is able to compare all sets of files with one command (like all 8 translator test output files). However, it also has an irritating feature where after it's done comparing files, it asks if there are more files to compare. No has to be entered to continue. There is not option to prevent this. Since there are two compares (one for the parser files, one for the translator files), no has to be entered after the comparing the parser file before the translator files are compared.

One last problem was discovered that affects both the print token and print small token functions.  Numeric constants were not being output as intended. The code was outputting an integer using the C %d format specifier and doubles using the %g specifier. The problem is that if the constant 1.0 (a double) was entered, it would be output as 1 making it impossible to know if it was an integer or a double. The raw strings entered for the numbers were suppose to be output -  the reason these strings were saved in the first place, to preserve the original string for later output by the Recreator.

Translator – Token Sub-Codes (Implementation)

The sub-code flag was implemented, which consisted of adding the sub-code memory to the Token class, adding the sub-code flag value definitions and modifying the print token test routine to output the flags.

The setting of the parentheses sub-code flag was handled in the do pending parentheses function, which checks if unnecessary parentheses were entered and appended a dummy parentheses token. The code was changed to set the parentheses sub-code flag of the last  token appended to the output. Two issues were discovered.

The first issue found was if two sets of unnecessary parentheses are entered, for example, A=((B)), then the parentheses sub-code flag can only be set once. Upon reproducing the original source, the Recreator will not know that there were two sets of unnecessary parentheses. So for this case, a dummy parentheses token will still be appending for each additional set of unnecessary parentheses entered.

Curiously, with this change, if three (or and odd number of) unnecessary sets of parentheses are entered, for the third (fifth, etc.) set, the parentheses sub-code flag gets set in the second (fourth, etc.) set's dummy parentheses token. Something the Recreator will need to handle.

The second issue found was if the last token appended was a hidden conversion code, the conversion code's token parentheses sub-code flag gets set. It is anticipated that this would cause a problem for the Recreator. The Recreator should be able to safely ignore the conversion codes, but if it needs to look for sub-code flags, these can't be ignored. To avoid this, the code was modified that if token's table entry has the new Hidden flag set, then the item previous to the conversion code has its parentheses sub-code set.

The setting of the comma sub-code flag was handled in the new equal token handler function. When an equal token is received, if the mode was a multiple comma assignment, then the comma sub-code flag is set when the token's code is set to the assign list operator. The comma sub-code flag will not be set of the mode was a multiple equal assignment.

Translator – Token Handlers (Implementation)

A TokenHandler typedef was needed to define the pointer to token handler function. I was not able to define the function pointer directly on the variables. This always proves difficult with more complex types, especially involving pointers. Fortunately, using typedef simplifies the issue. Here is the definition that was inserted before the TableEntry class:
class Translator;   // forward reference to Translator class
typedef TokenStatus (*TokenHandler)(Translator &p, Token *&token);
The TokenHandler type definition is then used for defining an token handler function pointers. Each of the token handlers were created using the existing code in the switch statement, where the code was modified to add the Translator pointer in front of all the Translator variables and the Translator scope (Translator::) was added to the Translator enumeration values.

The code that handles operators (which was after the switch statement for the special codes) was also put into a handler function. This greatly simplified the code at the end of the add token function. For processing the token, the temporary token handler function pointer is set to the code's table entry value. If the value is not set (is NULL), then the temporary pointer is set to the default operand token handler function. The function is called using the temporary pointer and it's status return value is immediately returned.

The program was compiled several times during the making of the changes. I got tired of running of the test cases (to output is redirected to a file in the base directory) and comparing to the official test output files (in the test directory), so I wrote a MSYS (bash) script to do it automatically and check all the test cases. An equivalent Windows batch file was also written, but does not work near as nice. Both will be included in the next release.

Friday, May 28, 2010

Translator – Token Handlers

The Translator's add token function is becoming quite large and at the current rate will become much larger as the different commands are implemented. It's never a good idea to have giant functions. Therefore, this routine needs to be broken up into separate functions. The code that contains the special token code handling (for equal, comma, closing parentheses, and end-of-line) will be separate functions. These functions will be called token handlers. Most of the commands will also have token handlers.

Having a switch statement on the token code where each case calls a token handler function is not  the most efficient implementation. The concern is not execution time, but the amount of code lines required, in other words, a large switch statement. A better implementation is to store a function pointer in each table entry where a code requires a token handler. The Translator will check if there is a function pointer and then call the function to process the token.

And here is where it gets complicated. Pointers to member functions are not allowed. So the token handlers can't be Translator member function. But they need access to all of the Translator data members. The solution was to make them C++ friend functions of the Translator class with an reference argument to the Translator instance (a Translator function will pass *this).

The token handlers functions will also require a reference to the current token pointer (a reference so that it can be changed for an error) and will return the status of the operation. The Status enumeration needs to be moved out of the Translator because in order to define the return value for the token handler function pointer, it needs to be defined before TableEntry (and Table). But Table needs to be defined before TableEntry. Catch 22.

A forward reference for the Translator class can be added before TableEntry (needed for the Translator reference argument, which is simply class followed by the class name and a semicolon), but not for enumerations inside the Translator. Therefore the status enumeration will be moved out of Translator and renamed to TokenStatus (appropriate for a token handler, and the word Token is shorter than Translator).

Thursday, May 27, 2010

Translator – LET Command

There is nothing special to say about the LET command – the format of assignment statements, less the optional LET keyword, has already been defined and implemented. When the Translator receives the LET command token, it will be pushed on the new command stack. The mode will be Command when the LET is received and, as the Translator is currently implemented, needs to left set to Command mode for the assignment statement to be processed as currently implemented.

When the assignment token is added to the output list, it will first check if there is a LET command token on top of the command stack, and if there is, then the LET sub-code flag will be set in the assignment token, the LET command will be popped from the command stack, and the LET token will be deleted.

There is a problem. The mode must be set to Command for the LET token to be accepted. The mode must be set to Command for the assignment statement. Some detection is necessary to prevent double LET keywords. To solve this problem, a new mode is needed, an Assignment mode. For most of the Translator, both Command and Assignment mode will be equivalent except for the processing of command tokens.

Wednesday, May 26, 2010

Translator – Command Processing

When processing tokens in a statement, it is necessary to know what command is currently being processed. For example, the SPC and TAB functions are only valid in the PRINT statement. If the command is pushed onto the hold stack, there will be other tokens on top of the command token. Therefore the current command can't be determined by looking at the top of the hold stack. This means another variable would be needed to store the current command.

Commands can also be nested within a line (for example, an assignment or PRINT inside an IF-THEN-ELSE statement), so a stack is still the ideal solution. The command tokens need to be pushed onto a separate stack from the hold stack, a command stack. The precedence of a command token will still be used to empty the hold stack, but the command token will be pushed onto the command stack instead. The current command can be accessed by looking at the top of the command stack.

Before getting started with designing and implementing the commands, it's important to mention that there is no attempt being made to follow any particular standard or existing BASIC for this project. Being a heavy GW-Basic user in the 80's and early 90's, a lot of the inspiration for this project comes from that experience.

Multiple statements will be supported – as way to fit more code on the screen. In GW-Basic, the is a general lack of any rigid multiple line control structures. There are limited ones like FOR-NEXT, WHILE-WEND, DEF-ENDDEF, but these are easily abused (mainly due to the interpreted nature of GW-Basic). Factor in the GOTO, ON-GOTO GOSUB and ON-GOSUB commands (not being supported here), and GW-Basic code could look very ugly.

For this project, there will be new modern control structures including some structures that don't exist in other BASIC or other languages. It is time to get started on the commands, which will be defined before implemented. One command has already been implemented, the assignment statement, less the optional LET keyword, so it's now time to implement this optional keyword...

Tuesday, May 25, 2010

Translator – Commands and Precedence

In the translated RPN list, the command token will generally end up at the end of the statement. To accomplish this, the command tokens need to be saved until the rest of the statement is translated. The best place to save the command tokens is on the hold stack with a very low precedence to keep them on the stack until the end of statement.

The appropriate precedence of commands would appear to be the same as the EOL token, so that when the EOL token is processed, the command tokens will be emptied from the stack. This implies that commands could empty other commands, but generally, this will not occur except for multiple keyword commands (like the IF-THEN-ELSE and FOR-TO-STEP commands).

The EOL token currently has the same precedence as assignment, closing parentheses, and comma tokens. It makes sense for assignment and commands to be the same precedence because assignment is technically a command. An assignment will never empty a command from the hold stack because the Translator never receives an assignment operator. An equals token is received as an equality operator, which has a higher precedence, so it won't empty any lower precedence commands. It's only after the stack emptying that an equals token may be changed to an assignment token.

Closing parentheses and comma tokens, being the same precedence, will empty all tokens with higher or same precedence, which is a problem, since command tokens will be the same precedence. This is currently not an issue because:
  1. An EOL token is not pushed onto the hold stack and therefore can't be emptied by a closing parentheses or comma.
  2. An assignment operator is not on the hold stack when a multiple assignment comma is processed, so the comma won't empty an assignment token.
  3. An assignment token is on the hold stack when a comma is processed within an array or function – the lower precedence array or function token will be on the stack before the assignment token, so it won't empty the assignment token.
  4. An assignment token is on the hold stack when a comma is processed not within an array or function (though possibly after an opening parentheses) – this is an unexpected comma and an error occurs.
  5. A closing parentheses may empty an assignment token from the stack, but since no opening parentheses, array or function token is found on the stack, an error occurs.
This means the precedence of closing parentheses and comma tokens need to be increased above assignment and command tokens so that they do not empty them from the hold stack, but below any other operator. Closing parentheses and comma tokens are never pushed onto the hold stack, so there is no worry about them being emptied from the hold stack by an EOL or command token (an assignment token never empties the hold stack).

Monday, May 24, 2010

Translator – Token Sub-Code

The internal code will contain sub-codes that will be used by the Recreator, thus eliminating the need to put dummy codes into the program. The Translator knows when information will be needed by the Recreator in reproducing the original source. A sub-code member will be added to the token class so that the Translator can pass this information to the Encoder. The Encoder will set the sub-codes in the internal code words.

Instead of adding the dummy parentheses token to the output list, the Translator will now set the parentheses sub-code in the last token appended to the output list. The closing parentheses token used for the dummy token is no longer needed, and will be deleted. The token output routine in the test code will output a ')' at the end of a token when the parentheses sub-code is present.

Similarly, if the LET keyword is present in front of an assignment, then the LET sub-code will be set in the assignment operator token. The token output routine in the test code will output a 'LET' at the end of a token when the LET sub-code is present. Before knowing exactly how this will be accomplished, it is necessary to defined how commands will be processed...

Sunday, May 23, 2010

Internal Code Format

The encoded BASIC program will be stored in memory in a very compact form. It will not be any kind of linked list of tokens like come out of the Translator. A linked list would have way too much overhead during execution and would waste a lot of memory. Instead, the program will be very simple format where each code will take up a single 16-bit word.

A 16-bit word has plenty of space to support all the codes, which currently stands at 137 (there will be lot more, but far less than the 65,536 numbers possible in a 16‑bit word). This handles the actual codes (operators, internal functions, and commands), but what about entered identifiers like variables, arrays, define and user functions, constants, and so on?

Entered identifiers will have an index value into a table, known as the Dictionary, which will contain the information about each identifier (like name, data type, number of array dimensions, size of array dimensions, number of arguments, argument data types, constant values, etc.). The index to the Dictionary entry will be stored in the program. During run-time, much of the information in the Dictionary will not be used.

These indexes will be preceded by a code. For example, one of these codes will push a double variable value onto the evaluation stack. The routine for this code will know to get the next 16-bit word that will contain the Dictionary index. Using a 16-bit word for the index implies a maximum of 65,536 Dictionary entries. This should be sufficient since subroutines and functions will each have their own Dictionary, with each having a maximum 65,536 Dictionary entries.

The 16-bit code word has more bits than are needed for the code value. The extra space can be user for other things. One use would be for information like the presence of unnecessary parentheses or the optional LET keyword. This information will be called a sub-code and ignored by run-time module, but would be used by the Recreator. The detail of the internal program doesn't need to defined right now, just the knowledge that there will be a sub-code present in the internal code. Next, what this means for the Translator...