mirror of
https://github.com/NikitaIvanovV/ctpv.git
synced 2025-03-01 16:51:19 +01:00
Show line and column on parse errors
This commit is contained in:
parent
ab47acdf04
commit
ab271fd493
10
config.c
10
config.c
@ -69,7 +69,7 @@ static int expect(enum TokenType type)
|
|||||||
if (token.type == TOK_ERR)
|
if (token.type == TOK_ERR)
|
||||||
return STAT_ERR;
|
return STAT_ERR;
|
||||||
|
|
||||||
print_errorf("unexpected token: %s, expected: %s",
|
PARSEERROR(token, "unexpected token: %s, expected: %s",
|
||||||
lexer_token_type_str(token.type),
|
lexer_token_type_str(token.type),
|
||||||
lexer_token_type_str(type));
|
lexer_token_type_str(type));
|
||||||
return STAT_ERR;
|
return STAT_ERR;
|
||||||
@ -139,9 +139,9 @@ static int new_preview(void)
|
|||||||
return STAT_OK;
|
return STAT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int priority(void)
|
static int priority(Token tok)
|
||||||
{
|
{
|
||||||
print_error("priority is not supported yet");
|
PARSEERROR(tok, "priority is not supported yet");
|
||||||
return STAT_ERR;
|
return STAT_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,9 +154,9 @@ static int command(void)
|
|||||||
if (strcmp(cmd_str, "preview") == 0)
|
if (strcmp(cmd_str, "preview") == 0)
|
||||||
return new_preview();
|
return new_preview();
|
||||||
else if (strcmp(cmd_str, "priority") == 0)
|
else if (strcmp(cmd_str, "priority") == 0)
|
||||||
return priority();
|
return priority(cmd);
|
||||||
|
|
||||||
print_errorf("unknown command: %s", cmd_str);
|
PARSEERROR(cmd, "unknown command: %s", cmd_str);
|
||||||
return STAT_ERR;
|
return STAT_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
70
lexer.c
70
lexer.c
@ -5,17 +5,6 @@
|
|||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
|
|
||||||
#define PARSEERROR(c, format, ...) \
|
|
||||||
print_errorf("config parse error:%u:%u " format, (c).line, (c).col \
|
|
||||||
__VA_OPT__(, ) __VA_ARGS__)
|
|
||||||
|
|
||||||
#define TOK_TYPE(t) ((Token){ .type = t })
|
|
||||||
|
|
||||||
#define NULL_TOK TOK_TYPE(TOK_NULL)
|
|
||||||
#define EOF_TOK TOK_TYPE(TOK_EOF)
|
|
||||||
#define END_TOK TOK_TYPE(TOK_END)
|
|
||||||
#define ERR_TOK TOK_TYPE(TOK_ERR)
|
|
||||||
|
|
||||||
#define READ_PUNCT(c, t, s) read_punct((c), (t), (s), LEN(s) - 1)
|
#define READ_PUNCT(c, t, s) read_punct((c), (t), (s), LEN(s) - 1)
|
||||||
|
|
||||||
#define EOF_CHAR (-1)
|
#define EOF_CHAR (-1)
|
||||||
@ -35,6 +24,9 @@ typedef struct {
|
|||||||
|
|
||||||
struct Lexer {
|
struct Lexer {
|
||||||
unsigned int line, col;
|
unsigned int line, col;
|
||||||
|
struct {
|
||||||
|
unsigned int line, col;
|
||||||
|
} tok_pos;
|
||||||
InputBuffer input_buf;
|
InputBuffer input_buf;
|
||||||
TokenQueue tok_queue;
|
TokenQueue tok_queue;
|
||||||
VectorChar *text_buf;
|
VectorChar *text_buf;
|
||||||
@ -223,9 +215,16 @@ static void read_while(Lexer *ctx, Predicate p, int add)
|
|||||||
add_text_buf(ctx, '\0');
|
add_text_buf(ctx, '\0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline Token get_tok(Lexer *ctx, enum TokenType type)
|
||||||
|
{
|
||||||
|
return (Token){ .type = type,
|
||||||
|
.line = ctx->tok_pos.line,
|
||||||
|
.col = ctx->tok_pos.col };
|
||||||
|
}
|
||||||
|
|
||||||
static inline Token read_end(Lexer *ctx)
|
static inline Token read_end(Lexer *ctx)
|
||||||
{
|
{
|
||||||
Token tok = NULL_TOK;
|
Token tok = get_tok(ctx, TOK_NULL);
|
||||||
|
|
||||||
while (peek_char(ctx) == '\n') {
|
while (peek_char(ctx) == '\n') {
|
||||||
char c = peek_char(ctx);
|
char c = peek_char(ctx);
|
||||||
@ -233,7 +232,7 @@ static inline Token read_end(Lexer *ctx)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
next_char(ctx);
|
next_char(ctx);
|
||||||
tok = END_TOK;
|
tok = get_tok(ctx, TOK_END);
|
||||||
}
|
}
|
||||||
|
|
||||||
return tok;
|
return tok;
|
||||||
@ -244,12 +243,15 @@ static inline Token read_symbol(Lexer *ctx)
|
|||||||
char c = peek_char(ctx);
|
char c = peek_char(ctx);
|
||||||
|
|
||||||
if (!isalpha(c))
|
if (!isalpha(c))
|
||||||
return NULL_TOK;
|
return get_tok(ctx, TOK_NULL);
|
||||||
|
|
||||||
size_t p = get_text_buf_len(ctx);
|
size_t p = get_text_buf_len(ctx);
|
||||||
read_while(ctx, isalnum, 1);
|
read_while(ctx, isalnum, 1);
|
||||||
|
|
||||||
return (Token){ TOK_STR, { .sp = p } };
|
Token tok = get_tok(ctx, TOK_STR);
|
||||||
|
tok.val.sp = p;
|
||||||
|
|
||||||
|
return tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline Token read_digit(Lexer *ctx)
|
static inline Token read_digit(Lexer *ctx)
|
||||||
@ -257,7 +259,7 @@ static inline Token read_digit(Lexer *ctx)
|
|||||||
char c = peek_char(ctx);
|
char c = peek_char(ctx);
|
||||||
|
|
||||||
if (!isdigit(c))
|
if (!isdigit(c))
|
||||||
return NULL_TOK;
|
return get_tok(ctx, TOK_NULL);
|
||||||
|
|
||||||
size_t len = get_text_buf_len(ctx);
|
size_t len = get_text_buf_len(ctx);
|
||||||
read_while(ctx, isdigit, 1);
|
read_while(ctx, isdigit, 1);
|
||||||
@ -265,7 +267,10 @@ static inline Token read_digit(Lexer *ctx)
|
|||||||
int i = atoi(get_text_buf_at(ctx, len));
|
int i = atoi(get_text_buf_at(ctx, len));
|
||||||
set_text_buf_len(ctx, len);
|
set_text_buf_len(ctx, len);
|
||||||
|
|
||||||
return (Token){ TOK_INT, { .i = i } };
|
Token tok = get_tok(ctx, TOK_INT);
|
||||||
|
tok.val.i = i;
|
||||||
|
|
||||||
|
return tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token read_punct(Lexer *ctx, int type, char *s, int n)
|
static Token read_punct(Lexer *ctx, int type, char *s, int n)
|
||||||
@ -273,14 +278,14 @@ static Token read_punct(Lexer *ctx, int type, char *s, int n)
|
|||||||
Token tok;
|
Token tok;
|
||||||
|
|
||||||
if (peek_char(ctx) == EOF_CHAR)
|
if (peek_char(ctx) == EOF_CHAR)
|
||||||
return EOF_TOK;
|
return get_tok(ctx, TOK_EOF);
|
||||||
|
|
||||||
int ret = cmp_nextn(ctx, n, s);
|
int ret = cmp_nextn(ctx, n, s);
|
||||||
|
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
tok.type = type;
|
tok.type = type;
|
||||||
else
|
else
|
||||||
return NULL_TOK;
|
return get_tok(ctx, TOK_NULL);
|
||||||
|
|
||||||
skipn_char(ctx, n);
|
skipn_char(ctx, n);
|
||||||
|
|
||||||
@ -302,16 +307,17 @@ static Token read_block(Lexer *ctx)
|
|||||||
Token open_tok, body_tok, close_tok;
|
Token open_tok, body_tok, close_tok;
|
||||||
|
|
||||||
if ((open_tok = read_block_open(ctx)).type == TOK_NULL)
|
if ((open_tok = read_block_open(ctx)).type == TOK_NULL)
|
||||||
return NULL_TOK;
|
return get_tok(ctx, TOK_NULL);
|
||||||
|
|
||||||
body_tok = (Token){ TOK_STR, { .sp = get_text_buf_len(ctx) } };
|
body_tok = get_tok(ctx, TOK_STR);
|
||||||
|
body_tok.val.sp = get_text_buf_len(ctx);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
close_tok = read_block_close(ctx);
|
close_tok = read_block_close(ctx);
|
||||||
|
|
||||||
if (close_tok.type == TOK_EOF) {
|
if (close_tok.type == TOK_EOF) {
|
||||||
PARSEERROR(*ctx, "unclosed block");
|
PARSEERROR(*ctx, "unclosed block");
|
||||||
return ERR_TOK;
|
return get_tok(ctx, TOK_ERR);
|
||||||
} else if (close_tok.type != TOK_NULL) {
|
} else if (close_tok.type != TOK_NULL) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -335,12 +341,13 @@ static Token read_block(Lexer *ctx)
|
|||||||
return t; \
|
return t; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ATTEMPT_READ_CHAR(ctx, ch, type) \
|
#define ATTEMPT_READ_CHAR(ctx, tok, ch, type_) \
|
||||||
do { \
|
do { \
|
||||||
char c = peek_char(ctx); \
|
char c = peek_char(ctx); \
|
||||||
if (c == (ch)) { \
|
if (c == (ch)) { \
|
||||||
|
(tok).type = (type_); \
|
||||||
next_char(ctx); \
|
next_char(ctx); \
|
||||||
return (type); \
|
return (tok); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@ -351,10 +358,15 @@ Token lexer_get_token(Lexer *ctx)
|
|||||||
|
|
||||||
read_while(ctx, isblank, 0);
|
read_while(ctx, isblank, 0);
|
||||||
|
|
||||||
ATTEMPT_READ_CHAR(ctx, EOF_CHAR, EOF_TOK);
|
ctx->tok_pos.line = ctx->line;
|
||||||
ATTEMPT_READ_CHAR(ctx, '/', TOK_TYPE(TOK_SLASH));
|
ctx->tok_pos.col = ctx->col;
|
||||||
ATTEMPT_READ_CHAR(ctx, '*', TOK_TYPE(TOK_STAR));
|
|
||||||
ATTEMPT_READ_CHAR(ctx, '.', TOK_TYPE(TOK_DOT));
|
Token tok = get_tok(ctx, TOK_NULL);
|
||||||
|
|
||||||
|
ATTEMPT_READ_CHAR(ctx, tok, EOF_CHAR, TOK_EOF);
|
||||||
|
ATTEMPT_READ_CHAR(ctx, tok, '/', TOK_SLASH);
|
||||||
|
ATTEMPT_READ_CHAR(ctx, tok, '*', TOK_STAR);
|
||||||
|
ATTEMPT_READ_CHAR(ctx, tok, '.', TOK_DOT);
|
||||||
|
|
||||||
ATTEMPT_READ(ctx, read_end);
|
ATTEMPT_READ(ctx, read_end);
|
||||||
ATTEMPT_READ(ctx, read_symbol);
|
ATTEMPT_READ(ctx, read_symbol);
|
||||||
@ -362,7 +374,7 @@ Token lexer_get_token(Lexer *ctx)
|
|||||||
ATTEMPT_READ(ctx, read_block);
|
ATTEMPT_READ(ctx, read_block);
|
||||||
|
|
||||||
PARSEERROR((*ctx), "cannot handle character: %c", peek_char(ctx));
|
PARSEERROR((*ctx), "cannot handle character: %c", peek_char(ctx));
|
||||||
return ERR_TOK;
|
return get_tok(ctx, TOK_ERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *lexer_get_string(Lexer *ctx, Token tok)
|
char *lexer_get_string(Lexer *ctx, Token tok)
|
||||||
|
5
lexer.h
5
lexer.h
@ -4,9 +4,14 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define PARSEERROR(c, format, ...) \
|
||||||
|
print_errorf("config:%u:%u " format, (c).line, \
|
||||||
|
(c).col __VA_OPT__(, ) __VA_ARGS__)
|
||||||
|
|
||||||
typedef struct Lexer Lexer;
|
typedef struct Lexer Lexer;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
int line, col;
|
||||||
enum TokenType {
|
enum TokenType {
|
||||||
TOK_NULL,
|
TOK_NULL,
|
||||||
TOK_EOF,
|
TOK_EOF,
|
||||||
|
Loading…
Reference in New Issue
Block a user