📄 expr.c
字号:
case 'j':
tp = tp_int;
break;
case 't':
tp = tp_ptrdiff;
break;
case 'z':
tp = tp_size;
break;
default:
tp = tp_uint;
break;
}
check_parameter (fname, num, ptp, promote_type (tp));
return fstr + 1;
case 'a':
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
switch (optional) {
case 'L':
tp = tp_longdouble;
break;
default:
tp = tp_double;
break;
}
check_parameter (fname, num, ptp, tp);
return fstr + 1;
case 's':
tp = tp_string;
check_parameter (fname, num, ptp, tp);
return fstr + 1;
case 'p':
tp = tp_pointer;
check_parameter (fname, num, ptp, tp);
return fstr + 1;
case 'n':
switch (optional) {
case 'l':
tp = tp_long;
break;
case 'h':
tp = tp_short;
break;
default:
tp = tp_int;
break;
}
check_pointer_parameter (fname, num, ptp, tp);
return fstr + 1;
default:
break;
}
break;
default:
CANNOT_REACH_HERE ();
break;
}
return fstr;
}
static const CHAR *check_scanf P5 (const CHAR *, fname, int, num,
const CHAR *, fstr, enum fpos *, pos,
const TYP *, ptp)
{
int suppress;
CHAR optional;
TYP *tp;
if (fstr == NIL_CHAR || *fstr == (CHAR) 0) {
if (ptp != NIL_TYP) {
message (WARN_COUNTPARAM, fname);
}
return NIL_CHAR;
}
pos = pos; /* stops compilers generating warning about pos not being used */
for (; *fstr; fstr++) {
suppress = 0;
switch (*fstr) {
case '%':
fstr++;
/* optional assignment-suppressing character */
if (*fstr == (CHAR) '*') {
suppress++;
fstr++;
}
/* optional decimal integer that specifies maximum field width */
while (('0' <= *fstr) && (*fstr <= '9')) {
fstr++;
}
/* optional size of object */
switch (*fstr) {
case 'h':
case 'l':
case 'L':
optional = *fstr++;
break;
default:
optional = (CHAR) 0;
break;
}
/* type of conversion */
switch (*fstr) {
case 'd':
case 'i':
case 'n':
switch (optional) {
case 'l':
tp = tp_long;
break;
case 'h':
tp = tp_short;
break;
default:
tp = tp_int;
break;
}
if (suppress) {
continue;
}
check_pointer_parameter (fname, num, ptp, tp);
return fstr + 1;
case 'o':
case 'u':
case 'x':
switch (optional) {
case 'l':
tp = tp_ulong;
break;
case 'h':
tp = tp_ushort;
break;
default:
tp = tp_uint;
break;
}
if (suppress) {
continue;
}
check_pointer_parameter (fname, num, ptp, tp);
return fstr + 1;
case 'e':
case 'f':
case 'g':
if (suppress) {
continue;
}
switch (optional) {
case 'L':
tp = tp_longdouble;
break;
case 'l':
tp = tp_double;
break;
default:
tp = tp_float;
break;
}
check_pointer_parameter (fname, num, ptp, tp);
return fstr + 1;
case '[':
fstr++;
if (*fstr == (CHAR) '^') {
fstr++;
}
if (*fstr == (CHAR) ']') {
fstr++;
}
while (*fstr && *fstr != (CHAR) ']') {
fstr++;
}
/*lint -fallthrough */
case 'c':
case 's':
if (suppress) {
continue;
}
check_array_parameter (fname, num, ptp);
return fstr + 1;
case 'P':
if (suppress) {
continue;
}
tp = tp_pointer;
check_pointer_parameter (fname, num, ptp, tp);
return fstr + 1;
default:
break;
}
break;
default:
break;
}
}
return NIL_CHAR;
}
#endif /* SYNTAX_CORRECT */
#endif /* FORMAT_CHECK */
/*
* parmlist will build a list of parameter expressions in a function call and
* return a pointer to the last expression parsed. since parameters are
* generally pushed from right to left we get just what we asked for...
*/
static EXPR *parmlist P2 (const EXPR *, ep, const BLOCK *, block)
{
SYM *sp = block ? symbolsof (block) : NIL_SYM;
SYM *sp1 = sp;
EXPR *ep1, *ep2;
TYP *tp, *tp2;
int pnum = 0;
const CHAR *fname =
ep->nodetype == en_sym ? nameof (ep->v.sp) : (const CHAR *) "";
#ifndef SYNTAX_CORRECT
#ifdef FORMAT_CHECK
enum fpos format_position;
const CHAR *fstr = NIL_CHAR;
struct pflike
{
const CHAR **name;
int num;
const CHAR *(*func)
P_ ((const CHAR *, int, const CHAR *, enum fpos *, const TYP *));
};
struct pflike *pf = NULL;
static struct pflike printflike[] = {
{&fprintf_name, 2, check_printf},
{&printf_name, 1, check_printf},
{&sprintf_name, 2, check_printf},
{&fscanf_name, 2, check_scanf},
{&scanf_name, 1, check_scanf},
{&sscanf_name, 2, check_scanf},
{(const CHAR **) NULL, 0, NULL}
};
if (format_option) {
for (pf = &printflike[0]; pf->name; pf++) {
if (fname == *(pf->name)) {
break;
}
}
}
#endif /*FORMAT_CHECK */
if ((lang_option >= LANG_C90) && sp == NIL_SYM) {
message (WARN_NOPROTO, fname);
}
#endif /* SYNTAX_CORRECT */
ep1 = NIL_EXPR;
while (lastst != tk_closepa) {
pnum++;
ep2 = exprnc (); /* evaluate a parameter */
if (ep2 == NIL_EXPR) {
return NIL_EXPR;
}
check_set (ep2);
check_sequence_accessed (ep2);
tp2 = tp = ep2->etp;
#ifndef SYNTAX_CORRECT
if (is_void (tp)) {
message (ERR_VOIDPARM, fname);
break;
}
#endif /* SYNTAX_CORRECT */
if (sp != NIL_SYM) { /* do prototype checking */
/* skip enumeration constants etc. */
while ((sp1 != NIL_SYM) && (is_const (sp1) || is_member (sp1)))
sp1 = nextsym (sp1);
if (sp1 == NIL_SYM || is_void (typeof (sp1))) {
#ifndef SYNTAX_CORRECT
message (ERR_COUNTPARAM, fname);
#endif /* SYNTAX_CORRECT */
} else if (!promoteparam_option && !is_ellipsis (typeof (sp1))) {
if (is_array_type (typeof (sp1))) {
ep2 = implicit_castop (ep2, tp_pointer);
} else {
ep2 = implicit_castop (ep2, typeof (sp1));
}
}
}
/*
* do the default promotions
*/
switch (tp->type) {
case bt_char:
case bt_charu:
case bt_uchar:
case bt_schar:
case bt_short:
case bt_ushort:
case bt_float:
if (sp1 == NIL_SYM || promoteparam_option
|| is_ellipsis (typeof (sp1))) {
TYP *tp1 = promote_type (tp);
#ifndef SYNTAX_CORRECT
if ((lang_option >= LANG_C90) && (sp1 == NIL_SYM)
&& (tp->size < tp1->size)) {
message (WARN_PROMOTE, pnum, fname, nameoftype (tp1));
}
#endif /* SYNTAX_CORRECT */
ep2 = implicit_castop (ep2, tp1);
}
break;
case bt_double:
case bt_longdouble:
case bt_struct:
case bt_union:
/* trap struct assigns */
uses_structassign = TRUE;
break;
default:
break;
}
#ifndef SYNTAX_CORRECT
#ifdef FORMAT_CHECK
if (format_option && (pf != NULL)) {
if ((pf->num == pnum) && (ep2->nodetype == en_labcon)) {
fstr = get_stringlit (ep2->v.l);
format_position = format_start;
} else if (fstr != NULL) {
fstr =
(pf->func) (fname, pnum, fstr, &format_position,
ep2->etp);
}
}
#endif /*FORMAT_CHECK */
#endif /* SYNTAX_CORRECT */
if (sp1 != NIL_SYM && !is_ellipsis (typeof (sp1))) {
/*
* Check to see if this would cause a problem if compiled by a
* K&R compiler.
*/
tp = promote_type (typeof (sp1));
tp2 = promote_type (tp2);
if (is_array_type (tp)) {
tp = tp_pointer;
}
if (is_array_type (tp2)) {
tp2 = tp_pointer;
}
#ifndef SYNTAX_CORRECT
if (!is_same_size (tp, tp2)) {
message (WARN_PARAMSIZE, pnum, fname);
}
#endif /* SYNTAX_CORRECT */
sp1 = nextsym (sp1);
}
ep1 = mk_node (en_list, ep2, ep1, tp_void);
if (lastst != tk_comma) {
break;
}
getsym ();
}
#ifndef SYNTAX_CORRECT
/* skip enumeration constants etc. */
while ((sp1 != NIL_SYM) && (is_const (sp1) || is_member (sp1)))
sp1 = nextsym (sp1);
if (sp1 != NIL_SYM && !is_ellipsis (typeof (sp1))
&& !is_void (typeof (sp1))) {
message (ERR_COUNTPARAM, fname);
}
#ifdef FORMAT_CHECK
else if (format_option && (fstr != NIL_CHAR) && (pf != NULL)) {
VOIDCAST (pf->func) (fname, pnum, fstr, &format_position, NIL_TYP);
}
#endif /* FORMAT_CHECK */
#endif /* SYNTAX_CORRECT */
return ep1;
}
/*
* primary will parse a primary expression and set the node pointer returning
* the type of the expression parsed. primary expressions are any of:
* id
* constant
* string
* ( expression )
* primary[ expression ]
* primary.id
* primary->id
* primary( parameter list )
* primary++
* primary--
* ( type-name ) { initializer-list }
* ( type-name ) { initializer-list , }
* -- or just a semicolon, yields empty expression --
*
*/
static EXPR *primary P0 (void)
{
EXPR *ep, *ep1, *ep2;
SYM *sp;
TYP *tp, *tp1;
switch (lastst) {
case tk_id:
ep = nameref ();
if (ep == NIL_EXPR) {
return NIL_EXPR;
}
/*
* function names alone are pointers to functions.
* If followed by '(', the reference is stripped off
* later.
*/
if (is_func (ep->etp)) {
ep->etp = mk_type (tp_pointer, ep->etp);
}
break;
case tk_iconst:
tp = tp_int;
goto const1; /*lint !e801*/ /* use of goto is deprecated */
case tk_uconst:
tp = tp_uint;
goto const1; /*lint !e801*/ /* use of goto is deprecated */
case tk_lconst:
tp = tp_long;
goto const1; /*lint !e801*/ /* use of goto is deprecated */
case tk_ulconst:
tp = tp_ulong;
goto const1; /*lint !e801*/ /* use of goto is deprecated */
case tk_llconst:
tp = tp_longlong;
goto const1; /*lint !e801*/ /* use of goto is deprecated */
case tk_ullconst:
tp = tp_ulonglong;
goto const1; /*lint !e801*/ /* use of goto is deprecated */
case tk_wconst:
tp = tp_wchar;
const1:
ep = mk_icon ((IVAL) ival, tp);
getsym ();
break;
#ifdef FLOAT_SUPPORT
case tk_fconst:
tp = tp_float;
goto const2; /*lint !e801*/ /* use of goto is deprecated */
case tk_rconst:
tp = tp_double;
goto const2; /*lint !e801*/ /* use of goto is deprecated */
case tk_lrconst:
tp = tp_longdouble;
const2:
ep = mk_fcon (&rval, tp);
getsym ();
break;
#endif /* FLOAT_SUPPORT */
case tk_wsconst:
tp = tp_wstring;
goto string; /*lint !e801*/ /* use of goto is deprecated */
case tk_sconst:
tp = tp_string;
string:
if (sizeof_flag) {
ep = mk_node (en_size, NIL_EXPR, NIL_EXPR, tp);
ep->v.i = (IVAL) lastsymlen + 1L;
} else {
ep = mk_stringlit (lastsym, (size_t) lastsymlen);
ep->etp = tp;
}
getsym ();
break;
case tk_openpa:
getsym ();
if (is_type_name (lastst)) {
tp = type_name ();
needpunc (tk_closepa);
switch (lastst) {
case tk_begin:
if (lang_option >= LANG_C99) {
/*
* A postfix expression that consists of a
* parenthesized type name followed by a
* brace-enclosed list of initializers is a
* compound literal. It provides an unnamed
* object whose value is given by the initializer
* list.
*
* The type name shall specify an object type or
* an array of unknown size, but not a variable
* length array type.
*/
if (is_object_type (tp)) {
if (is_variable_array_type (tp)) {
message (ERR_VARRAY);
}
} else {
message (ERR_OBJECT);
}
getsym ();
/*
* If the compound literal occurs outside the body
* of a function, the object has static storage
* duration; otherwise, it has automatic storage
* duration associated with the enclosing block.
*/
ep =
initializer_list (tp, 0L,
(global_flag ? sc_static :
sc_auto));
ep =
mk_node (en_literal, ep, mk_size (tp->size, tp_size),
tp);
if (lastst == tk_comma)
getsym ();
needpunc (tk_end);
return ep;
}
/*lint -fallthrough */
default:
ep = unary ();
#ifndef SYNTAX_CORRECT
if (ep == NIL_EXPR) {
message (ERR_IDEXPECT);
return NIL_EXPR;
}
#endif /* SYNTAX_CORRECT */
ep = explicit_castop (ep, tp);
break;
}
} else {
ep = expression ();
needpunc (tk_closepa);
if (ep == NIL_EXPR) {
return NIL_EXPR;
}
}
break;
default:
return NIL_EXPR;
}
for (;;) {
switch (lastst) {
case tk_openbr: /* build a subscript reference */
getsym ();
/*
* a[b] is defined as *(a+b), such exactly one of (a,b) must be a
* pointer and one of (a,b) must be an integer expression
*/
if (is_pointer_type (ep->etp)) {
ep2 = expression ();
ep1 = ep;
} else {
ep2 = ep;
ep1 = expression ();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -