![]() |
Previous | Table Of Contents | Next | ![]() |
Looking Ahead to Higher Level Languages
We have seen that the RPN calculator allows us to create unconditional branches via the GTO n statement. We can also construct conditional branches by pairing GTO n statements with conditional statements such as DSZ or x=0. By the standards of modern high-level languages such as C, C++, or Java this is a pretty crude notation. It is not immediately obvious that the following program statements:
correspond to the following flow chart logic:
The next language that we will study (in the 8051 microprocessor portion of this curriculum) is assembly language. Even though assembly language is still considered a low-level language the conditional branch statements are much more readable. An 8051 assembly language statement to branch (they call it a jump) when a value equals zero looks like:
The mnemonic JZ stands for "jump if zero". Note that we get to employ arbitrary text for the labels rather than the single digit numbers allowed by the RPN calculator's LBL n statement. Most programmers find it a lot easier to visualize the following flow chart logic when they see this type of assembly language code.
But things get even better in a high-level language. A conditional branch in the C, C++, or Java languages looks like:
The power of the high-level language comes from the fact that we can put ANY expression that evaluates to true or false inside the parentheses seen in this if statement.
Higher level languages are designed to read more like English. But they also introduce scads of new syntax rules that specify exactly what statements the computer can understand. Beginning programmers often get frustrated by the need to master all the syntax rules before they can write programs. My curriculum is designed to avoid that frustration by starting with simple languages that you can quickly learn and use for practical purposes. We will incrementally climb from low-level to high-level languages in order that we can digest the syntax rules in bite size pieces, all the while continuing to write fun programs. For example, my 8051 microprocessor curriculum allows you to write short programs (usually about 20 statements) that scroll your name across an electronic signboard or guide a mouse through a maze to find a piece of cheese.
So at this time I want to begin to expose you to how the concepts that we have seen with the RPN calculator will mature in more powerful programming environments. I have already covered conditional branches and next I want to discuss syntax errors.
When you construct an RPN calculator program by clicking keys on the calculator's keypad it is impossible to cause a syntax error. This doesn't mean your program is guaranteed to work, as it is easy to cause a logic error. But it does mean that the individual statements will always be accepted into the calculator's program memory.
But you can cause a syntax error when you construct an RPN calculator program using Notepad and then load it into the simulator. I haven't mentioned it yet, but during the process that begins when you select File/Open from the menu bar, your program is checked for syntax errors. If any illegal statements are discovered then you will be alerted and those statements will not be entered into program memory slots. Let's take a look at this process.
The example program BadSyntax.txt holds the following statements:
When this .TXT file is loaded into the calculator's program memory you will receive four dialog box messages alerting you to the four syntax errors seen in program memory below. Note that the defective statements are not placed into program memory slots, they are simply ignored.
The only type of thing that the RPN calculator allows to be placed into its data memory is numbers. More specifically, all numbers are floating point numbers meaning they can be fractional and can have exponents. The fact that data memory can only hold one type of object makes programming the RPN calculator a lot simpler. High-level languages allow the programmer to populate data memory with floating point numbers, with integer numbers (which cannot be fractional nor have exponents), with unsigned numbers (which cannot be negative), with alphabet characters, with foreign language symbols, with digitized sound samples, with colored pixels representing pictures, etc. A lot of the complexity inherent in a high-level language follows from the fact that the programmer must explicitly declare the types of objects he wants to place into data memory. He does this via variable declaration statements which, unfortunately, introduce a lot of syntax rules. Shown below are the C, C++, or Java statements which declare the programmer's intention to reserve data memory for an integer variable he will refer to as "x", a floating point variable he will refer to as "sum", and a string of up to 30 characters which he will refer to as "message":
Incidentally, one of the main reasons for all the program crashes that every Windows user sees all too often is that the program he is running tries to employ some section of memory in a manner incompatible with what that section of memory is actually holding.
As a final topic, let's return to my statement that in order to be useful a program usually needs to be incomplete. That is, it will usually require a passed parameter to be specified at run-time. Our RPN calculator programs accept a passed parameter either through the operand stack or data memory. The flexibility offered by the passed parameter is what gives the program a long useful lifetime since there will always be yet another test case for it to solve. This is because the passed parameters do not have to be fixed at compile-time (the time frame we write the program) but can remain unspecified until run-time.
In higher-level languages we place most of our code into subroutines which are now called functions or methods. These functions receive passed parameters from the calling code (whatever code calls into the function). For example, we might write a function (subroutine) that can compute and return a square root every time it is called. We decide to call this function "sqrt" and it obviously requires one passed parameter, the number (argument) for which we want the square root. In a high-level language the calling code makes a call to the sqrt function, passing in the argument 8, and receives the result back into a variable named "result" via a statement such as the following:
In this example the passed parameter is hard coded at the value 8. But more likely the argument would come from another variable like the variable we named "result". In high-level languages the programmer can select whatever names he wants for his variables, which are the values located in data memory. In our RPN calculator programs we had to access data memory by specifying a data memory address, such as the 3 in the statement RCL 3. But in a high-level language you simply state that you want to use an integer named "result" and the compiler goes and finds and reserves a data memory location to be used for this purpose.
![]() |
Previous | Table Of Contents | Next | ![]() |