We now have a working installation of the MSX-C compiler. We saw a very simple test program in chapter 12, and this week we’ll compile a program that actually does something.
We’re going to learn about:
- Command line parameters
- Input/output redirection
Along the way we’re also going to see some common compile-time errors and how to resolve them. This post doesn’t require or assume any previous programming experience. The content and example programs are based on chapter 4 of the book MSX-C入門上巻 (“Introduction to MSX-C, first part”) edited by ASCII Corporation in 1989.
Before we start go get something to drink. This is a long post.
From program input to execution
If you have previous experience with MSX BASIC then you’ll remember that entering the program and running it are both done under the same environment: the MSX BASIC interpreter:
When we program in C we’ll use different tools for each step of the process:
- Write our program using a text editor
- Compile the program: the compiler will process our source code and convert it into a file that can run on the computer
- Run the program under MSX-DOS(2)
The following is our first example program. Type it in your MSX using the AKID editor (or any other text editor you like) and save it with the filename “TRIANGLE.C”:
Note: for short programs like this one I won’t be linking to a downloadable source file, and instead I’ll post a screenshot of the source code. I believe that typing by hand programs written by other people is a very good way to learn the syntax of a programming language. That’s actually what we had to do back in the day: we typed example programs and games directly from magazine pages:
When you finish entering the code for the EXAMPLE.C program save the file and exit the text editor. Then try compiling it using the C.BAT batch file we prepared in chapter 12. If you made no errors while copying the program you should see each of the programs called from the batch file output their status message one after the other:
Assuming that everything went well you should now have a file called TRIANGLE.COM. Feel free to delete the TRIANGLE.REL, TRIANGLE.MAC and TRIANGLE.SYM files that were created during the compile process:
Fixing compilation errors
If you’ve written programs in BASIC before then you probably know that it’s relatively easy to locate errors in the code because the interpreter tells us the line number that contains the error. Look at the following example in BASIC:
This program contains two errors:
- Line 20: the keyword “FOA” doesn’t exist in BASIC. It should be written “FOR”.
- Line 200: there’s a text string instead of a BASIC instruction. This line will return an error if executed.
When running this program the BASIC interpreter immediately detects the error on line 20 and stops the program. We can then go and fix it and try again:
The BASIC program still contains an error in line 200, but the program runs fine because that line is never reached during execution.
C programs don’t work like this. The compiler must be able to understand the whole C source code of a program to be able to generate the executable. If there are syntax errors or undeclared symbols (functions, variables, constants, etc) then the program won’t compile.
Let’s see the most common errors:
Go back to the TRIANGLE.C program and modify line 7 so it will read putchr() instead putchar():
Trying to compile this program will return an error message explaining that the compiler doesn’t know about any function called putchr:
The error message “line 7 column 8: undeclared function ‘putchr'” explains that there’s an error on line 7 of the program. This can happen with variables and constants as well.
If you see this kind of error then check the program line especified in the error message and confirm that everything is spelt correctly. Be aware that C is case sensitive: putchar(), Putchar(), PUTCHAR() are all different function names.
Fix the error and let’s see the next common issue.
C uses semicolons to mark the end of a statement. If you miss one then the compiler will think that the statement continues, even if it’s in the following line. The compiler will keep reading the input file until it finds more code and will generate an error message.
To illustrate this, go back to the TRIANGLE.C program and remove the semicolon after the parameter ch in line 3:
Trying to compile this program will return an error in line 4, even though the missing semicolon belongs in line 3 (remember that we’re numbering lines starting from line 0):
If you find an error like this, and you’re sure that the line pointed by the error message is correct, check the previous lines in the program. It’s likely that something is missing.
Put the semicolon back, save the file, and let’s look at the next case.
Missing or unmatched braces or parentheses
This happens often and can sometimes be difficult to troubleshoot. Go back to the text editor and replace the closing bracket in the putline() function with a closing parenthesis:
Compiling a program that contains this kind of mistake will generate a lot of warnings and it will look a bit scary:
When you find lots of errors like in this screenshot the first thing you should do is check the line in the program where the first error happens, and the lines just before that one, and confirm that there are no missing parentheses, square or curly brackets.
Fix the TRIANGLE.C program and let’s continue. There’s no need to compile again because these three compile attempts didn’t touch the TRIANGLE.COM binary that we compiled before.
Running the program
To run the program just enter “TRIANGLE” in the MSX-DOS2 command line. It should display a nice triangle made of plus characters and then return to the command line. By default the height of the triangle is five characters:
Command line parameters
One nice thing of C is that it allows the programmer to easily accept command line parameters. Try running the TRIANGLE program again with a number after the program name:
Try running the program several times entering different parameters in the command line to see what happens. We’ll explain later how this works.
Redirection and pipes
Another very useful characteristic of C is how programs handle input and output streams. The input stream is where the program gets its data from, and it defaults to the keyboard. The output stream is where the program prints its output (status messages, results, etc), and it defaults to the screen. Connecting the output of one program to the input of another allows us to combine simple programs to perform more complex tasks.
Let’s see an example in order to illustrate this. Enter the following program, save it as DOUBLE.C and compile. You can delete the .MAC, .SYM and .REL files after compiling:
Try running the DOUBLE.COM program now and play around with it a bit. This program waits for you to enter a line of text on the keyboard and it will print it doubled when you press enter. It will keep running until you give it the End-of-file control code (CTRL-Z), or until you abort the program using CTRL-C:
Now we have two programs to play with:
- TRIANGLE.COM outputs text to the screen in the shape of a triangle
- DOUBLE.COM takes lines of text as input and doubles them
Let’s do some redirection tricks with these.
Redirection to a file (output redirection)
The > operator (greather than) redirects the output of a program to a file on disk. If the file already exists, it will be overwritten and the previous content will be lost.
Try this with our TRIANGLE program:
Under MSX-DOS2 this will also work with system commands (see note at the end about MSX-DOS1):
Sometimes we want to append to an existing file instead of overwriting it. We use the >> (append) operator for that:
IMPORTANT: there seems to be a bug in the MSX-C library when redirecting the output. See the end of this post for details.
Redirecting from a file (input redirection)
Input redirection works the other way: reads a file and passes the data to a program as input. To redirect the input we use the < (less than) operator. See this example:
It is also possible to combine the input and output redirection operators:
Piping (connecting two programs)
The pipe character (|) connects the output of one program to the input of another. It is very useful to perform complex operations based on simple programs. See these examples:
Under MSX-DOS2 this works with system commands too:
Summary of redirection and piping operators
Here’s a table for quick reference:
Redirection and pipes under MSX-DOS1
When we were talking about redirection and piping I said several times “under MSX-DOS2 this works with system commands too”. MSX-DOS1 doesn’t support redirection or piping. Programs compiled with MSX-C Ver.1.1 under MSX-DOS1 will support both redirection and piping because this functionality is included in the MSX-C runtime and added to the program during the linking phase. This is why a program compiled under MSX-C Ver.1.1 always produces a bigger binary than the same program compiled with MSX-C Ver.1.2.
Bug in output redirection in programs compiled with MSX-C
I’ve found that appending to files created by redirecting the output of a program compiled with MSX-C Ver.1.2 doesn’t always work. For example, the commands below should result in the tri.txt file containing two triangles, one below the other.
What I’ve found out is that appending to the file works: it grows in size every time there’s content added to it. However, the TYPE command only shows the first portion of the contents. The problem seems to be that MSX-C adds an extra character at the end of each execution that causes programs like TYPE or AKID to believe they’ve reached the end of the file, some thing like this:
First execution: BLAH BLAH BLAH BLAH<MARK> Second execution: BLAH BLAH BLAH BLAH<MARK>BLAH BLAH BLAH BLAH<MARK>
That <MARK> character shouldn’t be there. It’s probably something in how the MSX-C library handles the output. I’ll post more about this when I find out.
In this chapter we’ve entered a couple of small programs. One of them uses a command line parameter. We’ve handled a few of the most common problems during compilation and we’ve also learnt how to use redirection and pipes.
Next Friday we’ll see how to read C programs and we’ll play a bit with functions.
As always, if you have any questions about the content in this post just write them in the comments below.
This series of articles is supported by your donations. If you’re willing and able to donate, please visit the link below to register a small pledge. Every little amount helps.