Exemplo n.º 1
0
YourSensitiveString expand_lcl(const char * local, const char * value) {
	MACRO_EVAL_CONTEXT ctx = def_ctx;
	ctx.localname = local;
	gstr.set(expand_macro(value, TestingMacroSet, ctx));
	ystr = gstr.ptr();
	return ystr;
}
Exemplo n.º 2
0
struct token *expand(struct token *original)
{
    const struct token *list;
    struct token *res;

    /* Do nothing if there is nothing to expand. */
    if (!needs_expansion(original))
        return original;

    list = original;
    res = calloc(1, sizeof(*res));
    res[0] = token_end;
    while (list->token != END) {
        const struct macro *def = definition(*list);
        struct token **args;

        /* Only expand function-like macros if they appear as function
         * invocations, beginning with an open paranthesis. */
        if (def && !is_macro_expanded(def) &&
            (def->type != FUNCTION_LIKE || peek_next(list + 1) == '('))
        {
            args = read_args(list + 1, &list, def);
            res = concat(res, expand_macro(def, args));
        } else {
            res = append(res, *list++);
        }
    }

    free(original);
    return res;
}
Exemplo n.º 3
0
cell proc_macroexpand(const cell &arglist)
{
    cell macro;
    if (!arglist.car || (macro = proc_eval(*arglist.car)).type != v_macro)
        throw(exception("Error: expected macro as first argument to macroexpand."));
    return expand_macro(macro, arglist.cdr? *arglist.cdr : cell(v_list));
}
Exemplo n.º 4
0
YourSensitiveString expand_as(const char * prefix, const char * value) {
	MACRO_EVAL_CONTEXT ctx = def_ctx;
	ctx.subsys = prefix;
	gstr.set(expand_macro(value, TestingMacroSet, ctx));
	ystr = gstr.ptr();
	return ystr;
}
Exemplo n.º 5
0
extern li_object *li_eval(li_object *exp, li_object *env) {
    li_object *seq, *proc, *args;
    int done;

    done = 0;
    while (!li_is_self_evaluating(exp) && !done) {
        li_stack_trace_push(exp);
        if (li_is_symbol(exp)) {
            exp = li_environment_lookup(env, exp);
            done = 1;
        } else if (li_is_quoted(exp)) {
            check_special_form(li_cdr(exp) && !li_cddr(exp), exp);
            exp = li_cadr(exp);
            done = 1;
        } else if (li_is_quasiquoted(exp)) {
            check_special_form(li_cdr(exp) && !li_cddr(exp), exp);
            exp = eval_quasiquote(li_cadr(exp), env);
            done = 1;
        } else if (li_is_application(exp)) {
            proc = li_eval(li_car(exp), env);
            args = li_cdr(exp);
            if (li_is_procedure(proc))
                args = list_of_values(args, env);
            if (li_is_lambda(proc)) {
                env = extend_environment(li_to_lambda(proc).vars, args,
                        li_to_lambda(proc).env);
                for (seq = li_to_lambda(proc).body; seq && li_cdr(seq);
                        seq = li_cdr(seq))
                    li_eval(li_car(seq), env);
                exp = li_car(seq);
            } else if (li_is_macro(proc)) {
                exp = expand_macro(proc, args);
            } else if (li_is_primitive_procedure(proc)) {
                exp = li_to_primitive_procedure(proc)(args);
                done = 1;
            } else if (li_is_special_form(proc)) {
                exp = li_to_special_form(proc)(args, env);
            } else {
                li_error("not applicable", proc);
            }
        } else {
            li_error("unknown expression type", exp);
        }
        li_stack_trace_pop();
    }
    return exp;
}
Exemplo n.º 6
0
/*
 * eval - eval all macros and builtins calls
 *	  argc - number of elements in argv.
 *	  argv - element vector :
 *			argv[0] = definition of a user
 *				  macro or NULL if built-in.
 *			argv[1] = name of the macro or
 *				  built-in.
 *			argv[2] = parameters to user-defined
 *			   .	  macro or built-in.
 *			   .
 *
 * A call in the form of macro-or-builtin() will result in:
 *			argv[0] = nullstr
 *			argv[1] = macro-or-builtin
 *			argv[2] = nullstr
 *
 * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
 */
