started adding new error infrastructure

This commit is contained in:
Justin J. Meza 2012-03-24 11:58:04 -04:00
parent 508194029a
commit 5e8d706cf0
9 changed files with 403 additions and 177 deletions

View File

@ -27,6 +27,7 @@ SET(HDRS
parser.h
tokenizer.h
unicode.h
error.h
)
SET(SRCS
@ -36,6 +37,7 @@ SET(SRCS
parser.c
tokenizer.c
unicode.c
error.c
)
add_executable(lci ${SRCS} ${HDRS})

119
error.c Normal file
View File

@ -0,0 +1,119 @@
#include "error.h"
static const char *err_msgs[] = {
/* MN_ERROR_OPENING_FILE */
"Error opening file '%s'.\n",
/* MN_ERROR_CLOSING_FILE */
"Error closing file '%s'.\n",
/* LX_LINE_CONTINUATION */
"%s:%d: a line with continuation may not be followed by an empty line\n",
/* LX_MULTIPLE_LINE_COMMENT */
"%s:%d: multiple line comment may not appear on the same line as code\n",
/* LX_EXPECTED_TOKEN_DELIMITER */
"%s:%d: expected token delimiter after string literal\n",
/* TK_EXPECTED_FLOATING_POINT */
"%s:%u: expected floating point decimal value\n",
/* TK_EXPECTED_INTEGER */
"%s:%u: expected integer value\n",
/* TK_UNKNOWN_TOKEN */
"%s:%u: unknown token at: %s\n",
/* PR_UNKNOWN_IDENTIFIER_TYPE */
"%s:%u: unable to delete unknown identifier type\n",
/* PR_UNKNOWN_STATEMENT_TYPE */
"unable to delete unknown statement type\n",
/* PR_UNKNOWN_EXPRESSION_TYPE */
"unable to delete unknown expression type\n",
/* PR_EXPECTED_BOOLEAN */
"%s:%u: expected integer at: %s\n",
/* PR_EXPECTED_INTEGER */
"%s:%u: expected integer at: %s\n",
/* PR_EXPECTED_FLOAT */
"%s:%u: expected float at: %s\n",
/* PR_EXPECTED_STRING */
"%s:%u: expected string at: %s\n",
/* PR_EXPECTED_CONSTANT */
"%s:%u: expected constant value at: %s\n",
/* PR_EXPECTED_TYPE */
"%s:%u: expected type at: %s\n",
/* PR_EXPECTED_IDENTIFIER */
"%s:%u: expected identifier at: %s\n",
/* PR_EXPECTED_TOKEN */
"%s:%u: expected %s at: %s\n",
/* PR_INVALID_OPERATOR */
"%s:%u: invalid operator at: %s\n",
/* PR_EXPECTED_EXPRESSION */
"%s:%u: expected expression at: %s\n",
/* PR_EXPECTED_END_OF_EXPRESSION */
"%s:%u: expected end of expression at: %s\n",
/* PR_EXPECTED_END_OF_STATEMENT */
"%s:%u: expected end of statement at: %s\n",
/* PR_CANNOT_USE_STR_AS_LITERAL */
"%s:%u: cannot use an interpolated string as an OMG literal at: %s\n",
/* PR_LITERAL_MUST_BE_UNIQUE */
"%s:%u: OMG literal must be unique at: %s\n",
/* PR_EXPECTED_LOOP_NAME */
"%s:%u: expected loop name at: %s\n",
/* PR_EXPECTED_EITHER_TOKEN */
"%s:%u: expected %s or %s at: %s\n",
/* PR_EXPECTED_UNARY_FUNCTION */
"%s:%u: expected unary function at: %s\n",
/* PR_EXPECTED_MATCHING_LOOP_NAME */
"%s:%u: expected matching loop name at: %s\n",
/* PR_EXPECTED_STATEMENT */
"%s:%u: expected statement at: %s\n",
};
static const int err_codes[] = {
/* The 100 block is for the main body */
100, /* MN_ERROR_OPENING_FILE */
101, /* MN_ERROR_CLOSING_FILE */
/* The 200 block is for the lexer */
200, /* LX_LINE_CONTINUATION */
201, /* LX_MULTIPLE_LINE_COMMENT */
202, /* LX_EXPECTED_TOKEN_DELIMITER */
/* The 300 block is for the tokenizer */
300, /* TK_EXPECTED_FLOATING_POINT */
301, /* TK_EXPECTED_INTEGER */
302, /* TK_UNKNOWN_TOKEN */
/* The 400 block is for the parser */
400, /* PR_UNKNOWN_IDENTIFIER_TYPE */
401, /* PR_UNKNOWN_STATEMENT_TYPE */
402, /* PR_UNKNOWN_EXPRESSION_TYPE */
403, /* PR_EXPECTED_BOOLEAN */
404, /* PR_EXPECTED_INTEGER */
405, /* PR_EXPECTED_FLOAT */
406, /* PR_EXPECTED_STRING */
407, /* PR_EXPECTED_CONSTANT */
408, /* PR_EXPECTED_TYPE */
409, /* PR_EXPECTED_IDENTIFIER */
410, /* PR_EXPECTED_TOKEN */
411, /* PR_INVALID_OPERATOR */
412, /* PR_EXPECTED_EXPRESSION */
413, /* PR_EXPECTED_END_OF_EXPRESSION */
414, /* PR_EXPECTED_END_OF_STATEMENT */
415, /* PR_CANNOT_USE_STR_AS_LITERAL */
416, /* PR_LITERAL_MUST_BE_UNIQUE */
417, /* PR_EXPECTED_LOOP_NAME */
418, /* PR_EXPECTED_ONE_OF */
419, /* PR_EXPECTED_UNARY_FUNCTION */
420, /* PR_EXPECTED_MATCHING_LOOP_NAME */
421, /* PR_EXPECTED_STATEMENT */
/* The 500 block is for the interpreter */
};
void error2(ErrorType e, ...)
{
va_list args;
va_start(args, e);
vfprintf(stderr, err_msgs[e], args);
va_end(args);
exit(err_codes[e]);
}

69
error.h Normal file
View File

@ -0,0 +1,69 @@
/**
* Error type definitions.
*
* \file error.h
*
* \author Justin J. Meza
*
* \date 2012
*/
#ifndef __ERROR_H__
#define __ERROR_H__
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
/**
* Represents an error type. The error types are organized based on which
* module they occur in:
*
* - MN_* for the main body,
* - LX_* for the lexer,
* - TK_* for the tokenizer,
* - PR_* for the parser,
* - IN_* for the interpreter
*
* \note Remember to update the error message and error code arrays (in the
* error C file) with the appropriate error message and code.
*/
typedef enum {
MN_ERROR_OPENING_FILE,
MN_ERROR_CLOSING_FILE,
LX_LINE_CONTINUATION,
LX_MULTIPLE_LINE_COMMENT,
LX_EXPECTED_TOKEN_DELIMITER,
TK_EXPECTED_FLOATING_POINT,
TK_EXPECTED_INTEGER,
TK_UNKNOWN_TOKEN,
PR_UNKNOWN_IDENTIFIER_TYPE,
PR_UNKNOWN_STATEMENT_TYPE,
PR_UNKNOWN_EXPRESSION_TYPE,
PR_EXPECTED_BOOLEAN,
PR_EXPECTED_INTEGER,
PR_EXPECTED_FLOAT,
PR_EXPECTED_STRING,
PR_EXPECTED_CONSTANT,
PR_EXPECTED_TYPE,
PR_EXPECTED_IDENTIFIER,
PR_EXPECTED_TOKEN,
PR_INVALID_OPERATOR,
PR_EXPECTED_EXPRESSION,
PR_EXPECTED_END_OF_EXPRESSION,
PR_EXPECTED_END_OF_STATEMENT,
PR_CANNOT_USE_STR_AS_LITERAL,
PR_LITERAL_MUST_BE_UNIQUE,
PR_EXPECTED_LOOP_NAME,
PR_EXPECTED_EITHER_TOKEN,
PR_EXPECTED_UNARY_FUNCTION,
PR_EXPECTED_MATCHING_LOOP_NAME,
PR_EXPECTED_STATEMENT,
} ErrorType;
void error2(ErrorType, ...);
#endif /* __ERROR_H__ */

View File

@ -236,7 +236,7 @@ LexemeList *scanBuffer(const char *buffer, unsigned int size, const char *fname)
/* Make sure next line is not empty */
while (*test && isspace(*test)) {
if (*test == '\r' || *test == '\n') {
fprintf(stderr, "%s:%d: a line with continuation may not be followed by an empty line\n", fname, line);
error2(LX_LINE_CONTINUATION, fname, line);
deleteLexemeList(list);
return NULL;
}
@ -263,7 +263,7 @@ LexemeList *scanBuffer(const char *buffer, unsigned int size, const char *fname)
start++;
if (start == buffer || *start == ',' || *start == '\r' || *start == '\n')
continue;
fprintf(stderr, "%s:%d: multiple line comment may not appear on the same line as code\n", fname, line);
error2(LX_MULTIPLE_LINE_COMMENT, fname, line);
deleteLexemeList(list);
return NULL;
}
@ -295,7 +295,7 @@ LexemeList *scanBuffer(const char *buffer, unsigned int size, const char *fname)
&& strncmp(start + len, "'Z", 2)
&& strncmp(start + len, "...", 3)
&& strncmp(start + len, "\xE2\x80\xA6", 3)) {
fprintf(stderr, "%s:%d: expected token delimiter after string literal\n", fname, line);
error2(LX_EXPECTED_TOKEN_DELIMITER, fname, line);
deleteLexemeList(list);
return NULL;
}

