HP Prime Programming: An Introduction - Printable Version +- HP Forums (https://www.hpmuseum.org/forum) +-- Forum: HP Calculators (and very old HP Computers) (/forum-3.html) +--- Forum: Articles Forum (/forum-14.html) +--- Thread: HP Prime Programming: An Introduction (/thread-216.html) |
HP Prime Programming: An Introduction - Han - 12-23-2013 05:24 AM Last Update: JAN-24-2014 Fixed major error regarding "non-exported variables" This introduction will assume that the user does all programming on the calculator. That said, any source file may be written completely on a computer and transferred to the calculator or emulator, completely bypassing the built-in Program Editor. Part I: Editor, Compiler, Program Execution 1. Program Editor and Compiler Press the [Shift] key followed by the [1] key to view the Program Catalog. At the very top will always the source file for the current app. Below the source file for the current app are the source files of user programs. To create a new program, press New from the menu at the bottom of the screen. You will then be presented with a new input screen titled "New Program" and be required to enter in the name of the "new program." For this example, type in MYPROG. After pressing OK you will be presented with the Program Editor with a default template as shown below: Code:
When source code is compiled, a binary is created separate from the source code along with a pointer to the binary and a header consisting of exported variable/function names and argument information. At runtime, the header is used to enable access to exported functions or variables. Functions are called by their pointers. The header remains even after a reboot (warmstart) whereas the binary does not. If a function is called and its binary does not exist, then the binary will be compiled as needed without requiring user intervention. Remark: The phrase "new program" as used by the New menu option in the Program Catalog is misleading. The name specified in the input screen is the name of the source file. It is used by the system to create a template procedural function (i.e. a program, similar to -- but different from -- a mathematical function). However, the procedural function need not have the same name as the source file. That is, the user is free to change MYPROG() to something completely different from the source file name MYPROG. Moreover, one may even create several procedural functions within the same source file. In fact, one may even use a single source file to create all the programs and variables that will ever be used on the calculator! So "new program" should really be "new project" (conceptually speaking). 2. A word about upper and lower case One of the underlying principles in programming the HP Prime is that programs are essentially written as if commands will be executed in the Home view. One of the features of the Home view is that the command line parses commands without distinguishing upper and lower case. For example, print("Hello"); is parsed as PRINT("Hello"); -- even pRiNt("Hello"); is parsed the same way. However, inconsistent upper/lower case usage in source code is bad practice. Moreover, there are commands which behave differently when typed in upper case vs. lower case (i.e. they are different commands). That said, since programs are essentially a sequence of commands executed in the Home view, one may type the source code completely in lower case (while accounting for the few instances in which COMMAND() has counterpart named command()). This feature enables program creation on a computer without having to have CAPS LOCK enabled. 3. Adding lines of code In the code block above, we have a procedural function (i.e. a program) named MYPROG that does absolutely nothing. Rename the program PROG1, so that the source file MYPROG is distinct from the program contained within. Programs are simply sequences of commands separated by a semicolon (;) -- assuming default settings. Commands may be separated by carriage returns for legibility, though one is free to place all commands on a single line. Spaces and carriage returns are ignored by the compiler. That said, be careful as not all spaces are the same! The HP Prime uses Unicode, which means what appears as a space may not be the same character as an actual space! For this introduction, we will create a simple "hello world" program and then modify it to explore other programming options. A simple method for displaying a string is to use the MSGBOX command. Code:
4. Comments Comments may be inserted using two forward slashes (basically, two "division" symbols). Comments are ignored by the compiler. We may add comments to either annotate the source code or to debug the program by temporarily "disabling" a particular line of code. Code:
5. Running the program. There are two options for running a program. One is to use the Run menu option from the Program Catalog. Highlight the source name MYPROG and press Run. The other is to type the program's name into the command line. Press the [Home] key and type: PROG1() into the command line to see what the program does. A shortcut to actually typing out the program name is available through the toolbox key. Press the Toolbox key, and then select "User" from the menu. Selecting the desired source file and then program from the menu will place its name into the command line. Notice the difference between the two methods (in particular, running MYPROG vs. running PROG1. We will touch upon their differences in Part II.) Part II: Arguments and Local Variables 1. Passing arguments A procedural function (program) can be made to behave very much like a mathematical function in that arguments may be passed at runtime. Functional notation in mathematics takes the form \( f(x) \) where \( f\) is the name of the function and \( x \) is its argument (input). A procedural function is similar in that it also uses the name(argument) syntax. We will modify PROG1() so that it can take input at runtime. Suppose we wish to enable the user to type PROG1("Name") and have PROG1 display "Hello Name!" instead of "Hello world!". The modified source code would look like: Code:
Currently, programs can have up to 16 arguments. Each argument variable name is separated by a comma -- assuming default settings. The argument variables belong to the class of local variables. The template for such a function is as follows: Code:
Using a list is also a means of bypassing the 16 argument limit. Since lists may contain just about any type of object, we may even place all our arguments in a list and use only one argument variable name. The contents of the list are extracted using the syntax: listname(position). That is, if list is the variable name of a list, then list(2) is a "name" for the second object within list. Remark: When a program which takes arguments is executed from the Run menu option in the Program Catalog, then the argument variables are initialized to real numbers, and have a default value of 0. While this feature is nice in that it allows users to enter their arguments in a nice input form, the input form will only accept real-valued inputs and produce input errors otherwise. So while PROG1 was designed to expect a string of characters as its input, executing it from the Run menu option prevents users from actually using a string as an argument! 2. Local variables As mentioned above, input variables are a form of local variables. However, should our program need more variables that are distinct from those passed to the program, then they must be declared using the LOCAL declaration. While these declarations can be made anywhere within a program, most programmers tend to place all local variable declarations toward the top of the program block. Below are acceptable ways of declaring local variables for use within a program block. Code:
We now modify our code so that PROG1 will actually display some additional information stored in local variables. Code:
3. Scope of local variables When local variables are created by declaring them either as arguments of a program, or within a program block, then their scope is limited to that program only. In the example immediately above, the local variables var1 and var2 are only available to commands that are both within the definition of the program MYPROG1 and which come AFTER the declaration of each variable (e.g. the MSGBOX() command). It is possible to create a local variable whose scope is much wider -- covering the entire source file. In a previous edition, these local variables were mislabeled as "non-exported global variables." They have been confirmed to be local variables that are declared using a shorthand declaration style. But to get to the point, a local variable that is declared OUTSIDE of any program block is considered to be "global" to all programs within the source file as any programs defined after such a variable declaration may use that variable. However, it is local not only because it is normally declared with LOCAL, but that its scope is limited to within the source file. The following examples show how this type of local variable can be declared and used: Code:
The local variables var1 through var6 may be used by any program defined later in the source file. Unlike local variables declared inside a program block, such as var7, local variables declared outside of any program block retain their values even after program execution reaches completion and up until the source is recompiled. This is the only effective difference. They are still not accessible to programs defined in a separate source file, or the user. Part III: Global Variables and Calling Programs within a Program For this part, we will start with a completely new source file and create something useful, as opposed the the "Hello world" type of program in the previous parts. Begin by creating a new source file named PROJECT. Erase the default template that is created, and create the following program: Code:
1. Returning a value The program above simply takes a numerical value, presumably representing an angle in radians, and returns the angle as if measured in degrees. The code could be further shortened to simply have RETURN(a/PI*180) in between the BEGIN/END pair. The main concept here is the RETURN command. This command is used to end program execution as well as return a value back to the user (i.e. placed on the history in the Home screen). Even programs which do not have an explicit RETURN statement will still return a value -- namely the value of the very last command executed prior to the program reaching its end. Thus, we can accomplish the same goal of returning the value of a the angle in degrees to the Home screen by omitting the RETURN command! In the "Hello world" example, we simply displayed a message on the screen. After the program ended, a 1 appeared on the history in the Home view. This is what was returned by the MSGBOX command. However, if we had run the program from the Run menu option, then after pressing OK another dialogue box shows up with the message PROG1 1. Again, the value after PROG1 what was returned by the MSGBOX command. The RETURN command serves one additional purpose: returning program execution back to any calling programs. This will be explained later. 2. Calling a program within a program Now suppose that we want to create another program that needs to do angle conversion (from radians to degrees). In the example that follows, we will create a program that takes two angles (assumed to be in radians) of a triangle, and return the third angle in degrees. Within the same source file PROJECT we can add a second program so that the source file looks like the following: Code:
To use the THIRDANG program, simply type: THIRDANG(PI/3, PI/2); and the result is 30. 3. Global variables If you have not already read up on the various types of variables, it is recommended that you at least skim through this article about variable types and their priorities. In this section, we will only cover how to create global variables and their scope. In this current project, we have two programs which each use local variables for temporary data storage. We can replace the local variables with global variables so that the two programs can make use of the same variable without have to pass any sort of arguments from one to the other. For example, consider the following modification to the code above: Code:
4. Exporting vs. not exporting variables and programs The EXPORT command that appears in front of global variables and program definitions in the code above make the respective variables and programs visible to the entire system: the user, other programs, apps, etc. Sometimes it is necessary to "hide" such variables and programs from the user (or the Memory Browser to prevent clutter) so that their values are not altered, or to prevent other programs from other source files from tampering with the values or calling the programs. By removing the EXPORT command, all programs become invisible to the user, and to other programs from a different source file. And what was once a global variable becomes a local variable. Consider the following slight modification (the only changes are the removal of EXPORT from the global variable declaration section and from ANG()): Code:
Remark: The scope of exported global variables is system-wide. Just like the built-in system variables L0 through L9 may be used for list operations from anywhere in the system, exported variables may also be accessed from anywhere in the system. The scope of non-exported (local) variables is limited to the source file. Part IV: Block statements and control structures This is the final part to this introduction. We will explore some basic control structures below. 1. IF THEN END; and IF THEN ELSE END; If a particular command should only be executed if a certain condition is met, then the IF THEN END structure is a simple way to execute a sequence of commands only if the condition(s) are met. The syntax is Code:
Code:
Example: Angle mode independence. The really nice thing about this simple little program ANG() is that with a tiny modification, we can now create any program that always use angles in radians by having ANG() handle any conversions for us based on the user's settings. Consider ANG() modified to be: Code:
Remark: HAngle (home angle) is a global variable which reflects the system angle mode. If its value is 0, then the angle mode is radian. And if 1, then the angle mode is degree. There is yet another system variable which tracks the angle mode: AAngle (app angle). If AAngle is 0, then the app angle mode defaults to HAngle. If AAngle is 1, then the app angle mode is in radian, and 2 for degree. The app angle has higher priority than the system angle since an app is always in view. The second variation of conditional branching is Code:
Code:
2. CASE IF THEN END; END; If a program consists of several branches, of which only one will be executed based on certain conditions, then the CASE branch should be used. The syntax is Code:
Example: Basic Key/Touchscreen Handler. Below is a skeleton for a basic keyboard and touchscreen handler using the WAIT(-1) command. By passing -1 as the argument, WAIT will essentially pause the program and wait for input from either the keyboard or the touchscreen. If no input is received after a minute, then -1 is returned. Otherwise, either the key number (for a keypress) or a "mouse" list (for touchscreen gestures) will be returned. Due to the different types of objects (integer vs list) returned by this command, and the fact that mis-matched object types in a branch (such as an IF THEN END statement) will cause run-time errors, we must carefully parse the value(s) returned by WAIT. (Note that the touchscreen events MUST be parsed first in this implementation and that only part of the handler is shown; the necessary subroutines would need to be added accordingly.) Code:
Remark: The way WAIT(-1) processes a mouse event is not the way one might expect. That is, a mouse click generates three separate events, so that three consecutive instances of WAIT(-1) are required to finally capture the mouse click. So when a mouse click occurs, the first instance of WAIT(-1) returns a mouse-down event, the second instance of WAIT(-1) returns a mouse-up event, and finally the third instance of WAIT(-1) returns a mouse-click. The same goes for long clicks and other types of events. Please keep this in mind when creating a mouse/keyboard handler. |