Mercurial > ~dholland > hg > ag > index.cgi
diff examples/mpp/mas.syn @ 0:13d2b8934445
Import AnaGram (near-)release tree into Mercurial.
author | David A. Holland |
---|---|
date | Sat, 22 Dec 2007 17:52:45 -0500 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/mpp/mas.syn Sat Dec 22 17:52:45 2007 -0500 @@ -0,0 +1,494 @@ +{ +/* + * AnaGram, a System for Syntax Directed Programming + * C Macro preprocessor + * Macro argument substitution module + * + * Copyright 1993-2000 Parsifal Software. All Rights Reserved. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include "mpp.h" + +} + + +// Configuration Section + +[ + //far tables // uncomment for 16 bit environment + ~allow macros + line numbers + //escape backslashes // uncomment if using MSVC++ + pointer input + pointer type = token * + input values + ~error frame + error trace + ~lines and columns + ~backtrack + ~test range + default input type = token + ~declare pcb + parser file name = "#.cpp" + sticky { space } + enum { + eof =0, + SPACE =' ', + ANDAND ='A', // "&&" + ANDassign, // "&=" + ARROW, // "->" + CONCAT, // "##" + DECR, // "--" + DIVassign, // "/=" + ELLIPSIS, // "..." + EQ, // "==" + ERassign, // "^=" + GE, // ">=" + ICR, // "++" + LE, // "<=" + LS, // "<<" + LSassign, // "<<=" + MODassign, // "%=" + MINUSassign, // "-=" + MULTassign, // "*=" + NE, // "!=" + ORassign, // "|=" + OROR, // "||" + PLUSassign, // "+=" + RS, // ">>" + RSassign, // ">>=" + CHARACTERconstant, // character constant + STRINGliteral, // character string + HEXconstant =129, + OCTconstant, + DECconstant, + FLOATconstant, // real + NAME, + AUTO, // "auto" + BREAK, // "break" + CASE, // "case" + CHAR, // "char" + CONSTANT, // "const" + CONTINUE, // "continue" + DEFAULT, // "default" + DO, // "do" + DOUBLE, // "double" + ELSE, // "else" + ENUM, // "enum" + EXTERN, // "extern" + FLOAT, // "float" + FOR, // "for" + GOTO, // "goto" + IF, // "if" + INT, // "int" + LONG, // "long" + REGISTER, // "register" + RETURN, // "return" + SHORT, // "short" + SIGNED, // "signed" + SIZEOF, // "sizeof" + STATIC, // "static" + STRUCT, // "struct" + SWITCH, // "switch" + TYPEDEF, // "typedef" + UNION, // "union" + UNSIGNED, // "unsigned" + VOIDkey, // "void" + VOLATILE, // "volatile" + WHILE, // "while" + UNRECOGNIZED, + } +] + +grammar + ->space, parse unit?..., eof + + +// Accumulate optional space + +space + -> =reset(space_stack); + -> space, ' ':s ={if (args_only) space_stack << s;} + + +// Basic parse units + +parse unit + -> parameter expansion + -> simple parse unit, space =ta << space_stack; + -> concatenation, space =ta << space_stack; + -> macro:t, space =ta << t << space_stack; + +simple parse unit + -> ~eof - NAME - CONCAT - '#'- ' ':t =ta << t; + -> '#', parameter name:n =ta << make_string(n.handle); + -> variable:t =ta << t; + -> simple macro:t =expand_macro(t,0), concat(ta); + -> macro:t, space, '(', macro arg list:n, ')' =expand_macro(t,n), concat(ta); + -> defined, macro name:n =ta << defined(n.handle); + +(token) macro name + -> space, NAME:n =n; + -> space, '(', space, NAME:n, space, ')' =n; + +(token) variable, parameter name, simple macro, macro, defined + -> NAME:n =id_macro(n); + +parameter expansion + -> parameter name:name, space =expand_arg(name.handle), ta << space_stack; + + +// Implementation of "##" operator + +concatenation + -> left side, space, + parameter name:name =ta << args[name.handle], concatenate(); + -> left side, space, right side =concatenate(); + +left side + -> parameter name:n, space, CONCAT =ta << args[n.handle], ++ta; + -> simple parse unit, space, CONCAT =++ta; + -> macro:t, space, CONCAT =ta << t, ++ta; + -> concatenation, space, CONCAT =++ta; + +right side + -> ~eof - NAME - CONCAT - '#'- ' ':t =ta << t; + -> '#', parameter name:n =ta << make_string(n.handle); + -> not parameter:t =ta << t; + +(token) not parameter + -> variable + -> simple macro + -> macro + -> defined + + +// Gather Macro Arguments + +(unsigned) macro arg list + -> space = 0; + -> space, arg elements = 1; + -> macro arg list:n, ',', space, arg elements =n+1; + +initial arg element + -> ~eof - ',' - '(' - ')' - SPACE:t =++ta << t; + -> nested elements, ')':t =ta << t; + +arg element + -> ~eof - ',' - '(' - ')':t =ta << t; + -> nested elements, ')':t =concat(ta) << t; + +arg elements + -> initial arg element + -> arg elements, arg element + +nested elements + -> '(':t =++ta << t; + -> nested elements, arg element + -> nested elements, ',':t =ta << t; + + +{ // Embedded C +#include "array.h" // AnaGram\CLASSLIB\INCLUDE\array.h +#include "stack.h" // AnaGram\CLASSLIB\INCLUDE\stack.h + + +// Macro Definitions + +#define INPUT_CODE(T) (T).id +#define PCB (*mas_pcb) +#define SYNTAX_ERROR syntax_error(PCB.error_message); + + +// Static variables + +typedef stack<unsigned> unsigned_stack; // accomodate broken compilers + +static unsigned_stack active_macros(200,20); +static token **args; +static int args_only = 0; +static mas_pcb_type *mas_pcb; +static int n_concats = 0; +static int n_args; +static unsigned *params; +static token_accumulator space_stack(100); + + +/* + +expand_text() is a shell procedure which calls the mas parser a +number of times. It is used to expand arguments before substituting +them into a macro, and to expand the body of a macro. Notice that +expand_text() is recursive, since macros encountered during the an +expansion process may themselves need to be expanded. + +expand_text() takes three explicit arguments: + token *text: + points to a string of tokens, terminated by an eof token. + + int n: + specifies the number of arguments. Defaults to 0. The arguments + themselves are token strings on the token accumulator stack. + expand_text() makes copies of them and stores pointers to them in + the args array. + + unsigned *p: + An array of n dictionary indices which gives the names of the + parameters for which the arguments are to be substituted. p + defaults to NULL. + +global switches + Two global switches affect the expansion of text: if_clause and + args_only. Setting if_clause affects the treatment of the token + "defined". Setting args_only causes only macro parameters to be + expanded. + +*/ + +void expand_text(token *text, int n, unsigned *p) { + mas_pcb_type pcb; + +// Save old status + mas_pcb_type *save_pcb = mas_pcb; + int save_n_args = n_args; + token **save_args = args; + unsigned *save_params = params; + int save_switch = args_only; + +// pop args from accumlator stack and expand them + args_only = 0; + token **new_args; + int k = n; + if (n) { + new_args = new token*[n]; + args_only = 1; + while (k--) { + token t; + token top = *(token *) ta; + while (top.id == SPACE) ta >> t; //trim space on right + array<token> arg_tokens(ta, size(ta) + 1); + token *tp = arg_tokens; + while (tp->id == SPACE) tp++; //trim space on left + --ta; + mas_pcb = &pcb; + pcb.pointer = tp; + ++ta; + mas(); + new_args[k] = copy(ta); + --ta; + } + args_only = 0; + } + else new_args = NULL; + +// Expand text + args = new_args; + n_args = n; + params = p; + pcb.pointer = text; + mas_pcb = &pcb; + ++ta; + ++active_macros; + n_concats = 0; + mas(); + +// If any new tokens were created by concatenation, rescan + while (n_concats) { + array<token> expansion(ta,size(ta) + 1); + --ta; + pcb.pointer = expansion; + ++ta; + n_concats = 0; + n = size(active_macros); + +#ifdef _MSC_VER //Cope with peculiarity of MSVC++ + while (n--) macro[*((unsigned *)active_macros + n)].busy_flag = 1; +#else + while (n--) macro[active_macros[n]].busy_flag = 1; +#endif + mas(); + } + n = size(active_macros); +#ifdef _MSC_VER //Cope with peculiarity of MSVC++ + while (n--) macro[*((unsigned *)active_macros + n)].busy_flag = 0; +#else + while (n--) macro[active_macros[n]].busy_flag = 0; +#endif + --active_macros; + +// Discard argument strings + + n = n_args; + while (n--) delete [] args[n]; + if (n_args) delete [] args; + +// Restore old status + + args_only = save_switch; + args = save_args; + n_args = save_n_args; + params = save_params; + mas_pcb = save_pcb; +} + +/* + +expand_macro() is a shell procedure which sets up a call to +expand_text for a specific macro. + +*/ + +void expand_macro(token t, unsigned n_args) { + unsigned id = macro_id[t.handle]; + token *body = macro[id].body; + assert(n_args == macro[id].n_args); + if (body == NULL) { + while (n_args--) --ta; + ++ta; + return; + } + expand_text(body,n_args,macro[id].arg_names); +} + +/* + +expand_arg() is another shell procedure for expand_text() which does +a complete expansion of a single macro argument. + +*/ + +static void expand_arg(unsigned n) { + expand_text(args[n]); + concat(ta); +} + +/* + +id_macro() is very nearly the same as id_macro() in TS.SYN. The +primary difference is that this one deals in tokens, the other in +character strings. + +*/ + +static token id_macro(token t) { + unsigned n = n_args; + unsigned id; + + while (n--) if (t.handle == params[n]) { + CHANGE_REDUCTION(parameter_name); + t.handle = n; + return t; + } + if (args_only) return t; + if (if_clause && t.handle == defined_value) { + CHANGE_REDUCTION(defined); + return t; + } + id = macro_id[t.handle]; + if (id == 0) return t; + if (macro[id].busy_flag) return t; + active_macros << id; + if (macro[id].parens) CHANGE_REDUCTION(macro); + else CHANGE_REDUCTION(simple_macro); + return t; +} + +/* + +defined() is very nearly the same as defined() in TS.SYN. The primary +difference is that this one deals in tokens, the other in character +strings. + +*/ + +static token defined(unsigned handle) { + token t; + t.id = DECconstant; + t.handle = macro_id[handle] ? one_value : zero_value; + return t; +} + +/* + +concatenate() implements the splicing together of two tokens by the +"##" operator in a macro definition. Because of the way the grammar +has been written, spaces have already been trimmed on both sides of the +## by the parser. + +If there are actually two tokens to concatenate, the last token on +the left is popped off, its string value is obtained from the token +dictionary and pushed onto the string accumulator, ditto for the +first token on the right. The string is then identified and the token +is classified. If the new token is the name of a macro, a new scan +will be required to expand it. + +*/ + +static void concatenate(void) { + array<token> right_arg(ta, size(ta) + 1); + token t; + token *tp = right_arg; + + --ta; // discard right argument from stack + + if (size(ta) && tp->id != END_OF_FILE) { + ta >> t; // pop left token + ++sa << td[t.handle] << td[tp->handle]; // left string + right string + t.handle = td << sa.top(); // identify string + t.id = classify_token(sa.top()); // classify token + --sa; // discard string + ++tp; // discard old token on right + if (macro_id[t.handle]) n_concats++; // if macro, signal rescan + ta << t; // output new token + } + ta << tp; // remainder of right side +} + +/* + +make_string() implements the '#' operator in macro expansions, that +is, it turns its operand into a string constant. To do this it must +provide "" marks and must quote any embedded " or \ characters with +the \ character. + +*/ + +static token make_string(unsigned n) { + token *tp; + token t; + + tp = args[n]; + ++sa << '"'; + while (tp->id != END_OF_FILE) { + char *p = td[tp->handle]; + char c; + while ((c = *p++) != 0) { + if (c == '"' || c == '\\') sa << '\\'; + sa << c; + } + tp++; + } + sa << '"'; + t.id = STRINGliteral; + t.handle = td << sa.top(); + --sa; + return t; +} + +} // End of Embedded C