parser.c

Go to the documentation of this file.
00001 
00004 #include <stdio.h>
00005 #include <stdlib.h>             /* EXIT_SUCCESS */
00006 #include <errno.h>
00007 #include <string.h>
00008 #include "pair.h"
00009 #include "lexer.h"
00010 #include "template.h"
00011 #include "translator.h"
00012 #include "parser.h"
00013 
00017 #define EVAL(expr, err) if (expr) { errno = err; perror(pcerr); iret = EXIT_FAILURE; goto cleanup; }
00018 
00021 #define ALLOC(str, vector) EVAL((str = (char *) realloc(str, vector + sizeof('\0'))) == NULL, ENOMEM)
00022 
00025 #define STRCAT(stra, strb) ALLOC(stra, strlen(stra) + strlen(strb)); strcat(stra, strb)
00026 
00030 #define STRSUB(stra, strb, offset) ALLOC(stra, offset); sprintf(stra, "%.*s", offset, strb)
00031 
00033 #define NONE(a) a = (char *) malloc(0)
00034 
00038 int parse(char *pcin)
00039 {
00040   int i, iret = EXIT_SUCCESS;
00041   const char *pcmaskbase = "<[[:space:]]*?(%s)+?(.*?)>(.*?)</\\%d>";
00042   const char *pcdiv = "|";
00043   const char *pcerr = "parser.c parse()";
00044   char NONE(*pcmaskelement), NONE(*pcmask);
00045 
00046   /* Initialize template list. */
00047   EVAL(template(&te) != EXIT_SUCCESS, PARSE_ERR);
00048 
00049   /* Goal: element mask of the form `math|chem|music|...'. */
00050   for (i = 0; i < te.i; i++) {
00051     STRCAT(pcmaskelement, (te.pten + i)->pcclass);
00052     STRCAT(pcmaskelement, pcdiv);
00053   }
00054 
00055   /* Elide the terminal divider. */
00056   *(pcmaskelement + strlen(pcmaskelement) - strlen(pcdiv)) = '\0';
00057 
00058   /* Slight superfluity when %d recombined as integer; and on single-character classes. */
00059   ALLOC(pcmask, strlen(pcmaskelement) + strlen(pcmaskbase));
00060   sprintf(pcmask, pcmaskbase, pcmaskelement, PARSE_ELEMENT);
00061 
00062   /* Perform tokenization with callback.
00063      Important implication: class name associated with content is always the first pair! */
00064   EVAL(lex(pcin, pcmask, parsetag) != EXIT_SUCCESS, EINVAL);
00065 
00066  cleanup:
00067   templatefree(&te);
00068   free(pcmaskelement);
00069   free(pcmask);
00070   return iret;
00071 }
00072 
00075 void parsetag(char *pc)
00076 {
00077   int i, ire, aisub[PARSE_ARGS * PARSE_VECTOR], iret; /* iret: macro placeholder */
00078   pcre *pre;
00079   const char *pcre;
00080   const char *pcmask = "^<[[:space:]]*([^[:space:]]+)(.*?)>(.*)<";
00081   const char *pcerr = "parser.c parsetag()";
00082   char NONE(*pcclass), NONE(*pcpairs), NONE(*pccontent);
00083   pair_t pa;
00084 
00085   EVAL((pre = pcre_compile(pcmask, PARSE_OPT, &pcre, &ire, NULL)) == NULL, EINVAL);
00086   EVAL(pcre_exec(pre, NULL, pc, strlen(pc), 0, 0, aisub, 12) < PARSE_MATCH, EINVAL);
00087   STRSUB(pcclass, pc + aisub[PARSE_CLASS * PARSE_ARG + PARSE_BEGIN], aisub[PARSE_CLASS * PARSE_ARG + PARSE_END] - aisub[PARSE_CLASS * PARSE_ARG + PARSE_BEGIN]);
00088   STRSUB(pcpairs, pc + aisub[PARSE_PAIRS * PARSE_ARG + PARSE_BEGIN], aisub[PARSE_PAIRS * PARSE_ARG + PARSE_END] - aisub[PARSE_PAIRS * PARSE_ARG + PARSE_BEGIN]);
00089   STRSUB(pccontent, pc + aisub[PARSE_CONTENT * PARSE_ARG + PARSE_BEGIN], aisub[PARSE_CONTENT * PARSE_ARG + PARSE_END] - aisub[PARSE_CONTENT * PARSE_ARG + PARSE_BEGIN]);
00090   
00091   /* Shine constructor. */
00092   PAIRNEW(pa);
00093   /* Construct pair devised of class and content. */
00094   addpair(pcclass, pccontent, &pa);
00095   
00096   for (i = 0; i < te.i; i++) {
00097     if (strcmp(pcclass, (te.pten + i)->pcclass) == 0) {
00098       translate((te.pten + i)->pcdigest, &pa);
00099     }
00100   }
00101 
00102  cleanup:
00103   free(pcclass);
00104   free(pcpairs);
00105   free(pccontent);
00106 }

Generated on Tue Dec 7 06:38:25 2004 for CSCI101:ProjectLatex by  doxygen 1.3.9.1