View File

@ -20,6 +20,8 @@
#include <string.h>
#include <ctype.h>
#include "error.h"
#undef DEBUG
/**

8
main.c
View File

@ -114,6 +114,7 @@
#include "tokenizer.h"
#include "parser.h"
#include "interpreter.h"
#include "error.h"
#define READSIZE 512
@ -156,7 +157,6 @@ int main(int argc, char **argv)
while ((ch = getopt_long(argc, argv, shortopt, longopt, NULL)) != -1) {
switch (ch) {
default:
fprintf (stderr, "Incorrect option '%c'\n", ch);
help();
exit(EXIT_FAILURE);
case 'h':
@ -176,7 +176,7 @@ int main(int argc, char **argv)
node = NULL;
file = NULL;
if (!strncmp (argv[optind],"-\0",2)) {
if (!strncmp(argv[optind],"-\0",2)) {
file = stdin;
fname = "stdin";
}
@ -186,7 +186,7 @@ int main(int argc, char **argv)
}
if (!file) {
fprintf(stderr, "File does not exist.\n");
error2(MN_ERROR_OPENING_FILE, argv[optind]);
return 1;
}
@ -200,7 +200,7 @@ int main(int argc, char **argv)
}
if (fclose(file) != 0) {
fprintf(stderr, "Error closing file.\n");
error2(MN_ERROR_CLOSING_FILE, argv[optind]);
if (buffer) free(buffer);
return 1;
}

203
parser.c
View File

@ -306,7 +306,7 @@ void deleteIdentifierNode(IdentifierNode *node)
break;
}
default:
fprintf(stderr, "Unable to delete unknown identifier type\n");
error2(PR_UNKNOWN_IDENTIFIER_TYPE, node->fname, node->line);
break;
}
if (node->slot) deleteIdentifierNode(node->slot);
@ -515,7 +515,7 @@ void deleteStmtNode(StmtNode *node)
break;
}
default:
fprintf(stderr, "Unable to delete unknown statement type\n");
error2(PR_UNKNOWN_STATEMENT_TYPE);
break;
}
free(node);
@ -1158,7 +1158,7 @@ void deleteExprNode(ExprNode *node)
case ET_IMPVAR:
break; /* This expression type does not have any content */
default:
fprintf(stderr, "Unable to delete unknown expression type\n");
error2(PR_UNKNOWN_EXPRESSION_TYPE);
break;
}
free(node);
@ -1417,21 +1417,56 @@ int nextToken(Token ***tokenp,
}
/**
* Prints an error message of the form "FILE:LINE: INFO before: NEXT.\n", where
* LINE is the line the head of \a tokens appears on, INFO is \a info, and NEXT
* is the image of the head of \a tokens.
* A simple wrapper around the global error printing function tailored to
* general parser errors.
*
* \param [in] info The information to print.
* \param [in] type The type of error.
*
* \param [in] tokens The tokens being parsed when the error occurred.
*/
void error(const char *info,
Token **tokens)
void parser_error(ErrorType type,
Token **tokens)
{
fprintf(stderr, "%s:%u: %s at: %s\n",
error2(type, (*tokens)->fname, (*tokens)->line, (*tokens)->image);
}
/**
* A simple wrapper around the global error printing function tailored to
* expected token parser errors.
*
* \param [in] token The expected token's image.
*
* \param [in] tokens The tokens being parsed when the error occurred.
*/
void parser_error_expected_token(TokenType token,
Token **tokens)
{
error2(PR_EXPECTED_TOKEN,
(*tokens)->fname,
(*tokens)->line,
info,
keywords[token],
(*tokens)->image);
}
/**
* A simple wrapper around the global error printing function tailored to
* expected two token parser errors.
*
* \param [in] token1 The first expected token's image.
*
* \param [in] token2 The second expected token's image.
*
* \param [in] tokens The tokens being parsed when the error occurred.
*/
void parser_error_expected_either_token(TokenType token1,
TokenType token2,
Token **tokens)
{
error2(PR_EXPECTED_TOKEN,
(*tokens)->fname,
(*tokens)->line,
keywords[token1],
keywords[token2],
(*tokens)->image);
}
@ -1471,7 +1506,7 @@ ConstantNode *parseConstantNode(Token ***tokenp)
/* This should succeed; it was checked for above */
status = acceptToken(&tokens, TT_BOOLEAN);
if (!status) {
error("expected boolean", tokens);
parser_error(PR_EXPECTED_BOOLEAN, tokens);
goto parseConstantNodeAbort;
}
}
@ -1487,7 +1522,7 @@ ConstantNode *parseConstantNode(Token ***tokenp)
/* This should succeed; it was checked for above */
status = acceptToken(&tokens, TT_INTEGER);
if (!status) {
error("expected integer", tokens);
parser_error(PR_EXPECTED_INTEGER, tokens);
goto parseConstantNodeAbort;
}
}
@ -1503,7 +1538,7 @@ ConstantNode *parseConstantNode(Token ***tokenp)
/* This should succeed; it was checked for above */
status = acceptToken(&tokens, TT_FLOAT);
if (!status) {
error("expected float", tokens);
parser_error(PR_EXPECTED_FLOAT, tokens);
goto parseConstantNodeAbort;
}
}
@ -1528,12 +1563,12 @@ ConstantNode *parseConstantNode(Token ***tokenp)
/* This should succeed; it was checked for above */
status = acceptToken(&tokens, TT_STRING);
if (!status) {
error("expected string", tokens);
parser_error(PR_EXPECTED_STRING, tokens);
goto parseConstantNodeAbort;
}
}
else {
error("expected constant value", tokens);
parser_error(PR_EXPECTED_CONSTANT, tokens);
}
#ifdef DEBUG
@ -1625,7 +1660,7 @@ TypeNode *parseTypeNode(Token ***tokenp)
if (!ret) goto parseTypeNodeAbort;
}
else {
error("expected type", tokens);
parser_error(PR_EXPECTED_TYPE, tokens);
}
#ifdef DEBUG
@ -1698,7 +1733,7 @@ IdentifierNode *parseIdentifierNode(Token ***tokenp)
/* This should succeed; it was checked for above */
status = acceptToken(&tokens, TT_IDENTIFIER);
if (!status) {
error("expected identifier", tokens);
parser_error(PR_EXPECTED_IDENTIFIER, tokens);
goto parseIdentifierNodeAbort;
}
}
@ -1713,7 +1748,7 @@ IdentifierNode *parseIdentifierNode(Token ***tokenp)
data = expr;
}
else {
error("expected identifier", tokens);
parser_error(PR_EXPECTED_IDENTIFIER, tokens);
}
/* Check if there is a slot access */
@ -1781,7 +1816,7 @@ ExprNode *parseCastExprNode(Token ***tokenp)
/* Parse the cast token */
status = acceptToken(&tokens, TT_MAEK);
if (!status) {
error("expected MAEK", tokens);
parser_error_expected_token(TT_MAEK, tokens);
goto parseCastExprNodeAbort;
}
@ -1951,7 +1986,7 @@ ExprNode *parseFuncCallExprNode(Token ***tokenp)
/* Parse the function call token */
status = acceptToken(&tokens, TT_IZ);
if (!status) {
error("expected IZ", tokens);
parser_error_expected_token(TT_IZ, tokens);
goto parseFuncCallExprNodeAbort;
}
@ -1990,7 +2025,7 @@ ExprNode *parseFuncCallExprNode(Token ***tokenp)
/* Parse the end-of-argument token */
status = acceptToken(&tokens, TT_MKAY);
if (!status) {
error("expected MKAY", tokens);
parser_error_expected_token(TT_MKAY, tokens);
goto parseFuncCallExprNodeAbort;
}
@ -2167,7 +2202,7 @@ ExprNode *parseOpExprNode(Token ***tokenp)
#endif
}
else {
error("invalid operator", tokens);
parser_error(PR_INVALID_OPERATOR, tokens);
return NULL;
}
@ -2338,7 +2373,7 @@ ExprNode *parseExprNode(Token ***tokenp)
*tokenp = tokens;
}
else {
error("expected expression", tokens);
parser_error(PR_EXPECTED_EXPRESSION, tokens);
}
#ifdef DEBUG
@ -2381,7 +2416,7 @@ StmtNode *parseCastStmtNode(Token ***tokenp)
/* Remove the cast keywords from the token stream */
status = acceptToken(&tokens, TT_ISNOWA);
if (!status) {
error("expected IS NOW A", tokens);
parser_error_expected_token(TT_ISNOWA, tokens);
goto parseCastStmtNodeAbort;
}
@ -2392,7 +2427,7 @@ StmtNode *parseCastStmtNode(Token ***tokenp)
/* Make sure the statement ends with a newline */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of expression", tokens);
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
goto parseCastStmtNodeAbort;
}
@ -2452,7 +2487,7 @@ StmtNode *parsePrintStmtNode(Token ***tokenp)
/* Remove the print keyword from the token stream */
status = acceptToken(&tokens, TT_VISIBLE);
if (!status) {
error("expected VISIBLE", tokens);
parser_error_expected_token(TT_VISIBLE, tokens);
goto parsePrintStmtNodeAbort;
}
@ -2480,7 +2515,7 @@ StmtNode *parsePrintStmtNode(Token ***tokenp)
/* Make sure the statement ends with a newline */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of expression", tokens);
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
goto parsePrintStmtNodeAbort;
}
@ -2538,7 +2573,7 @@ StmtNode *parseInputStmtNode(Token ***tokenp)
/* Remove the input keyword from the token stream */
status = acceptToken(&tokens, TT_GIMMEH);
if (!status) {
error("expected GIMMEH", tokens);
parser_error_expected_token(TT_GIMMEH, tokens);
goto parseInputStmtNodeAbort;
}
@ -2549,7 +2584,7 @@ StmtNode *parseInputStmtNode(Token ***tokenp)
/* Make sure the statement ends with a newline */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of expression", tokens);
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
goto parseInputStmtNodeAbort;
}
@ -2610,7 +2645,7 @@ StmtNode *parseAssignmentStmtNode(Token ***tokenp)
/* Remove the assignment keyword from the token stream */
if (!acceptToken(&tokens, TT_R)) {
error("expected R", tokens);
parser_error_expected_token(TT_R, tokens);
goto parseAssignmentStmtNodeAbort;
}
@ -2621,7 +2656,7 @@ StmtNode *parseAssignmentStmtNode(Token ***tokenp)
/* Make sure the statement ends with a newline */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of statement", tokens);
parser_error(PR_EXPECTED_END_OF_STATEMENT, tokens);
goto parseAssignmentStmtNodeAbort;
}
@ -2686,7 +2721,7 @@ StmtNode *parseDeclarationStmtNode(Token ***tokenp)
/* Remove the declaration keywords from the token stream */
if (!acceptToken(&tokens, TT_HASA)) {
error("expected HAS A", tokens);
parser_error_expected_token(TT_HASA, tokens);
goto parseDeclarationStmtNodeAbort;
}
@ -2716,7 +2751,7 @@ StmtNode *parseDeclarationStmtNode(Token ***tokenp)
/* Make sure the statement ends with a newline */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of statement", tokens);
parser_error(PR_EXPECTED_END_OF_STATEMENT, tokens);
goto parseDeclarationStmtNodeAbort;
}
@ -2781,27 +2816,27 @@ StmtNode *parseIfThenElseStmtNode(Token ***tokenp)
/* Remove the if keyword from the token stream */
status = acceptToken(&tokens, TT_ORLY);
if (!status) {
error("expected O RLY?", tokens);
parser_error_expected_token(TT_ORLY, tokens);
goto parseIfThenElseStmtNodeAbort;
}
/* The if keyword must appear on its own line */
if (!acceptToken(&tokens, TT_NEWLINE)) {
error("expected end of expression", tokens);
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
goto parseIfThenElseStmtNodeAbort;
}
/* Parse the true branch keyword */
status = acceptToken(&tokens, TT_YARLY);
if (!status) {
error("expected YA RLY", tokens);
parser_error_expected_token(TT_YARLY, tokens);
goto parseIfThenElseStmtNodeAbort;
}
/* The true branch keyword must appear on its own line */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of expression", tokens);
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
goto parseIfThenElseStmtNodeAbort;
}
@ -2829,7 +2864,7 @@ StmtNode *parseIfThenElseStmtNode(Token ***tokenp)
/* The else-if keyword and guard must be on their own line */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of expression", tokens);
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
goto parseIfThenElseStmtNodeAbort;
}
@ -2848,7 +2883,7 @@ StmtNode *parseIfThenElseStmtNode(Token ***tokenp)
/* The else keyword must appear on its own line */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of expression", tokens);
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
goto parseIfThenElseStmtNodeAbort;
}
@ -2860,14 +2895,14 @@ StmtNode *parseIfThenElseStmtNode(Token ***tokenp)
/* Parse the end-if-block keyword */
status = acceptToken(&tokens, TT_OIC);
if (!status) {
error("expected OIC", tokens);
parser_error_expected_token(TT_OIC, tokens);
goto parseIfThenElseStmtNodeAbort;
}
/* The end-if-block keyword must appear on its own line */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of expression", tokens);
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
goto parseIfThenElseStmtNodeAbort;
}
@ -2934,14 +2969,14 @@ StmtNode *parseSwitchStmtNode(Token ***tokenp)
/* Remove the switch keyword from the token stream */
status = acceptToken(&tokens, TT_WTF);
if (!status) {
error("expected WTF?", tokens);
parser_error_expected_token(TT_WTF, tokens);
goto parseSwitchStmtNodeAbort;
}
/* The switch keyword must appear on its own line */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of expression", tokens);
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
goto parseSwitchStmtNodeAbort;
}
@ -2958,7 +2993,7 @@ StmtNode *parseSwitchStmtNode(Token ***tokenp)
/* Parse the case keyword */
status = acceptToken(&tokens, TT_OMG);
if (!status) {
error("expected OMG", tokens);
parser_error_expected_token(TT_OMG, tokens);
goto parseSwitchStmtNodeAbort;
}
@ -2971,7 +3006,7 @@ StmtNode *parseSwitchStmtNode(Token ***tokenp)
/* String interpolation is not allowed */
if (c->type == CT_STRING && strstr(c->data.s, ":{")) {
error("cannot use an interpolated string as an OMG literal", tokens);
parser_error(PR_CANNOT_USE_STR_AS_LITERAL, tokens);
goto parseSwitchStmtNodeAbort;
}
@ -2986,7 +3021,7 @@ StmtNode *parseSwitchStmtNode(Token ***tokenp)
&& fabs(c->data.f - test->data.f) < FLT_EPSILON)
|| (c->type == CT_STRING
&& !strcmp(c->data.s, test->data.s))) {
error("OMG literal must be unique", tokens);
parser_error(PR_LITERAL_MUST_BE_UNIQUE, tokens);
goto parseSwitchStmtNodeAbort;
}
}
@ -3003,7 +3038,7 @@ StmtNode *parseSwitchStmtNode(Token ***tokenp)
/* Make sure the guard appears on its own line */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of expression", tokens);
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
goto parseSwitchStmtNodeAbort;
}
@ -3022,7 +3057,7 @@ StmtNode *parseSwitchStmtNode(Token ***tokenp)
/* Make sure the default case keyword appears on its own line */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of expression", tokens);
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
goto parseSwitchStmtNodeAbort;
}
@ -3034,14 +3069,14 @@ StmtNode *parseSwitchStmtNode(Token ***tokenp)
/* Parse the end-switch keyword */
status = acceptToken(&tokens, TT_OIC);
if (!status) {
error("expected OIC", tokens);
parser_error_expected_token(TT_OIC, tokens);
goto parseSwitchStmtNodeAbort;
}
/* Make sure the end-switch keyword appears on its own line */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of expression", tokens);
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
goto parseSwitchStmtNodeAbort;
}
@ -3101,14 +3136,14 @@ StmtNode *parseBreakStmtNode(Token ***tokenp)
/* Remove the break keyword from the token stream */
status = acceptToken(&tokens, TT_GTFO);
if (!status) {
error("expected GTFO", tokens);
parser_error_expected_token(TT_GTFO, tokens);
goto parseBreakStmtNodeAbort;
}
/* The break keyword must appear on its own line */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of expression", tokens);
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
goto parseBreakStmtNodeAbort;
}
@ -3156,7 +3191,7 @@ StmtNode *parseReturnStmtNode(Token ***tokenp)
/* Remove the return keyword from the token stream */
status = acceptToken(&tokens, TT_FOUNDYR);
if (!status) {
error("expected FOUND YR", tokens);
parser_error_expected_token(TT_FOUNDYR, tokens);
goto parseReturnStmtNodeAbort;
}
@ -3167,7 +3202,7 @@ StmtNode *parseReturnStmtNode(Token ***tokenp)
/* The return statement must reside on its own line */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of expression", tokens);
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
goto parseReturnStmtNodeAbort;
}
@ -3250,7 +3285,7 @@ StmtNode *parseLoopStmtNode(Token ***tokenp)
/* Remove the loop-start keyword from the token stream */
status = acceptToken(&tokens, TT_IMINYR);
if (!status) {
error("expected IM IN YR", tokens);
parser_error_expected_token(TT_IMINYR, tokens);
goto parseLoopStmtNodeAbort;
}
@ -3258,7 +3293,7 @@ StmtNode *parseLoopStmtNode(Token ***tokenp)
name1 = parseIdentifierNode(&tokens);
if (!name1) goto parseLoopStmtNodeAbort;
else if (name1->type != IT_DIRECT) {
error("expected loop name", tokens);
parser_error(PR_EXPECTED_LOOP_NAME, tokens);
goto parseLoopStmtNodeAbort;
}
@ -3282,13 +3317,13 @@ StmtNode *parseLoopStmtNode(Token ***tokenp)
#endif
}
else {
error("expected UPPIN or NERFIN", tokens);
parser_error_expected_either_token(TT_UPPIN, TT_NERFIN, tokens);
goto parseLoopStmtNodeAbort;
}
/* Parse the required syntax */
if (!acceptToken(&tokens, TT_YR)) {
error("expected YR", tokens);
parser_error_expected_token(TT_YR, tokens);
goto parseLoopStmtNodeAbort;
}
@ -3354,7 +3389,7 @@ StmtNode *parseLoopStmtNode(Token ***tokenp)
/* Parse the function indicator */
status = acceptToken(&tokens, TT_IZ);
if (!status) {
error("expected IZ", tokens);
parser_error_expected_token(TT_IZ, tokens);
goto parseLoopStmtNodeAbort;
}
@ -3369,7 +3404,7 @@ StmtNode *parseLoopStmtNode(Token ***tokenp)
/* Check for unary function */
status = acceptToken(&tokens, TT_YR);
if (!status) {
error("expected unary function", tokens);
parser_error(PR_EXPECTED_UNARY_FUNCTION, tokens);
goto parseLoopStmtNodeAbort;
}
@ -3379,7 +3414,7 @@ StmtNode *parseLoopStmtNode(Token ***tokenp)
/* Make sure the argument is an identifier */
if (arg->type != ET_IDENTIFIER) {
error("expected identifier", tokens);
parser_error(PR_EXPECTED_IDENTIFIER, tokens);
goto parseLoopStmtNodeAbort;
}
@ -3401,7 +3436,7 @@ StmtNode *parseLoopStmtNode(Token ***tokenp)
/* Check for unary function */
status = acceptToken(&tokens, TT_MKAY);
if (!status) {
error("expected MKAY", tokens);
parser_error_expected_token(TT_MKAY, tokens);
goto parseLoopStmtNodeAbort;
}
@ -3456,7 +3491,7 @@ StmtNode *parseLoopStmtNode(Token ***tokenp)
/* All of the above should be on its own line */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of expression", tokens);
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
goto parseLoopStmtNodeAbort;
}
@ -3467,7 +3502,7 @@ StmtNode *parseLoopStmtNode(Token ***tokenp)
/* Parse the end-loop keywords */
status = acceptToken(&tokens, TT_IMOUTTAYR);
if (!status) {
error("expected IM OUTTA YR", tokens);
parser_error_expected_token(TT_IMOUTTAYR, tokens);
goto parseLoopStmtNodeAbort;
}
@ -3475,13 +3510,13 @@ StmtNode *parseLoopStmtNode(Token ***tokenp)
name2 = parseIdentifierNode(&tokens);
if (!name2) goto parseLoopStmtNodeAbort;
else if (name2->type != IT_DIRECT) {
error("expected loop name", tokens);
parser_error(PR_EXPECTED_LOOP_NAME, tokens);
goto parseLoopStmtNodeAbort;
}
/* Make sure the beginning-of-loop and end-of-loop names match */
if (strcmp((char *)(name1->id), (char *)(name2->id))) {
error("expected matching loop name", tokens);
parser_error(PR_EXPECTED_MATCHING_LOOP_NAME, tokens);
goto parseLoopStmtNodeAbort;
}
@ -3491,7 +3526,7 @@ StmtNode *parseLoopStmtNode(Token ***tokenp)
/* The end-of-loop structure should appear on its own line */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of expression", tokens);
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
goto parseLoopStmtNodeAbort;
}
@ -3577,14 +3612,14 @@ StmtNode *parseDeallocationStmtNode(Token ***tokenp)
/* Parse the deallocation token */
status = acceptToken(&tokens, TT_RNOOB);
if (!status) {
error("expected R NOOB", tokens);
parser_error_expected_token(TT_RNOOB, tokens);
goto parseDeallocationStmtNodeAbort;
}
/* The deallocation statement must reside on its own line */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of statement", tokens);
parser_error(PR_EXPECTED_END_OF_STATEMENT, tokens);
goto parseDeallocationStmtNodeAbort;
}
@ -3645,7 +3680,7 @@ StmtNode *parseFuncDefStmtNode(Token ***tokenp)
/* Parse the function definition token */
status = acceptToken(&tokens, TT_HOWIZ);
if (!status) {
error("expected HOW IZ", tokens);
parser_error_expected_token(TT_HOWIZ, tokens);
goto parseFuncDefStmtNodeAbort;
}
@ -3688,7 +3723,7 @@ StmtNode *parseFuncDefStmtNode(Token ***tokenp)
/* The function declaration should appear on its own line */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of statement", tokens);
parser_error(PR_EXPECTED_END_OF_STATEMENT, tokens);
goto parseFuncDefStmtNodeAbort;
}
@ -3699,14 +3734,14 @@ StmtNode *parseFuncDefStmtNode(Token ***tokenp)
/* Parse the end-function token */
status = acceptToken(&tokens, TT_IFUSAYSO);
if (!status) {
error("expected IF YOU SAY SO", tokens);
parser_error_expected_token(TT_IFUSAYSO, tokens);
goto parseFuncDefStmtNodeAbort;
}
/* The end-function token should appear on its own line */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of statement", tokens);
parser_error(PR_EXPECTED_END_OF_STATEMENT, tokens);
goto parseFuncDefStmtNodeAbort;
}
@ -3769,7 +3804,7 @@ StmtNode *parseAltArrayDefStmtNode(Token ***tokenp)
/* Parse the alternate array definition token */
status = acceptToken(&tokens, TT_OHAIIM);
if (!status) {
error("expected O HAI IM", tokens);
parser_error_expected_token(TT_OHAIIM, tokens);
goto parseAltArrayDefStmtNodeAbort;
}
@ -3788,7 +3823,7 @@ StmtNode *parseAltArrayDefStmtNode(Token ***tokenp)
* own line */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of statement", tokens);
parser_error(PR_EXPECTED_END_OF_STATEMENT, tokens);
goto parseAltArrayDefStmtNodeAbort;
}
@ -3800,14 +3835,14 @@ StmtNode *parseAltArrayDefStmtNode(Token ***tokenp)
* line */
status = acceptToken(&tokens, TT_KTHX);
if (!status) {
error("expected KTHX", tokens);
parser_error_expected_token(TT_KTHX, tokens);
goto parseAltArrayDefStmtNodeAbort;
}
/* The end-function token should appear on its own line */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of statement", tokens);
parser_error(PR_EXPECTED_END_OF_STATEMENT, tokens);
goto parseAltArrayDefStmtNodeAbort;
}
@ -3903,7 +3938,7 @@ StmtNode *parseStmtNode(Token ***tokenp)
/* The expression should appear on its own line */
if (!acceptToken(&tokens, TT_NEWLINE)) {
error("expected end of expression", tokens);
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
deleteExprNode(expr);
return NULL;
}
@ -3966,7 +4001,7 @@ StmtNode *parseStmtNode(Token ***tokenp)
/* The expression should appear on its own line */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of expression", tokens);
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
deleteExprNode(expr);
return NULL;
}
@ -3982,7 +4017,7 @@ StmtNode *parseStmtNode(Token ***tokenp)
*tokenp = tokens;
}
else {
error("expected statement", tokens);
parser_error(PR_EXPECTED_STATEMENT, tokens);
}
#ifdef DEBUG
@ -4088,7 +4123,7 @@ MainNode *parseMainNode(Token **tokens)
/* All programs must start with the HAI token */
status = acceptToken(&tokens, TT_HAI);
if (!status) {
error("expected HAI", tokens);
parser_error_expected_token(TT_HAI, tokens);
goto parseMainNodeAbort;
}
@ -4102,7 +4137,7 @@ MainNode *parseMainNode(Token **tokens)
/* Make sure the header line ends with a newline */
status = acceptToken(&tokens, TT_NEWLINE);
if (!status) {
error("expected end of statement", tokens);
parser_error(PR_EXPECTED_END_OF_STATEMENT, tokens);
goto parseMainNodeAbort;
}
@ -4113,7 +4148,7 @@ MainNode *parseMainNode(Token **tokens)
/* Make sure the program ends with KTHXBYE */
status = acceptToken(&tokens, TT_KTHXBYE);
if (!status) {
error("expected KTHXBYE", tokens);
parser_error_expected_token(TT_KTHXBYE, tokens);
goto parseMainNodeAbort;
}

