#include // for FILE * enum Token_type { TOKEN_INVALID, // an error // put invalid token into Token.str // Examples: & TOKEN_LINE_LABEL, // a label on a line, in the first column // labels start with [a-z_], followed by [a-z0-9_] // will be no more than 80 characters long // put label into Token.str // Examples: buf_23, BIG_BUF TOKEN_OPCODE, // an opcode (or a pseudo-op) // Not in first column (that would be TOKEN_LINE_LABEL) // put which one into Token.opcode // Examples: ADD, brz, Ret TOKEN_COMMA, // a comma // Example: , TOKEN_INT, // An integer, whether hex or decimal // put the value into Token.val // Example: -12 (decimal), #34 (decimal), xB01c, xDEAD TOKEN_REGISTER, // put the number (0-7) into Token.val // Examples: R0, r1, ... R7 TOKEN_LABEL, // a label as an operand (e.g., BR foo) // Not in the first column. // Otherwise, same rules as TOKEN_LINE_LABEL // put label into Token.str }; enum Token_opcode { OPCODE_ADD, OPCODE_AND, OPCODE_BR, OPCODE_BRZ, OPCODE_JMP, OPCODE_JSR, OPCODE_JSRR, OPCODE_LD, OPCODE_LDI, OPCODE_LDR, OPCODE_LEA, OPCODE_NOT, OPCODE_RET, OPCODE_ST, OPCODE_STI, OPCODE_STR, }; struct Token { int line_number; // first line is 1 enum Token_type type; enum Token_opcode opcode; // TOKEN_OPCODE char *str; // TOKEN_INVALID, TOKEN_LINE_LABEL, TOKEN_LABEL // Must be dynamically allocated int val; // TOKEN_INT, TOKEN_REGISTER }; // Scan the next token. // Return NULL at end of file. // Otherwise, allocate a struct Token, fill it in, and return it. struct Token *scan_token(FILE *); // Free all the memory allocated by scan_token(). void free_token(struct Token *);