/* * Copyright (C) 2019 Vivien Kraus * * 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 3 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, see * . */ %code requires { struct marchande_parser_behavior; typedef struct marchande_parser_behavior marchande_parser_behavior; struct marchande_completer_candidate; typedef struct marchande_completer_candidate marchande_completer_candidate; } %{ #include #include #include int _marchande_lex (_MARCHANDE_STYPE *yylval, void *scanner); void _marchande_error (marchande_parser_behavior *behavior, int *prompt_type, void *scanner, marchande_completer_candidate **completions, const char *error) { (void) error; } int _marchande_wrap () { return 1; } void _marchande_add_completion (marchande_completer_candidate **completions, const char *candidate); %} %define api.pure full %define api.push-pull both %parse-param {marchande_parser_behavior *behavior} %parse-param {int *prompt_type} %parse-param {marchande_completer_candidate **completions} %param {void * scanner} %define api.prefix {_marchande_} %define api.value.type union %token THAT %token WILL %token BE %token ALL %token A %token KG %token BUNCH %token BUNCHES %token OF %token POTATOES %token RADISHES %token END_OF_PHRASE %token INTEGER %token DECIMAL %token UNKNOWN_WORD %destructor { free ($$); } UNKNOWN_WORD %type bunches %type weight %token LANG_EN %token LANG_FR %token CE %token SERA %token TOUT %token DE %token UNE %token BOTTE %token BOTTES %token PATATES %token RADIS %type bottes %type poids %token MODE_DEFAULT %token MODE_COMPLETE %token AUTOCOMPLETE %% run: MODE_DEFAULT LANG_EN interaction | MODE_DEFAULT LANG_FR interaction_fr | MODE_COMPLETE LANG_EN completion | MODE_COMPLETE LANG_FR completion_fr | MODE_COMPLETE error { yyerrok; } ; interaction: %empty | interaction command | interaction error END_OF_PHRASE { *prompt_type = 1; behavior->syntax_error (behavior->data); yyerrok; } command: THAT WILL BE ALL { YYACCEPT; } | weight OF POTATOES { behavior->buy_potatoes (behavior->data, $1); *prompt_type = 1; } | bunches OF RADISHES { behavior->buy_radishes (behavior->data, $1); *prompt_type = 1; } | weight OF UNKNOWN_WORD { behavior->value_error (behavior->data, $3); *prompt_type = 1; free ($3); } | bunches OF UNKNOWN_WORD { behavior->value_error (behavior->data, $3); *prompt_type = 1; free ($3); } weight: DECIMAL KG { $$ = $1; } | INTEGER KG { $$ = (double) $1; } ; bunches: A BUNCH { $$ = 1; } | INTEGER BUNCHES { $$ = $1; } ; completion: AUTOCOMPLETE { _marchande_add_completion (completions, "that"); /* Don't provide completions for the numbers */ } | AUTOCOMPLETE WILL { _marchande_add_completion (completions, "that"); } | THAT AUTOCOMPLETE { _marchande_add_completion (completions, "will"); } | THAT WILL AUTOCOMPLETE { _marchande_add_completion (completions, "be"); } | THAT WILL BE AUTOCOMPLETE { _marchande_add_completion (completions, "all"); } | weight OF AUTOCOMPLETE { _marchande_add_completion (completions, "potatoes"); } | INTEGER AUTOCOMPLETE { if ($1 == 1) { _marchande_add_completion (completions, "bunch"); } else { _marchande_add_completion (completions, "bunches"); } _marchande_add_completion (completions, "kg"); } | DECIMAL AUTOCOMPLETE OF { _marchande_add_completion (completions, "kg"); } | DECIMAL AUTOCOMPLETE KG { /* Cannot complete a decimal number */ } | INTEGER AUTOCOMPLETE OF RADISHES { if ($1 == 1) { _marchande_add_completion (completions, "bunch"); } else { _marchande_add_completion (completions, "bunches"); } } | AUTOCOMPLETE BUNCH OF RADISHES { _marchande_add_completion (completions, "1"); _marchande_add_completion (completions, "a"); } interaction_fr: %empty | interaction_fr command_fr | interaction_fr error END_OF_PHRASE { *prompt_type = 1; behavior->syntax_error (behavior->data); yyerrok; } ; command_fr: CE SERA TOUT { YYACCEPT; } | poids DE PATATES { behavior->buy_potatoes (behavior->data, $1); *prompt_type = 1; } | bottes DE RADIS { behavior->buy_radishes (behavior->data, $1); *prompt_type = 1; } | poids DE UNKNOWN_WORD { behavior->value_error (behavior->data, $3); *prompt_type = 1; free ($3); } | bottes DE UNKNOWN_WORD { behavior->value_error (behavior->data, $3); *prompt_type = 1; free ($3); } ; poids: weight { $$ = $1; } ; bottes: UNE BOTTE { $$ = 1; } | INTEGER BOTTES { $$ = $1; } ; completion_fr: AUTOCOMPLETE { _marchande_add_completion (completions, "ce"); } | AUTOCOMPLETE SERA { _marchande_add_completion (completions, "ce"); } | CE AUTOCOMPLETE { _marchande_add_completion (completions, "sera"); } | CE SERA AUTOCOMPLETE { _marchande_add_completion (completions, "tout"); } | poids DE AUTOCOMPLETE { _marchande_add_completion (completions, "patates"); } | INTEGER AUTOCOMPLETE { if ($1 == 1) { _marchande_add_completion (completions, "botte"); } else { _marchande_add_completion (completions, "bottes"); } _marchande_add_completion (completions, "kg"); } | DECIMAL AUTOCOMPLETE DE { _marchande_add_completion (completions, "kg"); } | INTEGER AUTOCOMPLETE DE RADIS { if ($1 == 1) { _marchande_add_completion (completions, "botte"); } else { _marchande_add_completion (completions, "bottes"); } } | AUTOCOMPLETE BOTTE DE RADIS { _marchande_add_completion (completions, "1"); _marchande_add_completion (completions, "une"); } ; %%