View File

@ -1,81 +1,5 @@
#include "tokenizer.h"
static const char *keywords[] = {
"", /* TT_INTEGER */
"", /* TT_FLOAT */
"", /* TT_STRING */
"", /* TT_IDENTIFIER */
"", /* TT_BOOLEAN */
"IT", /* TT_IT */
"ITZ LIEK A", /* TT_ITZLIEKA */
"NOOB", /* TT_NOOB */
"NUMBR", /* TT_NUMBR */
"NUMBAR", /* TT_NUMBAR */
"TROOF", /* TT_TROOF */
"YARN", /* TT_YARN */
"BUKKIT", /* TT_BUKKIT */
"", /* TT_EOF */
"", /* TT_NEWLINE */
"HAI", /* TT_HAI */
"KTHXBYE", /* TT_KTHXBYE */
"HAS A", /* TT_HASA */
"ITZ A", /* TT_ITZA */
"ITZ", /* TT_ITZ */
"R NOOB", /* TT_RNOOB */
"R", /* TT_R */
"AN YR", /* TT_ANYR */
"AN", /* TT_AN */
"SUM OF", /* TT_SUMOF */
"DIFF OF", /* TT_DIFFOF */
"PRODUKT OF", /* TT_PRODUKTOF */
"QUOSHUNT OF", /* TT_QUOSHUNTOF */
"MOD OF", /* TT_MODOF */
"BIGGR OF", /* TT_BIGGROF */
"SMALLR OF", /* TT_SMALLROF */
"BOTH OF", /* TT_BOTHOF */
"EITHER OF", /* TT_EITHEROF */
"WON OF", /* TT_WONOF */
"NOT", /* TT_NOT */
"MKAY", /* TT_MKAY */
"ALL OF", /* TT_ALLOF */
"ANY OF", /* TT_ANYOF */
"BOTH SAEM", /* TT_BOTHSAEM */
"DIFFRINT", /* TT_DIFFRINT */
"MAEK", /* TT_MAEK */
"A", /* TT_A */
"IS NOW A", /* TT_ISNOWA */
"VISIBLE", /* TT_VISIBLE */
"SMOOSH", /* TT_SMOOSH */
"!", /* TT_BANG */
"GIMMEH", /* TT_GIMMEH */
"O RLY?", /* TT_ORLY */
"YA RLY", /* TT_YARLY */
"MEBBE", /* TT_MEBBE */
"NO WAI", /* TT_NOWAI */
"OIC", /* TT_OIC */
"WTF?", /* TT_WTF */
"OMG", /* TT_OMG */
"OMGWTF", /* TT_OMGWTF */
"GTFO", /* TT_GTFO */
"IM IN YR", /* TT_IMINYR */
"UPPIN", /* TT_UPPIN */
"NERFIN", /* TT_NERFIN */
"YR", /* TT_YR */
"TIL", /* TT_TIL */
"WILE", /* TT_WILE */
"IM OUTTA YR", /* TT_IMOUTTAYR */
"HOW IZ", /* TT_HOWIZ */
"IZ", /* TT_IZ */
"IF U SAY SO", /* TT_IFUSAYSO */
"FOUND YR", /* TT_FOUNDYR */
"SRS", /* TT_SRS */
"'Z", /* TT_APOSTROPHEZ */
"O HAI IM", /* TT_OHAIIM */
"IM LIEK", /* TT_IMLIEK */
"KTHX", /* TT_KTHX */
"" /* TT_ENDOFTOKENS */
};
/**
* Checks if a string follows the format for an integer. Specifically, it
* checks if the string matches the regular expression: (-?[1-9][0-9]*|0).
@ -376,16 +300,14 @@ Token **tokenizeLexemes(LexemeList *list)
/* Float */
else if (isFloat(image)) {
token = createToken(TT_FLOAT, image, fname, line);
if (sscanf(lexeme->image, "%f", &(token->data.f)) != 1) {
fprintf(stderr, "Expected floating point decimal value.\n");
}
if (sscanf(lexeme->image, "%f", &(token->data.f)) != 1)
error2(TK_EXPECTED_FLOATING_POINT, fname, line);
}
/* Integer */
else if (isInteger(image)) {
token = createToken(TT_INTEGER, image, fname, line);
if (sscanf(lexeme->image, "%i", &(token->data.i)) != 1) {
fprintf(stderr, "Expected integer value.\n");
}
if (sscanf(lexeme->image, "%i", &(token->data.i)) != 1)
error2(TK_EXPECTED_INTEGER, fname, line);
}
/* FAIL */
else if (!strcmp(image, "FAIL")) {
@ -441,7 +363,7 @@ Token **tokenizeLexemes(LexemeList *list)
token = createToken(TT_EOF, "end of file", fname, line);
}
else {
fprintf(stderr, "%s:%u: unknown token at: %s\n", fname, line, image);
error2(TK_UNKNOWN_TOKEN, fname, line, image);
/* Clean up */
deleteToken(ret[retsize - 1]);
ret[retsize - 1] = NULL;

View File

@ -20,6 +20,7 @@
#include <string.h>
#include "lexer.h"
#include "error.h"
#undef DEBUG
@ -28,8 +29,7 @@
* the semantic type of token data or the lexemes which make up the particular
* token.
*
* \note Remember to update the keywords array (in the tokens C file) with the
* token image.
* \note Remember to update the keywords array (below) with the token image.
*/
typedef enum {
TT_INTEGER, /**< Integer literal. */
@ -104,9 +104,86 @@ typedef enum {
TT_OHAIIM, /**< Alternate array declaration. */
TT_IMLIEK, /**< Alternate inherited object declaration. */
TT_KTHX, /**< End of alternate array declaration. */
TT_ENDOFTOKENS /**< The end of this enum -- don't move it! */
TT_ENDOFTOKENS /**< Sentinel end of this enum -- don't move it! */
} TokenType;
static const char *keywords[] = {
"", /* TT_INTEGER */
"", /* TT_FLOAT */
"", /* TT_STRING */
"", /* TT_IDENTIFIER */
"", /* TT_BOOLEAN */
"IT", /* TT_IT */
"ITZ LIEK A", /* TT_ITZLIEKA */
"NOOB", /* TT_NOOB */
"NUMBR", /* TT_NUMBR */
"NUMBAR", /* TT_NUMBAR */
"TROOF", /* TT_TROOF */
"YARN", /* TT_YARN */
"BUKKIT", /* TT_BUKKIT */
"", /* TT_EOF */
"", /* TT_NEWLINE */
"HAI", /* TT_HAI */
"KTHXBYE", /* TT_KTHXBYE */
"HAS A", /* TT_HASA */
"ITZ A", /* TT_ITZA */
"ITZ", /* TT_ITZ */
"R NOOB", /* TT_RNOOB */
"R", /* TT_R */
"AN YR", /* TT_ANYR */
"AN", /* TT_AN */
"SUM OF", /* TT_SUMOF */
"DIFF OF", /* TT_DIFFOF */
"PRODUKT OF", /* TT_PRODUKTOF */
"QUOSHUNT OF", /* TT_QUOSHUNTOF */
"MOD OF", /* TT_MODOF */
"BIGGR OF", /* TT_BIGGROF */
"SMALLR OF", /* TT_SMALLROF */
"BOTH OF", /* TT_BOTHOF */
"EITHER OF", /* TT_EITHEROF */
"WON OF", /* TT_WONOF */
"NOT", /* TT_NOT */
"MKAY", /* TT_MKAY */
"ALL OF", /* TT_ALLOF */
"ANY OF", /* TT_ANYOF */
"BOTH SAEM", /* TT_BOTHSAEM */
"DIFFRINT", /* TT_DIFFRINT */
"MAEK", /* TT_MAEK */
"A", /* TT_A */
"IS NOW A", /* TT_ISNOWA */
"VISIBLE", /* TT_VISIBLE */
"SMOOSH", /* TT_SMOOSH */
"!", /* TT_BANG */
"GIMMEH", /* TT_GIMMEH */
"O RLY?", /* TT_ORLY */
"YA RLY", /* TT_YARLY */
"MEBBE", /* TT_MEBBE */
"NO WAI", /* TT_NOWAI */
"OIC", /* TT_OIC */
"WTF?", /* TT_WTF */
"OMG", /* TT_OMG */
"OMGWTF", /* TT_OMGWTF */
"GTFO", /* TT_GTFO */
"IM IN YR", /* TT_IMINYR */
"UPPIN", /* TT_UPPIN */
"NERFIN", /* TT_NERFIN */
"YR", /* TT_YR */
"TIL", /* TT_TIL */
"WILE", /* TT_WILE */
"IM OUTTA YR", /* TT_IMOUTTAYR */
"HOW IZ", /* TT_HOWIZ */
"IZ", /* TT_IZ */
"IF U SAY SO", /* TT_IFUSAYSO */
"FOUND YR", /* TT_FOUNDYR */
"SRS", /* TT_SRS */
"'Z", /* TT_APOSTROPHEZ */
"O HAI IM", /* TT_OHAIIM */
"IM LIEK", /* TT_IMLIEK */
"KTHX", /* TT_KTHX */
"" /* TT_ENDOFTOKENS */
};
/**
* Stores token data with semantic meaning.
*/