wireshark/tools/npl/parser.l

1430 lines
27 KiB
Plaintext

/*
* Copyright 2012-2013, Jakub Zawadzki <darkjames-ws@darkjames.pl>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
%option noyywrap
%option nounput
%option noyy_scan_buffer
%option noyy_scan_bytes
%option noyy_scan_string
%option yylineno
%option never-interactive
%option case-insensitive
%{
#define YY_DECL static token_type_t yylex(void)
#include <setjmp.h>
#include "ast.h"
#include "xmem.h"
typedef enum {
TOKEN_ERROR = -1,
TOKEN_EOF = 0,
TOKEN_INCLUDE,
TOKEN_STRUCT,
TOKEN_PRIVATE_STRUCT,
TOKEN_CONST,
TOKEN_PROTOCOL,
TOKEN_WHILE,
TOKEN_DYNAMIC_SWITCH,
TOKEN_SWITCH,
TOKEN_TABLE,
TOKEN_CASE,
TOKEN_DEFAULT,
TOKEN_ID,
TOKEN_STR,
TOKEN_CHAR,
TOKEN_DIGIT,
TOKEN_FLOAT,
TOKEN_LPAREN,
TOKEN_RPAREN,
TOKEN_LBRACKET,
TOKEN_RBRACKET,
TOKEN_LCURLY,
TOKEN_RCURLY,
TOKEN_ANDAND,
TOKEN_OROR,
TOKEN_EQUAL,
TOKEN_NOTEQUAL,
TOKEN_NOTEQUAL2,
TOKEN_LEQUAL,
TOKEN_GEQUAL,
TOKEN_ASSIGN,
TOKEN_ASSIGN_PLUS,
TOKEN_PLUS,
TOKEN_MINUS,
TOKEN_MULTIPLY,
TOKEN_DIV,
TOKEN_LOGIC_OR,
TOKEN_OR,
TOKEN_LOGIC_AND,
TOKEN_AND,
TOKEN_NOT,
TOKEN_NEG,
TOKEN_XOR,
TOKEN_SHL,
TOKEN_SHR,
TOKEN_PERCENT,
TOKEN_DOLLAR,
TOKEN_COND,
TOKEN_COLON,
TOKEN_SEMICOLON,
TOKEN_DOT,
TOKEN_COMMA,
TOKEN_LESS,
TOKEN_GREATER,
TOKEN_NUMBER,
TOKEN_UNSIGNED_NUMBER,
TOKEN_DECIMAL,
TOKEN_TIME,
TOKEN_BYTE_ORDER,
TOKEN_DISPLAY_FORMAT,
TOKEN_SIZE
} token_type_t;
%}
%x cppcomment
%x lch
%x lstr
%x lstrescape
DIGIT10 [0-9]
DIGIT16 [0-9a-fA-F]
ID [_a-zA-Z][_a-zA-Z0-9]*
%%
include return TOKEN_INCLUDE;
struct return TOKEN_STRUCT;
_struct return TOKEN_PRIVATE_STRUCT;
const return TOKEN_CONST;
protocol return TOKEN_PROTOCOL;
while return TOKEN_WHILE;
DynamicSwitch return TOKEN_DYNAMIC_SWITCH;
switch return TOKEN_SWITCH;
table return TOKEN_TABLE;
case return TOKEN_CASE;
default return TOKEN_DEFAULT;
Number return TOKEN_NUMBER;
UnsignedNumber return TOKEN_UNSIGNED_NUMBER;
Decimal return TOKEN_DECIMAL;
Time return TOKEN_TIME;
ByteOrder return TOKEN_BYTE_ORDER;
DisplayFormat return TOKEN_DISPLAY_FORMAT;
Size return TOKEN_SIZE;
"(" return TOKEN_LPAREN;
")" return TOKEN_RPAREN;
"[" return TOKEN_LBRACKET;
"]" return TOKEN_RBRACKET;
"{" return TOKEN_LCURLY;
"}" return TOKEN_RCURLY;
and return TOKEN_ANDAND;
or return TOKEN_OROR;
"==" return TOKEN_EQUAL;
"!=" return TOKEN_NOTEQUAL;
"<>" return TOKEN_NOTEQUAL2;
">=" return TOKEN_GEQUAL;
"<=" return TOKEN_LEQUAL;
"+=" return TOKEN_ASSIGN_PLUS;
"=" return TOKEN_ASSIGN;
"+" return TOKEN_PLUS;
"-" return TOKEN_MINUS;
"*" return TOKEN_MULTIPLY;
"/" return TOKEN_DIV;
"||" return TOKEN_LOGIC_OR;
"|" return TOKEN_OR;
"&&" return TOKEN_LOGIC_AND;
"&" return TOKEN_AND;
"!" return TOKEN_NOT;
"~" return TOKEN_NEG;
"^" return TOKEN_XOR;
"<<" return TOKEN_SHL;
">>" return TOKEN_SHR;
"%" return TOKEN_PERCENT;
"$" return TOKEN_DOLLAR;
"?" return TOKEN_COND;
";" return TOKEN_SEMICOLON;
"." return TOKEN_DOT;
"," return TOKEN_COMMA;
":" return TOKEN_COLON;
"<" return TOKEN_LESS;
">" return TOKEN_GREATER;
"'" yymore(); BEGIN(lch);
<lch>{
"'" BEGIN(INITIAL); return TOKEN_CHAR;
"\n" return TOKEN_ERROR;
. yymore();
}
"\"" yymore(); BEGIN(lstr);
<lstr>{
"\"" BEGIN(INITIAL); return TOKEN_STR;
"\\" yymore(); BEGIN(lstrescape);
"\n" return TOKEN_ERROR;
. yymore();
}
<lstrescape>{
"\n" return TOKEN_ERROR;
. yymore(); BEGIN(lstr);
}
"//" BEGIN(cppcomment);
<cppcomment>{
"\n" BEGIN(INITIAL);
. ;
}
"/*" {
int nested = 1;
int ch, last_ch;
last_ch = '*';
/* XXX, can comments be nested? (can't be determinated by current example file set) */
do {
ch = input();
if (last_ch == '*' && ch == '/')
nested--;
if (last_ch == '/' && ch == '*')
nested++;
if (ch == EOF)
return TOKEN_ERROR;
last_ch = ch;
} while(nested);
}
{ID} return TOKEN_ID;
{DIGIT10}+"."{DIGIT10}* return TOKEN_FLOAT;
{DIGIT10}+ return TOKEN_DIGIT;
"0x"{DIGIT16}+ return TOKEN_DIGIT;
[[:space:]] ;
. return TOKEN_ERROR;
%%
static const char *yyfilename;
static int token;
static const char *token_name(token_type_t tok) {
static char buf[64];
switch (tok) {
case TOKEN_EOF: return "<<eof>>";
case TOKEN_ERROR: return "<<error>>";
case TOKEN_ID:
return "<ID>";
case TOKEN_STR:
return "<STR>";
case TOKEN_CHAR:
return "<CHAR>";
case TOKEN_DIGIT:
return "<DIGIT>";
case TOKEN_FLOAT:
return "<FLOAT>";
case TOKEN_STRUCT:
return "struct";
case TOKEN_PRIVATE_STRUCT:
return "_struct";
case TOKEN_CONST:
return "const";
case TOKEN_WHILE:
return "while";
case TOKEN_SWITCH:
return "switch";
case TOKEN_DYNAMIC_SWITCH:
return "dynamic switch";
case TOKEN_CASE:
return "case";
/* ... */
default:
;
}
snprintf(buf, sizeof(buf), "<token #%d>", tok);
return buf;
}
static jmp_buf parser_exception;
static void xfail(void) { longjmp(parser_exception, 1); }
static void next_token(void) { token = yylex(); }
static inline int is_token(token_type_t tok) { return (token == tok); }
static void _strange(int line) {
fprintf(stdout, "?!?!? %s:%d got: %d (%s) @%s:%d\n", __FILE__, line, token, yytext, yyfilename, yylineno);
}
#define strange() _strange(__LINE__)
static void _nomatch(int line) {
fprintf(stdout, "!!!! %s:%d got: %d (%s) @%s:%d\n", __FILE__, line, token, yytext, yyfilename, yylineno);
xfail();
}
#define nomatch() _nomatch(__LINE__)
static void _accept(token_type_t tok, int line) {
if (tok != token) {
fprintf(stdout, "%s:%d got: %d (%s) expected %s @%s:%d\n", __FILE__, line, token, yytext, token_name(tok), yyfilename, yylineno);
xfail();
}
next_token();
}
#define accept(tok) _accept(tok, __LINE__)
static int is_id(void) {
/* Some NPL files use keyword as ID (sucks...) */
return
is_token(TOKEN_PROTOCOL) ||
is_token(TOKEN_SIZE) ||
is_token(TOKEN_DEFAULT) ||
is_token(TOKEN_NUMBER) ||
is_token(TOKEN_DECIMAL) ||
is_token(TOKEN_TIME) ||
is_token(TOKEN_BYTE_ORDER) ||
is_token(TOKEN_OROR) || is_token(TOKEN_ANDAND) ||
is_token(TOKEN_STRUCT) || is_token(TOKEN_TABLE) ||
is_token(TOKEN_ID);
}
static char *_accept_id(int line) {
char *id;
if (!is_id()) {
fprintf(stdout, "%s:%d got: %d (%s) expected %s @%s:%d\n", __FILE__, line, token, yytext, token_name(TOKEN_ID), yyfilename, yylineno);
xfail();
}
id = xstrdup(yytext);
next_token();
return id;
}
#define accept_id() _accept_id(__LINE__)
static unsigned int _accept_int(int line) {
unsigned int num;
if (token != TOKEN_DIGIT) {
fprintf(stdout, "%s:%d got: %d (%s) expected %s @%s:%d\n", __FILE__, line, token, yytext, token_name(TOKEN_DIGIT), yyfilename, yylineno);
xfail();
}
if (yytext[0] == '0' && yytext[1] == 'x')
num = strtol(yytext + 2, NULL, 16);
else
num = strtol(yytext, NULL, 10);
next_token();
return num;
}
#define accept_int() _accept_int(__LINE__)
static char *_accept_str(int line) {
size_t len;
char *str;
if (token != TOKEN_STR) {
fprintf(stdout, "%s:%d got: %d (%s) expected %s @%s:%d\n", __FILE__, line, token, yytext, token_name(TOKEN_STR), yyfilename, yylineno);
xfail();
}
len = strlen(yytext);
if (len < 2 || yytext[0] != '"' || yytext[len-1] != '"')
xfail();
#if 0
char *ptr;
size_t i;
ptr = str = xmalloc(len-2+1);
for (i = 1; i < len-1; i++) {
if (yytext[i] == '\\') {
i++;
if (yytext[i] == '0' && yytext[i+1] == 'x') {
i += 2;
// XXX
*ptr++ = yytext[i];
} else
switch (yytext[i]) {
case '0':
*ptr++ = '\0';
break;
case '\\':
*ptr++ = '\\';
break;
case 'r':
*ptr++ = '\r';
break;
case 'n':
*ptr++ = '\n';
break;
case 't':
*ptr++ = '\t';
break;
case '"':
*ptr++ = '"';
break;
case '\'':
*ptr++ = '\'';
break;
default:
fprintf(stdout, "unrecog: %c @ %d\n", yytext[i], yylineno);
*ptr++ = yytext[i];
}
} else
*ptr++ = yytext[i];
}
*ptr = '\0';
#else
len -= 2;
/* escaping is done almost like in C so don't unescape (cause it'd require escaping later...) */
str = xmalloc(len + 1);
memcpy(str, yytext + 1, len);
str[len] = '\0';
#endif
next_token();
return str;
}
#define accept_str() _accept_str(__LINE__)
static int is_token_accept(token_type_t tok) {
if (is_token(tok)) {
next_token();
return 1;
}
return 0;
}
static int is_params(void) { return is_token(TOKEN_LPAREN); }
static void
parse_params(npl_params_t *p)
{
int i = 0;
accept(TOKEN_LPAREN);
do {
if (i == NPL_PARAMS_MAX) {
fprintf(stdout, "i == NPL_PARAMS_MAX");
xfail();
}
p->args[i++] = accept_id();
} while (is_token_accept(TOKEN_COMMA));
accept(TOKEN_RPAREN);
p->count = i;
}
static void parse_expression(npl_expression_t *expr);
static npl_expression_t *xparse_expression(void);
static void
parse_primary(npl_expression_t *expr)
{
if (is_id()) {
expr->type = EXPRESSION_ID;
expr->id.id = accept_id();
return;
}
if (is_token(TOKEN_DIGIT)) {
expr->type = EXPRESSION_INT;
expr->num.digit = accept_int();
return;
}
if (is_token(TOKEN_FLOAT)) {
// XXX ast
accept(TOKEN_FLOAT);
expr->type = -1;
return;
}
if (is_token(TOKEN_CHAR)) {
// XXX ast
accept(TOKEN_CHAR);
expr->type = -2;
return;
}
if (is_token(TOKEN_STR)) {
expr->type = EXPRESSION_STR;
expr->str.str = accept_str();
return;
}
if (is_token_accept(TOKEN_LPAREN)) {
parse_expression(expr);
accept(TOKEN_RPAREN);
return;
}
nomatch();
}
/* ExpressionList = Expression, { ",", Expression } ; */
static void
parse_expression_list(npl_expression_list_t **ptr)
{
do {
npl_expression_list_t *cur = xnew(npl_expression_list_t);
*ptr = cur;
ptr = &(cur->next);
cur->expr = xparse_expression();
} while (is_token_accept(TOKEN_COMMA));
*ptr = NULL;
}
static void
parse_expression1(npl_expression_t *expr)
{
parse_primary(expr);
do {
if (is_token_accept(TOKEN_LPAREN)) { /* foo() */
npl_expression_t *fun = xdup(npl_expression_t, expr);
npl_expression_list_t *args = NULL;
if (!is_token(TOKEN_RPAREN))
parse_expression_list(&args);
accept(TOKEN_RPAREN);
expr->type = EXPRESSION_CALL;
expr->call.fn = fun;
expr->call.args = args;
} else if (is_token_accept(TOKEN_DOLLAR)) { /* arr$[field1, field2, ...] */
npl_expression_t *base = xdup(npl_expression_t, expr);
npl_expression_list_t *indexes;
accept(TOKEN_LBRACKET);
parse_expression_list(&indexes);
accept(TOKEN_RBRACKET);
expr->type = EXPRESSION_MULTI_INDEX;
expr->aarr.base = base;
expr->aarr.indexes = indexes;
} else if (is_token_accept(TOKEN_LBRACKET)) { /* arr[10] */
npl_expression_t *base = xdup(npl_expression_t, expr);
npl_expression_t *idx;
idx = xparse_expression();
accept(TOKEN_RBRACKET);
expr->type = EXPRESSION_INDEX;
expr->arr.base = base;
expr->arr.index = idx;
} else if (is_token_accept(TOKEN_DOT)) {
npl_expression_t *base = xdup(npl_expression_t, expr);
char *field;
field = accept_id();
expr->type = EXPRESSION_FIELD;
expr->fld.base = base;
expr->fld.field = field;
} else
break;
} while (1);
}
static void
parse_expression2(npl_expression_t *expr)
{
npl_op1_t op;
do {
op =
(is_token_accept(TOKEN_MINUS)) ? OP1_MINUS :
(is_token_accept(TOKEN_NOT)) ? OP1_NOT :
(is_token_accept(TOKEN_NEG)) ? OP1_NEG :
OP1_INVALID;
if (op != OP1_INVALID) {
expr->type = EXPRESSION_UNARY;
expr->u.operator = op;
expr = expr->u.operand = xnew(npl_expression_t);
}
} while (op != OP1_INVALID);
parse_expression1(expr);
}
static void
parse_expression3(npl_expression_t *expr)
{
npl_op2_t op;
parse_expression2(expr);
again:
op =
(is_token_accept(TOKEN_MULTIPLY)) ? OP2_MULTIPLY :
(is_token_accept(TOKEN_DIV)) ? OP2_DIV :
(is_token_accept(TOKEN_PERCENT)) ? OP2_MOD :
OP2_INVALID;
if (op != OP2_INVALID) {
npl_expression_t *operand = xdup(npl_expression_t, expr);
npl_expression_t *e;
expr->b.operand2 = e = xnew(npl_expression_t);
parse_expression3(e);
expr->b.operator = op;
expr->b.operand1 = operand;
expr->type = EXPRESSION_BINARY;
goto again;
}
}
static void
parse_expression4(npl_expression_t *expr)
{
npl_op2_t op;
parse_expression3(expr);
again:
op =
(is_token_accept(TOKEN_PLUS)) ? OP2_PLUS :
(is_token_accept(TOKEN_MINUS)) ? OP2_MINUS :
OP2_INVALID;
if (op != OP2_INVALID) {
npl_expression_t *operand = xdup(npl_expression_t, expr);
npl_expression_t *e;
expr->b.operand2 = e = xnew(npl_expression_t);
parse_expression4(e);
expr->b.operator = op;
expr->b.operand1 = operand;
expr->type = EXPRESSION_BINARY;
goto again;
}
}
static void
parse_expression5(npl_expression_t *expr)
{
npl_op2_t op;
parse_expression4(expr);
again:
op =
(is_token_accept(TOKEN_SHL)) ? OP2_SHL :
(is_token_accept(TOKEN_SHR)) ? OP2_SHR :
OP2_INVALID;
if (op != OP2_INVALID) {
npl_expression_t *operand = xdup(npl_expression_t, expr);
npl_expression_t *e;
expr->b.operand2 = e = xnew(npl_expression_t);
parse_expression5(e);
expr->b.operator = op;
expr->b.operand1 = operand;
expr->type = EXPRESSION_BINARY;
goto again;
}
}
static void
parse_expression6(npl_expression_t *expr)
{
npl_op2_t op;
parse_expression5(expr);
again:
op =
(is_token_accept(TOKEN_LESS)) ? OP2_LESS :
(is_token_accept(TOKEN_GREATER)) ? OP2_GREATER :
(is_token_accept(TOKEN_LEQUAL)) ? OP2_LEQUAL :
(is_token_accept(TOKEN_GEQUAL)) ? OP2_GEQUAL :
OP2_INVALID;
if (op != OP2_INVALID) {
npl_expression_t *operand = xdup(npl_expression_t, expr);
npl_expression_t *e;
expr->b.operand2 = e = xnew(npl_expression_t);
parse_expression6(e);
expr->b.operator = op;
expr->b.operand1 = operand;
expr->type = EXPRESSION_BINARY;
goto again;
}
}
static void
parse_expression7(npl_expression_t *expr)
{
npl_op2_t op;
parse_expression6(expr);
again:
op =
(is_token_accept(TOKEN_EQUAL)) ? OP2_EQUAL :
(is_token_accept(TOKEN_NOTEQUAL)) ? OP2_NOTEQUAL :
(is_token_accept(TOKEN_NOTEQUAL2)) ? OP2_NOTEQUAL :
OP2_INVALID;
if (op != OP2_INVALID) {
npl_expression_t *operand = xdup(npl_expression_t, expr);
npl_expression_t *e;
expr->b.operand2 = e = xnew(npl_expression_t);
parse_expression7(e);
expr->b.operator = op;
expr->b.operand1 = operand;
expr->type = EXPRESSION_BINARY;
goto again;
}
}
static void
parse_expression8(npl_expression_t *expr)
{
parse_expression7(expr);
again:
if (is_token_accept(TOKEN_AND)) {
npl_expression_t *operand = xdup(npl_expression_t, expr);
npl_expression_t *e;
expr->b.operand2 = e = xnew(npl_expression_t);
parse_expression8(e);
expr->b.operator = OP2_AND;
expr->b.operand1 = operand;
expr->type = EXPRESSION_BINARY;
goto again;
}
}
static void
parse_expression9(npl_expression_t *expr)
{
parse_expression8(expr);
again:
if (is_token_accept(TOKEN_XOR)) {
npl_expression_t *operand = xdup(npl_expression_t, expr);
npl_expression_t *e;
expr->b.operand2 = e = xnew(npl_expression_t);
parse_expression9(e);
expr->b.operator = OP2_XOR;
expr->b.operand1 = operand;
expr->type = EXPRESSION_BINARY;
goto again;
}
}
static void
parse_expression10(npl_expression_t *expr)
{
parse_expression9(expr);
again:
if (is_token_accept(TOKEN_OR)) {
npl_expression_t *operand = xdup(npl_expression_t, expr);
npl_expression_t *e;
expr->b.operand2 = e = xnew(npl_expression_t);
parse_expression10(e);
expr->b.operator = OP2_OR;
expr->b.operand1 = operand;
expr->type = EXPRESSION_BINARY;
goto again;
}
}
static void
parse_expression11(npl_expression_t *expr)
{
npl_op2_t op;
parse_expression10(expr);
again:
op =
(is_token_accept(TOKEN_LOGIC_AND)) ? OP2_LOGIC_AND :
(is_token_accept(TOKEN_ANDAND)) ? OP2_LOGIC_AND :
OP2_INVALID;
if (op != OP2_INVALID) {
npl_expression_t *operand = xdup(npl_expression_t, expr);
npl_expression_t *e;
expr->b.operand2 = e = xnew(npl_expression_t);
parse_expression11(e);
expr->b.operator = op;
expr->b.operand1 = operand;
expr->type = EXPRESSION_BINARY;
goto again;
}
}
static void
parse_expression12(npl_expression_t *expr)
{
npl_op2_t op;
parse_expression11(expr);
again:
op =
(is_token_accept(TOKEN_LOGIC_OR)) ? OP2_LOGIC_OR :
(is_token_accept(TOKEN_OROR)) ? OP2_LOGIC_OR :
OP2_INVALID;
if (op != OP2_INVALID) {
npl_expression_t *operand = xdup(npl_expression_t, expr);
npl_expression_t *e;
expr->b.operand2 = e = xnew(npl_expression_t);
parse_expression12(e);
expr->b.operator = op;
expr->b.operand1 = operand;
expr->type = EXPRESSION_BINARY;
goto again;
}
}
static void
parse_expression13(npl_expression_t *expr)
{
parse_expression12(expr);
if (is_token_accept(TOKEN_COND)) {
npl_expression_t *operand = xdup(npl_expression_t, expr);
npl_expression_t *e;
expr->c.test_expr = operand;
e = xnew(npl_expression_t);
parse_expression(e);
expr->c.true_expr = e;
accept(TOKEN_COLON);
e = xnew(npl_expression_t);
parse_expression13(e);
expr->c.false_expr = e;
expr->type = EXPRESSION_COND;
}
}
static npl_expression_t *
xparse_expression(void)
{
npl_expression_t *expr = xnew(npl_expression_t);
parse_expression(expr);
return expr;
}
static void
parse_expression(npl_expression_t *expr)
{
npl_op2_t op;
parse_expression13(expr);
op =
(is_token_accept(TOKEN_ASSIGN)) ? OP2_ASSIGN :
(is_token_accept(TOKEN_ASSIGN_PLUS)) ? OP2_ASSIGN_PLUS :
OP2_INVALID;
if (op != OP2_INVALID) {
npl_expression_t *operand = xdup(npl_expression_t, expr);
expr->b.operand2 = xparse_expression();
expr->b.operator = op;
expr->b.operand1 = operand;
expr->type = EXPRESSION_BINARY;
}
}
static int is_attribute(void) { return is_token(TOKEN_LBRACKET); }
static npl_attribute_list_t **
pparse_attributes(npl_attribute_list_t **ptr)
{
accept(TOKEN_LBRACKET);
do {
npl_attribute_list_t *cur = xnew(npl_attribute_list_t);
*ptr = cur;
ptr = &(cur->next);
cur->expr = xparse_expression();
if (is_token_accept(TOKEN_SEMICOLON))
{ }
else if (is_token_accept(TOKEN_COMMA))
{ }
}
while (!is_token(TOKEN_RBRACKET));
// while (is_token_accept(TOKEN_COMMA));
accept(TOKEN_RBRACKET);
return ptr;
}
static void
parse_all_attributes(npl_attribute_list_t **attr_ptr)
{
while (is_attribute())
attr_ptr = pparse_attributes(attr_ptr);
*attr_ptr = NULL;
}
static void parse_statement(npl_statement_t *st);
static npl_statement_t *
xparse_statement(void)
{
npl_statement_t *st = xnew(npl_statement_t);
parse_statement(st);
return st;
}
static void
parse_switch_body(npl_switch_t *sw)
{
struct npl_switch_case **ptr = &sw->cases;
while (is_token(TOKEN_CASE)) {
struct npl_switch_case *cur = xnew(struct npl_switch_case);
*ptr = cur;
ptr = &(cur->next);
accept(TOKEN_CASE);
parse_expression(&cur->e);
accept(TOKEN_COLON);
if (!is_token(TOKEN_CASE) && !is_token(TOKEN_DEFAULT)) {
cur->st = xparse_statement();
is_token_accept(TOKEN_SEMICOLON);
}
}
*ptr = NULL;
if (is_token_accept(TOKEN_DEFAULT)) {
accept(TOKEN_COLON);
sw->default_st = xparse_statement();
}
}
static void
parse_switch(npl_switch_t *sw)
{
accept(TOKEN_SWITCH);
if (is_token_accept(TOKEN_LPAREN)) {
sw->switch_expr = xparse_expression();
accept(TOKEN_RPAREN);
}
accept(TOKEN_LCURLY);
parse_switch_body(sw);
accept(TOKEN_RCURLY);
is_token_accept(TOKEN_SEMICOLON);
}
static void
parse_dynamic_switch(npl_switch_t *sw)
{
accept(TOKEN_DYNAMIC_SWITCH);
sw->switch_expr = xparse_expression();
accept(TOKEN_LCURLY);
parse_switch_body(sw);
accept(TOKEN_RCURLY);
is_token_accept(TOKEN_SEMICOLON);
}
static int is_statement(void) {
return
is_token(TOKEN_WHILE) ||
is_token(TOKEN_TABLE) ||
is_token(TOKEN_STRUCT) || is_token(TOKEN_PRIVATE_STRUCT) ||
is_token(TOKEN_SWITCH) || is_token(TOKEN_DYNAMIC_SWITCH) ||
is_id() || is_attribute() ||
#if 1
is_token(TOKEN_SEMICOLON) ||
#endif
0
;
}
/* Statements = { Statement } ; */
static struct _npl_statements *
xparse_statements(void)
{
struct _npl_statements *ret;
struct _npl_statements **ptr = &ret;
while (is_statement()) {
struct _npl_statements *cur = xnew(struct _npl_statements);
parse_statement(&cur->st);
*ptr = cur;
ptr = &(cur->next);
}
*ptr = NULL;
return ret;
}
static void
parse_while(npl_statement_t *st)
{
accept(TOKEN_WHILE);
if (is_id())
st->w.id = accept_id();
accept(TOKEN_LBRACKET);
parse_expression(&st->w.expr);
accept(TOKEN_RBRACKET);
accept(TOKEN_LCURLY);
st->w.sts = xparse_statements();
accept(TOKEN_RCURLY);
is_token_accept(TOKEN_SEMICOLON);
}
static int is_formatting(void) { return is_token(TOKEN_ASSIGN); }
/* Formatting = "=", Expression ; */
static npl_expression_t *
xparse_formatting(void)
{
npl_expression_t *format;
accept(TOKEN_ASSIGN);
format = xnew(npl_expression_t);
parse_expression(format);
return format;
}
static void parse_table(npl_table_t *);
static void parse_struct(npl_struct_t *s, int statement);
static void
parse_statement(npl_statement_t *st)
{
parse_all_attributes(&st->attr_list);
if (is_token(TOKEN_WHILE)) {
parse_while(st);
st->type = STATEMENT_WHILE;
return;
}
if (is_token(TOKEN_TABLE)) {
parse_table(&st->t.data);
st->type = STATEMENT_TABLE;
return;
}
if (is_token(TOKEN_STRUCT) || is_token(TOKEN_PRIVATE_STRUCT)) {
parse_struct(&st->s.data, 1);
st->type = STATEMENT_STRUCT;
return;
}
if (is_token(TOKEN_SWITCH)) {
parse_switch(&(st->sw.data));
st->type = STATEMENT_SWITCH;
return;
}
if (is_token(TOKEN_DYNAMIC_SWITCH)) {
parse_dynamic_switch(&(st->sw.data));
st->type = STATEMENT_DYNAMIC_SWITCH;
return;
}
#if 1
if (is_token(TOKEN_SEMICOLON)) {
accept(TOKEN_SEMICOLON);
st->type = -3;
return;
}
#endif
st->type = STATEMENT_FIELD;
st->f.t_id = accept_id();
if (is_token_accept(TOKEN_LPAREN)) {
parse_expression_list(&st->f.params);
accept(TOKEN_RPAREN);
} else
st->f.params = NULL;
st->f.id = accept_id();
if (is_token_accept(TOKEN_COLON))
st->f.bits = accept_int();
else if (is_token_accept(TOKEN_LBRACKET)) {
st->f.arr = xparse_expression();
accept(TOKEN_RBRACKET);
}
if (is_formatting())
st->f.format = xparse_formatting();
if (is_token_accept(TOKEN_LCURLY)) {
st->f.sts = xparse_statements();
accept(TOKEN_RCURLY);
is_token_accept(TOKEN_SEMICOLON);
return;
}
accept(TOKEN_SEMICOLON);
}
/* Protocol = "protocol", ID, [Params], [Formatting], "{", Statements, "}", ";" ; */
static void
parse_protocol(npl_protocol_t *p)
{
accept(TOKEN_PROTOCOL);
p->id = accept_id();
if (is_params())
parse_params(&p->params);
if (is_formatting())
p->format = xparse_formatting();
accept(TOKEN_LCURLY);
p->sts = xparse_statements();
accept(TOKEN_RCURLY);
is_token_accept(TOKEN_SEMICOLON);
}
static void
parse_struct(npl_struct_t *s, int statement)
{
if (is_token_accept(TOKEN_STRUCT))
s->private = 0;
else if (is_token_accept(TOKEN_PRIVATE_STRUCT))
s->private = 1;
else
nomatch();
if (!statement || is_id())
s->id = accept_id();
if (is_params())
parse_params(&s->params);
if (statement) {
if (is_token_accept(TOKEN_LBRACKET)) {
s->count_expr = xparse_expression();
accept(TOKEN_RBRACKET);
}
}
if (is_formatting())
s->format = xparse_formatting();
accept(TOKEN_LCURLY);
s->sts = xparse_statements();
accept(TOKEN_RCURLY);
is_token_accept(TOKEN_SEMICOLON);
}
/* Table = "table", ID, [Params], "{", "switch", [ "(", Expr, ")" ], {TableCase}, [DefaultCase], "}", ";" ;
DefaultCase = "default", ":", Expression", ";" ;
*/
static void
parse_table(npl_table_t *t)
{
accept(TOKEN_TABLE);
t->id = accept_id();
if (is_params())
parse_params(&t->params);
accept(TOKEN_LCURLY);
{
struct npl_table_case **ptr;
accept(TOKEN_SWITCH);
if (is_token_accept(TOKEN_LPAREN)) {
t->switch_expr = xparse_expression();
accept(TOKEN_RPAREN);
}
accept(TOKEN_LCURLY);
ptr = &(t->cases);
while (is_token_accept(TOKEN_CASE)) {
struct npl_table_case *cur;
cur = *ptr = xnew(struct npl_table_case);
ptr = &(cur->next);
parse_expression(&(cur->e));
accept(TOKEN_COLON);
while (is_token_accept(TOKEN_CASE)) {
cur = *ptr = xnew(struct npl_table_case);
ptr = &(cur->next);
parse_expression(&(cur->e));
accept(TOKEN_COLON);
}
cur->return_expr = xparse_expression();
accept(TOKEN_SEMICOLON);
}
*ptr = NULL;
if (is_token_accept(TOKEN_DEFAULT)) {
accept(TOKEN_COLON);
t->default_expr = xparse_expression();
accept(TOKEN_SEMICOLON);
}
accept(TOKEN_RCURLY);
}
accept(TOKEN_RCURLY);
is_token_accept(TOKEN_SEMICOLON);
}
static int
is_type(void)
{
return
is_token(TOKEN_DECIMAL) ||
is_token(TOKEN_NUMBER) ||
is_token(TOKEN_TIME) ||
is_token(TOKEN_UNSIGNED_NUMBER);
}
/* Type = BasicType, ID, [Params], "{", {TypeAttr}, "}" ;
BasicType = "Decimal" | "Number" | "Time" | "UnsignedNumber" ;
TypeAttr = AttrName, "=", Expression ;
AttrName = "ByteOrder" | "DisplayFormat" | "Size" ;
*/
static void
parse_type(npl_type_t *t)
{
if (is_token_accept(TOKEN_DECIMAL))
t->type = FIELD_DECIMAL;
else if (is_token_accept(TOKEN_NUMBER))
t->type = FIELD_NUMBER;
else if (is_token_accept(TOKEN_TIME))
t->type = FIELD_TIME;
else if (is_token_accept(TOKEN_UNSIGNED_NUMBER))
t->type = FIELD_UNSIGNED_NUMBER;
else
nomatch();
t->id = accept_id();
if (is_params())
parse_params(&t->params);
accept(TOKEN_LCURLY);
while (!is_token(TOKEN_RCURLY)) {
npl_expression_t **ptr;
if (is_token_accept(TOKEN_BYTE_ORDER))
ptr = &t->byte_order;
else if (is_token_accept(TOKEN_DISPLAY_FORMAT))
ptr = &t->display_format;
else if (is_token_accept(TOKEN_SIZE))
ptr = &t->size;
else
nomatch();
#if 0
if (*ptr)
fprintf(stdout, "already got %s attr!\n", str);
#endif
accept(TOKEN_ASSIGN);
*ptr = xparse_expression();
if (is_token_accept(TOKEN_COMMA))
{ }
else if (is_token_accept(TOKEN_SEMICOLON))
{ }
}
accept(TOKEN_RCURLY);
}
/* Const = "const", ID, "=", Expression, ";" ; */
static void
parse_const(npl_const_t *c)
{
accept(TOKEN_CONST);
c->id = accept_id();
accept(TOKEN_ASSIGN);
parse_expression(&c->expr);
accept(TOKEN_SEMICOLON);
}
/* Declaration = Attributes
| Struct
| Table
| Const
| Protocol
| Type
| ( "include", STR )
;
*/
static void
parse_decl(npl_decl_t *d)
{
parse_all_attributes(&d->attr_list);
if (is_token(TOKEN_STRUCT)) {
d->type = DECL_STRUCT;
parse_struct(&d->s.data, 0);
} else if (is_token(TOKEN_TABLE)) {
d->type = DECL_TABLE;
parse_table(&d->t.data);
} else if (is_token(TOKEN_CONST)) {
d->type = DECL_CONST;
parse_const(&d->c.data);
} else if (is_token(TOKEN_PROTOCOL)) {
d->type = DECL_PROTOCOL;
parse_protocol(&d->p.data);
} else if (is_type()) {
d->type = DECL_TYPE;
parse_type(&d->ty.data);
} else if (is_token_accept(TOKEN_INCLUDE)) {
d->type = DECL_INCLUDE;
d->i.file = accept_str(); /* XXX, it's C-escaped */ /* XXX, unix / vs dos \\ */
} else
nomatch();
}
/* NPL = { Declaration } ; */
static void
parse_npl(npl_code_t *code)
{
struct _npl_decl_list **ptr = &(code->decls);
while (!is_token_accept(TOKEN_EOF)) {
struct _npl_decl_list *cur = xnew(struct _npl_decl_list);
*ptr = cur;
ptr = &(cur->next);
parse_decl(&cur->d);
}
*ptr = NULL;
}
int
npl_parse_file(npl_code_t *code, FILE *f, const char *filename)
{
volatile int parse_ok = 0;
yyfilename = filename;
yyin = f;
if (!setjmp(parser_exception)) {
next_token();
parse_npl(code);
parse_ok = 1;
}
yylex_destroy();
return (parse_ok == 1);
}