|
#define | LC3AS_VAR extern |
|
#define | ERR_OPEN_READ "could not open '%s' for reading." |
|
#define | ERR_OPEN_WRITE "could not open '%s' for writing." |
|
#define | ERR_LINE_TOO_LONG "source line too long (max is %d)" |
|
#define | ERR_NO_ORIG "no .ORIG directive found" |
|
#define | ERR_MULTIPLE_ORIG "multiple .ORIG found" |
|
#define | ERR_NO_END "no .END directive found" |
|
#define | ERR_ORIG_NOT_1ST "instruction(s) appear before .ORIG" |
|
#define | ERR_END_NOT_LAST "instruction(s) appear after .END - ignored" |
|
#define | ERR_EXPECTED_COMMA "expected comma, got '%s'" |
|
#define | ERR_EXPECTED_REG "expected register (R0-R7), got '%s'" |
|
#define | ERR_EXPECT_REG_IMM "expected register or immediate, got '%s'" |
|
#define | ERR_BAD_LABEL "label '%s' contains illegal characters" |
|
#define | ERR_MISSING_OP "expected LC3 op, got '%s'" |
|
#define | ERR_MISSING_OPERAND "too few operand(s)" |
|
#define | ERR_EXTRA_OPERAND "extra operand(s) '%s'" |
|
#define | ERR_DUPLICATE_LABEL "label '%s' previously defined" |
|
#define | ERR_MISSING_LABEL "label '%s' never defined" |
|
#define | ERR_BAD_PCOFFSET "PCoffset to '%s' out of range" |
|
#define | ERR_BAD_IMM "immediate '%s' (bad format)" |
|
#define | ERR_IMM_TOO_BIG "immediate '%s' out of range" |
|
#define | ERR_EXPECTED_STR "expected quoted string, got '%s'" |
|
#define | ERR_BAD_STR "unterminated string '%s'" |
|
#define | ERR_EXPECTED_FILL "expected .FILL value, got '%s'" |
|
#define | ERR_BAD_CHAR_CONST "incorrect character constant \"%s\"" |
|
This file defines the interface to a C file assembler.c that you will complete. This is the main portion of an assembler for LC3.
This is a substantial assignment. One way to attack larger projects is to break the problem into pieces and code those pieces individually. You have already done this for the files util.c
and symbol.c
. Instead of writing large functions (e.g. asm_pass_one(), asm_pass_two()
), decompose them into a series of calls to shorter functions which do required subtasks. The decomposition may be continued until each low level function is easy to write correctly. If you find any one function getting "too" large, think about what the code does and decompose it into several smaller functions. In fact, if you can give the task a good symbolic name, you can postpone writing it until later. This is because the name implies "what" the function does. "How" it is done, will be determined when that function is coded. It is perfectly fine to have functions that are only called once from the code. The idea is that each of these functions peform a straight forward subtask. And it is perfectly fine to have functions that are only one or a few lines of code.
A good rule of thumb is that a function is too large if you can not see the entire function on a single page.
- Author
- Fritz Sieker
void asm_error |
( |
const char * |
msg, |
|
|
|
... |
|
) |
| |
A function to print error messages. This function takes a minimum of one parameter. It is exaclty like the printf()
function. The first parameter is a formatting string. This will be one of the values defined above that starts with ERR_
.The remaining parameters (if any) are the actual values to be printed (generally a token). The function prints the word ERROR:
and the the value of srcLineNum
along with the information provided by the parameters. It must be used for reporting all errors. After printing the error, the global variable numErrors
is incremented. This function relies on the static variable srcLineNum
in assembler.c
. Suppose one wanted to report that a file could not be opened for reading. The C code might look line this.
FIlE* f = fopen(filename, "r");
if (f == NULL) {
asm_error(ERR_OPEN_READ, filename);
// any other actions
}
Ideally, this function would throw an exception.
- Parameters
-
msg | - the formating string (one of the ERR_xxx macros) |
... | - a list of values to be substitued into the format string. |