bp/grammar.c

94 lines
2.5 KiB
C

/*
* grammar.c - Code for defining grammars (sets of rules)
*/
#include "grammar.h"
#include "compiler.h"
#include "utils.h"
const char *BPEG_BUILTIN_GRAMMAR = (
"crlf=\\r\\n;\n"
"cr=\\r;\n" "r=\\r;\n"
"anglebraces=`< *(anglebraces / ~~`>) `>;\n"
"brackets=`[ *(brackets / ~~`]) `];\n"
"braces=`{ *(braces / ~~`}) `};\n"
"parens=`( *(parens / ~~`)) `);\n"
"id=(`a-z/`A-Z/`_) *(`a-z/`A-Z/`_/`0-9);\n"
"HEX=`0-9/`A-F;\n"
"Hex=`0-9/`a-f/`A-F;\n"
"hex=`0-9/`a-f;\n"
"number=+`0-9 ?(`. *`0-9) / `. +`0-9;\n"
"int=+`0-9;\n"
"digit=`0-9;\n"
"Abc=`a-z/`A-Z;\n"
"ABC=`A-Z;\n"
"abc=`a-z;\n"
"esc=\\e;\n" "e=\\e;\n"
"tab=\\t;\n" "t=\\t;\n"
"nl=\\n;\n" "lf=\\n;\n" "n=\\n;\n"
"c-block-comment='/*' &&'*/';\n"
"c-line-comment='//' &$;\n"
"c-comment=c-line-comment / c-block-comment;\n"
"hash-comment=`# &$;\n"
"comment=!(/);\n" // No default definition, can be overridden
"WS=` /\\t/\\n/\\r/comment;\n"
"ws=` /\\t;\n"
"$$=!$.;\n"
"$=!.;\n"
"^^=!<$.;\n"
"^=!<.;\n"
"__=*(` /\\t/\\n/\\r/comment);\n"
"_=*(` /\\t);\n"
);
grammar_t *new_grammar(void)
{
grammar_t *g = calloc(sizeof(grammar_t), 1);
g->definitions = calloc(sizeof(def_t), (g->capacity = 128));
load_grammar(g, BPEG_BUILTIN_GRAMMAR);
return g;
}
void add_def(grammar_t *g, const char *src, const char *name, vm_op_t *op)
{
if (g->size >= g->capacity) {
g->definitions = realloc(g->definitions, (g->capacity += 32));
}
int i = g->size;
g->definitions[i].source = src;
g->definitions[i].name = name;
g->definitions[i].op = op;
++g->size;
}
void load_grammar(grammar_t *g, const char *src)
{
vm_op_t *mainpat = NULL;
do {
src = after_spaces(src);
if (!*src) break;
const char *name = src;
const char *name_end = after_name(name);
check(name_end > name, "Invalid name for definition");
name = strndup(name, (size_t)(name_end-name));
src = after_spaces(name_end);
check(matchchar(&src, '='), "Expected '=' in definition");
vm_op_t *op = bpeg_pattern(src);
check(op, "Couldn't load definition");
add_def(g, src, name, op);
if (mainpat == NULL) {
mainpat = op;
g->pattern = op;
}
src = op->end;
} while (*src && matchchar(&src, ';'));
}
/*
* Print a BPEG grammar in human-readable form.
*/
void print_grammar(grammar_t *g)
{
if (g->pattern) print_pattern(g->pattern);
}