// == Prolog AST-stream term Parser for FlatZinc ============================== // // (C) 2015 Salvador Abreu // // ---------------------------------------------------------------------------- // Based on the Parser for FlatZinc 1.1 // by Nick Nethercote and Julien Fischer // // NOTE: the parser produced by the following grammar does not ensure // that expressions are type correct. Further type-checking after parsing // is required for this. // // This file is in the public domain, and can be used without copyright // restrictions. %{ #include #include #include "types.h" // -- AST stack macros: ------------------------------------------------------- // AST (POP, (PUSH)) // ASTT (POP, (PUSH), TRANS) // INIT (STACK) // PUSH (ITEM) // CONS () // NIL () #define AST(pop, push) \ { \ printf ("[%s|_T] > [", pop); \ printf push; \ printf ("|_T].\n"); \ } #define ASTT(pop, push, trans) \ { \ printf ("[%s|_T] > [", pop); \ printf push; \ printf ("|_T] :- "); \ printf trans; \ printf (".\n"); \ } #define INIT(x) \ { \ printf ("_ > %s.\n", x); \ } #define PRE() \ { \ printf ("_T > ["); \ } #define POST() \ { \ printf ("|_T].\n"); \ } #define PUSH(x) \ { \ printf ("_T > ["); \ printf x; \ printf ("|_T].\n"); \ } // pop an item and a list, push new list (CONS) #define CONS() AST ("H,T", ("[H|T]")) // pop a list and an item, push new list (RCONS) #define RCONS() AST ("T,H", ("[H|T]")) // push the empty list #define NIL() PUSH (("[]")) %} // Possible values for attributed tokens. %union { UNION_DEFS (); }; // Token kinds %token INT_LITERAL STRING_LITERAL FLOAT_LITERAL IDENT UNDERSCORE_IDENT ARRAY BOOL CONSTRAINT FALSE FLOAT INT MAXIMIZE MINIMIZE OF PREDICATE SATISFY SET SOLVE TRUE VAR DOTDOT COLONCOLON %right ',' %% //--------------------------------------------------------------------------- // Model top-level //--------------------------------------------------------------------------- // Nb: these rules are left-recursive, which is good for Yacc as they run in // constant stack space. Earlier versions were right-recursive, and this // caused stack overflows on large models. The error recovery isn't great, // but it's better than none. model : { INIT ("[]"); } pred_decl_items { AST ("X", ("preds(X)")); } var_decl_items { AST ("X", ("vars(X)")); } constraint_items { AST ("X", ("constrs(X)")); } model_end { AST ("S,C,V,P", ("fzn(P, V, C, S)")); } pred_decl_items : pred_decl_items pred_decl_item ';' { CONS (); } | pred_decl_items error ';' { yyerrok; } | /* empty */ { NIL (); } var_decl_items : var_decl_items var_decl_item ';' { CONS (); } | /* empty */ { NIL (); } constraint_items: constraint_items constraint_item ';' { CONS (); } | /* empty */ { NIL (); } model_end : solve_item ';' //--------------------------------------------------------------------------- // Items //--------------------------------------------------------------------------- pred_decl_item: PREDICATE IDENT '(' pred_decl_args ')' var_decl_item: /* -> [ var(ID,TYPE,INIT,ANNOT) | _ ] */ VAR non_array_ti_expr_tail ':' ident_anns var_decl_item2 { AST ("VAL,AN,ID,T", ("var(ID, T, VAL, AN)")); } | non_array_ti_expr_tail ':' ident_anns '=' expr { AST ("VAL,AN,ID,T", ("var(ID, T, VAL, AN)")); } | ARRAY '[' INT_LITERAL DOTDOT INT_LITERAL ']' OF array_decl_tail { AST ("VAL,AN,ID,T", ("var(ID, array(T,%d,%d), VAL, AN)", $3, $5)); } var_decl_item2: /* -> [ VAL | _ ] */ '=' expr { } | /*empty*/ { NIL (); } array_decl_tail: /* -> [ TYPE,VAL,ANNOT,ID | _ ] */ non_array_ti_expr_tail ':' ident_anns '=' array_literal | VAR non_array_ti_expr_tail ':' ident_anns array_decl_tail2 array_decl_tail2: /* -> [ VAL | _ ] */ '=' array_literal { } | /*empty*/ { NIL (); } ident_anns: /* -> [ ANNOT,ID | _ ] */ IDENT { PUSH (("'%s'", $1)); } annotations | UNDERSCORE_IDENT { PUSH (("'%s'", $1)); } annotations constraint_item: /* -> [ constraint(...) | ] */ CONSTRAINT constraint_elem annotations { AST ("A,C", ("constraint(C,A)")); } constraint_elem: /* -> [ CONSTR_ID, EXPRLIST | _ ] */ IDENT '(' exprs ')' { ASTT ("AL", ("C"), ("C =.. ['%s'|AL]", $1)); } solve_item: /* -> [ solve(S,A) | _ ] */ SOLVE annotations solve_kind { AST ("S,A", ("solve(S, A)")); } solve_kind: SATISFY { PUSH (("satisfy")); } | MINIMIZE expr { AST ("E", ("minimize(E)")); } | MAXIMIZE expr { AST ("E", ("maximize(E)")); } //--------------------------------------------------------------------------- // Predicate parameters //--------------------------------------------------------------------------- pred_decl_args: pred_decl_arg "," pred_decl_args | pred_decl_arg pred_decl_arg: non_array_ti_expr_tail ':' IDENT { AST ("T", ("T:'%s'", $3)); } | VAR non_array_ti_expr_tail ':' IDENT { AST ("T", ("var(T):'%s'", $4)); } | ARRAY '[' pred_arg_array_index ']' OF pred_arg_array_tail ':' IDENT { AST ("T,U,L", ("var(array(T,L,U)):'%s'", $8)); } pred_arg_array_index: /* -> [ UB, LB | _ ] */ INT { PUSH (("_,1")); } | INT_LITERAL DOTDOT INT_LITERAL { PUSH (("%d,%d", $3, $1)); } pred_arg_array_tail: /* -> [ TYPE | _ ] */ non_array_ti_expr_tail { } | VAR non_array_ti_expr_tail { AST ("T", ("var(T)")); } //--------------------------------------------------------------------------- // Type-Inst Expression Tails //--------------------------------------------------------------------------- non_array_ti_expr_tail: scalar_ti_expr_tail | set_ti_expr_tail scalar_ti_expr_tail: bool_ti_expr_tail | int_ti_expr_tail | float_ti_expr_tail bool_ti_expr_tail: BOOL { PUSH (("bool")); } int_ti_expr_tail: INT { PUSH (("int")); } | INT_LITERAL DOTDOT INT_LITERAL { PUSH (("int(%d,%d)", $1, $3)); } | '{' int_literals '}' { AST ("Ls", ("int(Ls)")); } int_literals: INT_LITERAL ',' int_literals { AST ("Ls", ("[%d|Ls]", $1)); } | INT_LITERAL { PUSH (("[%d]", $1)); } float_ti_expr_tail: FLOAT { PUSH (("float")); } | FLOAT_LITERAL DOTDOT FLOAT_LITERAL { PUSH (("float(%g,%g)", $1, $3)); } set_ti_expr_tail: SET OF int_ti_expr_tail { AST ("T", ("set(T)")); } //--------------------------------------------------------------------------- // Expressions //--------------------------------------------------------------------------- exprs: expr ',' exprs { RCONS (); } | expr { AST ("E", ("[E]")); } expr: bool_literal | INT_LITERAL { PUSH (("lit(%d,int)", $1.ival)); } | FLOAT_LITERAL { PUSH (("lit(%g,float)", $1.rval)); } | STRING_LITERAL { PUSH (("lit(\"%s\",string)", $1.sval)); } | set_literal | array_literal | array_access_expr | IDENT { PUSH (("id('%s')", $1)); } | UNDERSCORE_IDENT { PUSH (("id('%s')", $1)); } | IDENT '(' exprs ')' /* An annotation value with > 0 arguments. */ bool_literal: FALSE { PUSH (("lit(false,bool)")); } | TRUE { PUSH (("lit(true,bool)")); } set_literal: '{' exprs '}' { AST ("Es", ("lit(Es,set(_))")); } | '{' '}' { PUSH (("lit([],set(_))")); } | INT_LITERAL DOTDOT INT_LITERAL { int i; PRE(); printf ("lit(["); for (i=$1.ival; i<$3.ival; ++i) printf ("%d, ", i); printf ("%d], set(int))", $3.ival); POST(); } array_literal: '[' exprs ']' { AST ("Es", ("lit(Es,array(_))")); } | '[' ']' { PUSH (("lit([],array(_))")); } array_access_expr: IDENT '[' INT_LITERAL ']' { PUSH (("aref('%s',lit(%d,int),_)",$1,$3)); } | UNDERSCORE_IDENT '[' INT_LITERAL ']' { PUSH (("aref('%s',lit(%d,int),_)",$1,$3)); } //--------------------------------------------------------------------------- // Annotations //--------------------------------------------------------------------------- annotations: COLONCOLON expr annotations { AST ("As, E", ("[E|As]")); } | /* empty */ { NIL (); } %% #include "lex.yy.c" char* filename; int main(int argc, char *argv[]) { if (argc == 1) { yyin = stdin; } else if (argc == 2) { filename = argv[1]; yyin = fopen(filename, "r"); if (yyin == NULL) { fprintf(stderr, "cannot open file: '%s'\n", filename); exit(1); } } else { fprintf(stderr, "Usage: %s [FILE.fzn]\n", argv[0]); exit(1); } yyparse(); return 0; } int yyerror(char *s) { if (0 == strcmp(yytext, "")) { fprintf(stderr, "%s:%d: %s before end of file\n", filename, yylineno, s); } else { fprintf(stderr, "%s:%d: %s before '%s'\n", filename, yylineno, s, yytext); } return 0; } /* ** This is only defined so the Flex library isn't needed. */ int yywrap() { return 1; }