?? cc.c
字號:
/* parser suite - and / or / nothing / something parsers parser = [token] -> ([token],status) implemented as sideeffecting on [token], returns status.*/# include "cc.h"STATUS p_andparse0 (p, q)/*Serial composition of parsers. Doesfirst p then q. Put p's instructions on thetop of the program stack, then layer q's above it.This version has full rewind of the input stream onfailure, but this can be altered to single tokenlookahead by deleting the line of code marked.*/PARSER *p, *q;{ static status tok; /* why can't this be static? */ MARK; tok = (*p) (); if (BADSTATUS (tok)){ /* error */ RELEASE; return tok; } tok = (*q) (); if (BADSTATUS (tok)) /* error */ { REWIND; /* remove this line for 1-token LA parsing */ return tok; /* fail */ } pushDECR; RELEASE; return tok; /* succeed */}STATUS p_orparse0 (p, q)/*alternate composition of parsers. Tries p first,and if it doesnt work, tries q. Code correspondingto the successful parse is placed on the program stack.If both fail, the routine relies on p and q's auto-rewindmechanisms to do the rewind for it.*/PARSER p, q;{ static status tok; /* I don't see why this can't be static */ tok = p (); if (BADSTATUS (tok)) /* error */ tok = q (); /* retry */ return tok; /* whatever */}STATUS p_many0 (p)/*parser which tries p any number of timesuntil p fails, but returns success anyhow.*/PARSER *p;{ int repeat = 0; while (GOODSTATUS((*p) ())) repeat++;/* we no longer need stack manipulations */# ifdef STACKMANIPS switch(repeat) { case 0: pushINCR; break; case 1: break; default:pushMANIP(-(repeat-1)); break; }# endif return (SUCCESS);}STATUS p_iter0 (repeat, p)/*parser which tries p repeat number of times exactly*/PARSER *p;int repeat;{ static int k; static status tok; MARK; k = repeat; while (k-->0) { tok = (*p) (); if (BADSTATUS(tok)) { REWIND; return tok; } }#ifdef STACKMANIPS switch(repeat) { case 0: pushINCR; break; case 1: break; default:pushMANIP(-(repeat-1)); break; }#endif RELEASE; return tok;}STATUS p_until0(p)/* This parser skips until p succeeds, when it returns with p's value. It's equivalent to a foo = p | ? foo, but more efficient by a small bit of the call stack for each fail of p. */PARSER *p;{ static STATUS tok; while (*pstr) { tok = (*p)(); if GOODSTATUS(tok) return tok; MOVEON; } return FAILURE;}STATUS p_some0 (p)/*At least one repetition of parser p*/PARSER *p;{ status tok; tok = (*p) (); if (GOODSTATUS(tok)){ tok = p_many0 (p); pushDECR; /* bound to succeed */ return(tok); } return tok;}STATUS p_option0 (p)/* optionally p */PARSER *p;{ static status tok; tok = (*p) (); if (GOODSTATUS(tok)) return tok; pushINCR; return(SUCCESS);}STATUS p_range0 (p)/*checks whether *pstr satisfies predicate p.p must take a TOKEN as arg. That is a mistake. It should bean int (a PARAM).*/PREDICATE *p;{ VALUE v; if ((*p) (*pstr)) { v = lvbuff[(int)(pstr-buffer)]; MOVEON; pushVALUE(v); return (OK(v)); } return (FAILURE);}STATUS p_attach (p,f)PARSER *p;ACTION *f;{ static status tok; tok = (*p) (); if (GOODSTATUS(tok)) { pushACTION(f); return tok; } return tok;}STATUS p_prepend (f,p)PARSER *p;ACTION *f;{ static status tok; MARK; pushACTION(f); tok = (*p) (); if (GOODSTATUS(tok)) { RELEASE; return tok; } REWIND; return tok;}STATUS p_hidden0 (p)PARSER *p;/*parser which tries p, but doesnt moveon, just reports the resultof p.*/{ static status tok; MARK; tok = (*p) (); REWIND; if(GOODSTATUS(tok)) { /* we have to show we were here to keep in V(n) step */ pushVALUE(tok); return tok; } return tok;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -