/* $Id: cmd.y,v 1.39 2004/04/03 04:17:37 jmuelmen Exp $ */ %{ #include #include #include #include #include #include "parse.h" #include "shell.h" #include "act.h" extern char *yytext; extern int yyint; extern double yyfloat; char yy_empty_file; #define yylex() ambush_lex() int ambush_lex (); void yyerror (const char *s) { printf("%s\n", s); } #define parse_err(x, args...) \ { fflush(stdout); \ printf("Error: "); \ printf((x), (args)); \ printf("\n"); \ return 1; \ } %} %token IDENTIFIER STRING_LITERAL INT_CONST FLOAT_CONST TIME_CONST PERIOD_CONST %token INT FLOAT STRING TIME PERIOD DECL %token INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP %token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN %token SUB_ASSIGN AND_ASSIGN %token XOR_ASSIGN OR_ASSIGN %token IF AT EVERY ATOMIC SEQUENTIAL %start file /* For the grammar we mostly lobotomize Jeff Lee's ANSI C grammar. * Jutta Degener maintains the ANSI C grammar at * http://www.lysator.liu.se/c/ANSI-C-grammar-y.html */ %% primary_expr : identifier { parse_action_t *act; value_t *args[1]; args[0] = &ident_get_idx($1)->cont.val; /* if the identifier is undeclared, bitch about it */ if (!ident_get_idx($1)->is_declared) parse_err("Undeclared identifier %s", ident_get_idx($1)->name); /* make the action */ act = parse_action_create(fetch_ident, args, 1); /* stick it in the parse buffer and return the index */ $$ = parsebuf_buf(act); } | INT_CONST { /* make a no-op action and set the return value to our * integer constant */ parse_action_t *act = parse_action_create(NULL, 0, 0); value_t ret_val; ret_val.val_type = val_int; ret_val.value.v_int = yyint; value_copy(&act->ret, &ret_val); /* stick it in the parse buffer and return the index */ $$ = parsebuf_buf(act); } | FLOAT_CONST { parse_action_t *act = parse_action_create(NULL, 0, 0); value_t ret_val; ret_val.val_type = val_float; ret_val.value.v_float = yyfloat; value_copy(&act->ret, &ret_val); $$ = parsebuf_buf(act); } | TIME_CONST { parse_action_t *act = parse_action_create(NULL, 0, 0); value_t ret_val; ret_val.val_type = val_time; /* parse the time out of the string */ atot(&ret_val.value.v_time, yytext); value_copy(&act->ret, &ret_val); $$ = parsebuf_buf(act); } | PERIOD_CONST | STRING_LITERAL { parse_action_t *act = parse_action_create(NULL, 0, 0); value_t ret_val = { val_string }; /* get the literal, but kill the leading and trailing quote */ strncpy(ret_val.value.v_string, yytext + 1, STRING_LIT_LEN); ret_val.value.v_string[strlen(ret_val.value.v_string) - 1] = 0; value_copy(&act->ret, &ret_val); $$ = parsebuf_buf(act); } | '(' expr ')' { $$ = $2; } ; postfix_expr : primary_expr | identifier '(' ')' { parse_action_t *act = parse_action_create(NULL, 0, 0); ident_t *id = ident_get_idx($1); /* check that the identifier is a function name */ if (id->type != func) parse_err("%s is not a function name", id->name); act->type = call_s; act->statement.func_call.func = id->cont.func; act->statement.func_call.arg_list = NULL; /* we should check that the function accepts no arguments! */ /* ... do stuff here ... */ $$ = parsebuf_buf(act); } | identifier '(' argument_expr_list ')' { parse_action_t *act = parse_action_create(NULL, 0, 0); ident_t *id = ident_get_idx($1); parse_action_t *argl = parsebuf_get_idx($3); /* check that the identifier is a function name */ if (id->type != func) parse_err("%s is not a function name", id->name); act->type = call_s; act->statement.func_call.func = id->cont.func; act->statement.func_call.arg_list = argl; /* we should check that the arguments match up */ /* ... do stuff here ... */ $$ = parsebuf_buf(act); } | postfix_expr INC_OP { value_t *args[1]; parse_action_t *act; /* fix me! I want to be the identifier lookup! */ args[0] = &parsebuf_get_idx($1)->ret; act = parse_action_create(inc_post, args, 1); if (typecheck_inc_post(&act->ret, args, 1)) parse_err("Incompatible type in increment %s", ""); $$ = parsebuf_buf(act); } | postfix_expr DEC_OP { value_t *args[1]; parse_action_t *act; printf("Postfix decrement\n"); args[0] = &parsebuf_get_idx($1)->ret; act = parse_action_create(dec_post, args, 1); if (typecheck_dec_post(&act->ret, args, 1)) parse_err("Incompatible type in decrement %s", ""); $$ = parsebuf_buf(act); } ; argument_expr_list : assignment_expr { /* make a call_s-typed parse action whose first argument is the value of the argument expression */ parse_action_t *act = parse_action_create(NULL, 0, 0); value_t *val = &parsebuf_get_idx($1)->ret; act->type = call_s; act->args[0] = val; act->statement.func_call.func = NULL; act->statement.func_call.arg_list = NULL; $$ = parsebuf_buf(act); } | argument_expr_list ',' assignment_expr { /* make a call_s-typed parse action whose first argument is the value of the argument expression */ parse_action_t *act = parse_action_create(NULL, 0, 0); parse_action_t *prev = parsebuf_get_idx($1); value_t *val = &parsebuf_get_idx($3)->ret; int argc = 0; act->type = call_s; act->args[0] = val; act->statement.func_call.func = NULL; act->statement.func_call.arg_list = NULL; /* tack the new argument on to the existing arg list */ while (prev->statement.func_call.arg_list) { prev = prev->statement.func_call.arg_list; argc++; } if (argc > MAX_ARGS) parse_err("Too many arguments to %s!", ""); prev->statement.func_call.arg_list = act; parsebuf_buf(act); } ; unary_expr : postfix_expr | INC_OP identifier { value_t *args[1]; parse_action_t *act; args[0] = &ident_get_idx($2)->cont.val; if (!ident_get_idx($1)->is_declared) parse_err("Undeclared identifier %s", ident_get_idx($1)->name); act = parse_action_create(inc_pre, args, 1); if (typecheck_inc_pre(&act->ret, args, 1)) parse_err("Incompatible type in increment %s", ""); $$ = parsebuf_buf(act); } | DEC_OP identifier { value_t *args[1]; parse_action_t *act; args[0] = &parsebuf_get_idx($2)->ret; act = parse_action_create(dec_pre, args, 1); if (typecheck_dec_pre(&act->ret, args, 1)) parse_err("Incompatible type in decrement %s", ""); $$ = parsebuf_buf(act); } ; unary_operator : '+' | '-' | '!' ; cast_expr : unary_expr ; multiplicative_expr : cast_expr | multiplicative_expr '*' cast_expr { value_t *args[2]; parse_action_t *act; args[0] = &parsebuf_get_idx($1)->ret; args[1] = &parsebuf_get_idx($3)->ret; act = parse_action_create(multiply, args, 2); if (typecheck_multiply(&act->ret, args, 2)) parse_err("Incompatible types in subtraction %s", ""); $$ = parsebuf_buf(act); } | multiplicative_expr '/' cast_expr { value_t *args[2]; parse_action_t *act; args[0] = &parsebuf_get_idx($1)->ret; args[1] = &parsebuf_get_idx($3)->ret; act = parse_action_create(divide, args, 2); if (typecheck_divide(&act->ret, args, 2)) parse_err("Incompatible types in division %s", ""); $$ = parsebuf_buf(act); } | multiplicative_expr '%' cast_expr { value_t *args[2]; parse_action_t *act; args[0] = &parsebuf_get_idx($1)->ret; args[1] = &parsebuf_get_idx($3)->ret; act = parse_action_create(modulus, args, 2); if (typecheck_modulus(&act->ret, args, 2)) parse_err("Incompatible types in division %s", ""); $$ = parsebuf_buf(act); } ; additive_expr : multiplicative_expr | additive_expr '+' multiplicative_expr { value_t *args[2]; parse_action_t *act; args[0] = &parsebuf_get_idx($1)->ret; args[1] = &parsebuf_get_idx($3)->ret; act = parse_action_create(add, args, 2); if (typecheck_add(&act->ret, args, 2)) parse_err("Incompatible types in addition %s", ""); $$ = parsebuf_buf(act); } | additive_expr '-' multiplicative_expr { value_t *args[2]; parse_action_t *act; args[0] = &parsebuf_get_idx($1)->ret; args[1] = &parsebuf_get_idx($3)->ret; act = parse_action_create(subtract, args, 2); if (typecheck_subtract(&act->ret, args, 2)) parse_err("Incompatible types in subtraction %s", ""); $$ = parsebuf_buf(act); } ; shift_expr : additive_expr ; relational_expr : shift_expr | relational_expr '<' shift_expr { value_t *args[2]; parse_action_t *act; args[0] = &parsebuf_get_idx($1)->ret; args[1] = &parsebuf_get_idx($3)->ret; act = parse_action_create(less, args, 2); if (typecheck_less(&act->ret, args, 2)) parse_err("Incompatible types in comparison %s", ""); $$ = parsebuf_buf(act); } | relational_expr '>' shift_expr { value_t *args[2]; parse_action_t *act; args[0] = &parsebuf_get_idx($1)->ret; args[1] = &parsebuf_get_idx($3)->ret; act = parse_action_create(greater, args, 2); if (typecheck_greater(&act->ret, args, 2)) parse_err("Incompatible types in comparison %s", ""); $$ = parsebuf_buf(act); } | relational_expr LE_OP shift_expr { value_t *args[2]; parse_action_t *act; args[0] = &parsebuf_get_idx($1)->ret; args[1] = &parsebuf_get_idx($3)->ret; act = parse_action_create(less_eq, args, 2); if (typecheck_less_eq(&act->ret, args, 2)) parse_err("Incompatible types in comparison %s", ""); $$ = parsebuf_buf(act); } | relational_expr GE_OP shift_expr { value_t *args[2]; parse_action_t *act; args[0] = &parsebuf_get_idx($1)->ret; args[1] = &parsebuf_get_idx($3)->ret; act = parse_action_create(greater_eq, args, 2); if (typecheck_greater_eq(&act->ret, args, 2)) parse_err("Incompatible types in comparison %s", ""); $$ = parsebuf_buf(act); } ; equality_expr : relational_expr | equality_expr EQ_OP relational_expr { value_t *args[2]; parse_action_t *act; args[0] = &parsebuf_get_idx($1)->ret; args[1] = &parsebuf_get_idx($3)->ret; act = parse_action_create(equal, args, 2); if (typecheck_equal(&act->ret, args, 2)) parse_err("Incompatible types in comparison %s", ""); $$ = parsebuf_buf(act); } | equality_expr NE_OP relational_expr { value_t *args[2]; parse_action_t *act; args[0] = &parsebuf_get_idx($1)->ret; args[1] = &parsebuf_get_idx($3)->ret; act = parse_action_create(not_equal, args, 2); if (typecheck_not_equal(&act->ret, args, 2)) parse_err("Incompatible types in comparison %s", ""); $$ = parsebuf_buf(act); } ; and_expr : equality_expr | and_expr '&' equality_expr ; exclusive_or_expr : and_expr | exclusive_or_expr '^' and_expr ; inclusive_or_expr : exclusive_or_expr | inclusive_or_expr '|' exclusive_or_expr ; logical_and_expr : inclusive_or_expr | logical_and_expr AND_OP inclusive_or_expr ; logical_or_expr : logical_and_expr | logical_or_expr OR_OP logical_and_expr { } ; conditional_expr : logical_or_expr /* | logical_or_expr '?' logical_or_expr ':' conditional_expr { value_t *args[2] = { &ident_get_idx($1)->cont.val, &parsebuf_get_idx($3)->ret }; parse_action_t *act; } */ ; assignment_expr : conditional_expr | identifier assignment_operator assignment_expr { void (*func) (value_t *, value_t **, int); value_t *args[2]; parse_action_t *act; args[0] = &ident_get_idx($1)->cont.val; args[1] = &parsebuf_get_idx($3)->ret; if (!ident_get_idx($1)->is_declared) parse_err("Undeclared identifier %s", ident_get_idx($1)->name); switch ($2) { case '=': func = assign; break; case MUL_ASSIGN: func = mul_assign; break; case DIV_ASSIGN: func = div_assign; break; case MOD_ASSIGN: func = mod_assign; break; case ADD_ASSIGN: func = add_assign; break; case SUB_ASSIGN: func = sub_assign; break; case AND_ASSIGN: func = and_assign; break; case XOR_ASSIGN: func = xor_assign; break; case OR_ASSIGN: func = or_assign; break; } act = parse_action_create(func, args, 2); $$ = parsebuf_buf(act); } ; assignment_operator : '=' { $$ = '='; } | MUL_ASSIGN { $$ = MUL_ASSIGN; } | DIV_ASSIGN { $$ = DIV_ASSIGN; } | MOD_ASSIGN { $$ = MOD_ASSIGN; } | ADD_ASSIGN { $$ = ADD_ASSIGN; } | SUB_ASSIGN { $$ = SUB_ASSIGN; } | AND_ASSIGN { $$ = AND_ASSIGN; } | XOR_ASSIGN { $$ = XOR_ASSIGN; } | OR_ASSIGN { $$ = OR_ASSIGN; } ; expr : assignment_expr { $$ = $1; } | expr ',' assignment_expr { $$ = $1; } ; declaration : init_declarator_list ';' ; init_declarator_list : init_declarator | init_declarator_list ',' init_declarator ; init_declarator : declarator { /* check that we're not declared already */ if (ident_get_idx($1)->is_declared) parse_err("%s is already declared", ident_get_idx($1)->name); ident_get_idx($1)->is_declared = 1; } | declarator '=' initializer { parse_action_t *act; value_t *args[2]; args[0] = &ident_get_idx($1)->cont.val; args[1] = &parsebuf_get_idx($3)->ret; if (ident_get_idx($1)->is_declared) parse_err("%s is already declared", ident_get_idx($1)->name); ident_get_idx($1)->is_declared = 1; act = parse_action_create(assign, args, 2); $$ = parsebuf_buf(act); } ; type_specifier : INT { $$ = INT; } | FLOAT { $$ = FLOAT; } | STRING { $$ = STRING; } | TIME { $$ = TIME; } | PERIOD { $$ = PERIOD; } ; declarator : type_specifier identifier { ident_t *id = ident_get_idx($2); switch ($1) { case INT: id->cont.val.val_type = val_int; break; case FLOAT: id->cont.val.val_type = val_float; break; case TIME: id->cont.val.val_type = val_time; break; case PERIOD: id->cont.val.val_type = val_period; break; case STRING: id->cont.val.val_type = val_string; break; } $$ = $2; } ; initializer : assignment_expr ; statement : compound_statement | expression_statement | selection_statement | schedule_statement | atomic_statement | sequential_statement ; compound_statement : '{' '}' | '{' statement_list '}' | '{' declaration_list '}' | '{' declaration_list statement_list '}' ; declaration_list : declaration | declaration_list declaration ; statement_list : statement | statement_list statement ; expression_statement : ';' | expr ';' ; selection_statement : IF { /* mark everything that follows as if statement */ parse_action_t *act = parse_action_create(NULL, NULL, 0); $$ = parsebuf_buf(act); } '(' expr ')' { /* if statement needs the return value of the predicate */ value_t *pred_return = &parsebuf_get_idx($4)->ret; parse_action_t *act = parsebuf_get_idx($2); /* args[0] holds the value of the predicate */ act->args[0] = pred_return; parsebuf_buf(act->statement.statement.eop = parse_action_create(NULL, NULL, 0)); } statement { parse_action_t *act = parsebuf_get_idx($2); act->type = if_s; parsebuf_buf(act->statement.statement.eos = parse_action_create(NULL, NULL, 0)); /* also give the if statement a mutex */ pthread_mutex_init(&act->statement.statement.mut, NULL); $$ = $2; } ; atomic_statement : ATOMIC { /* make a parse action that says we're doing something atomic */ parse_action_t *act = parse_action_create(NULL, NULL, 0); act->type = begin_atomic; $$ = parsebuf_buf(act); } statement { /* make a parse action that says we're done doing something atomic */ parse_action_t *act = parse_action_create(NULL, NULL, 0); act->type = end_atomic; $$ = parsebuf_buf(act); } ; sequential_statement : SEQUENTIAL { /* mark everything that follows as sequential */ parse_action_t *act = parse_action_create(NULL, NULL, 0); act->type = begin_sequential; $$ = parsebuf_buf(act); } statement { /* done with the sequential statement */ parse_action_t *act = parse_action_create(NULL, NULL, 0); act->type = end_sequential; $$ = parsebuf_buf(act); } ; schedule_statement : AT { /* mark everything that follows as at statement */ parse_action_t *act = parse_action_create(NULL, NULL, 0); $$ = parsebuf_buf(act); } '(' expr ')' { /* at statement needs the return value of the predicate */ value_t *pred_return = &parsebuf_get_idx($4)->ret; parse_action_t *act = parsebuf_get_idx($2); /* args[0] holds the value of the predicate */ act->args[0] = pred_return; parsebuf_buf(act->statement.statement.eop = parse_action_create(NULL, NULL, 0)); } statement { parse_action_t *act = parsebuf_get_idx($2); act->type = at_s; parsebuf_buf(act->statement.statement.eos = parse_action_create(NULL, NULL, 0)); /* also give the at statement a mutex */ pthread_mutex_init(&act->statement.statement.mut, NULL); $$ = $2; } | EVERY { /* mark everything that follows as schedule statement */ parse_action_t *act = parse_action_create(NULL, NULL, 0); $$ = parsebuf_buf(act); } '(' expr ')' { /* schedule statement needs the return value of the predicate */ value_t *pred_return = &parsebuf_get_idx($4)->ret; parse_action_t *act = parsebuf_get_idx($2); /* args[0] holds the value of the predicate */ act->args[0] = pred_return; parsebuf_buf(act->statement.statement.eop = parse_action_create(NULL, NULL, 0)); } statement { parse_action_t *act = parsebuf_get_idx($2); act->type = sched_s; parsebuf_buf(act->statement.statement.eos = parse_action_create(NULL, NULL, 0)); /* also give the schedule statement a mutex */ pthread_mutex_init(&act->statement.statement.mut, NULL); $$ = $2; } ; file : /* empty file */ | declaration_list | declaration_list statement_list | statement_list ; identifier : IDENTIFIER { $$ = ident_index(yytext); } ; %%