void
eval(const char *argv[], int argc, int td, int is_traced)
{
	size_t mark = SIZE_MAX;

	expansion_id++;
	if (td & RECDEF)
		m4errx(1, "expanding recursive definition for %s.", argv[1]);
	if (is_traced)
		mark = trace(argv, argc, infile+ilevel);
	if (td == MACRTYPE)
		expand_macro(argv, argc);
	else
		expand_builtin(argv, argc, td);
	if (mark != SIZE_MAX)
		finish_trace(mark);
}
Exemplo n.º 7
0
static void
expand_token (struct obstack *obs, token_type t, token_data *td, int line)
{
  symbol *sym;

  switch (t)
    { /* TOKSW */
    case TOKEN_EOF:
    case TOKEN_MACDEF:
      break;

    case TOKEN_OPEN:
    case TOKEN_COMMA:
    case TOKEN_CLOSE:
    case TOKEN_SIMPLE:
    case TOKEN_STRING:
      shipout_text (obs, TOKEN_DATA_TEXT (td), strlen (TOKEN_DATA_TEXT (td)),
                    line);
      break;

    case TOKEN_WORD:
      sym = lookup_symbol (TOKEN_DATA_TEXT (td), SYMBOL_LOOKUP);
      if (sym == NULL || SYMBOL_TYPE (sym) == TOKEN_VOID
          || (SYMBOL_TYPE (sym) == TOKEN_FUNC
              && SYMBOL_BLIND_NO_ARGS (sym)
              && peek_token () != TOKEN_OPEN))
        {
#ifdef ENABLE_CHANGEWORD
          shipout_text (obs, TOKEN_DATA_ORIG_TEXT (td),
                        strlen (TOKEN_DATA_ORIG_TEXT (td)), line);
#else
          shipout_text (obs, TOKEN_DATA_TEXT (td),
                        strlen (TOKEN_DATA_TEXT (td)), line);
#endif
        }
      else
        expand_macro (sym);
      break;

    default:
      M4ERROR ((warning_status, 0,
                "INTERNAL ERROR: bad token type in expand_token ()"));
      abort ();
    }
}
Exemplo n.º 8
0
/*
 * eval - eval all macros and builtins calls
 *	  argc - number of elements in argv.
 *	  argv - element vector :
 *			argv[0] = definition of a user
 *				  macro or nil if built-in.
 *			argv[1] = name of the macro or
 *				  built-in.
 *			argv[2] = parameters to user-defined
 *			   .	  macro or built-in.
 *			   .
 *
 * A call in the form of macro-or-builtin() will result in:
 *			argv[0] = nullstr
 *			argv[1] = macro-or-builtin
 *			argv[2] = nullstr
 *
 * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
 */
