summaryrefslogtreecommitdiff
path: root/agen5/tpParse.c
diff options
context:
space:
mode:
Diffstat (limited to 'agen5/tpParse.c')
-rw-r--r--agen5/tpParse.c400
1 files changed, 400 insertions, 0 deletions
diff --git a/agen5/tpParse.c b/agen5/tpParse.c
new file mode 100644
index 0000000..8f053c6
--- /dev/null
+++ b/agen5/tpParse.c
@@ -0,0 +1,400 @@
+
+/**
+ * @file tpParse.c
+ *
+ * Time-stamp: "2012-04-22 10:05:41 bkorb"
+ *
+ * This module will load a template and return a template structure.
+ *
+ * This file is part of AutoGen.
+ * Copyright (c) 1992-2012 Bruce Korb - all rights reserved
+ *
+ * AutoGen 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.
+ *
+ * AutoGen 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 <http://www.gnu.org/licenses/>.
+ */
+
+#if defined(DEBUG_ENABLED)
+static int tplNestLevel = 0;
+
+static char const zTDef[] = "%-10s (%d) line %d end=%d, strlen=%d\n";
+#endif
+
+/* = = = START-STATIC-FORWARD = = = */
+static mac_func_t
+func_code(char const ** ppzScan);
+
+static char const *
+find_mac_end(char const ** ppzMark);
+
+static char const *
+find_mac_start(char const * pz, macro_t** ppM, templ_t* pTpl);
+
+static char const *
+find_macro(templ_t * pTpl, macro_t ** ppM, char const ** ppzScan);
+/* = = = END-STATIC-FORWARD = = = */
+
+/*
+ * Return the enumerated function type corresponding
+ * to a name pointed to by the input argument.
+ */
+static mac_func_t
+func_code(char const ** ppzScan)
+{
+ fn_name_type_t const * pNT;
+ char const * pzFuncName = *ppzScan;
+ int hi, lo, av;
+ int cmp;
+
+ /*
+ * IF the name starts with a punctuation, then it is some sort of
+ * alias. Find the function in the alias portion of the table.
+ */
+ if (IS_PUNCTUATION_CHAR(*pzFuncName)) {
+ hi = FUNC_ALIAS_HIGH_INDEX;
+ lo = FUNC_ALIAS_LOW_INDEX;
+ do {
+ av = (hi + lo)/2;
+ pNT = fn_name_types + av;
+ cmp = (int)(*(pNT->pName)) - (int)(*pzFuncName);
+
+ /*
+ * For strings that start with a punctuation, we
+ * do not need to test for the end of token
+ * We will not strip off the marker and the load function
+ * will figure out what to do with the code.
+ */
+ if (cmp == 0)
+ return pNT->fType;
+ if (cmp > 0)
+ hi = av - 1;
+ else lo = av + 1;
+ } while (hi >= lo);
+ return FTYP_BOGUS;
+ }
+
+ if (! IS_VAR_FIRST_CHAR(*pzFuncName))
+ return FTYP_BOGUS;
+
+ hi = FUNC_NAMES_HIGH_INDEX;
+ lo = FUNC_NAMES_LOW_INDEX;
+
+ do {
+ av = (hi + lo)/2;
+ pNT = fn_name_types + av;
+ cmp = strneqvcmp(pNT->pName, pzFuncName, (int)pNT->cmpLen);
+ if (cmp == 0) {
+ /*
+ * Make sure we matched to the end of the token.
+ */
+ if (IS_VARIABLE_NAME_CHAR(pzFuncName[pNT->cmpLen]))
+ break;
+
+ /*
+ * Advance the scanner past the macro name.
+ * The name is encoded in the "fType".
+ */
+ *ppzScan = pzFuncName + pNT->cmpLen;
+ return pNT->fType;
+ }
+ if (cmp > 0)
+ hi = av - 1;
+ else lo = av + 1;
+ } while (hi >= lo);
+
+ /*
+ * Save the name for later lookup
+ */
+ cur_macro->md_name_off = (current_tpl->td_scan - current_tpl->td_text);
+ {
+ char * pzCopy = current_tpl->td_scan;
+ char * pe = SPN_VALUE_NAME_CHARS(pzFuncName);
+ size_t l = pe - pzFuncName;
+ memcpy(pzCopy, pzFuncName, l);
+ pzCopy += l;
+ pzFuncName += l;
+
+ /*
+ * Names are allowed to contain colons, but not end with them.
+ */
+ if (pzCopy[-1] == ':')
+ pzCopy--, pzFuncName--;
+
+ *(pzCopy++) = NUL;
+ *ppzScan = pzFuncName;
+ current_tpl->td_scan = pzCopy;
+ }
+
+ /*
+ * "Unknown" means we have to check again before we
+ * know whether to assign it to "FTYP_INVOKE" or "FTYP_COND".
+ * That depends on whether or not we find a named template
+ * at template instantiation time.
+ */
+ return FTYP_UNKNOWN;
+}
+
+static char const *
+find_mac_end(char const ** ppzMark)
+{
+ char const * pzMark = *ppzMark + st_mac_len;
+ char const * pzFunc;
+ char const * pzNextMark;
+ char const * pzEndMark;
+
+ /*
+ * Set our pointers to the start of the macro text
+ */
+ for (;;) {
+ pzMark = SPN_NON_NL_WHITE_CHARS(pzMark);
+ if (*pzMark != NL)
+ break;
+ tpl_line++;
+ pzMark++;
+ }
+
+ pzFunc = pzMark;
+ cur_macro->md_code = func_code(&pzMark);
+ cur_macro->md_line = tpl_line;
+ *ppzMark = pzMark;
+
+ /*
+ * Find the end. (We must.) If the thing is empty, treat as a comment,
+ * but warn about it.
+ */
+ pzEndMark = strstr(pzMark, end_mac_mark);
+ if (pzEndMark == NULL)
+ AG_ABEND(FIND_MAC_END_NOPE);
+
+ if (pzEndMark == pzFunc) {
+ cur_macro->md_code = FTYP_COMMENT;
+ fprintf(trace_fp, FIND_MAC_END_EMPTY,
+ current_tpl->td_file, tpl_line);
+ return pzEndMark;
+ }
+
+ /*
+ * Back up over a preceding backslash. It is a flag to indicate the
+ * removal of the end of line white space.
+ */
+ if (pzEndMark[-1] == '\\')
+ pzEndMark--;
+
+ pzNextMark = strstr(pzMark, st_mac_mark);
+ if (pzNextMark == NULL)
+ return pzEndMark;
+
+ if (pzEndMark > pzNextMark)
+ AG_ABEND(FIND_MAC_END_NESTED);
+
+ return pzEndMark;
+}
+
+static char const *
+find_mac_start(char const * pz, macro_t** ppM, templ_t* pTpl)
+{
+ char * pzCopy;
+ char const * pzEnd;
+ char const * res = strstr(pz, st_mac_mark);
+ macro_t * pM = *ppM;
+
+ if (res == pz)
+ return res;
+
+ /*
+ * There is some text here. Make a text macro entry.
+ */
+ pzCopy = pTpl->td_scan;
+ pzEnd = (res != NULL) ? res : pz + strlen(pz);
+ pM->md_txt_off = pzCopy - pTpl->td_text;
+ pM->md_code = FTYP_TEXT;
+ pM->md_line = tpl_line;
+
+#if defined(DEBUG_ENABLED)
+ if (HAVE_OPT(SHOW_DEFS)) {
+ int ct = tplNestLevel;
+ fprintf(trace_fp, "%3u ", (unsigned int)(pM - pTpl->td_macros));
+ do { fputs(" ", trace_fp); } while (--ct > 0);
+
+ fprintf(trace_fp, zTDef, ag_fun_names[ FTYP_TEXT ], FTYP_TEXT,
+ pM->md_line, pM->md_end_idx, (unsigned int)(pzEnd - pz));
+ }
+#endif
+
+ do {
+ if ((*(pzCopy++) = *(pz++)) == NL)
+ tpl_line++;
+ } while (pz < pzEnd);
+
+ *(pzCopy++) = NUL;
+ *ppM = pM + 1;
+ pTpl->td_scan = pzCopy;
+
+ return res; /* may be NULL, if there are no more macros */
+}
+
+static char const *
+find_macro(templ_t * pTpl, macro_t ** ppM, char const ** ppzScan)
+{
+ char const * pzScan = *ppzScan;
+ char const * pzMark;
+
+ pzMark = find_mac_start(pzScan, ppM, pTpl);
+
+ /*
+ * IF no more macro marks are found, THEN we are done...
+ */
+ if (pzMark == NULL)
+ return pzMark;
+
+ /*
+ * Find the macro code and the end of the macro invocation
+ */
+ cur_macro = *ppM;
+ pzScan = find_mac_end(&pzMark);
+
+ /*
+ * Count the lines in the macro text and advance the
+ * text pointer to after the marker.
+ */
+ {
+ char const * pzMacEnd = pzScan;
+ char const * pz = pzMark;
+
+ for (;;pz++) {
+ pz = strchr(pz, NL);
+ if ((pz == NULL) || (pz > pzMacEnd))
+ break;
+ tpl_line++;
+ }
+
+ /*
+ * Strip white space from the macro
+ */
+ pzMark = SPN_WHITESPACE_CHARS(pzMark);
+
+ if (pzMark != pzMacEnd) {
+ pzMacEnd = SPN_WHITESPACE_BACK( pzMark, pzMacEnd);
+ (*ppM)->md_txt_off = (uintptr_t)pzMark;
+ (*ppM)->md_res = (long)(pzMacEnd - pzMark);
+ }
+ }
+
+ /*
+ * IF the end macro mark was preceded by a backslash, then we remove
+ * trailing white space from there to the end of the line.
+ */
+ if ((*pzScan != '\\') || (strncmp(end_mac_mark, pzScan, end_mac_len) == 0))
+ pzScan += end_mac_len;
+
+ else {
+ char const * pz;
+ pzScan += end_mac_len + 1;
+ pz = SPN_NON_NL_WHITE_CHARS(pzScan);
+ if (*pz == NL) {
+ pzScan = pz + 1;
+ tpl_line++;
+ }
+ }
+
+ *ppzScan = pzScan;
+ return pzMark;
+}
+
+LOCAL macro_t *
+parse_tpl(macro_t * mac, char const ** p_scan)
+{
+ char const * scan = *p_scan;
+ templ_t * tpl = current_tpl;
+
+#if defined(DEBUG_ENABLED)
+ static char const zTUndef[] = "%-10s (%d) line %d - MARKER\n";
+
+ #define DEBUG_DEC(l) l--
+
+ if ( ((tplNestLevel++) > 0)
+ && HAVE_OPT(SHOW_DEFS)) {
+ int ct = tplNestLevel;
+ macro_t* pPm = mac-1;
+
+ fprintf(trace_fp, "%3u ", (unsigned int)(pPm - tpl->td_macros));
+ do { fputs(" ", trace_fp); } while (--ct > 0);
+
+ fprintf(trace_fp, zTUndef, ag_fun_names[ pPm->md_code ],
+ pPm->md_code, pPm->md_line);
+ }
+#else
+ #define DEBUG_DEC(l)
+#endif
+
+ while (find_macro(tpl, &mac, &scan) != NULL) {
+ /*
+ * IF the called function returns a NULL next macro pointer,
+ * THEN some block has completed. The returned scanning pointer
+ * will be non-NULL.
+ */
+ {
+ load_proc_p_t const fn = load_proc_table[mac->md_code];
+ macro_t * nxt_mac = fn(tpl, mac, &scan);
+
+#if defined(DEBUG_ENABLED)
+ if (HAVE_OPT(SHOW_DEFS)) {
+ mac_func_t ft = mac->md_code;
+ int ln = mac->md_line;
+ int ct = tplNestLevel;
+ if (mac->md_code == FTYP_BOGUS)
+ fputs(" ", trace_fp);
+ else fprintf(trace_fp, "%3u ",
+ (unsigned int)(mac - tpl->td_macros));
+
+ do { fputs(" ", trace_fp); } while (--ct > 0);
+
+ if (mac->md_code == FTYP_BOGUS)
+ fprintf(trace_fp, zTUndef, ag_fun_names[ ft ], ft, ln);
+ else {
+ char const * pz;
+ if (ft >= FUNC_CT)
+ ft = FTYP_SELECT;
+ pz = (mac->md_txt_off == 0)
+ ? zNil
+ : (tpl->td_text + mac->md_txt_off);
+ fprintf(trace_fp, zTDef, ag_fun_names[ft], mac->md_code,
+ ln, mac->md_end_idx, (unsigned int)strlen(pz));
+ }
+ }
+#endif
+
+ if (nxt_mac == NULL) {
+ *p_scan = scan;
+ DEBUG_DEC(tplNestLevel);
+ return mac;
+ }
+ mac = nxt_mac;
+ }
+ }
+
+ DEBUG_DEC(tplNestLevel);
+
+ /*
+ * We reached the end of the input string.
+ * Return a NULL scanning pointer and a pointer to the end.
+ */
+ *p_scan = NULL;
+ return mac;
+}
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of agen5/tpParse.c */