From 5312ef23c63c01be712d0fda3e401e5fa6ba35f1 Mon Sep 17 00:00:00 2001 From: "kr.angelov" Date: Fri, 25 May 2012 07:27:29 +0000 Subject: [PATCH] added pgf-service.c in the robust parser' --- src/runtime/c/utils/pgf-service.c | 309 ++++++++++++++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100644 src/runtime/c/utils/pgf-service.c diff --git a/src/runtime/c/utils/pgf-service.c b/src/runtime/c/utils/pgf-service.c new file mode 100644 index 000000000..bc9d8f923 --- /dev/null +++ b/src/runtime/c/utils/pgf-service.c @@ -0,0 +1,309 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NO_FCGI_DEFINES +#include +#include +#include + +#define ISXDIGIT(c) ( \ + (c >= 48 && c <= 57) || \ + ((c & ~0x20) >= 65 && (c & ~0x20) <= 70) \ +) + +void +url_escape(char *str) +{ + char *pr = str, *pw = str; + size_t len = strlen(str); + + for (;;) { + if ((pr - str) >= len) + break; + + if (*pr == '%' && + ((pr - str)+2) < len && + ISXDIGIT(*(pr+1)) && + ISXDIGIT(*(pr+2))) + { + pr++; + + char hexstr[3]; + hexstr[0] = *pr++; + hexstr[1] = *pr++; + hexstr[2] = 0; + + char *ptr; + int ch = strtoul(hexstr, &ptr, 16); + *pw++ = (char) (ch & 0x7f); + } + else if(*pr == '+') { + *pw++ = ' '; + } + else { + *pw++ = *pr++; + } + } + + *pw++ = 0; +} + +static int +generate_graphviz_expr(PgfExpr expr, int *pid, + GuWriter* wtr, GuExn* err, GuPool* pool) +{ + int id; + + GuVariantInfo ei = gu_variant_open(expr); + switch (ei.tag) { + case PGF_EXPR_FUN: { + PgfExprFun* fun = ei.data; + id = (*pid)++; + gu_printf(wtr, err, "n%d[label = \"", id); + gu_string_write(fun->fun, wtr, err); + gu_puts("\", style = \"solid\", shape = \"plaintext\"]\n", wtr, err); + break; + } + case PGF_EXPR_APP: { + PgfExprApp* app = ei.data; + id = generate_graphviz_expr(app->fun, pid, wtr, err, pool); + int arg_id = generate_graphviz_expr(app->arg, pid, wtr, err, pool); + gu_printf(wtr, err, "n%d -- n%d [style = \"solid\"]\n", id, arg_id); + break; + } + case PGF_EXPR_ABS: + case PGF_EXPR_LIT: { + PgfExprLit* lit = ei.data; + id = (*pid)++; + gu_printf(wtr, err, "n%d[label = \"", id); + + GuVariantInfo ei = gu_variant_open(lit->lit); + switch (ei.tag) { + case PGF_LITERAL_STR: { + PgfLiteralStr* lit = ei.data; + gu_puts("\\\"", wtr, err); + gu_string_write(lit->val, wtr, err); + gu_puts("\\\"", wtr, err); + break; + } + case PGF_LITERAL_INT: { + PgfLiteralInt* lit = ei.data; + gu_printf(wtr, err, "%d", lit->val); + break; + } + case PGF_LITERAL_FLT: { + PgfLiteralFlt* lit = ei.data; + gu_printf(wtr, err, "%lf", lit->val); + break; + } + default: + gu_impossible(); + } + + gu_puts("\", style = \"solid\", shape = \"plaintext\"]\n", wtr, err); + break; + } + case PGF_EXPR_META: + id = (*pid)++; + gu_printf(wtr, err, "n%d[label = \"?\", style = \"solid\", shape = \"plaintext\"]\n", id); + break; + case PGF_EXPR_VAR: + case PGF_EXPR_TYPED: + case PGF_EXPR_IMPL_ARG: + gu_impossible(); + break; + default: + gu_impossible(); + } + + return id; +} + +static void +generate_graphviz(PgfExpr expr, GuWriter* wtr, GuExn* err, GuPool* pool) +{ + int id = 0; + + gu_puts("graph {\n", wtr, err); + generate_graphviz_expr(expr, &id, wtr, err, pool); + gu_puts("}", wtr, err); +} + +static int +render(PgfExpr expr, GuPool* pool) +{ + int pid; + int pc[2]; /* Parent to child pipe */ + int cp[2]; /* Child to parent pipe */ + char ch; + + /* Make pipes */ + if (pipe(pc) < 0) + return 0; + if (pipe(cp) < 0) + return 0; + + /* Create a child to run command. */ + switch (pid = fork()) + { + case -1: + return 0; + case 0: + /* Child. */ + dup2(cp[1], 1); /* Make stdout go to write + end of pipe. */ + dup2(pc[0], 0); /* Make stdin come from read + end of pipe. */ + close(pc[1]); + close(cp[0]); + + char *args[] = {"dot", "-Tsvg", NULL}; + execvp(args[0], args); + + exit(1); + default: { + /* Parent. */ + FILE* fstream = fdopen(pc[1], "w"); + GuOut* out = gu_file_out(fstream, pool); + GuWriter* wtr = gu_new_utf8_writer(out, pool); + GuExn* err = gu_new_exn(NULL, gu_kind(type), pool); + + generate_graphviz(expr, wtr, err, pool); + fclose(fstream); + + close(cp[1]); + while (read(cp[0], &ch, 1) == 1) + { + FCGI_putchar(ch); + } + return 1; + } + } +} + +int main () +{ + // Create the pool that is used to allocate everything + GuPool* pool = gu_new_pool(); + int status = EXIT_SUCCESS; + + FILE* infile = fopen("/home/krasimir/www.grammaticalframework.org/examples/PennTreebank/ParseEngAbs.pgf", "r"); + if (infile == NULL) { + fprintf(stderr, "couldn't open the grammar\n"); + status = EXIT_FAILURE; + goto fail; + } + + // Create an input stream from the input file + GuIn* in = gu_file_in(infile, pool); + + // Create an exception frame that catches all errors. + GuExn* err = gu_new_exn(NULL, gu_kind(type), pool); + + // Read the PGF grammar. + PgfPGF* pgf = pgf_read(in, pool, err); + + // If an error occured, it shows in the exception frame + if (!gu_ok(err)) { + fprintf(stderr, "Reading PGF failed\n"); + status = EXIT_FAILURE; + goto fail_read; + } + + GuString cat = gu_str_string("Utt", pool); + GuString lang = gu_str_string("ParseEng", pool); + PgfConcr* concr = + gu_map_get(pgf->concretes, &lang, PgfConcr*); + if (!concr) { + status = EXIT_FAILURE; + goto fail; + } + + // Register a callback for the literal category Symbol + pgf_parser_add_literal(concr, gu_str_string("Symb", pool), + &pgf_nerc_literal_callback); + + while (FCGI_Accept() >= 0) { + char* sentence = getenv("QUERY_STRING"); + if (sentence == NULL || + (sentence = strchr(sentence, '=')) == NULL) { + FCGI_printf("Content-type: text/html\r\n" + "\r\n" + "Please specify a sentence to parse\r\n"); + } else { + sentence++; + + // We create a temporary pool for translating a single + // sentence, so our memory usage doesn't increase over time. + GuPool* ppool = gu_new_pool(); + + char* tmp = gu_malloc(ppool, strlen(sentence)+2); + strcpy(tmp, sentence); + url_escape(tmp); + int len = strlen(tmp); + tmp[len] = '\n'; + tmp[len+1] = '\0'; + sentence = tmp; + + // Begin parsing a sentence of the specified category + PgfParseState* state = + pgf_parser_init_state(concr, cat, 0, pool); + if (state == NULL) { + FCGI_printf("Content-type: text/html\r\n" + "\r\n" + "Couldn't begin parsing"); + goto fail_request; + } + + GuReader *rdr = + gu_string_reader(gu_str_string(sentence, ppool), ppool); + PgfLexer *lexer = + pgf_new_lexer(rdr, ppool); + + // Tokenization + GuExn* lex_err = gu_new_exn(NULL, gu_kind(type), ppool); + PgfToken tok = pgf_lexer_next_token(lexer, lex_err, ppool); + while (!gu_exn_is_raised(lex_err)) { + // feed the token to get a new parse state + state = pgf_parser_next_state(state, tok, ppool); + if (!state) { + FCGI_printf("Content-type: text/html\r\n" + "\r\n" + "Unexpected token"); + goto fail_request; + } + + tok = pgf_lexer_next_token(lexer, lex_err, ppool); + } + + // Now begin enumerating the resulting syntax trees + GuEnum* result = pgf_parse_result(state, ppool); + + PgfExprProb* ep = gu_next(result, PgfExprProb*, ppool); + + FCGI_printf("Content-type: image/svg+xml\r\n\r\n"); + + render(ep->expr, ppool); + +fail_request: + gu_pool_free(ppool); + } + } + +fail_read: + fclose(infile); +fail: + gu_pool_free(pool); + return status; +}