void
eval(const char *argv[], int argc, int td)
{
	ssize_t mark = -1;

	expansion_id++;
	if (td & RECDEF)
		errx(1, "%s at line %lu: expanding recursive definition for %s",
			CURRENT_NAME, CURRENT_LINE, argv[1]);
	if (traced_macros && is_traced(argv[1]))
		mark = trace(argv, argc, infile+ilevel);
	if (td == MACRTYPE)
		expand_macro(argv, argc);
	else
		expand_builtin(argv, argc, td);
    	if (mark != -1)
		finish_trace(mark);
}
Exemplo n.º 9
0
/************************************************************************
**  get_actuals :  Paren must already be found.  If all the actuals can
**		be read, the macro is pushed and expansion begins. Otherwise,
**		this function is quickly exited and lets the tiny lexer take
**		care of rescanning.
************************************************************************/
void   get_actuals(pdefn_t pdef, int n_formals)
{
    /*
    **	The only concern with this is that a rescan could finish while
    **	this is trying to collect actuals.  When a rescan finishes, it
    **	may reset Act_ptr and Exp_ptr.  Unless these are saved before the
    **	end of rescan is handled, the part of the actual collected so far
    **	would be lost.
    */
    REG	ptext_t	start;
    UCHAR		c;
    ptext_t	actuals_start;
    int			paste;
    int			level;

    *Exp_ptr++ = PREVCH();			/* must be oparen */
    level = 0;
    actuals_start = Act_ptr;

    while( level >= 0) {
	if(Exp_ptr >= ELIMIT) {
	    fatal_in_macro(10056);
	}
more_white:
	if( ! can_get_non_white()) {
	    return;
	}
	if(CHARMAP(CHECKCH()) == LX_SLASH) {
	    SKIPCH();
	    if(skip_comment()) {
		goto more_white;
	    }
	    else {
		start = Exp_ptr;
		*Exp_ptr++ = '/';
	    }
	}
	else {
	    start = Exp_ptr;
	}
	paste = FALSE;

	for(;;) {
	    switch(CHARMAP(c = GETCH())) {
	    case LX_CPAREN:
		if(--level < 0) {
		    goto leave_loop;
		}
		break;
	    case LX_COMMA:
		/*
		**	if the comma is not at level == 0, it is part of
		**	a parenthesized list and not a delimiter
		*/
		if(level == 0) {
		    goto leave_loop;
		}
		break;
	    case LX_SLASH:
		if( ! skip_comment()) {
		    break;
		}
		if(*(Exp_ptr - 1) == ' ') {
		    continue;
		}
		c = ' ';
		break;
	    case LX_CR:
	    case LX_NL:
	    case LX_WHITE:
		UNGETCH();		/* This char is valid white space */
		if( ! can_get_non_white()) {
		    return;
		}
		continue;
		break;
	    case LX_OPAREN:
		++level;
		break;
	    case LX_DQUOTE:
	    case LX_SQUOTE:
		Exp_ptr = gather_chars(Exp_ptr, c);
		continue;
		break;
	    case LX_ID:
		*Exp_ptr++ = c;
		while(LXC_IS_IDENT(c = GETCH())) {
		    if(Exp_ptr >= ELIMIT) {
			fatal_in_macro(10056);
		    }
		    *Exp_ptr++ = c;
		}
		if(CHARMAP(c) != LX_MACFORMAL) {
		    UNGETCH();
		    continue;
		}
		paste = TRUE;
		/*
		**	FALLTHROUGH
		*/
	    case LX_MACFORMAL:
		move_to_exp(do_macformal(&paste));
		continue;
		break;
	    case LX_STRFORMAL:
		move_to_exp_esc('"', do_strformal());
		continue;
		break;
	    case LX_CHARFORMAL:
		move_to_exp_esc('\'', do_strformal());
		continue;
		break;
	    case LX_EOS:
		/*
		**	Will saving this pointers create dead space in the
		**	buffers?  Yes, but only temporarily.
		**
		**	handle_eos() may reset Act_ptr and Exp_ptr to the
		**	beginning of the buffers if a rescan is finishing
		**	and Macro_depth is going to be 0.  ANSI allows
		**	actuals to start within a macro defintion and be
		**	completed (further actuals and closing paren) later
		**	in the text.
		**
		**	These buffer pointers will eventually be reset to
		**	the beginnings of their respective buffers when the
		**	macro for the actuals being collected right now
		**	finish rescan
		**
		**	This is special handling for folks who use
		**	unbalanced parens in macro definitions
		*/
		{
		    ptext_t	Exp_save;
		    ptext_t	Act_save;
		    int	eos_res;

		    Exp_save = Exp_ptr;
		    Act_save = Act_ptr;
		    if((eos_res = handle_eos()) & (ACTUAL_EOS | RESCAN_EOS)) {
			return;
		    }
		    Act_ptr = Act_save;
		    Exp_ptr = Exp_save;
		    if(eos_res == BACKSLASH_EOS) {	/* ??? DFP QUESTION  */
			*Exp_ptr++ = c;		/*  save the \  */
			c = get_non_eof();	/*  get char following \  */
			break;
		    }
		}
		continue;
		break;
	    }
	    *Exp_ptr++ = c;
	}
leave_loop:
	/*
		**	if the last character was whitespace, hose it
		*/
	if(CHARMAP(*(Exp_ptr - 1)) == LX_WHITE) {
	    Exp_ptr--;
	}
	/*
	**	if Exp_ptr <= start, foo() was read, don't incr N_actuals
	*/
	if(Exp_ptr > start) {
	    N_actuals++;
	    move_to_actual(start, Exp_ptr);
	}
	*Exp_ptr++ = c;
    }

    P_actuals = actuals_start;
    if(n_formals < N_actuals) {
	Msg_Temp = GET_MSG (4002);
        SET_MSG (Msg_Text, Msg_Temp, Reuse_1);
	warning(4002);
    }
    else if(n_formals > N_actuals) {
	Msg_Temp = GET_MSG (4003);
        SET_MSG (Msg_Text, Msg_Temp, Reuse_1);
	warning(4003);
    }

    if(DEFN_TEXT(pdef)) {
	push_macro(pdef);
	expand_macro();
    }
    else {
	/*
		**	the macro expands to nothing (no definition)
		**	This essentially means delete the macro and its actuals
		**	from the expanded text
		*/
	Act_ptr = P_actuals;	/* reset pointer to get rid of actuals */
	Exp_ptr = Save_Exp_ptr;	/* delete macro & actuals from exp text */
    }
}
Exemplo n.º 10
0
/************************************************************************
**  handle_eos : handle the end of a string.
************************************************************************/
int   handle_eos(void)
{
    if(PREVCH() == '\\') {
	if(checknl()) {
	    return(FILE_EOS);
	}
	else {
	    return(BACKSLASH_EOS);
	}
    }
    if(Macro_depth == 0) {	/* found end of file buffer or backslash */
	if(io_eob()) {		/* end of buffer in here is bad */
	    Msg_Temp = GET_MSG(1004);
	    SET_MSG (Msg_Text, Msg_Temp);
	    fatal (1004);
	}
	return(FILE_EOS);
    }

    again:
    switch(GETCH()) {
    case EOS_PAD:
        goto again;
    case EOS_ACTUAL:
	/*
	** Just finished expanding actual.  Check to see if there are
	** any more actuals to be expanded.  If there are, set up to
	** expand them and return.  Otherwise, set up to expand defn
	*/

	/* move expanded text of this actual to act_buffer */
	move_to_actual(CURRENT_TEXT, Exp_ptr);

	/* reset Exp_ptr for more expansions at this macro depth */
	Exp_ptr = CURRENT_TEXT;

	/* expand next actual if there, otherwise expand definition */
	expand_macro();

	return(ACTUAL_EOS);
	break;
    case EOS_DEFINITION:
	if(rescan_expansion()) {
	    return(RESCAN_EOS);
	}
	else {
	    return(DEFINITION_EOS);
	}
	break;
    case EOS_RESCAN:
	/*
	** Reset Current_char, Exp_ptr and Act_ptr, pop the macro
	*/

	/*	get input from the previous stream */
	Current_char = CURRENT_STRING;

	/* mark this macro as not expanding */
	DEFN_EXPANDING(CURRENT_MACRO)--;


	/*
	**	if looking for the actuals of a macro, these pointers
	**	should really not be reset, however, it is cleaner to
	**	save them before calling handle_eos, and restore them
	**	upon returning, than check a static variable here.
	*/
	if(Macro_depth == 1) {
	    Act_ptr = ACT_BUFFER;
	    Exp_ptr = EXP_BUFFER;
	}
	--Macro_depth;
	return(DEFINITION_EOS);
	break;
	/* the following conditional compile is so brackets match */
    }
}
Exemplo n.º 11
0
static void mcpp_main( void)
/*
 * Main process for mcpp -- copies tokens from the current input stream
 * (main file or included file) to the output file.
 */
{
    int     c;                      /* Current character            */
    char *  wp;                     /* Temporary pointer            */
    DEFBUF *    defp;               /* Macro definition             */
    int     line_top;       /* Is in the line top, possibly spaces  */
    LINE_COL    line_col;   /* Location of macro call in source     */

    keep_comments = option_flags.c && !no_output;
    keep_spaces = option_flags.k;       /* Will be turned off if !compiling */
    line_col.col = line_col.line = 0L;

    /*
     * This loop is started "from the top" at the beginning of each line.
     * 'wrong_line' is set TRUE in many places if it is necessary to write
     * a #line record.  (But we don't write them when expanding macros.)
     *
     * 'newlines' variable counts the number of blank lines that have been
     * skipped over.  These are then either output via #line records or
     * by outputting explicit blank lines.
     * 'newlines' will be cleared on end of an included file by get_ch().
     */
    while (1) {                             /* For the whole input  */
        newlines = 0;                       /* Count empty lines    */

        while (1) {                         /* For each line, ...   */
            out_ptr = output;               /* Top of the line buf  */
            c = get_ch();
            if (src_col)
                break;  /* There is a residual tokens on the line   */
            while (char_type[ c] & HSP) {   /* ' ' or '\t'          */
                if (c != COM_SEP)
                    *out_ptr++ = c; /* Retain line top white spaces */
                                    /* Else skip 0-length comment   */
                c = get_ch();
            }
            if (c == '#') {                 /* Is 1st non-space '#' */
                directive();                /* Do a #directive      */
            } else if (mcpp_mode == STD && option_flags.dig && c == '%') {
                    /* In POST_STD digraphs are already converted   */
                if (get_ch() == ':') {      /* '%:' i.e. '#'        */
                    directive();            /* Do a #directive      */
                } else {
                    unget_ch();
                    if (! compiling) {
                        skip_nl();
                        newlines++;
                    } else {
                        break;
                    }
                }
            } else if (c == CHAR_EOF) {     /* End of input         */
                break;
            } else if (! compiling) {       /* #ifdef false?        */
                skip_nl();                  /* Skip to newline      */
                newlines++;                 /* Count it, too.       */
            } else if (in_asm && ! no_output) { /* In #asm block    */
                put_asm();                  /* Put out as it is     */
            } else if (c == '\n') {         /* Blank line           */
                if (keep_comments)
                    mcpp_fputc( '\n', OUT); /* May flush comments   */
                else
                    newlines++;             /* Wait for a token     */
            } else {
                break;                      /* Actual token         */
            }
        }

        if (c == CHAR_EOF)                  /* Exit process at      */
            break;                          /*   end of input       */

        /*
         * If the loop didn't terminate because of end of file, we
         * know there is a token to compile.  First, clean up after
         * absorbing newlines.  newlines has the number we skipped.
         */
        if (no_output) {
            wrong_line = FALSE;
        } else {
            if (wrong_line || newlines > 10) {
                sharp( NULL, 0);            /* Output # line number */
                if (keep_spaces && src_col) {
                    while (src_col--)       /* Adjust columns       */
                        mcpp_fputc( ' ', OUT);
                    src_col = 0;
                }
            } else {                        /* If just a few, stuff */
                while (newlines-- > 0)      /* them out ourselves   */
                    mcpp_fputc('\n', OUT);
            }
        }

        /*
         * Process each token on this line.
         */
        line_top = TRUE;
        while (c != '\n' && c != CHAR_EOF) {    /* For the whole line   */
            /*
             * has_pragma is set to TRUE so as to execute _Pragma() operator
             * when the psuedo macro _Pragma() is found.
             */
            int     has_pragma;

            if ((mcpp_debug & MACRO_CALL) && ! in_directive) {
                line_col.line = src_line;       /* Location in source   */
                line_col.col = infile->bptr - infile->buffer - 1;
            }
            if (scan_token( c, (wp = out_ptr, &wp), out_wend) == NAM
                    && (defp = is_macro( &wp)) != NULL) {   /* A macro  */
                wp = expand_macro( defp, out_ptr, out_wend, line_col
                        , & has_pragma);    /* Expand it completely */
                if (line_top) {     /* The first token is a macro   */
                    char *  tp = out_ptr;
                    while (char_type[ *tp & UCHARMAX] & HSP)
                        tp++;           /* Remove excessive spaces  */
                    memmove( out_ptr, tp, strlen( tp) + 1);
                    wp -= (tp - out_ptr);
                }
                if (has_pragma) {           /* Found _Pramga()      */
                    do_pragma_op();         /* Do _Pragma() operator*/
                    out_ptr = output;       /* Do the rest of line  */
                    wrong_line = TRUE;      /* Line-num out of sync */
                } else {
                    out_ptr = wp;
                }
                if (keep_spaces && wrong_line && infile
                        && *(infile->bptr) != '\n' && *(infile->bptr) != EOS) {
                    src_col = infile->bptr - infile->buffer;
                    /* Remember the current colums  */
                    break;                  /* Do sharp() now       */
                }
            } else {                        /* Not a macro call     */
                out_ptr = wp;               /* Advance the place    */
                if (wrong_line)             /* is_macro() swallowed */
                    break;                  /*      the newline     */
            }
            while (char_type[ c = get_ch()] & HSP) {    /* Horizontal space */
                if (c != COM_SEP)           /* Skip 0-length comment*/
                    *out_ptr++ = c;
            }
            line_top = FALSE;               /* Read over some token */
        }                                   /* Loop for line        */

        putout( output);                    /* Output the line      */
    }                                       /* Continue until EOF   */
}
Exemplo n.º 12
0
static int parse_fields (char *msg)
{
	char stemp[MAX_MSG_LEN+1];
	char *e;
	char *save;

	strcpy (stemp, msg);
	e = strtok_r (stemp, "*#", &save);
	while (e != NULL) {

	  switch (*e) {

	    case 'A': 
	      
	      switch (e[1]) {
	        case 'A':
	          parse_object_name (e);
	          break;
	        case 'B':
	          parse_symbol (e);
	          break;
	        case 'C':
	          /*
	           * New in 1.2: test for 10 digit callsign.
	           */
	          if (tt_call10_to_text(e+2,1,stemp) == 0) {
	             strcpy(m_callsign, stemp);
	          }
	          break;
	        default:
	          parse_callsign (e);
	          break;
	      }
	      break;

	    case 'B': 
	      parse_location (e);
	      break;

	    case 'C': 
	      parse_comment (e);
	      break;

	    case '0': 
	    case '1': 
	    case '2': 
	    case '3': 
	    case '4': 
	    case '5': 
	    case '6': 
	    case '7': 
	    case '8': 
	    case '9': 
	      expand_macro (e);
	      break;

	    case '\0':
	      /* Empty field.  Just ignore it. */
	      /* This would happen if someone uses a leading *. */
	      break;

	    default:

	      text_color_set(DW_COLOR_ERROR);
	      dw_printf ("Entry does not start with A, B, C, or digit: \"%s\"\n", msg);
	      return (TT_ERROR_D_MSG);

	  }
	
	  e = strtok_r (NULL, "*#", &save);
	}

	return (0);

} /* end parse_fields */
Exemplo n.º 13
0
cell proc_eval(const cell &x)
{
    bool listvars = false;
    if (listvars)
        proc_listvars(cell());
    if (x.type == v_string || x.type == v_number || x.type == v_function)
        return x;
    else if (x.type == v_symbol)
    {
        //std::cout << "fetching var " << x.str << ": " << toString(env->get(x.str)) << "\n";
        return env->get(x.str);
    }
    else if (x.type == v_list)
    {
        if (!x.car)
            return nil;
        cell head = proc_eval(*x.car);
        if (head.type == v_proc)
            return head.proc(x.cdr? *x.cdr : nil);
        if (head.type == v_function)
        {
            std::shared_ptr<environment> oldenv = env;
            std::shared_ptr<environment> newenv(new environment(head.env));
            const cell *name_iter = head.car;
            const cell *arg_iter = x.cdr;
            while (arg_iter && arg_iter->car && name_iter && name_iter->car)
            {
                if (name_iter->car->str == "&REST")
                {
                    if (!(name_iter->cdr && name_iter->cdr->car && name_iter->cdr->car->type == v_symbol))
                        throw(exception("Error: expected name for &rest parameter"));
                    cell head(v_list);
                    cell *tail = &head;
                    while (arg_iter && arg_iter->car)
                    {
                        tail->car = new cell();
                        *tail->car = proc_eval(*arg_iter->car);
                        tail->cdr = new cell(v_list);
                        tail = tail->cdr;
                        arg_iter = arg_iter->cdr;
                    }
                    newenv->vars[name_iter->cdr->car->str] = head;
                    name_iter = name_iter->cdr->cdr;
                    break;                              //skip the outer loop so we don't dereference the null car pointer.
                }
                newenv->vars[name_iter->car->str] = proc_eval(*arg_iter->car);
                arg_iter = arg_iter->cdr;
                name_iter = name_iter->cdr;
            }
            if (arg_iter && arg_iter->car)
                throw(exception("Error: too many arguments to function"));
            if (name_iter && name_iter->car)
                throw(exception("Error: too few arguments to function"));
            env = newenv;
            cell result;
            cell *body_iter = head.cdr;
            while (body_iter && body_iter->car)
            {
                result = proc_eval(*body_iter->car);
                body_iter = body_iter->cdr;
            }
            env = oldenv;
            return result;
        }
        if (head.type == v_macro)
            return proc_eval(expand_macro(head, x.cdr? *x.cdr : cell(v_list)));

        throw(exception("Error: attempt to call non-proc"));

    }
    else
    {
        throw(exception("Unrecognised cell type! (eval)"));
    }
}
Exemplo n.º 14
0
void
expand_macro(source_t *src, string_t *destination, wchar_t *current_string,
    boolean_t cmd)
{
	string_t str;
	wchar_t buf[STRING_BUFFER_LENGTH];
	wchar_t closer = L'\0';
	unsigned int closer_level = 0;
	wchar_t *block_start;
	boolean_t quote_seen;

	/*
	 * First, we copy the (macro-expanded) macro name into string.
	 */
	INIT_STRING_FROM_STACK(str, buf);

recheck_first_char:
	/*
	 * Check the first char of the macro name to figure out what to do.
	 */
	switch (source_popchar(src)) {
	case L'\0':
		src = get_next_block_fn(src);
		if (src == NULL) {
			fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 114,
			    "'$' at end of string `%ls'"), current_string);
		}
		if (src->src_error_converting == B_TRUE) {
			fatal_reader_mksh(NOCATGETS("Internal error: Invalid"
			    " byte sequence in expand_macro()"));
		}
		goto recheck_first_char;
	case L'(':
		/*
		 * Multi-character name.
		 */
		closer = L')';
		break;
	case L'{':
		/*
		 * Multi-character name.
		 */
		closer = L'}';
		break;
	case L'\n':
		fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 115,
		    "'$' at end of line"));
		break;
	default:
		/*
		 * Single-character macro name.  Just suck it up.
		 */
		append_char(*src->src_str.str_p, &str);
		goto next_step;
	}

	/*
	 * Handle multi-character macro names:
	 */
	block_start = src->src_str.str_p;
	quote_seen = B_FALSE;
	for (;; (void) source_popchar(src)) {
		wchar_t c;
		switch (c = source_peekchar(src)) {
		case L'\0':
			append_string_wide(block_start, &str,
			    src->src_str.str_p - block_start);
			src = get_next_block_fn(src);
			if (src == NULL) {
				if (current_string != NULL) {
					fatal_reader_mksh(catgets(
					    libmksdmsi18n_catd, 1, 116,
					    "Unmatched `%lc' in string `%ls'"),
					    closer == L'}' ? L'{' : L'(',
					    current_string);
				} else {
					fatal_reader_mksh(catgets(
					    libmksdmsi18n_catd, 1, 117,
					    "Premature EOF"));
				}
			}
			if (src->src_error_converting == B_TRUE) {
				fatal_reader_mksh(NOCATGETS("Internal error: "
				    "Invalid byte sequence in expand_macro()"));
			}
			block_start = src->src_str.str_p;
			src->src_str.str_p--; /* because we're about to pop */
			continue;
		case L'\n':
			fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 118,
			    "Unmatched `%lc' on line"),
			    closer == L'}' ? L'{' : L'(');
			break;
		case L'\\':
			/*
			 * Quote '$' in macro value:
			 */
			if (cmd == B_FALSE) {
				quote_seen = quote_seen == B_TRUE ? B_FALSE :
				    B_TRUE;
			}
			continue;
		case L'$':
			/*
			 * Macro names may reference macros.
			 * This expands the value of such macros into the
			 * macro name string.
			 */
			if (quote_seen == B_TRUE) {
				append_string_wide(block_start, &str,
				    src->src_str.str_p - block_start - 1);
				block_start = src->src_str.str_p;
				break;
			}
			append_string_wide(block_start, &str,
			    src->src_str.str_p - block_start);
			/*
			 * Move past the $ for this macro, and expand
			 * the reference:
			 */
			(void) source_popchar(src);
			expand_macro(src, &str, current_string, cmd);
			block_start = src->src_str.str_p;
			src->src_str.str_p--; /* because about to pop */
			break;
		case L'(':
			/*
			 * Allow nested pairs of () in the macro name.
			 */
			if (closer == L')')
				closer_level++;
			break;
		case L'{':
			/*
			 * Allow nested pairs of {} in the macro name.
			 */
			if (closer == L'}')
				closer_level++;
			break;
		case L')':
		case L'}':
			/*
			 * End of the name.  Save the string in the macro
			 * name string.
			 */
			if (c == closer && --closer_level == 0) {
				append_string_wide(block_start, &str,
				    src->src_str.str_p - block_start);
				/*
				 * Discard the closer character, and get out:
				 */
				(void) source_popchar(src);
				goto next_step;
			}
			break;
		}
		quote_seen = B_FALSE;
	}

