%{
/*
* Gregorio is a program that translates gabc files to GregorioTeX
* This file implements the vowel rule parser.
*
* Copyright (C) 2015-2021 The Gregorio Project (see CONTRIBUTORS.md)
*
* 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 .
*/
#include "config.h"
#include
#include
#include
#include "bool.h"
#include "struct.h"
#include "unicode.h"
#include "messages.h"
#include "vowel.h"
#include "vowel-rules.h"
#include "vowel-rules-l.h"
/* NOTE: This parser might allocate a new value for language; this value MUST
* BE FREED after the parser returns (if the value of the language pointer
* changes, then free the pointer). This parser DOES free the language
* pointer before changing it, if status points to RFPS_ALIASED. */
/* uncomment it if you want to have an interactive shell to understand the
* details on how bison works for a certain input */
/*int gregorio_vowel_rulefile_debug=1;*/
static void gregorio_vowel_rulefile_error(const char *const filename,
char **const language __attribute__((__unused__)),
rulefile_parse_status *const status __attribute__((__unused__)),
const char *const error_str)
{
gregorio_messagef("gregorio_vowel_rulefile_parse", VERBOSITY_ERROR, 0,
_("%s: %s"), filename, error_str);
}
/* this returns false until the language *after* the desired language */
static __inline bool match_language(char **language,
rulefile_parse_status *status, char *const name)
{
if (*status == RFPS_FOUND) {
free(name);
return true;
}
if (strcmp(*language, name) == 0) {
*status = RFPS_FOUND;
}
free(name);
return false;
}
static __inline void alias(char **const language,
rulefile_parse_status *const status, char *const name,
char *const target)
{
if (strcmp(*language, name) == 0) {
gregorio_messagef("alias", VERBOSITY_INFO, 0, _("Aliasing %s to %s"),
name, target);
if (*status == RFPS_ALIASED) {
free(*language);
}
*language = target;
*status = RFPS_ALIASED;
} else {
free(target);
}
free(name);
}
static __inline void add(const rulefile_parse_status *const status,
void (*const fn)(const char *), char *const value)
{
if (*status == RFPS_FOUND) {
fn(value);
}
free(value);
}
#define _MATCH(NAME) if (match_language(language, status, NAME)) YYACCEPT
#define _ALIAS(NAME, TARGET) alias(language, status, NAME, TARGET)
#define _ADD(TABLE, CHARS) add(status, gregorio_##TABLE##_table_add, CHARS)
%}
%name-prefix "gregorio_vowel_rulefile_"
%parse-param { const char *const filename }
%parse-param { char **language }
%parse-param { rulefile_parse_status *const status }
%token LANGUAGE VOWEL PREFIX SUFFIX SECONDARY ALIAS SEMICOLON TO
%token NAME CHARACTERS INVALID
%%
rules
:
| rules rule
;
rule
: LANGUAGE NAME SEMICOLON { _MATCH($2); }
| ALIAS NAME TO NAME SEMICOLON { _ALIAS($2, $4); }
| VOWEL vowels SEMICOLON
| PREFIX prefixes SEMICOLON
| SUFFIX suffixes SEMICOLON
| SECONDARY secondaries SEMICOLON
;
vowels
:
| vowels CHARACTERS { _ADD(vowel, $2); }
;
prefixes
:
| prefixes CHARACTERS { _ADD(prefix, $2); }
;
suffixes
:
| suffixes CHARACTERS { _ADD(suffix, $2); }
;
secondaries
:
| secondaries CHARACTERS { _ADD(secondary, $2); }
;