/* * Copyright 2012-2013, Jakub Zawadzki * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ %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 #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); { "'" BEGIN(INITIAL); return TOKEN_CHAR; "\n" return TOKEN_ERROR; . yymore(); } "\"" yymore(); BEGIN(lstr); { "\"" BEGIN(INITIAL); return TOKEN_STR; "\\" yymore(); BEGIN(lstrescape); "\n" return TOKEN_ERROR; . yymore(); } { "\n" return TOKEN_ERROR; . yymore(); BEGIN(lstr); } "//" BEGIN(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 "<>"; case TOKEN_ERROR: return "<>"; case TOKEN_ID: return ""; case TOKEN_STR: return ""; case TOKEN_CHAR: return ""; case TOKEN_DIGIT: return ""; case TOKEN_FLOAT: return ""; 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), "", 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); }