Blog

Relearning MSX #17: Command line parameters, redirection and pipes

Posted by in MSX, Retro, Technology | March 13, 2015

msx_magazine_1990-02_msx-pdt_ad

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
  • Pipes

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:

BASIC_interpreter

Entering a program and running it under MSX BASIC

When we program in C we’ll use different tools for each step of the process:

  1. Write our program using a text editor
  2. Compile the program: the compiler will process our source code and convert it into a file that can run on the computer
  3. 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”:

example_c

example.c (click to enlarge)

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:

MSX_magazine_1991-11_p108-109

Short BASIC programs (MSX Magazine, November 1991) Click to enlarge

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:

example_c_compile_highlighed

Result of compiling the TRIANGLE.C program with command line “C TRIANGLE”. Click to enlarge.

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:

example_c_dir

Result of compiling the TRIANGLE.C program. Click to enlarge.

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:

MSX_BASIC_syntax_error

Syntax error on line 20 of MSX BASIC program. Click to enlarge.

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:

MSX_BASIC_error_undetected

MSX BASIC program with error in line 200. Click to enlarge.

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:

Undeclared symbols

Go back to the TRIANGLE.C program and modify line 7 so it will read putchr() instead putchar():

example_c_putchr

TRIANGLE.C: putchar() misspelt as putchr(). Click to enlarge.

Trying to compile this program will return an error message explaining that the compiler doesn’t know about any function called putchr:

example_c_putchr_error

Undeclared function ‘putchr’. Click to enlarge.

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.

Missing semicolons

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:

example_c_missing_semicolon

Semicolon missing after the declaration of the parameter ch. Click to enlarge.

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):

example_c_missing_semicolon_error

Compile error: missing semicolon. Click to enlarge.

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:

example_c_bracket

Unmatched closing bracket in a C function. Click to enlarge.

Compiling a program that contains this kind of mistake will generate a lot of warnings and it will look a bit scary:

example_c_bracket_error

Errors attempting to compile a program with unmatched closing brackets. Click to enlarge.

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:

triangle_default

Running the TRIANGLE.COM program without parameters. Click to enlarge.

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:

triangle_3

The TRIANGLE program generating triangles of height 3. Click to enlarge.

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:

double_c

DOUBLE.C. Click to enlarge.

double_c_compile

Compiling DOUBLE.C and deleting unwanted files. Click to enlarge.

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:

double_output

DOUBLE.COM output. Click to enlarge.

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:

redir_triangle

Redirecting TRIANGLE’s output to a file. Click to enlarge.

Under MSX-DOS2 this will also work with system commands (see note at the end about MSX-DOS1):

redir_dir

Redirecting DIR to a file. Click to enlarge.

Sometimes we want to append to an existing file instead of overwriting it. We use the >> (append) operator for that:

redir_dir_append

Appending to a file using redirection. Click to enlarge.

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:

redir_input_double

Input redirection. Click to enlarge.

It is also possible to combine the input and output redirection operators:

redir_input_and_output

Redirecting both input and output. Click to enlarge.

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:

pipe_triangle_double

Pipe the output of TRIANGLE to the input of DOUBLE. Click to enlarge.

Under MSX-DOS2 this works with system commands too:

pipe_dir_double

Piping the output of DIR to DOUBLE. Click to enlarge.

Summary of redirection and piping operators

Here’s a table for quick reference:

redirection_and_pipe_operators

Notes

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.

redir_append_fails

Output redirection doesn’t work properly. Click to enlarge.

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.

Next week…

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.

Javi Lavandeira’s Patreon page

6 comments on “Relearning MSX #17: Command line parameters, redirection and pipes

  1. Pingback: Relearning MSX #17: Command line parameters, redirection and pipes | Vintage is the New Old

  2. Javi, like marcelo santos, I got an unexpected illegal .tco file at 0:1 when compiling, but deleting the old one doesn’t seems to fix the problem. Did I missed something?

  3. Sergi García on said:

    Daniel, you are right the c.bat file has to be called without extension. This is because the third line of the bat file expects a .tco file instead of a .c file. CG -K %3 %1

Leave a Reply

Your email address will not be published. Required fields are marked *