%{
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999-2002, 2004, 2007, 2009-2012, 2014-2017 Free
Software Foundation, Inc.
GNU Mailutils 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, or (at your option)
any later version.
GNU Mailutils 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 GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#include <mh.h>
#include <mh_format.h>
#include <sys/stat.h>
int yyerror (const char *s);
int yylex (void);
static mu_opool_t tokpool; /* Temporary token storage */
/* Lexical context */
enum context
{
ctx_init, /* Normal text */
ctx_if, /* After %< or %? */
ctx_expr, /* Expression within cond */
ctx_func, /* after (func */
};
static enum context ctx_stack[512];
size_t ctx_tos;
static inline void
ctx_push (enum context ctx)
{
if (ctx_tos == MU_ARRAY_SIZE (ctx_stack))
{
yyerror ("context nesting level too deep");
exit (1);
}
ctx_stack[ctx_tos++] = ctx;
}
static inline void
ctx_pop (void)
{
if (ctx_tos == 0)
{
yyerror ("out of context");
abort ();
}
ctx_tos--;
}
static inline enum context
ctx_get (void)
{
return ctx_stack[ctx_tos-1];
}
enum node_type
{
fmtnode_print,
fmtnode_literal,
fmtnode_number,
fmtnode_body,
fmtnode_comp,
fmtnode_funcall,
fmtnode_cntl,
fmtnode_typecast,
};
struct node
{
enum node_type nodetype;
enum mh_type datatype;
int printflag;
struct node *prev, *next;
union
{
char *str;
long num;
struct node *arg;
struct
{
int fmtspec;
struct node *arg;
} prt;
struct
{
mh_builtin_t *builtin;
struct node *arg;
} funcall;
struct
{
struct node *cond;
struct node *iftrue;
struct node *iffalse;
} cntl;
} v;
};
static struct node *parse_tree;
static struct node *new_node (enum node_type nodetype, enum mh_type datatype);
static struct node *printelim (struct node *root);
static void codegen (mh_format_t *fmt, int tree);
static struct node *typecast (struct node *node, enum mh_type type);
%}
%union {
char *str;
char const *mesg;
long num;
struct {
struct node *head, *tail;
} nodelist;
struct node *nodeptr;
mh_builtin_t *builtin;
int fmtspec;
struct {
enum mh_type type;
union
{
char *str;
long num;
} v;
} arg;
};
%token <num> NUMBER "number"
%token <str> STRING "string" COMPONENT "component"
%token <arg> ARGUMENT "argument"
%token <builtin> FUNCTION "function name"
%token IF "%<" ELIF "%?" ELSE "%|" FI "%>"
%token <fmtspec> FMTSPEC "format specifier"
%token BOGUS
%token EOFN ")"
%type <nodelist> list zlist elif_list
%type <nodeptr> item escape component funcall cntl argument
%type <nodeptr> cond cond_expr elif_part else_part printable
%type <builtin> function
%type <fmtspec> fmtspec
%error-verbose
%%
input : list
{
parse_tree = $1.head;
}
;
list : item
{
$$.head = $$.tail = $1;
}
| list item
{
$2->prev = $1.tail;
$1.tail->next = $2;
$1.tail = $2;
$$ = $1;
}
;
item : STRING
{
struct node *n = new_node (fmtnode_literal, mhtype_str);
n->v.str = $1;
$$ = new_node (fmtnode_print, mhtype_str);
$$->v.prt.arg = n;
}
| escape
;
escape : cntl
| fmtspec printable
{
if ($2->printflag & MHA_NOPRINT)
$$ = $2;
else
{
$$ = new_node (fmtnode_print, $2->datatype);
$$->v.prt.fmtspec = ($2->printflag & MHA_IGNOREFMT) ? 0 : $1;
$$->v.prt.arg = $2;
}
}
;
printable : component
| funcall
;
component : COMPONENT
{
if (mu_c_strcasecmp ($1, "body") == 0)
$$ = new_node (fmtnode_body, mhtype_str);
else
{
$$ = new_node (fmtnode_comp, mhtype_str);
$$->v.str = $1;
}
}
;
funcall : function argument EOFN
{
struct node *arg;
ctx_pop
|