next_step:
	/*
	 * We have the macro name.  Inspect it to see if it specifies
	 * any translations of the value.
	 */
	_process_macro_name(&str, destination, cmd);

	if (str.str_free_after_use == B_TRUE)
		free(str.str_buf_start);
}
Exemplo n.º 15
0
/*
 *	expand_value(value, destination, cmd)
 *
 *	Recursively expands all macros in the string value.
 *	destination is where the expanded value should be appended.
 *
 *	Parameters:
 *		value		The value we are expanding
 *		destination	Where to deposit the expansion
 *		cmd		If we are evaluating a command line we
 *				turn \ quoting off
 *
 *	Global variables used:
 */
void
expand_value(name_t *value, string_t *destination, boolean_t cmd)
{
	source_t *src;
	wchar_t *block_start;
	boolean_t quote_seen = B_FALSE;

	if (value == NULL) {
		/*
		 * Make sure to get a string allocated even if it
		 * will be empty.
		 * XXX this seems like it might be a misunderstanding
		 * of the interface?  Surely we can guarantee that
		 * every string_t is allocated correctly...
		 */
		append_string_wide(L"", destination, FIND_LENGTH);
		destination->str_end = destination->str_p;
		return;
	}
	if (value->n_dollar == B_FALSE) {
		/*
		 * If the value we are expanding does not contain
		 * any $, we don't have to parse it.
		 */
		append_string_name(value, destination);
		destination->str_end = destination->str_p;
		return;
	}

	if (value->n_being_expanded == B_TRUE) {
		fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 113,
		    "Loop detected when expanding macro value `%ls'"),
		    value->n_key);
	}
	value->n_being_expanded = B_TRUE;

	src = source_from_wchar(value->n_key);

	/*
	 * We parse the string in segments.
	 * We read characters until we find a $, then we append what we have
	 * read so far (since last $ processing) to the destination.  When
	 * we find a '$', we call expand_macro() and let it expand that
	 * particular $ reference into destination.
	 */
	quote_seen = B_FALSE;
	block_start = src->src_str.str_p;
	for (;; (void) source_popchar(src)) {
		switch (source_peekchar(src)) {
		case L'\\':
			/* Quote $ in macro value */
			if (cmd == B_FALSE) {
				quote_seen = quote_seen == B_TRUE ? B_FALSE :
				    B_TRUE;
			}
			continue;
		case L'$':
			/* Save the plain string we found since */
			/* start of string or previous $ */
			if (quote_seen == B_TRUE) {
				append_string_wide(block_start, destination,
				    src->src_str.str_p - block_start - 1);
				block_start = src->src_str.str_p;
				break;
			}
			append_string_wide(block_start, destination,
			    src->src_str.str_p - block_start);
			/*
			 * Move past the $ for this macro, and expand
			 * the reference:
			 */
			(void) source_popchar(src);
			expand_macro(src, destination,
			    src->src_str.str_buf_start, cmd);
			block_start = src->src_str.str_p + 1;
			break;
		case L'\0':
			/* The string ran out. Get some more */
			append_string_wide(block_start, destination,
			    src->src_str.str_p - block_start);

			src = get_next_block_fn(src);
			if (src == NULL) {
				/*
				 * We're done.
				 */
				destination->str_end = destination->str_p;
				value->n_being_expanded = B_FALSE;
				return;
			}
			if (src->src_error_converting == B_TRUE) {
				fatal_reader_mksh(NOCATGETS("Internal error: "
				    "Invalid byte sequence in expand_value()"));
			}
			block_start = src->src_str.str_p;
			src->src_str.str_p--; /* because we're about to pop */
			continue;
		}
		quote_seen = B_FALSE;
	}
#if 0
out:
	if (src->src_string.str_free_after_use == B_TRUE)
		free(sourceb.src_string.str_buf_start);
#endif
}
Exemplo n.º 16
0
// The expand helpers return a ystr, and also store the malloc'ed return value
// in an auto_free_ptr so that the will be automatically freed by the next REQUIRE
//
YourSensitiveString expand(const char * value) {
	gstr.set(expand_macro(value, TestingMacroSet, def_ctx));
	ystr = gstr.ptr();
	return ystr;
}