%{ #include #include #include "expr.h" static gint op_column = 0; static gint yycolumn = 0; /* !! to be taken from scanner */ static GE_EXPRESSION *ph = NULL; static GList *placeholders = NULL; static compose_prefix(GE_EXPRESSION *arg, guint op); static compose_infix(GE_EXPRESSION *left, GE_EXPRESSION *right, guint op, guint prec, gint kind); static compose_free(GE_EXPRESSION *left, GE_EXPRESSION *right, gchar *op); static GE_EXPRESSION* as_alias(const gchar *str); static GE_EXPRESSION* int_to_closure(gint i); static void message(const gchar *msg, gint col); static gchar *No_expression = "No expression."; #define is_character 2 #define is_integer 7 #define is_real 13 #define is_string 17 %} %union { gchar c; gint i; guint n; gdouble d; gchar *s; GList *l; GE_EXPRESSION *x; }; %token GE_COMMENT %token GE_LBB "[[" %token GE_LCC "{{" %token GE_RCC "}}" %token GE_PP "++" %token E_WHEN E_CHECK E_UNTIL E_CLASS E_IF E_LOOP E_DO E_FROM %token E_ALL E_DEBUG E_ONCE E_CREATE E_OLD GE_ASSIGN E_LIKE %token E_SYMBOL E_ONCE_STRING E_STRFREEOP E_COMMENT E_BREAK E_KEYWORD %token GE_INLINE GE_ALIAS GE_CLOSURE GE_PLACEHOLDER %token GE_ARROW %token GE_UP_FRAME %token E_CHARACTER %token E_INTEGER %token E_REAL %token E_IDENTIFIER E_STRING %token '=' E_NE E_NOT_TILDE E_GE '>' E_LE '<' %token '^' E_MOD '*' '/' E_DIV E_FREEOP '+' '-' E_DOTDOT %token E_CHARERR E_INTERR E_REALERR E_STRERR %left E_IMPLIES %left E_OR E_XOR %left E_AND %left '=' E_NE '<' '>' E_LE E_GE '~' E_NOT_TILDE %left '+' '-' %left '*' '/' E_DIV E_MOD %right '^' %left E_DOTDOT %left E_FREEOP %left E_NOT %type multi_dot left query alias_name qualified %type args indices %type brackets %type single range open_indices detailed open_detail %type multi multi_or_all %type closure_id %type ident %type up_frame %% multi : detailed { $$ = $1; } | multi ',' detailed { $$ = expr_last($1); $$->next = $3; if ($$->details) { placeholders = g_list_last(placeholders); GE_push_back((GE_EXPRESSION**)&placeholders->data); } $$ = $1; } | multi ',' error { $$ = $1; message(No_expression, yycolumn-1); } ; detailed: range { $$ = $1; } | open_detail multi_or_all GE_RCC { $$ = $1; $$->details = $2; placeholders = g_list_last(placeholders); GE_push_back((GE_EXPRESSION**)&placeholders->data); } | open_detail multi_or_all error { message("Right double brace expected.", yycolumn); } | open_detail error { message("Expression expected.", yycolumn); } ; open_detail: range GE_LCC { $$ = $1; placeholders = g_list_append(placeholders, expr_bottom($1)); } | range '{' { message("Left double brace expected.", yycolumn); } ; multi_or_all: multi { $$ = $1; } | E_ALL { $$ = GE_new_expression(); $$->kind = is_all; $$->name = "1"; } | E_ALL E_INTEGER { $$ = GE_new_expression(); $$->kind = is_all; $$->name = "2"; } ; range : single { $$ = $1; } | open_indices indices ']' ']' { $$ = expr_bottom($1); $$->arg = $2; $$ = $1; placeholders = g_list_last(placeholders); GE_push_back((GE_EXPRESSION**)&placeholders->data); } | open_indices indices error { message("Right double bracket expected.", yycolumn); } | open_indices error { message("Indices expected.", yycolumn); } ; open_indices: single GE_LBB { $$ = GE_new_expression(); $$->parent = expr_bottom($1); $$->column = $1->column; $$->is_range = TRUE; $1->down = $$; placeholders = g_list_append(placeholders, $$); $$ = $1; } ; indices : single ',' single { $$ = $1; $$->next = $3; } | single '`' single { $$ = GE_new_expression(); $$->column = $3->column; $$->kind = is_count; $$->arg = $3; $1->next = $$; $$ = $1; } | E_ALL { $$ = GE_new_expression(); $$->column = yycolumn; $$->kind = is_all; } | E_IF single { $$ = GE_new_expression(); $$->column = $2->column; $$->kind = is_if; } | E_IF error { message(No_expression, yycolumn); } | single { message("Count or upper index expected.", yycolumn); } | single ',' error { message("Upper index expected.", yycolumn); } ; single : multi_dot { $$ = $1; } | '+' single %prec E_NOT { compose_prefix($2, plus_op); $$ = $2; } | '-' single %prec E_NOT { compose_prefix($2, minus_op); $$ = $2; } | E_NOT single { compose_prefix($2, not_op); $$ = $2; } | E_FREEOP single { compose_free(NULL, $2, $1); $$ = $2; } | '+' error { message("Operand expected.", yycolumn); } | '-' error { message("Operand expected.", yycolumn); } | E_NOT error { message("Operand expected.", yycolumn); } | E_FREEOP error { message("Operand expected.", yycolumn); } | single E_FREEOP single { compose_free($1,$3,$2); $$ = $1; } | single '^' single { compose_infix($1,$3,power_op,7,0); $$ = $1; } | single '*' single { compose_infix($1,$3,mult_op,6,0); $$ = $1; } | single '/' single { compose_infix($1,$3,div_op,6,0); $$ = $1; } | single E_DIV single { compose_infix($1,$3,idiv_op,6,0); $$ = $1; } | single E_MOD single { compose_infix($1,$3,imod_op,6,0); $$ = $1; } | single '+' single { compose_infix($1,$3,plus_op,5,0); $$ = $1; } | single '-' single { compose_infix($1,$3,minus_op,5,0); $$ = $1; } | single E_DOTDOT single { compose_infix($1,$3,interval_op,5,0); $$ = $1; } | single '=' single { compose_infix($1,$3,eq_op,4,is_equality); $$ = $1; } | single E_NE single { compose_infix($1,$3,ne_op,4,is_equality); $$ = $1; } | single '~' single { compose_infix($1,$3,sim_op,4,is_equality); $$ = $1; } | single E_NOT_TILDE single { compose_infix($1,$3,nsim_op,4,is_equality); $$ = $1; } | single '<' single { compose_infix($1,$3,lt_op,4,0); $$ = $1; } | single E_LE single { compose_infix($1,$3,le_op,4,0); $$ = $1; } | single '>' single { compose_infix($1,$3,gt_op,4,0); $$ = $1; } | single E_GE single { compose_infix($1,$3,ge_op,4,0); $$ = $1; } | single E_AND single { compose_infix($1,$3,and_op,3,0); $$ = $1; } | single E_OR single { compose_infix($1,$3,or_op,2,0); $$ = $1; } | single E_XOR single { compose_infix($1,$3,2,xor_op,0); $$ = $1; } | single E_IMPLIES single { compose_infix($1,$3,implies_op,1,0); $$ = $1; } | single E_FREEOP error { message("Right operand expected.", yycolumn); } | single '^' error { message("Right operand expected.", yycolumn); } | single '*' error { message("Right operand expected.", yycolumn); } | single '/' error { message("Right operand expected.", yycolumn); } | single E_DIV error { message("Right operand expected.", yycolumn); } | single E_MOD error { message("Right operand expected.", yycolumn); } | single '+' error { message("Right operand expected.", yycolumn); } | single '-' error { message("Right operand expected.", yycolumn); } | single '=' error { message("Right operand expected.", yycolumn); } | single E_NE error { message("Right operand expected.", yycolumn); } | single '<' error { message("Right operand expected.", yycolumn); } | single '>' error { message("Right operand expected.", yycolumn); } | single E_LE error { message("Right operand expected.", yycolumn); } | single E_GE error { message("Right operand expected.", yycolumn); } | single '~' error { message("Right operand expected.", yycolumn); } | single E_NOT_TILDE error { message("Right operand expected.", yycolumn); } | single E_AND error { message("Right operand expected.", yycolumn); } | single E_OR error { message("Right operand expected.", yycolumn); } | single E_XOR error { message("Right operand expected.", yycolumn); } | single E_IMPLIES error { message("Right operand expected.", yycolumn); } ; multi_dot: left { $$ = $1; } | multi_dot '.' qualified { $$ = expr_bottom($1); if ($3->kind == is_details) { $$->details = $3; $3->parent = $$; } else {; $$->down = $3; } $$ = $1; } | multi_dot brackets { $$ = GE_new_expression(); $$->column = $2->column; expr_bottom($1)->down = $$; $$->parent = $1; $$->kind = is_bracket; $$->arg = $2; $$ = $1; } ; qualified: query { $$ = $1; } | alias_name { if ($1->kind>0 && $1->kind!=is_details) { message("Immediate alias name must not be qualified.", yycolumn); } $$ = $1; } ; up_frame: '^' { $$ = 1; } | GE_UP_FRAME { $$ = $1; } ; left : query { $$ = $1; } | up_frame query { $$ = $2; $$->up_frame_count = $1; } | alias_name { if ($1->kind = is_details) {; message("Details may not start an expression.", yycolumn); } $$ = $1; } | '(' single ')' { $$ = $2; } | '(' single error { message("Right parenthesis expected.", yycolumn); } | '(' error ')' { message(No_expression, yycolumn); } | closure_id { $$ = $1; } | E_CHARACTER { $$ = GE_new_expression(); $$->column = yycolumn; $$->kind = is_character; $$->name = ""; /* !! should be yytext; */ } | E_STRING { $$ = GE_new_expression(); $$->column = yycolumn; $$->kind = is_string; $$->name = $1; } | E_INTEGER { $$ = GE_new_expression(); $$->column = yycolumn; $$->kind = is_integer; $$->name = ""; /* !! should be yytext; */ } | E_REAL { $$ = GE_new_expression(); $$->column = yycolumn; $$->kind = is_real; $$->name = ""; /* !! should be yytext; */ } | GE_PLACEHOLDER { if (!placeholders) { message("Placeholders are not allowed here.", yycolumn); } else if (g_list_length(placeholders) < strlen($1)) { message("Not as many nested details.", yycolumn); } ph = g_list_nth_data(placeholders, g_list_length(placeholders)-strlen($1)); if (ph) { if ($1[0]=':' && !ph->is_range) { message("Index placeholders are not allowed here.", yycolumn); } $$ = GE_new_expression(); $$->column = yycolumn-1; $$->kind = is_placeholder; $$->name = $1; $$->parent = ph; } } ; brackets: '[' args ']' { $$ = $2; op_column = yycolumn; } | '[' args error { message("Right bracket expected.", yycolumn); } | '[' error { message(No_expression, yycolumn); } ; args: single { $$ = $1; } | args ',' single { $$ = expr_last($1); $$->next = $3; $$ = $1; } | args ',' error { message(No_expression, yycolumn); } ; query : ident { $$ = GE_new_expression(); $$->column = op_column; $$->name = $1; } | ident '(' args ')' { $$ = GE_new_expression(); $$->column = op_column; $$->name = $1; $$->arg = $3; } | ident '(' ')' { message(No_expression, yycolumn); } | ident '(' args error { message("Right parenthesis expected.", yycolumn); } | ident '(' error { message(No_expression, yycolumn); } ; alias_name: GE_ALIAS { $$ = GE_new_expression(); *($$) = *as_alias($1); } ; closure_id: GE_CLOSURE { $$ = int_to_closure(atoi($1+1)); } ; ident : E_IDENTIFIER { $$ = $1; op_column = yycolumn; } ; %% static compose_prefix(GE_EXPRESSION *arg, guint op) { } static compose_infix(GE_EXPRESSION *left, GE_EXPRESSION * right, guint op, guint prec, gint kind) { } static compose_free(GE_EXPRESSION *left, GE_EXPRESSION * right, gchar *op) { } static GE_EXPRESSION* as_alias(const gchar *str) { } static GE_EXPRESSION* int_to_closure(gint i) { } static void message(const gchar *msg, gint col) { }