#include #include #include #include #ifdef _WIN32 #include #endif #include "data.h" #include "reader.h" #include "writer.h" #include "printer.h" #include "typechecker.h" #include "linearizer.h" #include "parser.h" #include "graphviz.h" #include "aligner.h" #include "generator.h" static void pgf_exn_clear(PgfExn* err) { err->type = PGF_EXN_NONE; err->code = 0; err->msg = NULL; } #define PGF_API_BEGIN \ pgf_exn_clear(err); \ \ try \ #define PGF_API_END \ catch (pgf_systemerror& e) { \ err->type = PGF_EXN_SYSTEM_ERROR; \ err->code = e.code(); \ err->msg = e.filepath(); \ } catch (pgf_error& e) { \ err->type = PGF_EXN_PGF_ERROR; \ err->msg = strdup(e.what()); \ } PGF_API PgfDB *pgf_read_pgf(const char* fpath, PgfRevision *revision, PgfProbsCallback *probs_callback, PgfExn* err) { PgfDB *db = NULL; FILE *in = NULL; PGF_API_BEGIN { in = fopen(fpath, "rb"); if (!in) { throw pgf_systemerror(errno, fpath); } fseek(in, 0, SEEK_END); size_t pgf_size = ftell(in); fseek(in, 0, SEEK_SET); db = new PgfDB(NULL, 0, 0, pgf_size*7); db->set_file_path(fpath); { DB_scope scope(db, WRITER_SCOPE); db->start_transaction(); PgfReader rdr(in,probs_callback); ref pgf = rdr.read_pgf(); fclose(in); db->set_transaction_object(pgf.as_object()); *revision = db->register_revision(pgf.as_object(), PgfDB::get_txn_id()); db->commit(pgf.as_object()); } db->ref_count++; return db; } PGF_API_END if (db != NULL) delete db; if (in != NULL) fclose(in); return NULL; } PGF_API PgfDB *pgf_boot_ngf(const char* pgf_path, const char* ngf_path, PgfRevision *revision, PgfProbsCallback *probs_callback, PgfExn* err) { PgfDB *db = NULL; FILE *in = NULL; PGF_API_BEGIN { in = fopen(pgf_path, "rb"); if (!in) { throw pgf_systemerror(errno, pgf_path); } fseek(in, 0, SEEK_END); size_t pgf_size = ftell(in); fseek(in, 0, SEEK_SET); db = new PgfDB(ngf_path, O_CREAT | O_EXCL | O_RDWR, #ifndef _WIN32 S_IRUSR | S_IWUSR, #else _S_IREAD | _S_IWRITE, #endif pgf_size*7); { DB_scope scope(db, WRITER_SCOPE); db->start_transaction(); PgfReader rdr(in,probs_callback); ref pgf = rdr.read_pgf(); fclose(in); db->set_transaction_object(pgf.as_object()); *revision = db->register_revision(pgf.as_object(), PgfDB::get_txn_id()); db->commit(pgf.as_object()); } db->ref_count++; return db; } PGF_API_END if (in != NULL) fclose(in); if (db != NULL) { delete db; remove(ngf_path); } return NULL; } #if defined(__linux__) || defined(__APPLE__) #include PGF_API PgfDB *pgf_boot_ngf_cookie(void *cookie, #if defined(__linux__) ssize_t (*readfn)(void *, char *, size_t), #else int (*readfn)(void *, char *, int), #endif const char* ngf_path, PgfRevision *revision, PgfProbsCallback *probs_callback, PgfExn* err) { PgfDB *db = NULL; FILE *in = NULL; PGF_API_BEGIN { #if defined(__linux__) cookie_io_functions_t io_funcs = { readfn, NULL, NULL, NULL }; FILE *in = fopencookie(cookie, "rb", io_funcs); #else FILE *in = fropen(cookie, readfn); #endif if (!in) { throw pgf_systemerror(errno); } db = new PgfDB(ngf_path, O_CREAT | O_EXCL | O_RDWR, #ifndef _WIN32 S_IRUSR | S_IWUSR, #else _S_IREAD | _S_IWRITE, #endif getpagesize()); { DB_scope scope(db, WRITER_SCOPE); db->start_transaction(); PgfReader rdr(in,probs_callback); ref pgf = rdr.read_pgf(); fclose(in); db->set_transaction_object(pgf.as_object()); *revision = db->register_revision(pgf.as_object(), PgfDB::get_txn_id()); db->commit(pgf.as_object()); } db->ref_count++; return db; } PGF_API_END if (in != NULL) fclose(in); if (db != NULL) { delete db; remove(ngf_path); } return NULL; } #endif PGF_API PgfDB *pgf_read_ngf(const char *fpath, PgfRevision *revision, PgfExn* err) { PgfDB *db = NULL; PGF_API_BEGIN { db = new PgfDB(fpath, O_RDWR, 0, 0); { DB_scope scope(db, READER_SCOPE); ref pgf = db->get_active_revision(); *revision = 0; if (pgf != 0) { *revision = db->register_revision(pgf.as_object(), PgfDB::get_txn_id()-1); db->ref_count++; } } return db; } PGF_API_END if (db != NULL) delete db; return NULL; } PGF_API PgfDB *pgf_new_ngf(PgfText *abstract_name, const char *fpath, size_t init_size, PgfRevision *revision, PgfExn* err) { PgfDB *db = NULL; PGF_API_BEGIN { db = new PgfDB(fpath, O_CREAT | O_EXCL | O_RDWR, #ifndef _WIN32 S_IRUSR | S_IWUSR, #else _S_IREAD | _S_IWRITE, #endif init_size); { DB_scope scope(db, WRITER_SCOPE); db->start_transaction(); ref pgf = PgfDB::malloc(); pgf->major_version = PGF_MAJOR_VERSION; pgf->minor_version = PGF_MINOR_VERSION; pgf->gflags = 0; pgf->abstract.name = PgfDB::malloc(abstract_name->size+1); memcpy(&(*pgf->abstract.name), abstract_name, sizeof(PgfText)+abstract_name->size+1); pgf->abstract.aflags = 0; pgf->abstract.funs = 0; pgf->abstract.cats = 0; pgf->concretes = 0; db->set_transaction_object(pgf.as_object()); *revision = db->register_revision(pgf.as_object(), PgfDB::get_txn_id()); db->commit(pgf.as_object()); } db->ref_count++; return db; } PGF_API_END if (db != NULL) { delete db; if (fpath != NULL) remove(fpath); } return NULL; } PGF_API void pgf_merge_pgf(PgfDB *db, PgfRevision revision, const char* fpath, PgfExn* err) { FILE *in = NULL; PGF_API_BEGIN { in = fopen(fpath, "rb"); if (!in) { throw pgf_systemerror(errno, fpath); } { DB_scope scope(db, WRITER_SCOPE); ref pgf = db->revision2pgf(revision); PgfReader rdr(in,NULL); rdr.merge_pgf(pgf); } } PGF_API_END if (in != NULL) fclose(in); } PGF_API void pgf_write_pgf(const char* fpath, PgfDB *db, PgfRevision revision, PgfText **langs, PgfExn* err) { FILE *out = NULL; PGF_API_BEGIN { out = fopen(fpath, "wb"); if (!out) { throw pgf_systemerror(errno, fpath); } { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); PgfWriter wtr(langs, out); wtr.write_pgf(pgf); } } PGF_API_END end: if (out != NULL) fclose(out); } #if defined(__linux__) || defined(__APPLE__) PGF_API void pgf_write_pgf_cookie (void *cookie, #if defined(__linux__) ssize_t (*writefn)(void *, const char *, size_t), #else int (*writefn)(void *, const char *, int), #endif PgfDB *db, PgfRevision revision, PgfText **langs, // null terminated list or null PgfExn* err) { FILE *out = NULL; PGF_API_BEGIN { #if defined(__linux__) cookie_io_functions_t io_funcs = { NULL, writefn, NULL, NULL }; out = fopencookie(cookie, "wb", io_funcs); #else out = fwopen(cookie, writefn); #endif if (!out) { throw pgf_systemerror(errno, ""); } { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); PgfWriter wtr(langs, out); wtr.write_pgf(pgf); } } PGF_API_END if (out != NULL) fclose(out); } #endif PGF_API const char *pgf_file_path(PgfDB *db) { return db->get_file_path(); } PGF_API void pgf_free_revision(PgfDB *db, PgfRevision revision) { try { ref pgf = db->revision2pgf(revision); db->rollback(pgf.as_object()); db->unregister_revision(revision); db->ref_count--; } catch (std::runtime_error& e) { // silently ignore and hope for the best } if (!db->ref_count) delete db; } PGF_API void pgf_free_concr_revision(PgfDB *db, PgfConcrRevision revision) { try { DB_scope scope(db, READER_SCOPE); db->unregister_revision(revision); db->ref_count--; } catch (std::runtime_error& e) { // silently ignore and hope for the best } if (!db->ref_count) delete db; } PGF_API PgfText *pgf_abstract_name(PgfDB *db, PgfRevision revision, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); return textdup(&(*pgf->abstract.name)); } PGF_API_END return NULL; } PGF_API void pgf_iter_categories(PgfDB *db, PgfRevision revision, PgfItor *itor, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); namespace_iter(pgf->abstract.cats, itor, err); } PGF_API_END } PGF_API void pgf_iter_concretes(PgfDB *db, PgfRevision revision, PgfItor *itor, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); size_t index = 0; std::function)> f = [db,revision,itor,err,&index](ref concr) { PgfConcrRevision rev = db->register_concr_revision(revision, index); index++; db->ref_count++; itor->fn(itor, &concr->name, rev, err); return (err->type == PGF_EXN_NONE); }; namespace_iter(pgf->concretes, f); } PGF_API_END } PGF_API PgfConcrRevision pgf_get_concrete(PgfDB *db, PgfRevision revision, PgfText *name, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); size_t index; ref concr = namespace_lookup_index(pgf->concretes, name, &index); if (concr == 0) return 0; db->ref_count++; return db->register_concr_revision(revision, index); } PGF_API_END return 0; } PGF_API PgfType pgf_start_cat(PgfDB *db, PgfRevision revision, PgfUnmarshaller *u, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); PgfText *startcat = (PgfText *) alloca(sizeof(PgfText)+9); startcat->size = 8; strcpy(startcat->text, "startcat"); ref flag = namespace_lookup(pgf->abstract.aflags, startcat); if (flag != 0) { switch (ref::get_tag(flag->value)) { case PgfLiteralStr::tag: { auto lstr = ref::untagged(flag->value); PgfType type = pgf_read_type(&lstr->val, u); if (type == 0) break; return type; } } } PgfText *s = (PgfText *) alloca(sizeof(PgfText)+2); s->size = 1; s->text[0] = 'S'; s->text[1] = 0; return u->dtyp(0,NULL,s,0,NULL); } PGF_API_END return 0; } PGF_API PgfTypeHypo *pgf_category_context(PgfDB *db, PgfRevision revision, PgfText *catname, size_t *n_hypos, PgfUnmarshaller *u, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); ref abscat = namespace_lookup(pgf->abstract.cats, catname); if (abscat == 0) { *n_hypos = 0; return NULL; } PgfDBMarshaller m; PgfTypeHypo *hypos = (PgfTypeHypo *) malloc(abscat->context.size() * sizeof(PgfTypeHypo)); for (size_t i = 0; i < abscat->context.size(); i++) { hypos[i].bind_type = abscat->context[i].bind_type; hypos[i].cid = textdup(abscat->context[i].cid); hypos[i].type = m.match_type(u, abscat->context[i].type.as_object()); } *n_hypos = abscat->context.size(); return hypos; } PGF_API_END *n_hypos = 0; return NULL; } PGF_API prob_t pgf_category_prob(PgfDB *db, PgfRevision revision, PgfText *catname, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); ref abscat = namespace_lookup(pgf->abstract.cats, catname); if (abscat == 0) { return INFINITY; } return abscat->prob; } PGF_API_END return INFINITY; } PGF_API void pgf_iter_functions(PgfDB *db, PgfRevision revision, PgfItor *itor, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); pgf_exn_clear(err); namespace_iter(pgf->abstract.funs, itor, err); } PGF_API_END } PGF_API void pgf_iter_functions_by_prefix(PgfDB *db, PgfRevision revision, PgfText *prefix, PgfItor *itor, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); pgf_exn_clear(err); namespace_iter_prefix(pgf->abstract.funs, prefix, itor, err); } PGF_API_END } PGF_API void pgf_iter_functions_by_cat(PgfDB *db, PgfRevision revision, PgfText *cat, PgfItor *itor, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); std::function)> f = [itor,err](ref fun) { itor->fn(itor, &fun->name, fun.as_object(), err); return (err->type == PGF_EXN_NONE); }; probspace_iter(pgf->abstract.funs_by_cat, cat, f, false); } PGF_API_END } PGF_API PgfType pgf_function_type(PgfDB *db, PgfRevision revision, PgfText *funname, PgfUnmarshaller *u, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); ref absfun = namespace_lookup(pgf->abstract.funs, funname); if (absfun == 0) return 0; return PgfDBMarshaller().match_type(u, absfun->type.as_object()); } PGF_API_END return 0; } PGF_API int pgf_function_is_constructor(PgfDB *db, PgfRevision revision, PgfText *funname, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); ref absfun = namespace_lookup(pgf->abstract.funs, funname); if (absfun == 0) return false; return (absfun->bytecode == 0); } PGF_API_END return false; } PGF_API prob_t pgf_function_prob(PgfDB *db, PgfRevision revision, PgfText *funname, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); ref absfun = namespace_lookup(pgf->abstract.funs, funname); if (absfun == 0) return INFINITY; return absfun->prob; } PGF_API_END return INFINITY; } PGF_API PgfText *pgf_concrete_name(PgfDB *db, PgfConcrRevision revision, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref concr = db->revision2concr(revision); return textdup(&concr->name); } PGF_API_END return NULL; } PGF_API PgfText *pgf_concrete_language_code(PgfDB *db, PgfConcrRevision revision, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref concr = db->revision2concr(revision); size_t size = strlen("language"); PgfText *language = (PgfText *) alloca(sizeof(PgfText)+size+1); language->size = size; strcpy((char*) &language->text, "language"); ref flag = namespace_lookup(concr->cflags, language); if (flag != 0 && ref::get_tag(flag->value) == PgfLiteralStr::tag) { ref lstr = ref::untagged(flag->value); return textdup(&lstr->val); } } PGF_API_END return NULL; } PGF_API PgfText *pgf_print_expr(PgfExpr e, PgfPrintContext *ctxt, int prio, PgfMarshaller *m) { PgfPrinter printer(ctxt,prio,m); m->match_expr(&printer, e); return printer.get_text(); } PGF_API PgfText *pgf_print_ident(PgfText *name) { PgfPrinter printer(NULL,0,NULL); printer.efun(name); return printer.get_text(); } PGF_API PgfExpr pgf_read_expr(PgfText *input, PgfUnmarshaller *u) { PgfExprParser parser(input, u); PgfExpr res = parser.parse_expr(); if (!parser.eof()) { if (res != 0) u->free_ref(res); return 0; } return res; } PGF_API PgfExpr pgf_read_expr_ex(PgfText *input, const char **end_pos, PgfUnmarshaller *u) { PgfExprParser parser(input, u); PgfExpr expr = parser.parse_expr(); *end_pos = parser.get_token_pos(); return expr; } PGF_API prob_t pgf_expr_prob(PgfDB *db, PgfRevision revision, PgfExpr e, PgfMarshaller *m, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); PgfExprProbEstimator estimator(pgf, m); m->match_expr(&estimator, e); return estimator.get_prob(); } PGF_API_END return 0; } PGF_API PgfText *pgf_print_type(PgfType ty, PgfPrintContext *ctxt, int prio, PgfMarshaller *m) { PgfPrinter printer(ctxt,prio,m); m->match_type(&printer, ty); return printer.get_text(); } PGF_API PgfText *pgf_print_context(size_t n_hypos, PgfTypeHypo *hypos, PgfPrintContext *ctxt, int prio, PgfMarshaller *m) { PgfPrinter printer(ctxt,prio,m); for (size_t i = 0; i < n_hypos; i++) { if (i > 0) printer.puts(" "); printer.hypo(&hypos[i],4); } return printer.get_text(); } PGF_API PgfType pgf_read_type(PgfText *input, PgfUnmarshaller *u) { PgfExprParser parser(input, u); PgfType res = parser.parse_type(); if (!parser.eof()) { u->free_ref(res); return 0; } return res; } PGF_API PgfTypeHypo *pgf_read_context(PgfText *input, PgfUnmarshaller *u, size_t *n_hypos) { PgfExprParser parser(input, u); PgfTypeHypo *res = parser.parse_context(n_hypos); if (!parser.eof()) { for (size_t i = 0; i < *n_hypos; i++) { free(res[i].cid); u->free_ref(res[i].type); } *n_hypos = (size_t) -1; return NULL; } return res; } PGF_API PgfText *pgf_print_category_internal(object o) { ref abscat = o; PgfInternalMarshaller m; PgfPrinter printer(NULL,0,&m); printer.puts("cat "); printer.efun(&abscat->name); for (size_t i = 0; i < abscat->context.size(); i++) { printer.puts(" "); PgfTypeHypo hypo; hypo.bind_type = abscat->context[i].bind_type; hypo.cid = abscat->context[i].cid; hypo.type = abscat->context[i].type.as_object(); printer.hypo(&hypo,4); } printer.nprintf(32, " ; -- %g", abscat->prob); return printer.get_text(); } PGF_API PgfText *pgf_print_start_cat_internal(PgfDB *db, PgfRevision revision, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); PgfText *startcat = (PgfText *) alloca(sizeof(PgfText)+9); startcat->size = 8; strcpy(startcat->text, "startcat"); ref flag = namespace_lookup(pgf->abstract.aflags, startcat); if (flag != 0) { PgfInternalMarshaller m; PgfPrinter printer(NULL,0,&m); printer.puts("startcat = "); m.match_lit(&printer, flag->value); return printer.get_text(); } } PGF_API_END return NULL; } PGF_API PgfText *pgf_print_function_internal(object o) { ref absfun = o; PgfInternalMarshaller m; PgfPrinter printer(NULL,0,&m); printer.puts(absfun->bytecode != 0 ? "fun " : "data "); printer.efun(&absfun->name); printer.puts(" : "); m.match_type(&printer, absfun->type.as_object()); printer.nprintf(32, " ; -- %g", absfun->prob); return printer.get_text(); } PGF_API void pgf_iter_lincats(PgfDB *db, PgfConcrRevision cnc_revision, PgfItor *itor, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref concr = db->revision2concr(cnc_revision); namespace_iter(concr->lincats, itor, err); } PGF_API_END } PGF_API void pgf_iter_lins(PgfDB *db, PgfConcrRevision cnc_revision, PgfItor *itor, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref concr = db->revision2concr(cnc_revision); namespace_iter(concr->lins, itor, err); } PGF_API_END } PGF_INTERNAL bool pgf_is_case_sensitive(ref concr) { PgfText *case_sensitive = (PgfText *) alloca(sizeof(PgfText)+15); case_sensitive->size = 14; strcpy(case_sensitive->text, "case_sensitive"); ref flag = namespace_lookup(concr->cflags, case_sensitive); if (flag != 0) { switch (ref::get_tag(flag->value)) { case PgfLiteralStr::tag: { auto lstr = ref::untagged(flag->value); if (lstr->val.size == 3 && strcmp(lstr->val.text, "off") == 0) return false; } } } return true; } class PGF_INTERNAL_DECL PgfMorphoScanner : public PgfPhraseScanner { public: PgfMorphoScanner(PgfMorphoCallback* callback) { this->callback = callback; } virtual void space(PgfTextSpot *start, PgfTextSpot *end, PgfExn* err) { } virtual void start_matches(PgfTextSpot *end, PgfExn* err) { } virtual void match(ref lin, size_t lin_idx, PgfExn* err) { ref field = lin->lincat->fields[lin_idx]; callback->fn(callback, &lin->absfun->name, field, lin->lincat->abscat->prob+lin->absfun->prob, err); } virtual void end_matches(PgfTextSpot *end, PgfExn* err) { } private: PgfMorphoCallback* callback; }; PGF_API void pgf_lookup_morpho(PgfDB *db, PgfConcrRevision cnc_revision, PgfText *sentence, PgfMorphoCallback* callback, PgfExn* err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref concr = db->revision2concr(cnc_revision); bool case_sensitive = pgf_is_case_sensitive(concr); PgfMorphoScanner scanner(callback); size_t n_items; phrasetable_lookup(concr->phrasetable, sentence, case_sensitive, &scanner, err); } PGF_API_END } class PGF_INTERNAL_DECL PgfCohortsScanner : public PgfPhraseScanner { public: PgfCohortsScanner(PgfCohortsCallback* callback) { this->callback = callback; } virtual void space(PgfTextSpot *start, PgfTextSpot *end, PgfExn* err) { match_start = end->pos; } virtual void start_matches(PgfTextSpot *end, PgfExn* err) { } virtual void match(ref lin, size_t seq_index, PgfExn* err) { ref field = lin->lincat->fields[seq_index % lin->lincat->fields.size()]; callback->morpho.fn(&callback->morpho, &lin->absfun->name, field, lin->lincat->abscat->prob+lin->absfun->prob, err); } virtual void end_matches(PgfTextSpot *end, PgfExn* err) { callback->fn(callback, match_start, end->pos, err); } private: size_t match_start; PgfCohortsCallback* callback; }; PGF_API void pgf_lookup_cohorts(PgfDB *db, PgfConcrRevision cnc_revision, PgfText *sentence, PgfCohortsCallback* callback, PgfExn* err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref concr = db->revision2concr(cnc_revision); bool case_sensitive = pgf_is_case_sensitive(concr); PgfCohortsScanner scanner(callback); phrasetable_lookup_cohorts(concr->phrasetable, sentence, case_sensitive, &scanner, err); } PGF_API_END } PGF_API void pgf_iter_sequences(PgfDB *db, PgfConcrRevision cnc_revision, PgfSequenceItor *itor, PgfMorphoCallback *callback, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref concr = db->revision2concr(cnc_revision); /* PgfPhrasetableIds *seq_ids = new PgfPhrasetableIds(); seq_ids->start(concr); phrasetable_iter(concr, concr->phrasetable, itor, callback, seq_ids, err); return seq_ids; */ } PGF_API_END } PGF_API void pgf_get_lincat_counts_internal(object o, size_t *counts) { ref lincat = o; counts[0] = lincat->fields.size(); counts[1] = lincat->n_lindefs; counts[2] = lincat->rules.size() - lincat->n_lindefs; } PGF_API PgfText *pgf_get_lincat_field_internal(object o, size_t i) { ref lincat = o; return &*lincat->fields[i]; } PGF_API size_t pgf_get_lin_rules_count(object o) { ref lin = o; return lin->rules.size(); } PGF_API PgfText *pgf_print_lindef_internal(object o, size_t i) { ref lincat = o; PgfInternalMarshaller m; PgfPrinter printer(NULL,0,&m); ref rule = lincat->rules[i]; if (rule->vars != 0) { printer.lvar_ranges(rule->vars, NULL); printer.puts(" "); } printer.efun(&lincat->name); printer.puts("("); printer.lparam(rule->res); printer.puts(") -> "); printer.efun(&lincat->name); printer.puts("[String(0)]; "); printer.lparam(rule->lin_idx); printer.puts(" : "); printer.symbols(rule->syms.as_vector()); return printer.get_text(); } PGF_API PgfText *pgf_print_linref_internal(object o, size_t i) { ref lincat = o; PgfInternalMarshaller m; PgfPrinter printer(NULL,0,&m); ref rule = lincat->rules[lincat->n_lindefs+i]; if (rule->vars != 0) { printer.lvar_ranges(rule->vars, NULL); printer.puts(" "); } printer.puts("String(0) -> "); printer.efun(&lincat->name); printer.puts("["); printer.efun(&lincat->name); printer.puts("("); printer.lparam(rule->args[0]); printer.puts(")]; "); printer.lparam(rule->lin_idx); printer.puts(" : "); printer.symbols(rule->syms.as_vector()); return printer.get_text(); } PGF_API PgfText *pgf_print_lin_internal(object o, size_t i) { ref lin = o; PgfInternalMarshaller m; PgfPrinter printer(NULL,0,&m); ref rule = lin->rules[i]; ref ty = lin->absfun->type; if (rule->vars != 0) { printer.lvar_ranges(rule->vars, NULL); printer.puts(" "); } printer.efun(&ty->name); printer.puts("("); printer.lparam(rule->res); printer.puts(") -> "); printer.efun(&lin->name); printer.puts("["); for (size_t j = 0; j < rule->args.size(); j++) { if (j > 0) printer.puts(","); printer.efun(&ty->hypos.elem(j)->type->name); printer.puts("("); printer.lparam(rule->args[j]); printer.puts(")"); } printer.puts("]; "); printer.lparam(rule->lin_idx); printer.puts(" : "); printer.symbols(rule->syms.as_vector()); return printer.get_text(); } PGF_API PgfText *pgf_sequence_get_text_internal(object o) { ref rule = o; PgfPrinter printer(NULL,0,NULL); for (size_t i = 0; i < rule->syms.size(); i++) { if (i > 0) printer.puts(" "); PgfSymbol sym = rule->syms[i]; switch (ref::get_tag(sym)) { case PgfSymbolKS::tag: { auto sym_ks = ref::untagged(sym); printer.puts(&sym_ks->token); break; } default: return NULL; } } return printer.get_text(); } PGF_API PgfExpr pgf_check_expr(PgfDB *db, PgfRevision revision, PgfExpr e, PgfType ty, PgfMarshaller *m, PgfUnmarshaller *u, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); PgfTypechecker checker(pgf,m,u,err); return checker.check_expr(e, ty); } PGF_API_END return 0; } PGF_API PgfType pgf_infer_expr(PgfDB *db, PgfRevision revision, PgfExpr* pe, PgfMarshaller *m, PgfUnmarshaller *u, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); PgfTypechecker checker(pgf,m,u,err); return checker.infer_expr(pe); } PGF_API_END return 0; } PGF_API PgfType pgf_check_type(PgfDB *db, PgfRevision revision, PgfType ty, PgfMarshaller *m, PgfUnmarshaller *u, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); PgfTypechecker checker(pgf,m,u,err); return checker.check_type(ty); } PGF_API_END return 0; } PGF_API PgfExpr pgf_generate_random(PgfDB *db, PgfRevision revision, PgfConcrRevision *concr_revisions, size_t n_concr_revisions, PgfType type, size_t depth, uint64_t *seed, prob_t *prob, PgfMarshaller *m, PgfUnmarshaller *u, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); PgfRandomGenerator gen(pgf, depth, seed, m, u); for (size_t i = 0; i < n_concr_revisions; i++) { gen.addConcr(db->revision2concr(concr_revisions[i])); } PgfExpr expr = m->match_type(&gen, type); if (expr != 0) { *prob = gen.getProb(); return expr; } } PGF_API_END return 0; } PGF_API PgfExpr pgf_generate_random_from (PgfDB *db, PgfRevision revision, PgfConcrRevision *concr_revisions, size_t n_concr_revisions, PgfExpr expr, size_t depth, uint64_t *seed, prob_t *prob, PgfMarshaller *m, PgfUnmarshaller *u, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); PgfRandomGenerator gen(pgf, depth, seed, m, u); for (size_t i = 0; i < n_concr_revisions; i++) { gen.addConcr(db->revision2concr(concr_revisions[i])); } PgfExpr new_expr = m->match_expr(&gen, expr); if (new_expr != 0) { *prob = gen.getProb(); return new_expr; } } PGF_API_END return 0; } PGF_API PgfExprEnum *pgf_generate_all(PgfDB *db, PgfRevision revision, PgfConcrRevision *concr_revisions, size_t n_concr_revisions, PgfType type, size_t depth, PgfMarshaller *m, PgfUnmarshaller *u, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); PgfExhaustiveGenerator *gen = new PgfExhaustiveGenerator(pgf, depth, m, u); for (size_t i = 0; i < n_concr_revisions; i++) { gen->addConcr(db->revision2concr(concr_revisions[i])); } m->match_type(gen, type); return gen; } PGF_API_END return NULL; } PGF_API PgfRevision pgf_start_transaction(PgfDB *db, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); ref pgf = db->get_active_revision(); db->start_transaction(); ref new_pgf = PgfDB::malloc(); new_pgf->major_version = pgf->major_version; new_pgf->minor_version = pgf->minor_version; new_pgf->gflags = pgf->gflags; new_pgf->abstract.name = pgf->abstract.name; new_pgf->abstract.aflags = pgf->abstract.aflags; new_pgf->abstract.funs = pgf->abstract.funs; new_pgf->abstract.cats = pgf->abstract.cats; new_pgf->abstract.funs_by_cat = pgf->abstract.funs_by_cat; new_pgf->concretes = pgf->concretes; db->set_transaction_object(new_pgf.as_object()); object rev = db->register_revision(new_pgf.as_object(), PgfDB::get_txn_id()); PgfDB::free(pgf); db->ref_count++; return rev; } PGF_API_END return 0; } PGF_API void pgf_commit_transaction(PgfDB *db, PgfRevision revision, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); ref new_pgf = db->revision2pgf(revision); db->commit(new_pgf.as_object()); } PGF_API_END } PGF_API PgfRevision pgf_checkout_revision(PgfDB *db, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->get_active_revision(); object rev = 0; if (pgf != 0) { rev = db->register_revision(pgf.as_object(), PgfDB::get_txn_id()-1); db->ref_count++; } return rev; } PGF_API_END return 0; } PGF_API PgfText *pgf_create_function(PgfDB *db, PgfRevision revision, PgfText *name_pattern, PgfType ty, size_t arity, char *bytecode, prob_t prob, PgfMarshaller *m, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); PgfDBUnmarshaller u(m); ref pgf = db->revision2pgf(revision); PgfNameAllocator nalloc(name_pattern); Namespace funs = nalloc.allocate(pgf->abstract.funs); if (funs == 0) throw pgf_error("A function with that name already exists"); PgfText *name; ref absfun; nalloc.fetch_name_value(&name, &absfun); absfun->type = m->match_type(&u, ty); absfun->arity = arity; absfun->bytecode = bytecode ? PgfDB::malloc(0) : 0; absfun->prob = prob; pgf->abstract.funs = funs; PgfProbspace funs_by_cat = probspace_insert(pgf->abstract.funs_by_cat, absfun); pgf->abstract.funs_by_cat = funs_by_cat; return name; } PGF_API_END return NULL; } static ref clone_concrete(ref pgf, ref concr) { ref clone = concr; if (!current_db->is_transient_object(clone.as_object())) { clone = PgfDB::malloc(concr->name.size+1); clone->cflags = concr->cflags; clone->lins = concr->lins; clone->lincats = concr->lincats; clone->phrasetable = concr->phrasetable; clone->printnames = concr->printnames; clone->last_fid = concr->last_fid; memcpy(&clone->name, &concr->name, sizeof(PgfText)+concr->name.size+1); ref old_concr; Namespace concrs = namespace_replace(pgf->concretes, clone, &old_concr); pgf->concretes = concrs; PgfDB::free(concr, concr->name.size+1); } return clone; } static void drop_lin(ref concr, PgfText *name) { ref lin; Namespace lins = namespace_delete(concr->lins, name, &lin); if (lin != 0) { PgfConcrLin::release(lin); } concr->lins = lins; } PGF_API void pgf_drop_function(PgfDB *db, PgfRevision revision, PgfText *name, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); ref pgf = db->revision2pgf(revision); ref fun; Namespace funs = namespace_delete(pgf->abstract.funs, name, &fun); if (fun != 0) { PgfProbspace funs_by_cat = probspace_delete(pgf->abstract.funs_by_cat, fun); pgf->abstract.funs_by_cat = funs_by_cat; std::function(ref)> f = [name,pgf](ref concr){ concr = clone_concrete(pgf, concr); drop_lin(concr,name); return concr; }; namespace_map(pgf->concretes, f); PgfAbsFun::release(fun); } pgf->abstract.funs = funs; } PGF_API_END } PGF_API void pgf_create_category(PgfDB *db, PgfRevision revision, PgfText *name, size_t n_hypos, PgfTypeHypo *context, prob_t prob, PgfMarshaller *m, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); PgfDBUnmarshaller u(m); ref pgf = db->revision2pgf(revision); ref abscat = PgfDB::malloc(name->size+1); vector new_context = vector::alloc(n_hypos); abscat->context = new_context; abscat->prob = prob; memcpy(&abscat->name, name, sizeof(PgfText)+name->size+1); for (size_t i = 0; i < n_hypos; i++) { abscat->context[i].bind_type = context[i].bind_type; abscat->context[i].cid = textdup_db(context[i].cid); abscat->context[i].type = m->match_type(&u, context[i].type); } Namespace cats = namespace_insert(pgf->abstract.cats, abscat); if (cats == 0) { throw pgf_error("A category with that name already exists"); } pgf->abstract.cats = cats; } PGF_API_END } struct PGF_INTERNAL_DECL PgfDropItor : PgfItor { ref pgf; }; static void iter_drop_cat_helper(PgfItor *itor, PgfText *key, object value, PgfExn *err) { ref pgf = ((PgfDropItor*) itor)->pgf; std::function)> f = [key,err](ref concr) { drop_lin(concr, key); return (err->type == PGF_EXN_NONE); }; namespace_iter(pgf->concretes, f); ref fun; Namespace funs = namespace_delete(pgf->abstract.funs, key, &fun); fun = value; PgfAbsFun::release(fun); pgf->abstract.funs = funs; } PGF_API void pgf_drop_category(PgfDB *db, PgfRevision revision, PgfText *name, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); ref pgf = db->revision2pgf(revision); ref cat; Namespace cats = namespace_delete(pgf->abstract.cats, name, &cat); if (cat != 0) { std::function(ref)> f = [name,pgf](ref concr){ concr = clone_concrete(pgf, concr); ref lincat; Namespace lincats = namespace_delete(concr->lincats, name, &lincat); concr->lincats = lincats; return concr; }; namespace_map(pgf->concretes, f); PgfDropItor itor; itor.fn = iter_drop_cat_helper; itor.pgf = pgf; PgfProbspace funs_by_cat = probspace_delete_by_cat(pgf->abstract.funs_by_cat, name, &itor, err); pgf->abstract.funs_by_cat = funs_by_cat; PgfAbsCat::release(cat); } pgf->abstract.cats = cats; } PGF_API_END } PGF_API PgfConcrRevision pgf_create_concrete(PgfDB *db, PgfRevision revision, PgfText *name, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); ref pgf = db->revision2pgf(revision); size_t index; ref concr = namespace_lookup_index(pgf->concretes, name, &index); if (concr != 0) throw pgf_error("The concrete syntax already exists"); concr = PgfDB::malloc(name->size+1); concr->cflags = 0; concr->lins = 0; concr->lincats = 0; concr->phrasetable = 0; concr->printnames = 0; concr->last_fid = 0; memcpy(&concr->name, name, sizeof(PgfText)+name->size+1); Namespace concrs = namespace_insert(pgf->concretes, concr); if (concrs == 0) { throw pgf_error("A concrete language with that name already exists"); } pgf->concretes = concrs; object rev = db->register_concr_revision(revision, index); db->ref_count++; return rev; } PGF_API_END return 0; } PGF_API PgfConcrRevision pgf_clone_concrete(PgfDB *db, PgfRevision revision, PgfText *name, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); ref pgf = db->revision2pgf(revision); size_t index; ref concr = namespace_lookup_index(pgf->concretes, name, &index); if (concr == 0) throw pgf_error("Unknown concrete syntax"); concr = clone_concrete(pgf, concr); object rev = db->register_concr_revision(revision, index); db->ref_count++; return rev; } PGF_API_END return 0; } PGF_API void pgf_drop_concrete(PgfDB *db, PgfRevision revision, PgfText *name, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); ref pgf = db->revision2pgf(revision); ref concr; Namespace concrs = namespace_delete(pgf->concretes, name, &concr); if (concr != 0) PgfConcr::release(concr); pgf->concretes = concrs; } PGF_API_END } class PGF_INTERNAL PgfLinBuilder : public PgfLinBuilderIface { ref concr; vector> rules; object container; // what are we building? ref container_lincat; size_t var_index; size_t arg_index; size_t sym_index; size_t alt_index; size_t n_lindefs; size_t n_linrefs; size_t n_args; size_t rule_index; vector syms; size_t pre_sym_index; PgfParseTableMaker tm; const char *builder_error_msg = "Detected incorrect use of the linearization builder"; public: PgfLinBuilder(ref concr) : tm(concr) { this->concr = concr; this->rules = 0; this->var_index = 0; this->arg_index = 0; this->sym_index = (size_t) -1; this->alt_index = (size_t) -1; this->n_lindefs = 0; this->n_linrefs = 0; this->n_args = 0; this->rule_index = 0; this->syms = 0; this->pre_sym_index = (size_t) -1; } ref build(ref abscat, size_t n_fields, PgfText **fields, size_t n_lindefs, size_t n_linrefs, PgfBuildLinIface *build, PgfExn *err) { this->var_index = 0; this->arg_index = 0; this->sym_index = (size_t) -1; this->alt_index = (size_t) -1; this->n_lindefs = n_lindefs; this->n_linrefs = n_linrefs; this->n_args = 1; this->rule_index = 0; this->syms = 0; this->pre_sym_index = (size_t) -1; this->rules = vector>::alloc(n_lindefs+n_linrefs); ref lincat = PgfDB::malloc(abscat->name.size+1); memcpy(&lincat->name, &abscat->name, sizeof(PgfText)+abscat->name.size+1); lincat->abscat = abscat; lincat->n_lindefs = n_lindefs; lincat->rules= this->rules; vector> db_fields = vector>::alloc(n_fields); for (size_t i = 0; i < n_fields; i++) { ref name = textdup_db(fields[i]); db_fields[i] = name; } lincat->fields = db_fields; this->container = lincat.tagged(); this->container_lincat = 0; build->build(this, err); if (err->type == PGF_EXN_NONE && rule_index != rules.size()) { err->type = PGF_EXN_PGF_ERROR; err->msg = builder_error_msg; } if (err->type != PGF_EXN_NONE) { return 0; } return lincat; } ref build(ref absfun, size_t n_rules, PgfBuildLinIface *build, PgfExn *err) { ref lincat = namespace_lookup(concr->lincats, &absfun->type->name); if (lincat == 0) { throw pgf_error("Missing linearization category"); } this->var_index = 0; this->arg_index = 0; this->sym_index = (size_t) -1; this->alt_index = (size_t) -1; this->n_lindefs = n_rules; this->n_linrefs = n_linrefs; this->n_args = 1; this->rule_index = 0; this->syms = 0; this->pre_sym_index = (size_t) -1; this->rules = vector>::alloc(n_rules); ref lin = PgfDB::malloc(absfun->name.size+1); memcpy(&lin->name, &absfun->name, sizeof(PgfText)+absfun->name.size+1); lin->absfun = absfun; lin->lincat = lincat; lin->rules = this->rules; this->container = lin.tagged(); this->container_lincat = lincat; this->n_args = absfun->type->hypos.size(); build->build(this, err); if (err->type == PGF_EXN_NONE && rule_index != rules.size()) { err->type = PGF_EXN_PGF_ERROR; err->msg = builder_error_msg; } if (err->type != PGF_EXN_NONE) { return 0; } return lin; } void start_rule(size_t n_vars, size_t n_syms, PgfExn *err) { if (err->type != PGF_EXN_NONE) return; PGF_API_BEGIN { if (rule_index >= rules.size()) throw pgf_error(builder_error_msg); vector vars = (n_vars > 0) ? vector::alloc(n_vars) : 0; vector> args = (n_args > 0) ? vector>::alloc(n_args) : 0; ref rule = inline_vector::alloc(&PgfConcrRule::syms, n_syms); rule->vars = vars; rule->res = 0; rule->container = container; rule->args = args; rule->lin_idx = 0; rules[rule_index] = rule; var_index = 0; arg_index = 0; sym_index = 0; syms = rule->syms.as_vector(); } PGF_API_END } void add_argument(size_t i0, size_t n_terms, size_t *terms, PgfExn *err) { if (err->type != PGF_EXN_NONE) return; PGF_API_BEGIN { if (rule_index >= rules.size() || rules[rule_index]->args == 0 || arg_index >= rules[rule_index]->args.size()) throw pgf_error(builder_error_msg); ref param = PgfDB::malloc(n_terms*2*sizeof(size_t)); param->i0 = i0; param->n_terms = n_terms; for (size_t i = 0; i < n_terms; i++) { param->terms[i].factor = terms[2*i]; param->terms[i].var = terms[2*i+1]; } rules[rule_index]->args[arg_index] = param; arg_index++; } PGF_API_END } void set_result(size_t i0, size_t n_terms, size_t *terms, PgfExn *err) { if (err->type != PGF_EXN_NONE) return; PGF_API_BEGIN { if (rule_index >= rules.size() || rules[rule_index]->res != 0) throw pgf_error(builder_error_msg); ref res = PgfDB::malloc(n_terms*2*sizeof(size_t)); res->i0 = i0; res->n_terms = n_terms; for (size_t i = 0; i < n_terms; i++) { res->terms[i].factor = terms[2*i]; res->terms[i].var = terms[2*i+1]; } rules[rule_index]->res = res; } PGF_API_END } void set_lin_idx(size_t i0, size_t n_terms, size_t *terms, PgfExn *err) { if (err->type != PGF_EXN_NONE) return; PGF_API_BEGIN { if (rule_index >= rules.size() || rules[rule_index]->lin_idx != 0) throw pgf_error(builder_error_msg); ref lin_idx = PgfDB::malloc(n_terms*2*sizeof(size_t)); lin_idx->i0 = i0; lin_idx->n_terms = n_terms; for (size_t i = 0; i < n_terms; i++) { lin_idx->terms[i].factor = terms[2*i]; lin_idx->terms[i].var = terms[2*i+1]; } rules[rule_index]->lin_idx = lin_idx; } PGF_API_END } void add_variable(size_t var, size_t range, PgfExn *err) { if (err->type != PGF_EXN_NONE) return; PGF_API_BEGIN { if (rule_index >= rules.size()) throw pgf_error(builder_error_msg); ref rule = rules[rule_index]; if (rule->vars == 0 || var_index >= rule->vars.size()) throw pgf_error(builder_error_msg); ref var_range = rule->vars.elem(var_index); var_range->var = var; var_range->range = range; var_index++; } PGF_API_END } void add_symcat(size_t d, size_t i0, size_t n_terms, size_t *terms, PgfExn *err) { if (err->type != PGF_EXN_NONE) return; PGF_API_BEGIN { if (syms == 0 || sym_index == (size_t) -1 || sym_index >= syms.size()) throw pgf_error(builder_error_msg); if (d > n_args) throw pgf_error(builder_error_msg); ref symcat = PgfDB::malloc(n_terms*2*sizeof(size_t)); symcat->d = d; symcat->r.i0 = i0; symcat->r.n_terms = n_terms; for (size_t i = 0; i < n_terms; i++) { symcat->r.terms[i].factor = terms[2*i]; symcat->r.terms[i].var = terms[2*i+1]; } syms[sym_index] = symcat.tagged(); sym_index++; } PGF_API_END } void add_symlit(size_t d, size_t i0, size_t n_terms, size_t *terms, PgfExn *err) { if (err->type != PGF_EXN_NONE) return; PGF_API_BEGIN { if (syms == 0 || sym_index == (size_t) -1 || sym_index >= syms.size()) throw pgf_error(builder_error_msg); if (d > n_args) throw pgf_error(builder_error_msg); ref symlit = PgfDB::malloc(n_terms*2*sizeof(size_t)); symlit->d = d; symlit->r.i0 = i0; symlit->r.n_terms = n_terms; for (size_t i = 0; i < n_terms; i++) { symlit->r.terms[i].factor = terms[2*i]; symlit->r.terms[i].var = terms[2*i+1]; } syms[sym_index] = symlit.tagged(); sym_index++; } PGF_API_END } void add_symvar(size_t d, size_t r, PgfExn *err) { if (err->type != PGF_EXN_NONE) return; PGF_API_BEGIN { if (syms == 0 || sym_index == (size_t) -1 || sym_index >= syms.size()) throw pgf_error(builder_error_msg); if (d > n_args) throw pgf_error(builder_error_msg); ref symvar = PgfDB::malloc(); symvar->d = d; symvar->r = r; syms[sym_index] = symvar.tagged(); sym_index++; } PGF_API_END } void add_symks(PgfText *token, PgfExn *err) { if (err->type != PGF_EXN_NONE) return; PGF_API_BEGIN { if (syms == 0 || sym_index == (size_t) -1 || sym_index >= syms.size()) throw pgf_error(builder_error_msg); ref symtok = PgfDB::malloc(token->size+1); memcpy(&symtok->token, token, sizeof(PgfText)+token->size+1); syms[sym_index] = symtok.tagged(); sym_index++; } PGF_API_END } void start_symkp(size_t n_syms, size_t n_alts, PgfExn *err) { if (err->type != PGF_EXN_NONE) return; PGF_API_BEGIN { if (syms == 0 || sym_index == (size_t) -1 || sym_index >= syms.size() || pre_sym_index != (size_t) -1) throw pgf_error(builder_error_msg); vector def = vector::alloc(n_syms); ref symkp = inline_vector::alloc(&PgfSymbolKP::alts,n_alts); symkp->default_form = def; syms[sym_index] = symkp.tagged(); pre_sym_index = sym_index; syms = def; sym_index = 0; alt_index = 0; } PGF_API_END } void start_symkp_alt(size_t n_syms, size_t n_prefs, PgfText **prefs, PgfExn *err) { if (err->type != PGF_EXN_NONE) return; PGF_API_BEGIN { if (pre_sym_index == (size_t) -1) throw pgf_error(builder_error_msg); vector form = vector::alloc(n_syms); vector> prefixes = vector>::alloc(n_prefs); for (size_t i = 0; i < n_prefs; i++) { ref pref = textdup_db(prefs[i]); prefixes[i] = pref; } syms = rules[rule_index]->syms.as_vector(); ref symkp = ref::untagged(syms[pre_sym_index]); ref alt = symkp->alts.elem(alt_index); alt->form = form; alt->prefixes = prefixes; syms = form; sym_index = 0; } PGF_API_END } void end_symkp_alt(PgfExn *err) { if (err->type != PGF_EXN_NONE) return; PGF_API_BEGIN { if (pre_sym_index == (size_t) -1) throw pgf_error(builder_error_msg); syms = rules[rule_index]->syms.as_vector(); ref symkp = ref::untagged(syms[pre_sym_index]); if (alt_index >= symkp->alts.size()) throw pgf_error(builder_error_msg); alt_index++; } PGF_API_END } void end_symkp(PgfExn *err) { if (err->type != PGF_EXN_NONE) return; PGF_API_BEGIN { if (pre_sym_index == (size_t) -1) throw pgf_error(builder_error_msg); syms = rules[rule_index]->syms.as_vector(); sym_index = pre_sym_index+1; alt_index = 0; pre_sym_index = (size_t) -1; } PGF_API_END } void add_symbind(PgfExn *err) { if (err->type != PGF_EXN_NONE) return; PGF_API_BEGIN { if (syms == 0 || sym_index == (size_t) -1 || sym_index >= syms.size()) throw pgf_error(builder_error_msg); syms[sym_index] = ref(0).tagged(); sym_index++; } PGF_API_END } void add_symsoftbind(PgfExn *err) { if (err->type != PGF_EXN_NONE) return; PGF_API_BEGIN { if (syms == 0 || sym_index == (size_t) -1 || sym_index >= syms.size()) throw pgf_error(builder_error_msg); syms[sym_index] = ref(0).tagged(); sym_index++; } PGF_API_END } void add_symne(PgfExn *err) { if (err->type != PGF_EXN_NONE) return; PGF_API_BEGIN { if (syms == 0 || sym_index == (size_t) -1 || sym_index >= syms.size()) throw pgf_error(builder_error_msg); syms[sym_index] = ref(0).tagged(); sym_index++; } PGF_API_END } void add_symsoftspace(PgfExn *err) { if (err->type != PGF_EXN_NONE) return; PGF_API_BEGIN { if (syms == 0 || sym_index == (size_t) -1 || sym_index >= syms.size()) throw pgf_error(builder_error_msg); syms[sym_index] = ref(0).tagged(); sym_index++; } PGF_API_END } void add_symcapit(PgfExn *err) { if (err->type != PGF_EXN_NONE) return; PGF_API_BEGIN { if (syms == 0 || sym_index == (size_t) -1 || sym_index >= syms.size()) throw pgf_error(builder_error_msg); syms[sym_index] = ref(0).tagged(); sym_index++; } PGF_API_END } void add_symallcapit(PgfExn *err) { if (err->type != PGF_EXN_NONE) return; PGF_API_BEGIN { if (syms == 0 || sym_index == (size_t) -1 || sym_index >= syms.size()) throw pgf_error(builder_error_msg); syms[sym_index] = ref(0).tagged(); sym_index++; } PGF_API_END } void end_rule(PgfExn *err) { if (err->type != PGF_EXN_NONE) return; PGF_API_BEGIN { if (rule_index >= rules.size()) throw pgf_error(builder_error_msg); ref rule = rules[rule_index]; if (rule->res == 0) throw pgf_error(builder_error_msg); if (arg_index < n_args) throw pgf_error(builder_error_msg); if ((ref::get_tag(rule->container) == PgfConcrLin::tag) || (rule_index < n_lindefs)) { /*PgfParseIndex parse_index = parse_index_insert(concr->parse_index, rule); concr->parse_index = parse_index;*/ } rule_index++; } PGF_API_END } }; PGF_API void pgf_create_lincat(PgfDB *db, PgfRevision revision, PgfConcrRevision cnc_revision, PgfText *name, size_t n_fields, PgfText **fields, size_t n_lindefs, size_t n_linrefs, PgfBuildLinIface *build, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); ref pgf = db->revision2pgf(revision); ref concr = db->revision2concr(cnc_revision); ref abscat = namespace_lookup(pgf->abstract.cats, name); if (abscat == 0) { throw pgf_error("There is no corresponding category in the abstract syntax"); } ref lincat = PgfLinBuilder(concr).build(abscat, n_fields, fields, n_lindefs, n_linrefs, build, err); if (lincat != 0) { Namespace lincats = namespace_insert(concr->lincats, lincat); if (lincats == 0) { throw pgf_error("A linearization category with that name already exists"); } concr->lincats = lincats; } } PGF_API_END } PGF_API void pgf_drop_lincat(PgfDB *db, PgfRevision revision,PgfConcrRevision cnc_revision, PgfText *name, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); ref pgf = db->revision2pgf(revision); ref concr = db->revision2concr(cnc_revision); ref lincat; Namespace lincats = namespace_delete(concr->lincats, name, &lincat); if (lincat != 0) { // The lincat was indeed in the concrete syntax. // Remove the linearizations of all functions that // depend on it. std::function)> f = [concr](ref fun) { drop_lin(concr, &fun->name); return true; }; probspace_iter(pgf->abstract.funs_by_cat, name, f, true); // Finaly remove the lincat object itself. PgfConcrLincat::release(lincat); } concr->lincats = lincats; } PGF_API_END } PGF_API void pgf_create_lin(PgfDB *db, PgfRevision revision, PgfConcrRevision cnc_revision, PgfText *name, size_t n_rules, PgfBuildLinIface *build, PgfExn *err) { if (n_rules == 0) return; PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); ref pgf = db->revision2pgf(revision); ref concr = db->revision2concr(cnc_revision); ref absfun = namespace_lookup(pgf->abstract.funs, name); if (absfun == 0) { throw pgf_error("There is no corresponding function in the abstract syntax"); } ref lin = PgfLinBuilder(concr).build(absfun, n_rules, build, err); if (lin != 0) { Namespace lins = namespace_insert(concr->lins, lin); if (lins == 0) { throw pgf_error("A linearization function with that name already exists"); } concr->lins = lins; } } PGF_API_END } PGF_API void pgf_alter_lin(PgfDB *db, PgfRevision revision, PgfConcrRevision cnc_revision, PgfText *name, size_t n_rules, PgfBuildLinIface *build, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); ref pgf = db->revision2pgf(revision); ref concr = db->revision2concr(cnc_revision); ref absfun = namespace_lookup(pgf->abstract.funs, name); if (absfun == 0) { throw pgf_error("There is no corresponding function in the abstract syntax"); } ref lin = PgfLinBuilder(concr).build(absfun, n_rules, build, err); if (lin != 0) { ref old_lin; Namespace lins = namespace_replace(concr->lins, lin, &old_lin); concr->lins = lins; if (old_lin != 0) { PgfConcrLin::release(old_lin); } } } PGF_API_END } PGF_API void pgf_drop_lin(PgfDB *db, PgfRevision revision, PgfConcrRevision cnc_revision, PgfText *name, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); ref pgf = db->revision2pgf(revision); ref concr = db->revision2concr(cnc_revision); drop_lin(concr, name); } PGF_API_END } PGF_API int pgf_has_linearization(PgfDB *db, PgfConcrRevision revision, PgfText *name, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref concr = db->revision2concr(revision); ref lin = namespace_lookup(concr->lins, name); return (lin != 0); } PGF_API_END return 0; } PGF_API PgfText **pgf_category_fields(PgfDB *db, PgfConcrRevision revision, PgfText *name, size_t *p_n_fields, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref concr = db->revision2concr(revision); ref lincat = namespace_lookup(concr->lincats, name); if (lincat == 0) { *p_n_fields = 0; return NULL; } else { size_t n_fields = lincat->fields.size(); PgfText **fields = (PgfText **) malloc(sizeof(PgfText*)*n_fields); if (fields == 0) throw pgf_systemerror(ENOMEM); for (size_t i = 0; i < n_fields; i++) { fields[i] = textdup(lincat->fields[i]); } *p_n_fields = n_fields; return fields; } } PGF_API_END return NULL; } PGF_API PgfText *pgf_linearize(PgfDB *db, PgfConcrRevision revision, PgfExpr expr, PgfPrintContext *ctxt, PgfMarshaller *m, PgfExn* err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref concr = db->revision2concr(revision); PgfLinearizationOutput out; PgfLinearizer linearizer(ctxt, concr, m); m->match_expr(&linearizer, expr); linearizer.reverse_and_label(true); if (linearizer.resolve()) { linearizer.linearize(&out, 0); return out.get_text(); } } PGF_API_END return NULL; } PGF_API PgfText **pgf_linearize_all(PgfDB *db, PgfConcrRevision revision, PgfExpr expr, PgfPrintContext *ctxt, PgfMarshaller *m, size_t *n_variants, PgfExn* err) { *n_variants = 0; PgfText **variants = NULL; PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref concr = db->revision2concr(revision); PgfLinearizationOutput out; PgfLinearizer linearizer(ctxt, concr, m); m->match_expr(&linearizer, expr); linearizer.reverse_and_label(true); while (linearizer.resolve()) { linearizer.linearize(&out, 0); PgfText *text = out.get_text(); if (text != NULL) { variants = (PgfText **) realloc(variants, ((*n_variants)+1)*sizeof(PgfText **)); variants[(*n_variants)++] = text; } } return variants; } PGF_API_END free(variants); return NULL; } PGF_API PgfText **pgf_tabular_linearize(PgfDB *db, PgfConcrRevision revision, PgfExpr expr, PgfPrintContext *ctxt, PgfMarshaller *m, PgfExn* err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref concr = db->revision2concr(revision); PgfLinearizationOutput out; PgfLinearizer linearizer(ctxt, concr, m); m->match_expr(&linearizer, expr); linearizer.reverse_and_label(false); if (linearizer.resolve()) { ref lincat = linearizer.get_lincat(); if (lincat != 0) { PgfText **res = (PgfText **) malloc((lincat->fields.size()+1)*2*sizeof(PgfText*)); if (res == NULL) throw pgf_systemerror(ENOMEM); size_t pos = 0; for (size_t i = 0; i < lincat->fields.size(); i++) { linearizer.linearize(&out, i); PgfText *text = out.get_text(); if (text != NULL) { res[pos++] = textdup(&*lincat->fields[i]); res[pos++] = text; } } res[pos++] = NULL; res[pos++] = NULL; return res; } } } PGF_API_END return NULL; } PGF_API PgfText **pgf_tabular_linearize_all(PgfDB *db, PgfConcrRevision revision, PgfExpr expr, PgfPrintContext *ctxt, PgfMarshaller *m, PgfExn* err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref concr = db->revision2concr(revision); PgfLinearizationOutput out; PgfLinearizer linearizer(ctxt, concr, m); m->match_expr(&linearizer, expr); linearizer.reverse_and_label(false); size_t pos = 0; PgfText **res = NULL; while (linearizer.resolve()) { ref lincat = linearizer.get_lincat(); res = (PgfText **) realloc(res, (pos+(lincat->fields.size()+1)*2)*sizeof(PgfText*)); for (size_t i = 0; i < lincat->fields.size(); i++) { linearizer.linearize(&out, i); PgfText *text = out.get_text(); if (text != NULL) { res[pos++] = textdup(&*lincat->fields[i]); res[pos++] = text; } } res[pos++] = NULL; } res[pos++] = NULL; return res; } PGF_API_END return NULL; } PGF_API void pgf_bracketed_linearize(PgfDB *db, PgfConcrRevision revision, PgfExpr expr, PgfPrintContext *ctxt, PgfMarshaller *m, PgfLinearizationOutputIface *out, PgfExn* err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref concr = db->revision2concr(revision); PgfLinearizer linearizer(ctxt, concr, m); m->match_expr(&linearizer, expr); linearizer.reverse_and_label(true); if (linearizer.resolve()) { linearizer.linearize(out, 0); } } PGF_API_END } PGF_API void pgf_bracketed_linearize_all(PgfDB *db, PgfConcrRevision revision, PgfExpr expr, PgfPrintContext *ctxt, PgfMarshaller *m, PgfLinearizationOutputIface *out, PgfExn* err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref concr = db->revision2concr(revision); PgfLinearizer linearizer(ctxt, concr, m); m->match_expr(&linearizer, expr); linearizer.reverse_and_label(true); while (linearizer.resolve()) { linearizer.linearize(out, 0); out->flush(); } } PGF_API_END } struct PGF_INTERNAL_DECL PgfLincatUnmarshaller : PgfUnmarshaller { PgfLincatUnmarshaller(ref concr) { this->concr = concr; this->lincat = 0; } virtual PgfExpr eabs(PgfBindType btype, PgfText *name, PgfExpr body) { return 0; } virtual PgfExpr eapp(PgfExpr fun, PgfExpr arg) { return 0; } virtual PgfExpr elit(PgfLiteral lit) { return 0; } virtual PgfExpr emeta(PgfMetaId meta) { return 0; } virtual PgfExpr efun(PgfText *name) { return 0; } virtual PgfExpr evar(int index) { return 0; } virtual PgfExpr etyped(PgfExpr expr, PgfType typ) { return 0; } virtual PgfExpr eimplarg(PgfExpr expr) { return 0; } virtual PgfLiteral lint(size_t size, uintmax_t *v) { return 0; } virtual PgfLiteral lflt(double v) { return 0; } virtual PgfLiteral lstr(PgfText *v) { return 0; } virtual PgfType dtyp(size_t n_hypos, PgfTypeHypo *hypos, PgfText *cat, size_t n_exprs, PgfExpr *exprs) { lincat = namespace_lookup(concr->lincats, cat); return 0; } virtual void free_ref(object x) {}; ref concr; ref lincat; }; PGF_API PgfExprEnum *pgf_parse(PgfDB *db, PgfConcrRevision revision, PgfType ty, PgfMarshaller *m, PgfUnmarshaller *u, PgfText *sentence, PgfExn * err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref concr = db->revision2concr(revision); bool case_sensitive = pgf_is_case_sensitive(concr); PgfLincatUnmarshaller lincat_u(concr); m->match_type(&lincat_u, ty); if (lincat_u.lincat == 0) return 0; PgfParser *parser = new PgfParser(concr, sentence, case_sensitive, m, u); parser->prepare(lincat_u.lincat); return parser; } PGF_API_END return NULL; } PGF_API void pgf_free_expr_enum(PgfExprEnum *en) { delete en; } PGF_API PgfText *pgf_get_printname(PgfDB *db, PgfConcrRevision revision, PgfText *fun, PgfExn* err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref concr = db->revision2concr(revision); PgfText *printname = namespace_lookup(concr->printnames, fun)->printname; return textdup(printname); } PGF_API_END return NULL; } PGF_API void pgf_set_printname(PgfDB *db, PgfConcrRevision revision, PgfText *fun, PgfText *name, PgfExn* err) { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); ref concr = db->revision2concr(revision); ref printname = PgfDB::malloc(fun->size+1); memcpy(&printname->name, fun, sizeof(PgfText)+fun->size+1); printname->printname = textdup_db(name); ref old_printname; Namespace printnames = namespace_replace(concr->printnames, printname, &old_printname); if (old_printname != 0) { PgfConcrPrintname::release(old_printname); } concr->printnames = printnames; } PGF_API_END } PGF_API PgfLiteral pgf_get_global_flag(PgfDB *db, PgfRevision revision, PgfText *name, PgfUnmarshaller *u, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); ref flag = namespace_lookup(pgf->gflags, name); if (flag != 0) { return PgfDBMarshaller().match_lit(u, flag->value); } } PGF_API_END return 0; } PGF_API void pgf_set_global_flag(PgfDB *db, PgfRevision revision, PgfText *name, PgfLiteral value, PgfMarshaller *m, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); PgfDBUnmarshaller u(m); ref pgf = db->revision2pgf(revision); ref flag = PgfDB::malloc(name->size+1); memcpy(&flag->name, name, sizeof(PgfText)+name->size+1); PgfLiteral lit = m->match_lit(&u, value); flag->value = lit; ref old_flag; Namespace gflags = namespace_replace(pgf->gflags, flag, &old_flag); if (old_flag != 0) { PgfFlag::release(old_flag); } pgf->gflags = gflags; } PGF_API_END } PGF_API PgfLiteral pgf_get_abstract_flag(PgfDB *db, PgfRevision revision, PgfText *name, PgfUnmarshaller *u, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); ref flag = namespace_lookup(pgf->abstract.aflags, name); if (flag != 0) { return PgfDBMarshaller().match_lit(u, flag->value); } } PGF_API_END return 0; } PGF_API void pgf_set_abstract_flag(PgfDB *db, PgfRevision revision, PgfText *name, PgfLiteral value, PgfMarshaller *m, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); PgfDBUnmarshaller u(m); ref pgf = db->revision2pgf(revision); ref flag = PgfDB::malloc(name->size+1); memcpy(&flag->name, name, sizeof(PgfText)+name->size+1); PgfLiteral lit = m->match_lit(&u, value); flag->value = lit; ref old_flag; Namespace aflags = namespace_replace(pgf->abstract.aflags, flag, &old_flag); if (old_flag != 0) { PgfFlag::release(old_flag); } pgf->abstract.aflags = aflags; } PGF_API_END } PGF_API PgfLiteral pgf_get_concrete_flag(PgfDB *db, PgfConcrRevision revision, PgfText *name, PgfUnmarshaller *u, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref concr = db->revision2concr(revision); ref flag = namespace_lookup(concr->cflags, name); if (flag != 0) { return PgfDBMarshaller().match_lit(u, flag->value); } } PGF_API_END return 0; } PGF_API void pgf_set_concrete_flag(PgfDB *db, PgfConcrRevision revision, PgfText *name, PgfLiteral value, PgfMarshaller *m, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); PgfDBUnmarshaller u(m); ref concr = db->revision2concr(revision); ref flag = PgfDB::malloc(name->size+1); memcpy(&flag->name, name, sizeof(PgfText)+name->size+1); PgfLiteral lit = m->match_lit(&u, value); flag->value = lit; ref old_flag; Namespace cflags = namespace_replace(concr->cflags, flag, &old_flag); if (old_flag != 0) { PgfFlag::release(old_flag); } concr->cflags = cflags; } PGF_API_END } PGF_API PgfText * pgf_graphviz_abstract_tree(PgfDB *db, PgfRevision revision, PgfExpr expr, PgfMarshaller *m, PgfGraphvizOptions* opts, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); PgfAbstractGraphvizOutput out(&pgf->abstract, opts, m); return out.generate_graphviz(expr); } PGF_API_END return NULL; } PGF_API PgfText * pgf_graphviz_parse_tree(PgfDB *db, PgfConcrRevision revision, PgfExpr expr, PgfPrintContext *ctxt, PgfMarshaller *m, PgfGraphvizOptions* opts, PgfExn *err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref concr = db->revision2concr(revision); PgfLinearizationGraphvizOutput out; PgfLinearizer linearizer(ctxt, concr, m); m->match_expr(&linearizer, expr); linearizer.reverse_and_label(true); if (linearizer.resolve()) { linearizer.linearize(&out, 0); return out.generate_graphviz(opts); } } PGF_API_END return NULL; } PGF_API PgfText * pgf_graphviz_word_alignment(PgfDB *db, PgfConcrRevision* revisions, size_t n_revisions, PgfExpr expr, PgfPrintContext *ctxt, PgfMarshaller *m, PgfGraphvizOptions* opts, PgfExn* err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); PgfPrinter printer(NULL, 0, NULL); printer.puts("digraph {\n"); printer.puts("rankdir=LR ;\n"); printer.puts("node [shape = record"); if (opts->leafFont != NULL && *opts->leafFont) printer.nprintf(40, ", fontname = \"%s\"", opts->leafFont); if (opts->leafColor != NULL && *opts->leafColor) printer.nprintf(40, ", fontcolor = \"%s\"", opts->leafColor); printer.puts("] ;\n\n"); if (opts->leafEdgeStyle != NULL && *opts->leafEdgeStyle) printer.nprintf(40, "edge [style = %s];\n", opts->leafEdgeStyle); printer.puts("\n"); size_t last_n_phrases = 0; PgfAlignmentPhrase **last_phrases = NULL; for (size_t i = 0; i < n_revisions; i++) { ref concr = db->revision2concr(revisions[i]); PgfAlignerOutput out; PgfLinearizer linearizer(ctxt, concr, m); m->match_expr(&linearizer, expr); linearizer.reverse_and_label(true); if (linearizer.resolve()) { linearizer.linearize(&out, 0); out.flush(); printer.nprintf(40, " struct%zu[label=\"", i); size_t n_phrases; PgfAlignmentPhrase **phrases = out.get_phrases(&n_phrases); for (size_t j = 0; j < n_phrases; j++) { PgfAlignmentPhrase* phrase = phrases[j]; if (j > 0) printer.puts(" | "); printer.nprintf(16, " ", j); printer.puts(phrase->phrase); } printer.puts("\"] ;\n"); if (last_phrases != NULL) { for (size_t j = 0; j < n_phrases; j++) { PgfAlignmentPhrase* phrase = phrases[j]; for (size_t k = 0; k < phrase->n_fids; k++) { int fid = phrase->fids[k]; for (size_t l = 0; l < last_n_phrases; l++) { PgfAlignmentPhrase* last_phrase = last_phrases[l]; for (size_t r = 0; r < last_phrase->n_fids; r++) { int last_fid = last_phrase->fids[r]; if (fid == last_fid) { printer.nprintf(50, "struct%zu:n%zu:e -> struct%zu:n%zu:w ;\n",i-1,l,i,j); } } } } } } PgfAlignerOutput::free_phrases(last_phrases, last_n_phrases); last_n_phrases = n_phrases; last_phrases = phrases; } } PgfAlignerOutput::free_phrases(last_phrases, last_n_phrases); printer.puts("}"); return printer.get_text(); } PGF_API_END return NULL; } PGF_API PgfAlignmentPhrase ** pgf_align_words(PgfDB *db, PgfConcrRevision revision, PgfExpr expr, PgfPrintContext *ctxt, PgfMarshaller *m, size_t *n_phrases /* out */, PgfExn* err) { PGF_API_BEGIN { DB_scope scope(db, READER_SCOPE); ref concr = db->revision2concr(revision); PgfAlignerOutput out; PgfLinearizer linearizer(ctxt, concr, m); m->match_expr(&linearizer, expr); linearizer.reverse_and_label(true); if (linearizer.resolve()) { linearizer.linearize(&out, 0); out.flush(); return out.get_phrases(n_phrases); } } PGF_API_END return NULL; }