odyssey/sources/parser.h

177 lines
3.8 KiB
C
Raw Normal View History

2017-07-11 12:43:53 +00:00
#ifndef OD_PARSER_H
#define OD_PARSER_H
/*
2018-03-12 14:03:15 +00:00
* Odyssey.
2017-07-11 12:43:53 +00:00
*
* Advanced PostgreSQL connection pooler.
*/
typedef struct od_token od_token_t;
typedef struct od_keyword od_keyword_t;
typedef struct od_parser od_parser_t;
2017-07-11 12:43:53 +00:00
enum {
OD_PARSER_EOF,
OD_PARSER_ERROR,
OD_PARSER_NUM,
OD_PARSER_KEYWORD,
2017-07-11 12:43:53 +00:00
OD_PARSER_SYMBOL,
OD_PARSER_STRING
};
struct od_token
2017-07-11 12:43:53 +00:00
{
int type;
int line;
union {
uint64_t num;
struct {
char *pointer;
int size;
} string;
} value;
};
struct od_keyword
{
int id;
char *name;
int name_len;
};
#define od_keyword(name, token) \
{ token, name, sizeof(name) - 1 }
2017-07-11 12:43:53 +00:00
struct od_parser
{
char *pos;
char *end;
od_token_t backlog[4];
int backlog_count;
int line;
2017-07-11 12:43:53 +00:00
};
static inline void
od_parser_init(od_parser_t *parser, char *string, int size)
{
parser->pos = string;
parser->end = string + size;
parser->line = 0;
parser->backlog_count = 0;
}
static inline void
od_parser_push(od_parser_t *parser, od_token_t *token)
2017-07-11 12:43:53 +00:00
{
assert(parser->backlog_count < 4);
parser->backlog[parser->backlog_count] = *token;
parser->backlog_count++;
}
static inline int
od_parser_next(od_parser_t *parser, od_token_t *token)
2017-07-11 12:43:53 +00:00
{
/* try to use backlog */
if (parser->backlog_count > 0) {
*token = parser->backlog[parser->backlog_count - 1];
parser->backlog_count--;
return token->type;
}
/* skip white spaces and comments */
for (;;) {
while (parser->pos < parser->end && isspace(*parser->pos)) {
if (*parser->pos == '\n')
parser->line++;
parser->pos++;
}
if (od_unlikely(parser->pos == parser->end)) {
token->type = OD_PARSER_EOF;
return token->type;
}
if (*parser->pos != '#')
break;
while (parser->pos < parser->end && *parser->pos != '\n')
parser->pos++;
if (parser->pos == parser->end) {
token->type = OD_PARSER_EOF;
return token->type;
}
parser->line++;
}
/* symbols */
if (*parser->pos != '\"' && ispunct(*parser->pos)) {
2017-07-11 12:43:53 +00:00
token->type = OD_PARSER_SYMBOL;
token->line = parser->line;
token->value.num = *parser->pos;
parser->pos++;
return token->type;
}
/* digit */
if (isdigit(*parser->pos)) {
token->type = OD_PARSER_NUM;
token->line = parser->line;
token->value.num = 0;
while (parser->pos < parser->end && isdigit(*parser->pos)) {
token->value.num = (token->value.num * 10) + *parser->pos - '0';
parser->pos++;
}
return token->type;
}
/* keyword */
2017-07-11 12:43:53 +00:00
if (isalpha(*parser->pos)) {
token->type = OD_PARSER_KEYWORD;
2017-07-11 12:43:53 +00:00
token->line = parser->line;
token->value.string.pointer = parser->pos;
while (parser->pos < parser->end &&
(*parser->pos == '_' || isalpha(*parser->pos) ||
isdigit(*parser->pos)))
parser->pos++;
token->value.string.size =
parser->pos - token->value.string.pointer;
return token->type;
}
/* string */
if (*parser->pos == '\"') {
2017-07-11 12:43:53 +00:00
token->type = OD_PARSER_STRING;
token->line = parser->line;
parser->pos++;
token->value.string.pointer = parser->pos;
while (parser->pos < parser->end && *parser->pos != '\"') {
2017-07-11 12:43:53 +00:00
if (*parser->pos == '\n') {
token->type = OD_PARSER_ERROR;
return token->type;
}
parser->pos++;
}
if (od_unlikely(parser->pos == parser->end)) {
token->type = OD_PARSER_ERROR;
return token->type;
}
token->value.string.size =
parser->pos - token->value.string.pointer;
parser->pos++;
return token->type;
}
/* error */
token->type = OD_PARSER_ERROR;
token->line = parser->line;
return token->type;
}
static inline od_keyword_t*
od_keyword_match(od_keyword_t *list, od_token_t *token)
{
od_keyword_t *current = &list[0];
for (; current->name; current++) {
if (current->name_len != token->value.string.size)
continue;
if (strncasecmp(current->name, token->value.string.pointer,
token->value.string.size) == 0)
return current;
}
return NULL;
}
2017-07-11 12:43:53 +00:00
#endif /* OD_PARSER_H */