14226f635SJason King /*
24226f635SJason King  * Ported from LLVM's libcxxabi trunk/src/cxa_demangle.cpp
34226f635SJason King  * LICENSE.TXT contents is available as ../THIRDPARTYLICENSE
44226f635SJason King  *
54226f635SJason King  *                     The LLVM Compiler Infrastructure
64226f635SJason King  *
74226f635SJason King  * This file is dual licensed under the MIT and the University of Illinois Open
84226f635SJason King  * Source Licenses. See LICENSE.TXT for details.
94226f635SJason King  *
104226f635SJason King  */
114226f635SJason King 
124226f635SJason King /*
136bb387f3SJason King  * Copyright 2021 Jason King.
144226f635SJason King  */
154226f635SJason King #include <errno.h>
164226f635SJason King #include <note.h>
174226f635SJason King #include <string.h>
184226f635SJason King #include <setjmp.h>
194226f635SJason King #include <stdio.h>
204226f635SJason King #include <stdlib.h>
214226f635SJason King #include "demangle-sys.h"
224226f635SJason King #include "demangle_int.h"
234226f635SJason King #include "cxx.h"
244226f635SJason King 
254226f635SJason King #define	CPP_QUAL_CONST		(1U)
264226f635SJason King #define	CPP_QUAL_VOLATILE	(2U)
274226f635SJason King #define	CPP_QUAL_RESTRICT	(4U)
284226f635SJason King 
294226f635SJason King typedef struct cpp_db_s {
304226f635SJason King 	sysdem_ops_t	*cpp_ops;
314226f635SJason King 	jmp_buf		cpp_jmp;
324226f635SJason King 	name_t		cpp_name;
334226f635SJason King 	sub_t		cpp_subs;
344226f635SJason King 	templ_t		cpp_templ;
354226f635SJason King 	unsigned	cpp_cv;
364226f635SJason King 	unsigned	cpp_ref;
374226f635SJason King 	unsigned	cpp_depth;
384226f635SJason King 	boolean_t	cpp_parsed_ctor_dtor_cv;
394226f635SJason King 	boolean_t	cpp_tag_templates;
404226f635SJason King 	boolean_t	cpp_fix_forward_references;
414226f635SJason King 	boolean_t	cpp_try_to_parse_template_args;
424226f635SJason King } cpp_db_t;
434226f635SJason King 
444226f635SJason King #define	CK(x)						\
454226f635SJason King 	do {						\
464226f635SJason King 		if (!(x)) {				\
474226f635SJason King 			longjmp(db->cpp_jmp, 1);	\
484226f635SJason King 		}					\
494226f635SJason King 	NOTE(CONSTCOND)					\
504226f635SJason King 	} while (0)
514226f635SJason King 
524226f635SJason King #define	TOP_L(db) (&(name_top(&(db)->cpp_name)->strp_l))
534226f635SJason King #define	RLEN(f, l) ((size_t)((l) - (f)))
544226f635SJason King #define	NAMT(db, n) (nlen(db) - n)
554226f635SJason King 
564226f635SJason King static inline boolean_t is_xdigit(int);
574226f635SJason King 
584226f635SJason King static boolean_t nempty(cpp_db_t *);
594226f635SJason King static size_t nlen(cpp_db_t *);
604226f635SJason King static void nadd_l(cpp_db_t *, const char *, size_t);
614226f635SJason King static void njoin(cpp_db_t *, size_t, const char *);
624226f635SJason King static void nfmt(cpp_db_t *, const char *, const char *);
634226f635SJason King 
644226f635SJason King static void save_top(cpp_db_t *, size_t);
654226f635SJason King static void sub(cpp_db_t *, size_t);
664226f635SJason King 
674226f635SJason King static boolean_t tempty(const cpp_db_t *);
684226f635SJason King static size_t ttlen(const cpp_db_t *);
694226f635SJason King 
704226f635SJason King static void tsub(cpp_db_t *, size_t);
714226f635SJason King static void tpush(cpp_db_t *);
724226f635SJason King static void tpop(cpp_db_t *);
734226f635SJason King static void tsave(cpp_db_t *, size_t);
744226f635SJason King 
75*1cd08393SJason King static void db_init(cpp_db_t *, sysdem_ops_t *);
764226f635SJason King static void db_fini(cpp_db_t *);
774226f635SJason King static void dump(cpp_db_t *, FILE *);
784226f635SJason King 
794226f635SJason King static void demangle(const char *, const char *, cpp_db_t *);
804226f635SJason King 
814226f635SJason King static const char *parse_type(const char *, const char *, cpp_db_t *);
824226f635SJason King static const char *parse_builtin_type(const char *, const char *, cpp_db_t *);
834226f635SJason King static const char *parse_qual_type(const char *, const char *, cpp_db_t *);
844226f635SJason King static const char *parse_encoding(const char *, const char *, cpp_db_t *);
854226f635SJason King static const char *parse_dot_suffix(const char *, const char *, cpp_db_t *);
864226f635SJason King static const char *parse_block_invoke(const char *, const char *, cpp_db_t *);
874226f635SJason King static const char *parse_special_name(const char *, const char *, cpp_db_t *);
884226f635SJason King static const char *parse_name(const char *, const char *, boolean_t *,
894226f635SJason King     cpp_db_t *);
90*1cd08393SJason King static const char *parse_call_offset(const char *, const char *);
91*1cd08393SJason King static const char *parse_number(const char *, const char *);
924226f635SJason King static const char *parse_nested_name(const char *, const char *, boolean_t *,
934226f635SJason King     cpp_db_t *);
944226f635SJason King static const char *parse_local_name(const char *, const char *, boolean_t *,
954226f635SJason King     cpp_db_t *);
964226f635SJason King static const char *parse_unscoped_name(const char *, const char *, cpp_db_t *);
974226f635SJason King static const char *parse_template_args(const char *, const char *, cpp_db_t *);
984226f635SJason King static const char *parse_substitution(const char *, const char *, cpp_db_t *);
99*1cd08393SJason King static const char *parse_discriminator(const char *, const char *);
1004226f635SJason King static const char *parse_cv_qualifiers(const char *, const char *, unsigned *);
1014226f635SJason King static const char *parse_template_param(const char *, const char *, cpp_db_t *);
1024226f635SJason King static const char *parse_decltype(const char *, const char *, cpp_db_t *);
1034226f635SJason King static const char *parse_template_args(const char *, const char *, cpp_db_t *);
1044226f635SJason King static const char *parse_unqualified_name(const char *, const char *,
1054226f635SJason King     cpp_db_t *);
1064226f635SJason King static const char *parse_template_arg(const char *, const char *, cpp_db_t *);
1074226f635SJason King static const char *parse_expression(const char *, const char *, cpp_db_t *);
1084226f635SJason King static const char *parse_expr_primary(const char *, const char *, cpp_db_t *);
1094226f635SJason King static const char *parse_binary_expr(const char *, const char *,
1104226f635SJason King     const char *, cpp_db_t *);
1114226f635SJason King static const char *parse_prefix_expr(const char *, const char *,
1124226f635SJason King     const char *, cpp_db_t *);
1134226f635SJason King static const char *parse_gs(const char *, const char *, cpp_db_t *);
1144226f635SJason King static const char *parse_idx_expr(const char *, const char *, cpp_db_t *);
1154226f635SJason King static const char *parse_mm_expr(const char *, const char *, cpp_db_t *);
1164226f635SJason King static const char *parse_pp_expr(const char *, const char *, cpp_db_t *);
1174226f635SJason King static const char *parse_trinary_expr(const char *, const char *, cpp_db_t *);
1184226f635SJason King static const char *parse_new_expr(const char *, const char *, cpp_db_t *);
1194226f635SJason King static const char *parse_del_expr(const char *, const char *, cpp_db_t *);
1204226f635SJason King static const char *parse_cast_expr(const char *, const char *, cpp_db_t *);
1214226f635SJason King static const char *parse_sizeof_param_pack_expr(const char *, const char *,
1224226f635SJason King     cpp_db_t *);
1234226f635SJason King static const char *parse_typeid_expr(const char *, const char *, cpp_db_t *);
1244226f635SJason King static const char *parse_throw_expr(const char *, const char *, cpp_db_t *);
1254226f635SJason King static const char *parse_dot_star_expr(const char *, const char *, cpp_db_t *);
1264226f635SJason King static const char *parse_dot_expr(const char *, const char *, cpp_db_t *);
1274226f635SJason King static const char *parse_call_expr(const char *, const char *, cpp_db_t *);
1284226f635SJason King static const char *parse_arrow_expr(const char *, const char *, cpp_db_t *);
1294226f635SJason King static const char *parse_conv_expr(const char *, const char *, cpp_db_t *);
1304226f635SJason King static const char *parse_function_param(const char *, const char *, cpp_db_t *);
1314226f635SJason King static const char *parse_base_unresolved_name(const char *, const char *,
1324226f635SJason King     cpp_db_t *);
1334226f635SJason King static const char *parse_unresolved_name(const char *, const char *,
1344226f635SJason King     cpp_db_t *);
1354226f635SJason King static const char *parse_noexcept_expr(const char *, const char *, cpp_db_t *);
1364226f635SJason King static const char *parse_alignof(const char *, const char *, cpp_db_t *);
1374226f635SJason King static const char *parse_sizeof(const char *, const char *, cpp_db_t *);
1384226f635SJason King static const char *parse_unnamed_type_name(const char *, const char *,
1394226f635SJason King     cpp_db_t *);
1404226f635SJason King static const char *parse_ctor_dtor_name(const char *, const char *, cpp_db_t *);
1414226f635SJason King static const char *parse_source_name(const char *, const char *, cpp_db_t *);
1424226f635SJason King static const char *parse_operator_name(const char *, const char *, cpp_db_t *);
1434226f635SJason King static const char *parse_pack_expansion(const char *, const char *, cpp_db_t *);
1444226f635SJason King static const char *parse_unresolved_type(const char *, const char *,
1454226f635SJason King     cpp_db_t *);
1464226f635SJason King static const char *parse_unresolved_qualifier_level(const char *, const char *,
1474226f635SJason King     cpp_db_t *);
1484226f635SJason King static const char *parse_destructor_name(const char *, const char *,
1494226f635SJason King     cpp_db_t *);
1504226f635SJason King static const char *parse_function_type(const char *, const char *, cpp_db_t *);
1514226f635SJason King static const char *parse_array_type(const char *, const char *, cpp_db_t *);
1524226f635SJason King static const char *parse_pointer_to_member_type(const char *, const char *,
1534226f635SJason King     cpp_db_t *);
1544226f635SJason King static const char *parse_vector_type(const char *, const char *, cpp_db_t *);
1554226f635SJason King 
1564226f635SJason King size_t cpp_name_max_depth = 1024;	/* max depth of name stack */
1574226f635SJason King 
1584226f635SJason King char *
cpp_demangle(const char * src,size_t srclen,sysdem_ops_t * ops)1596a6cfa5dSJason King cpp_demangle(const char *src, size_t srclen, sysdem_ops_t *ops)
1604226f635SJason King {
1615eadbc30SToomas Soome 	char *volatile result = NULL;
1624226f635SJason King 	cpp_db_t db;
1634226f635SJason King 
164*1cd08393SJason King 	db_init(&db, ops);
165*1cd08393SJason King 
1664226f635SJason King 	if (setjmp(db.cpp_jmp) != 0)
1674226f635SJason King 		goto done;
1684226f635SJason King 
1694226f635SJason King 	errno = 0;
1704226f635SJason King 	demangle(src, src + srclen, &db);
1714226f635SJason King 
1724226f635SJason King 	if (errno == 0 && db.cpp_fix_forward_references &&
1734226f635SJason King 	    !templ_empty(&db.cpp_templ) &&
1744226f635SJason King 	    !sub_empty(&db.cpp_templ.tpl_items[0])) {
1754226f635SJason King 		db.cpp_fix_forward_references = B_FALSE;
1764226f635SJason King 		db.cpp_tag_templates = B_FALSE;
1774226f635SJason King 		name_clear(&db.cpp_name);
1784226f635SJason King 		sub_clear(&db.cpp_subs);
1794226f635SJason King 
1804226f635SJason King 		if (setjmp(db.cpp_jmp) != 0)
1814226f635SJason King 			goto done;
1824226f635SJason King 
1834226f635SJason King 		demangle(src, src + srclen, &db);
1844226f635SJason King 
1854226f635SJason King 		if (db.cpp_fix_forward_references) {
1864226f635SJason King 			errno = EINVAL;
1874226f635SJason King 			goto done;
1884226f635SJason King 		}
1894226f635SJason King 	}
1904226f635SJason King 
1914226f635SJason King 	if (errno != 0)
1924226f635SJason King 		goto done;
1934226f635SJason King 
1944226f635SJason King 	if (nempty(&db)) {
1954226f635SJason King 		errno = EINVAL;
1964226f635SJason King 		goto done;
1974226f635SJason King 	}
1984226f635SJason King 
1994226f635SJason King 	njoin(&db, 1, "");
2004226f635SJason King 
2014226f635SJason King 	if (nlen(&db) > 0) {
2024226f635SJason King 		str_t *s = TOP_L(&db);
203e239895eSToomas Soome 		char *res = zalloc(ops, s->str_len + 1);
204e239895eSToomas Soome 		if (res == NULL)
2054226f635SJason King 			goto done;
2064226f635SJason King 
207e239895eSToomas Soome 		(void) memcpy(res, s->str_s, s->str_len);
208e239895eSToomas Soome 		result = res;
2094226f635SJason King 	}
2104226f635SJason King 
2114226f635SJason King done:
2124226f635SJason King 	if (demangle_debug)
2134226f635SJason King 		dump(&db, stdout);
2144226f635SJason King 
2154226f635SJason King 	db_fini(&db);
2164226f635SJason King 	return (result);
2174226f635SJason King }
2184226f635SJason King 
2194226f635SJason King static void
demangle(const char * first,const char * last,cpp_db_t * db)2204226f635SJason King demangle(const char *first, const char *last, cpp_db_t *db)
2214226f635SJason King {
2224226f635SJason King 	const char *t = NULL;
2234226f635SJason King 
2244226f635SJason King 	if (first >= last) {
2254226f635SJason King 		errno = EINVAL;
2264226f635SJason King 		return;
2274226f635SJason King 	}
2284226f635SJason King 
2294226f635SJason King 	if (first[0] != '_') {
2304226f635SJason King 		t = parse_type(first, last, db);
2314226f635SJason King 		if (t == first) {
2324226f635SJason King 			errno = EINVAL;
2334226f635SJason King 			return;
2344226f635SJason King 		}
2354226f635SJason King 		goto done;
2364226f635SJason King 	}
2374226f635SJason King 
2384226f635SJason King 	if (last - first < 4) {
2394226f635SJason King 		errno = EINVAL;
2404226f635SJason King 		return;
2414226f635SJason King 	}
2424226f635SJason King 
2434226f635SJason King 	if (first[1] == 'Z') {
2444226f635SJason King 		t = parse_encoding(first + 2, last, db);
2454226f635SJason King 
2464226f635SJason King 		if (t != first + 2 && t != last && t[0] == '.') {
2474226f635SJason King 			t = parse_dot_suffix(t, last, db);
2484226f635SJason King 			if (nlen(db) > 1)
2494226f635SJason King 				njoin(db, 2, "");
2504226f635SJason King 		}
2514226f635SJason King 
2524226f635SJason King 		goto done;
2534226f635SJason King 	}
2544226f635SJason King 
2554226f635SJason King 	if (first[1] != '_' || first[2] != '_' || first[3] != 'Z')
2564226f635SJason King 		goto done;
2574226f635SJason King 
2584226f635SJason King 	t = parse_encoding(first + 4, last, db);
2594226f635SJason King 	if (t != first + 4 && t != last)
2604226f635SJason King 		t = parse_block_invoke(t, last, db);
2614226f635SJason King 
2624226f635SJason King done:
2634226f635SJason King 	if (t != last)
2644226f635SJason King 		errno = EINVAL;
2654226f635SJason King }
2664226f635SJason King 
2674226f635SJason King static const char *
parse_dot_suffix(const char * first,const char * last,cpp_db_t * db)2684226f635SJason King parse_dot_suffix(const char *first, const char *last, cpp_db_t *db)
2694226f635SJason King {
2704226f635SJason King 	VERIFY3P(first, <=, last);
2714226f635SJason King 
2724226f635SJason King 	if (first == last || first[0] != '.')
2734226f635SJason King 		return (first);
2744226f635SJason King 
2754226f635SJason King 	if (nempty(db))
2764226f635SJason King 		return (first);
2774226f635SJason King 
2784226f635SJason King 	nadd_l(db, first, RLEN(first, last));
2794226f635SJason King 	nfmt(db, " ({0})", NULL);
2804226f635SJason King 
2814226f635SJason King 	return (last);
2824226f635SJason King }
2834226f635SJason King 
2844226f635SJason King /*
2854226f635SJason King  * _block_invoke
2864226f635SJason King  * _block_invoke<digit>*
2874226f635SJason King  * _block_invoke_<digit>+
2884226f635SJason King  */
2894226f635SJason King static const char *
parse_block_invoke(const char * first,const char * last,cpp_db_t * db)2904226f635SJason King parse_block_invoke(const char *first, const char *last, cpp_db_t *db)
2914226f635SJason King {
2924226f635SJason King 	VERIFY3P(first, <=, last);
2934226f635SJason King 
2944226f635SJason King 	if (last - first < 13)
2954226f635SJason King 		return (first);
2964226f635SJason King 
2974226f635SJason King 	const char test[] = "_block_invoke";
2984226f635SJason King 	const char *t = first;
2994226f635SJason King 
3004226f635SJason King 	if (strncmp(first, test, sizeof (test) - 1) != 0)
3014226f635SJason King 		return (first);
3024226f635SJason King 
3034226f635SJason King 	t += sizeof (test);
3044226f635SJason King 	if (t == last)
3054226f635SJason King 		goto done;
3064226f635SJason King 
3074226f635SJason King 	if (t[0] == '_') {
3084226f635SJason King 		/* need at least one digit */
309*1cd08393SJason King 		if (t + 1 == last || ISDIGIT(t[1]))
3104226f635SJason King 			return (first);
3114226f635SJason King 		t += 2;
3124226f635SJason King 	}
3134226f635SJason King 
314*1cd08393SJason King 	while (t < last && ISDIGIT(t[0]))
3154226f635SJason King 		t++;
3164226f635SJason King 
3174226f635SJason King done:
3184226f635SJason King 	if (nempty(db))
3194226f635SJason King 		return (first);
3204226f635SJason King 
3214226f635SJason King 	nfmt(db, "invocation function for block in {0}", NULL);
3224226f635SJason King 	return (t);
3234226f635SJason King }
3244226f635SJason King 
3254226f635SJason King /*
3264226f635SJason King  * <encoding> ::= <function name><bare-function-type>
3274226f635SJason King  *            ::= <data name>
3284226f635SJason King  *            ::= <special name>
3294226f635SJason King  */
3304226f635SJason King static const char *
parse_encoding(const char * first,const char * last,cpp_db_t * db)3314226f635SJason King parse_encoding(const char *first, const char *last, cpp_db_t *db)
3324226f635SJason King {
3334226f635SJason King 	VERIFY3P(first, <=, last);
3344226f635SJason King 
3354226f635SJason King 	if (first == last)
3364226f635SJason King 		return (first);
3374226f635SJason King 
3384226f635SJason King 	const char *t = NULL;
3394226f635SJason King 	const char *t2 = NULL;
3404226f635SJason King 	unsigned cv = 0;
3414226f635SJason King 	unsigned ref = 0;
3424226f635SJason King 	boolean_t tag_templ_save = db->cpp_tag_templates;
3434226f635SJason King 
3444226f635SJason King 	if (++db->cpp_depth > 1)
3454226f635SJason King 		db->cpp_tag_templates = B_TRUE;
3464226f635SJason King 
3474226f635SJason King 	if (first[0] == 'G' || first[0] == 'T') {
3484226f635SJason King 		t = parse_special_name(first, last, db);
3494226f635SJason King 		goto done;
3504226f635SJason King 	}
3514226f635SJason King 
3524226f635SJason King 	boolean_t ends_with_template_args = B_FALSE;
3534226f635SJason King 	t = parse_name(first, last, &ends_with_template_args, db);
3544226f635SJason King 	if (t == first)
3554226f635SJason King 		goto fail;
3564226f635SJason King 
3574226f635SJason King 	cv = db->cpp_cv;
3584226f635SJason King 	ref = db->cpp_ref;
3594226f635SJason King 
3604226f635SJason King 	if (t == last || t[0] == 'E' || t[0] == '.')
3614226f635SJason King 		goto done;
3624226f635SJason King 
3634226f635SJason King 	db->cpp_tag_templates = B_FALSE;
3644226f635SJason King 	if (nempty(db) || str_length(TOP_L(db)) == 0)
3654226f635SJason King 		goto fail;
3664226f635SJason King 
3674226f635SJason King 	if (!db->cpp_parsed_ctor_dtor_cv && ends_with_template_args) {
3684226f635SJason King 		t2 = parse_type(t, last, db);
3694226f635SJason King 		if (t2 == t || nlen(db) < 2)
3704226f635SJason King 			goto fail;
3714226f635SJason King 
3724226f635SJason King 		str_pair_t *sp = name_top(&db->cpp_name);
3734226f635SJason King 
3744226f635SJason King 		if (str_length(&sp->strp_r) == 0)
3754226f635SJason King 			(void) str_append(&sp->strp_l, " ", 1);
3764226f635SJason King 
3774226f635SJason King 		nfmt(db, "{0:L}{1:L}", "{1:R}{0:R}");
3784226f635SJason King 		t = t2;
3794226f635SJason King 	}
3804226f635SJason King 
3814226f635SJason King 	if (t == last || nempty(db))
3824226f635SJason King 		goto fail;
3834226f635SJason King 
3844226f635SJason King 	size_t n = nlen(db);
3854226f635SJason King 
3864226f635SJason King 	if (t[0] == 'v') {
3874226f635SJason King 		t++;
3884226f635SJason King 	} else {
3894226f635SJason King 		for (;;) {
3904226f635SJason King 			t2 = parse_type(t, last, db);
3914226f635SJason King 			if (t2 == t || t == last)
3924226f635SJason King 				break;
3934226f635SJason King 
3944226f635SJason King 			t = t2;
3954226f635SJason King 		}
3964226f635SJason King 	}
3974226f635SJason King 
3984226f635SJason King 	/*
3994226f635SJason King 	 * a bit of a hack, but a template substitution can apparently be
4004226f635SJason King 	 * an empty string at the end of an argument list, so avoid
4014226f635SJason King 	 * <...., >
4024226f635SJason King 	 */
4034226f635SJason King 	if (NAMT(db, n) > 1 && str_pair_len(name_top(&db->cpp_name)) == 0)
4044226f635SJason King 		name_pop(&db->cpp_name, NULL);
4054226f635SJason King 
4064226f635SJason King 	njoin(db, NAMT(db, n), ", ");
4074226f635SJason King 	nfmt(db, "({0})", NULL);
4084226f635SJason King 
4094226f635SJason King 	str_t *s = TOP_L(db);
4104226f635SJason King 
4114226f635SJason King 	if (cv & CPP_QUAL_CONST) {
4124226f635SJason King 		CK(str_append(s, " const", 0));
4134226f635SJason King 	}
4144226f635SJason King 	if (cv & CPP_QUAL_VOLATILE) {
4154226f635SJason King 		CK(str_append(s, " volatile", 0));
4164226f635SJason King 	}
4174226f635SJason King 	if (cv & CPP_QUAL_RESTRICT) {
4184226f635SJason King 		CK(str_append(s, " restrict", 0));
4194226f635SJason King 	}
4204226f635SJason King 	if (ref == 1) {
4214226f635SJason King 		CK(str_append(s, " &", 0));
4224226f635SJason King 	}
4234226f635SJason King 	if (ref == 2) {
4244226f635SJason King 		CK(str_append(s, " &&", 0));
4254226f635SJason King 	}
4264226f635SJason King 
4274226f635SJason King 	nfmt(db, "{1:L}{0}{1:R}", NULL);
4284226f635SJason King 
4294226f635SJason King done:
4304226f635SJason King 	db->cpp_tag_templates = tag_templ_save;
4314226f635SJason King 	db->cpp_depth--;
4324226f635SJason King 	return (t);
4334226f635SJason King 
4344226f635SJason King fail:
4354226f635SJason King 	db->cpp_tag_templates = tag_templ_save;
4364226f635SJason King 	db->cpp_depth--;
4374226f635SJason King 	return (first);
4384226f635SJason King }
4394226f635SJason King 
4404226f635SJason King /*
4414226f635SJason King  * <special-name> ::= TV <type>    # virtual table
4424226f635SJason King  *                ::= TT <type>    # VTT structure (construction vtable index)
4434226f635SJason King  *                ::= TI <type>    # typeinfo structure
4444226f635SJason King  *                ::= TS <type>    # typeinfo name (null-terminated byte string)
4454226f635SJason King  *                ::= Tc <call-offset> <call-offset> <base encoding>
4464226f635SJason King  *                    # base is the nominal target function of thunk
4474226f635SJason King  *                    # first call-offset is 'this' adjustment
4484226f635SJason King  *                    # second call-offset is result adjustment
4494226f635SJason King  *                ::= T <call-offset> <base encoding>
4504226f635SJason King  *                    # base is the nominal target function of thunk
4514226f635SJason King  *                ::= GV <object name> # Guard variable for one-time init
4524226f635SJason King  *                                     # No <type>
4534226f635SJason King  *                ::= TW <object name> # Thread-local wrapper
4544226f635SJason King  *                ::= TH <object name> # Thread-local initialization
4554226f635SJason King  *      extension ::= TC <first type> <number> _ <second type>
4564226f635SJason King  *                                     # construction vtable for second-in-first
4574226f635SJason King  *      extension ::= GR <object name> # reference temporary for object
4584226f635SJason King  */
4594226f635SJason King static const char *
parse_special_name(const char * first,const char * last,cpp_db_t * db)4604226f635SJason King parse_special_name(const char *first, const char *last, cpp_db_t *db)
4614226f635SJason King {
4624226f635SJason King 	VERIFY3P(first, <=, last);
4634226f635SJason King 
4644226f635SJason King 	const char *t = first;
4654226f635SJason King 	const char *t1 = NULL;
4664226f635SJason King 	size_t n = nlen(db);
4674226f635SJason King 
4684226f635SJason King 	if (last - first < 2)
4694226f635SJason King 		return (first);
4704226f635SJason King 
4714226f635SJason King 	switch (t[0]) {
4724226f635SJason King 	case 'T':
4734226f635SJason King 		switch (t[1]) {
4744226f635SJason King 		case 'V':
4754226f635SJason King 			nadd_l(db, "vtable for", 0);
4764226f635SJason King 			t = parse_type(first + 2, last, db);
4774226f635SJason King 			break;
4784226f635SJason King 		case 'T':
4794226f635SJason King 			nadd_l(db, "VTT for", 0);
4804226f635SJason King 			t = parse_type(first + 2, last, db);
4814226f635SJason King 			break;
4824226f635SJason King 		case 'I':
4834226f635SJason King 			nadd_l(db, "typeinfo for", 0);
4844226f635SJason King 			t = parse_type(first + 2, last, db);
4854226f635SJason King 			break;
4864226f635SJason King 		case 'S':
4874226f635SJason King 			nadd_l(db, "typeinfo name for", 0);
4884226f635SJason King 			t = parse_type(first + 2, last, db);
4894226f635SJason King 			break;
4904226f635SJason King 		case 'c':
4914226f635SJason King 			nadd_l(db, "covariant return thunk to", 0);
492*1cd08393SJason King 			t1 = parse_call_offset(first + 2, last);
4934226f635SJason King 			if (t1 == t)
4944226f635SJason King 				return (first);
495*1cd08393SJason King 			t = parse_call_offset(t1, last);
4964226f635SJason King 			if (t == t1)
4974226f635SJason King 				return (first);
4984226f635SJason King 			t1 = parse_encoding(t, last, db);
4994226f635SJason King 			if (t1 == t)
5004226f635SJason King 				return (first);
5014226f635SJason King 			break;
5024226f635SJason King 		case 'C':
5034226f635SJason King 			t = parse_type(first + 2, last, db);
5044226f635SJason King 			if (t == first + 2)
5054226f635SJason King 				return (first);
506*1cd08393SJason King 			t1 = parse_number(t, last);
5074226f635SJason King 			if (*t1 != '_')
5084226f635SJason King 				return (first);
5094226f635SJason King 			t = parse_type(t1 + 1, last, db);
5104226f635SJason King 			if (t == t1 + 1 || nlen(db) < 2)
5114226f635SJason King 				return (first);
5124226f635SJason King 			nfmt(db, "construction vtable for {0}-in-{1}", NULL);
5134226f635SJason King 			return (t);
5144226f635SJason King 		case 'W':
5154226f635SJason King 			nadd_l(db, "thread-local wrapper routine for", 0);
5164226f635SJason King 			t = parse_name(first + 2, last, NULL, db);
5174226f635SJason King 			break;
5184226f635SJason King 		case 'H':
5194226f635SJason King 			nadd_l(db, "thread-local initialization routine for",
5204226f635SJason King 			    0);
5214226f635SJason King 			t = parse_name(first + 2, last, NULL, db);
5224226f635SJason King 			break;
5234226f635SJason King 		default:
5244226f635SJason King 			if (first[1] == 'v') {
5254226f635SJason King 				nadd_l(db, "virtual thunk to", 0);
5264226f635SJason King 			} else {
5274226f635SJason King 				nadd_l(db, "non-virtual thunk to", 0);
5284226f635SJason King 			}
5294226f635SJason King 
530*1cd08393SJason King 			t = parse_call_offset(first + 1, last);
5314226f635SJason King 			if (t == first + 1)
5324226f635SJason King 				return (first);
5334226f635SJason King 			t1 = parse_encoding(t, last, db);
5344226f635SJason King 			if (t == t1)
5354226f635SJason King 				return (first);
5364226f635SJason King 			t = t1;
5374226f635SJason King 			break;
5384226f635SJason King 		}
5394226f635SJason King 		break;
5404226f635SJason King 	case 'G':
5414226f635SJason King 		switch (first[1]) {
5424226f635SJason King 		case 'V':
5434226f635SJason King 			nadd_l(db, "guard variable for", 0);
5444226f635SJason King 			t = parse_name(first + 2, last, NULL, db);
5454226f635SJason King 			break;
5464226f635SJason King 		case 'R':
5474226f635SJason King 			nadd_l(db, "reference temporary for", 0);
5484226f635SJason King 			t = parse_name(first + 2, last, NULL, db);
5494226f635SJason King 			break;
5504226f635SJason King 		default:
5514226f635SJason King 			return (first);
5524226f635SJason King 		}
5534226f635SJason King 		break;
5544226f635SJason King 	default:
5554226f635SJason King 		return (first);
5564226f635SJason King 	}
5574226f635SJason King 
5584226f635SJason King 	size_t amt = NAMT(db, n);
5594226f635SJason King 	if (t == first + 2 || amt < 2)
5604226f635SJason King 		return (first);
5614226f635SJason King 
5624226f635SJason King 	njoin(db, amt, " ");
5634226f635SJason King 	return (t);
5644226f635SJason King }
5654226f635SJason King 
5664226f635SJason King /*
5674226f635SJason King  * <call-offset> ::= h <nv-offset> _
5684226f635SJason King  *               ::= v <v-offset> _
5694226f635SJason King  *
5704226f635SJason King  * <nv-offset> ::= <offset number>
5714226f635SJason King  *               # non-virtual base override
5724226f635SJason King  *
5734226f635SJason King  * <v-offset>  ::= <offset number> _ <virtual offset number>
5744226f635SJason King  *               # virtual base override, with vcall offset
5754226f635SJason King  */
5764226f635SJason King static const char *
parse_call_offset(const char * first,const char * last)577*1cd08393SJason King parse_call_offset(const char *first, const char *last)
5784226f635SJason King {
5794226f635SJason King 	VERIFY3P(first, <=, last);
5804226f635SJason King 
5814226f635SJason King 	const char *t = NULL;
5824226f635SJason King 	const char *t1 = NULL;
5834226f635SJason King 
5844226f635SJason King 	if (first == last)
5854226f635SJason King 		return (first);
5864226f635SJason King 
5874226f635SJason King 	if (first[0] != 'h' && first[0] != 'v')
5884226f635SJason King 		return (first);
5894226f635SJason King 
590*1cd08393SJason King 	t = parse_number(first + 1, last);
5914226f635SJason King 	if (t == first + 1 || t == last || t[0] != '_')
5924226f635SJason King 		return (first);
5934226f635SJason King 
5944226f635SJason King 	/* skip _ */
5954226f635SJason King 	t++;
5964226f635SJason King 
5974226f635SJason King 	if (first[0] == 'h')
5984226f635SJason King 		return (t);
5994226f635SJason King 
600*1cd08393SJason King 	t1 = parse_number(t, last);
6014226f635SJason King 	if (t == t1 || t1 == last || t1[0] != '_')
6024226f635SJason King 		return (first);
6034226f635SJason King 
6044226f635SJason King 	/* skip _ */
6054226f635SJason King 	t1++;
6064226f635SJason King 
6074226f635SJason King 	return (t1);
6084226f635SJason King }
6094226f635SJason King 
6104226f635SJason King /*
6114226f635SJason King  * <name> ::= <nested-name> // N
6124226f635SJason King  *        ::= <local-name> # See Scope Encoding below  // Z
6134226f635SJason King  *        ::= <unscoped-template-name> <template-args>
6144226f635SJason King  *        ::= <unscoped-name>
6154226f635SJason King  *
6164226f635SJason King  * <unscoped-template-name> ::= <unscoped-name>
6174226f635SJason King  *                          ::= <substitution>
6184226f635SJason King  */
6194226f635SJason King static const char *
parse_name(const char * first,const char * last,boolean_t * ends_with_template_args,cpp_db_t * db)6204226f635SJason King parse_name(const char *first, const char *last,
6214226f635SJason King     boolean_t *ends_with_template_args, cpp_db_t *db)
6224226f635SJason King {
6234226f635SJason King 	VERIFY3P(first, <=, last);
6244226f635SJason King 
6254226f635SJason King 	const char *t = first;
6264226f635SJason King 	const char *t1 = NULL;
6274226f635SJason King 
6284226f635SJason King 	if (last - first < 2)
6294226f635SJason King 		return (first);
6304226f635SJason King 
6314226f635SJason King 	/* extension: ignore L here */
6324226f635SJason King 	if (t[0] == 'L')
6334226f635SJason King 		t++;
6344226f635SJason King 
6354226f635SJason King 	switch (t[0]) {
6364226f635SJason King 	case 'N':
6374226f635SJason King 		t1 = parse_nested_name(t, last, ends_with_template_args, db);
6384226f635SJason King 		return ((t == t1) ? first : t1);
6394226f635SJason King 	case 'Z':
6404226f635SJason King 		t1 = parse_local_name(t, last, ends_with_template_args, db);
6414226f635SJason King 		return ((t == t1) ? first : t1);
6424226f635SJason King 	}
6434226f635SJason King 
6444226f635SJason King 	/*
6454226f635SJason King 	 * <unscoped-name>
6464226f635SJason King 	 * <unscoped-name> <template-args>
6474226f635SJason King 	 * <substitution> <template-args>
6484226f635SJason King 	 */
6494226f635SJason King 	t1 = parse_unscoped_name(t, last, db);
6504226f635SJason King 
6514226f635SJason King 	/* <unscoped-name> */
6524226f635SJason King 	if (t != t1 && t1[0] != 'I')
6534226f635SJason King 		return (t1);
6544226f635SJason King 
6554226f635SJason King 	if (t == t1) {
6564226f635SJason King 		t1 = parse_substitution(t, last, db);
6574226f635SJason King 		if (t == t1 || t1 == last || t1[0] != 'I')
6584226f635SJason King 			return (first);
6594226f635SJason King 	} else {
6604226f635SJason King 		save_top(db, 1);
6614226f635SJason King 	}
6624226f635SJason King 
6634226f635SJason King 	t = parse_template_args(t1, last, db);
6644226f635SJason King 	if (t1 == t || nlen(db) < 2)
6654226f635SJason King 		return (first);
6664226f635SJason King 
6674226f635SJason King 	nfmt(db, "{1:L}{0}", "{1:R}");
6684226f635SJason King 
6694226f635SJason King 	if (ends_with_template_args != NULL)
6704226f635SJason King 		*ends_with_template_args = B_TRUE;
6714226f635SJason King 
6724226f635SJason King 	return (t);
6734226f635SJason King }
6744226f635SJason King 
6754226f635SJason King /* BEGIN CSTYLED */
6764226f635SJason King /*
6774226f635SJason King  * <local-name> := Z <function encoding> E <entity name> [<discriminator>]
6784226f635SJason King  *              := Z <function encoding> E s [<discriminator>]
6794226f635SJason King  *              := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
6804226f635SJason King  */
6814226f635SJason King /* END CSTYLED */
6824226f635SJason King const char *
parse_local_name(const char * first,const char * last,boolean_t * ends_with_template_args,cpp_db_t * db)6834226f635SJason King parse_local_name(const char *first, const char *last,
6844226f635SJason King     boolean_t *ends_with_template_args, cpp_db_t *db)
6854226f635SJason King {
6864226f635SJason King 	VERIFY3P(first, <=, last);
6874226f635SJason King 
6884226f635SJason King 	const char *t = NULL;
6894226f635SJason King 	const char *t1 = NULL;
6904226f635SJason King 	const char *t2 = NULL;
6914226f635SJason King 
6924226f635SJason King 	if (first == last || first[0] != 'Z')
6934226f635SJason King 		return (first);
6944226f635SJason King 
6954226f635SJason King 	t = parse_encoding(first + 1, last, db);
6964226f635SJason King 	if (t == first + 1 || t == last || t[0] != 'E')
6974226f635SJason King 		return (first);
6984226f635SJason King 
6994226f635SJason King 	VERIFY(!nempty(db));
7004226f635SJason King 
7014226f635SJason King 	/* skip E */
7024226f635SJason King 	t++;
7034226f635SJason King 
7044226f635SJason King 	if (t[0] == 's') {
7054226f635SJason King 		nfmt(db, "{0:L}::string literal", "{0:R}");
706*1cd08393SJason King 		return (parse_discriminator(t, last));
7074226f635SJason King 	}
7084226f635SJason King 
7094226f635SJason King 	if (t[0] == 'd') {
710*1cd08393SJason King 		t1 = parse_number(t + 1, last);
7114226f635SJason King 		if (t1[0] != '_')
7124226f635SJason King 			return (first);
7134226f635SJason King 		t1++;
7144226f635SJason King 	} else {
7154226f635SJason King 		t1 = t;
7164226f635SJason King 	}
7174226f635SJason King 
7184226f635SJason King 	t2 = parse_name(t1, last, ends_with_template_args, db);
7194226f635SJason King 	if (t2 == t1)
7204226f635SJason King 		return (first);
7214226f635SJason King 
7224226f635SJason King 	nfmt(db, "{1:L}::{0}", "{1:R}");
7234226f635SJason King 
7244226f635SJason King 	/* parsed, but ignored */
7254226f635SJason King 	if (t[0] != 'd')
726*1cd08393SJason King 		t2 = parse_discriminator(t2, last);
7274226f635SJason King 
7284226f635SJason King 	return (t2);
7294226f635SJason King }
7304226f635SJason King 
7314226f635SJason King /* BEGIN CSTYLED */
7324226f635SJason King /*
7334226f635SJason King  * <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
7344226f635SJason King  *               ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
7354226f635SJason King  *
7364226f635SJason King  * <prefix> ::= <prefix> <unqualified-name>
7374226f635SJason King  *          ::= <template-prefix> <template-args>
7384226f635SJason King  *          ::= <template-param>
7394226f635SJason King  *          ::= <decltype>
7404226f635SJason King  *          ::= # empty
7414226f635SJason King  *          ::= <substitution>
7424226f635SJason King  *          ::= <prefix> <data-member-prefix>
7434226f635SJason King  *  extension ::= L
7444226f635SJason King  *
7454226f635SJason King  * <template-prefix> ::= <prefix> <template unqualified-name>
7464226f635SJason King  *                   ::= <template-param>
7474226f635SJason King  *                   ::= <substitution>
7484226f635SJason King  */
7494226f635SJason King /* END CSTYLED */
7504226f635SJason King static const char *
parse_nested_name(const char * first,const char * last,boolean_t * ends_with_template_args,cpp_db_t * db)7514226f635SJason King parse_nested_name(const char *first, const char *last,
7524226f635SJason King     boolean_t *ends_with_template_args, cpp_db_t *db)
7534226f635SJason King {
7544226f635SJason King 	VERIFY3P(first, <=, last);
7554226f635SJason King 
7564226f635SJason King 	if (first == last || first[0] != 'N')
7574226f635SJason King 		return (first);
7584226f635SJason King 
7594226f635SJason King 	unsigned cv = 0;
7604226f635SJason King 	const char *t = parse_cv_qualifiers(first + 1, last, &cv);
7614226f635SJason King 
7624226f635SJason King 	if (t == last)
7634226f635SJason King 		return (first);
7644226f635SJason King 
7654226f635SJason King 	boolean_t more = B_FALSE;
7664226f635SJason King 
7674226f635SJason King 	switch (t[0]) {
7684226f635SJason King 	case 'R':
7694226f635SJason King 		db->cpp_ref = 1;
7704226f635SJason King 		t++;
7714226f635SJason King 		break;
7724226f635SJason King 	case 'O':
7734226f635SJason King 		db->cpp_ref = 2;
7744226f635SJason King 		t++;
7754226f635SJason King 		break;
7764226f635SJason King 	case 'S':
7774226f635SJason King 		if (last - first < 2 || t[1] != 't')
7784226f635SJason King 			break;
7794226f635SJason King 		if (last - first == 2)
7804226f635SJason King 			return (first);
7814226f635SJason King 		nadd_l(db, "std", 3);
7824226f635SJason King 		more = B_TRUE;
7834226f635SJason King 		t += 2;
7844226f635SJason King 		break;
7854226f635SJason King 	}
7864226f635SJason King 
7874226f635SJason King 	boolean_t pop_subs = B_FALSE;
7884226f635SJason King 	boolean_t component_ends_with_template_args = B_FALSE;
7894226f635SJason King 
7904226f635SJason King 	while (t[0] != 'E' && t != last) {
7914226f635SJason King 		const char *t1 = NULL;
7924226f635SJason King 		size_t n = nlen(db);
7934226f635SJason King 		component_ends_with_template_args = B_FALSE;
7944226f635SJason King 
7954226f635SJason King 		switch (t[0]) {
7964226f635SJason King 		case 'S':
7974226f635SJason King 			if (t + 1 != last && t[1] == 't')
7984226f635SJason King 				break;
7994226f635SJason King 
8004226f635SJason King 			t1 = parse_substitution(t, last, db);
8014226f635SJason King 			if (t1 == t || t1 == last || NAMT(db, n) != 1)
8024226f635SJason King 				return (first);
8034226f635SJason King 
8044226f635SJason King 			if (!more) {
8054226f635SJason King 				nfmt(db, "{0}", NULL);
8064226f635SJason King 			} else {
8074226f635SJason King 				VERIFY3U(nlen(db), >, 1);
8084226f635SJason King 				nfmt(db, "{1:L}::{0}", "{1:R}");
8094226f635SJason King 				save_top(db, 1);
8104226f635SJason King 			}
8114226f635SJason King 
8124226f635SJason King 			more = B_TRUE;
8134226f635SJason King 			pop_subs = B_TRUE;
8144226f635SJason King 			t = t1;
8154226f635SJason King 			continue;
8164226f635SJason King 
8174226f635SJason King 		case 'T':
8184226f635SJason King 			t1 = parse_template_param(t, last, db);
8194226f635SJason King 			if (t1 == t || t1 == last || NAMT(db, n) != 1)
8204226f635SJason King 				return (first);
8214226f635SJason King 
8224226f635SJason King 			if (!more) {
8234226f635SJason King 				nfmt(db, "{0}", NULL);
8244226f635SJason King 			} else {
8254226f635SJason King 				VERIFY3U(nlen(db), >, 1);
8264226f635SJason King 				nfmt(db, "{1:L}::{0}", "{1:R}");
8274226f635SJason King 			}
8284226f635SJason King 
8294226f635SJason King 			save_top(db, 1);
8304226f635SJason King 			more = B_TRUE;
8314226f635SJason King 			pop_subs = B_TRUE;
8324226f635SJason King 			t = t1;
8334226f635SJason King 			continue;
8344226f635SJason King 
8354226f635SJason King 		case 'D':
8364226f635SJason King 			if (t + 1 != last && t[1] != 't' && t[1] != 'T')
8374226f635SJason King 				break;
8384226f635SJason King 			t1 = parse_decltype(t, last, db);
8394226f635SJason King 			if (t1 == t || t1 == last || NAMT(db, n) != 1)
8404226f635SJason King 				return (first);
8414226f635SJason King 
8424226f635SJason King 			if (!more) {
8434226f635SJason King 				nfmt(db, "{0}", NULL);
8444226f635SJason King 			} else {
8454226f635SJason King 				VERIFY3U(nlen(db), >, 1);
8464226f635SJason King 				nfmt(db, "{1:L}::{0}", "{1:R}");
8474226f635SJason King 			}
8484226f635SJason King 
8494226f635SJason King 			save_top(db, 1);
8504226f635SJason King 			more = B_TRUE;
8514226f635SJason King 			pop_subs = B_TRUE;
8524226f635SJason King 			t = t1;
8534226f635SJason King 			continue;
8544226f635SJason King 
8554226f635SJason King 		case 'I':
8564226f635SJason King 			/*
8574226f635SJason King 			 * Must have at least one component before
8584226f635SJason King 			 * <template-args>
8594226f635SJason King 			 */
8604226f635SJason King 			if (!more)
8614226f635SJason King 				return (first);
8624226f635SJason King 
8634226f635SJason King 			t1 = parse_template_args(t, last, db);
8644226f635SJason King 			if (t1 == t || t1 == last)
8654226f635SJason King 				return (first);
8664226f635SJason King 
8674226f635SJason King 			VERIFY3U(nlen(db), >, 1);
8684226f635SJason King 			nfmt(db, "{1:L}{0}", "{1:R}");
8694226f635SJason King 			save_top(db, 1);
8704226f635SJason King 			t = t1;
8714226f635SJason King 			component_ends_with_template_args = B_TRUE;
8724226f635SJason King 			continue;
8734226f635SJason King 
8744226f635SJason King 		case 'L':
8754226f635SJason King 			if (t + 1 == last)
8764226f635SJason King 				return (first);
8774226f635SJason King 			t++;
8784226f635SJason King 			continue;
8794226f635SJason King 
8804226f635SJason King 		default:
8814226f635SJason King 			break;
8824226f635SJason King 		}
8834226f635SJason King 
8844226f635SJason King 		t1 = parse_unqualified_name(t, last, db);
8854226f635SJason King 		if (t1 == t || t1 == last || NAMT(db, n) != 1)
8864226f635SJason King 			return (first);
8874226f635SJason King 
8884226f635SJason King 		if (!more) {
8894226f635SJason King 			nfmt(db, "{0}", NULL);
8904226f635SJason King 		} else {
8914226f635SJason King 			VERIFY3U(nlen(db), >, 1);
8924226f635SJason King 			nfmt(db, "{1:L}::{0}", "{1:R}");
8934226f635SJason King 		}
8944226f635SJason King 
8954226f635SJason King 		save_top(db, 1);
8964226f635SJason King 		more = B_TRUE;
8974226f635SJason King 		pop_subs = B_TRUE;
8984226f635SJason King 		t = t1;
8994226f635SJason King 	}
9004226f635SJason King 
9014226f635SJason King 	/* need to parse at least one thing */
9024226f635SJason King 	if (!more)
9034226f635SJason King 		return (first);
9044226f635SJason King 
9054226f635SJason King 	db->cpp_cv = cv;
9064226f635SJason King 	if (pop_subs && !sub_empty(&db->cpp_subs))
9074226f635SJason King 		sub_pop(&db->cpp_subs);
9084226f635SJason King 
9094226f635SJason King 	if (ends_with_template_args != NULL)
9104226f635SJason King 		*ends_with_template_args = component_ends_with_template_args;
9114226f635SJason King 
9124226f635SJason King 	if (t[0] != 'E')
9134226f635SJason King 		return (first);
9144226f635SJason King 
9154226f635SJason King 	return (t + 1);
9164226f635SJason King }
9174226f635SJason King 
9184226f635SJason King /*
9194226f635SJason King  * <template-arg> ::= <type>                   # type or template
9204226f635SJason King  *                ::= X <expression> E         # expression
9214226f635SJason King  *                ::= <expr-primary>           # simple expressions
9224226f635SJason King  *                ::= J <template-arg>* E      # argument pack
9234226f635SJason King  *                ::= LZ <encoding> E          # extension
9244226f635SJason King  */
9254226f635SJason King static const char *
parse_template_arg(const char * first,const char * last,cpp_db_t * db)9264226f635SJason King parse_template_arg(const char *first, const char *last, cpp_db_t *db)
9274226f635SJason King {
9284226f635SJason King 	VERIFY3P(first, <=, last);
9294226f635SJason King 
9304226f635SJason King 	const char *t = NULL;
9314226f635SJason King 	const char *t1 = NULL;
9324226f635SJason King 
9334226f635SJason King 	if (first == last)
9344226f635SJason King 		return (first);
9354226f635SJason King 
9364226f635SJason King 	switch (first[0]) {
9374226f635SJason King 	case 'X':
9384226f635SJason King 		t = parse_expression(first + 1, last, db);
9394226f635SJason King 		if (t == first + 1 || t[0] != 'E')
9404226f635SJason King 			return (first);
9414226f635SJason King 
9424226f635SJason King 		/* E */
9434226f635SJason King 		t++;
9444226f635SJason King 		break;
9454226f635SJason King 
9464226f635SJason King 	case 'J':
9474226f635SJason King 		t = first + 1;
9484226f635SJason King 		if (t == last)
9494226f635SJason King 			return (first);
9504226f635SJason King 
9514226f635SJason King 		while (t[0] != 'E') {
9524226f635SJason King 			t1 = parse_template_arg(t, last, db);
9534226f635SJason King 			if (t == t1)
9544226f635SJason King 				return (first);
9554226f635SJason King 			t = t1;
9564226f635SJason King 		}
9574226f635SJason King 
9584226f635SJason King 		/* E */
9594226f635SJason King 		t++;
9604226f635SJason King 		break;
9614226f635SJason King 
9624226f635SJason King 	case 'L':
9634226f635SJason King 		if (first + 1 == last || first[1] != 'Z') {
9644226f635SJason King 			t = parse_expr_primary(first, last, db);
9654226f635SJason King 		} else {
9664226f635SJason King 			t = parse_encoding(first + 2, last, db);
9674226f635SJason King 			if (t == first + 2 || t == last || t[0] != 'E')
9684226f635SJason King 				return (first);
9694226f635SJason King 
9704226f635SJason King 			/* E */
9714226f635SJason King 			t++;
9724226f635SJason King 		}
9734226f635SJason King 		break;
9744226f635SJason King 
9754226f635SJason King 	default:
9764226f635SJason King 		t = parse_type(first, last, db);
9774226f635SJason King 	}
9784226f635SJason King 
9794226f635SJason King 	return (t);
9804226f635SJason King }
9814226f635SJason King 
9824226f635SJason King /* BEGIN CSTYLED */
9834226f635SJason King /*
9844226f635SJason King  * <expression> ::= <unary operator-name> <expression>
9854226f635SJason King  *              ::= <binary operator-name> <expression> <expression>
9864226f635SJason King  *              ::= <ternary operator-name> <expression> <expression> <expression>
9874226f635SJason King  *              ::= cl <expression>+ E                                   # call
9884226f635SJason King  *              ::= cv <type> <expression>                               # conversion with one argument
9894226f635SJason King  *              ::= cv <type> _ <expression>* E                          # conversion with a different number of arguments
9904226f635SJason King  *              ::= [gs] nw <expression>* _ <type> E                     # new (expr-list) type
9914226f635SJason King  *              ::= [gs] nw <expression>* _ <type> <initializer>         # new (expr-list) type (init)
9924226f635SJason King  *              ::= [gs] na <expression>* _ <type> E                     # new[] (expr-list) type
9934226f635SJason King  *              ::= [gs] na <expression>* _ <type> <initializer>         # new[] (expr-list) type (init)
9944226f635SJason King  *              ::= [gs] dl <expression>                                 # delete expression
9954226f635SJason King  *              ::= [gs] da <expression>                                 # delete[] expression
9964226f635SJason King  *              ::= pp_ <expression>                                     # prefix ++
9974226f635SJason King  *              ::= mm_ <expression>                                     # prefix --
9984226f635SJason King  *              ::= ti <type>                                            # typeid (type)
9994226f635SJason King  *              ::= te <expression>                                      # typeid (expression)
10004226f635SJason King  *              ::= dc <type> <expression>                               # dynamic_cast<type> (expression)
10014226f635SJason King  *              ::= sc <type> <expression>                               # static_cast<type> (expression)
10024226f635SJason King  *              ::= cc <type> <expression>                               # const_cast<type> (expression)
10034226f635SJason King  *              ::= rc <type> <expression>                               # reinterpret_cast<type> (expression)
10044226f635SJason King  *              ::= st <type>                                            # sizeof (a type)
10054226f635SJason King  *              ::= sz <expression>                                      # sizeof (an expression)
10064226f635SJason King  *              ::= at <type>                                            # alignof (a type)
10074226f635SJason King  *              ::= az <expression>                                      # alignof (an expression)
10084226f635SJason King  *              ::= nx <expression>                                      # noexcept (expression)
10094226f635SJason King  *              ::= <template-param>
10104226f635SJason King  *              ::= <function-param>
10114226f635SJason King  *              ::= dt <expression> <unresolved-name>                    # expr.name
10124226f635SJason King  *              ::= pt <expression> <unresolved-name>                    # expr->name
10134226f635SJason King  *              ::= ds <expression> <expression>                         # expr.*expr
10144226f635SJason King  *              ::= sZ <template-param>                                  # size of a parameter pack
10154226f635SJason King  *              ::= sZ <function-param>                                  # size of a function parameter pack
10164226f635SJason King  *              ::= sp <expression>                                      # pack expansion
10174226f635SJason King  *              ::= tw <expression>                                      # throw expression
10184226f635SJason King  *              ::= tr                                                   # throw with no operand (rethrow)
10194226f635SJason King  *              ::= <unresolved-name>                                    # f(p), N::f(p), ::f(p),
10204226f635SJason King  *                                                                       # freestanding dependent name (e.g., T::x),
10214226f635SJason King  *                                                                       # objectless nonstatic member reference
10224226f635SJason King  *              ::= <expr-primary>
10234226f635SJason King  */
10244226f635SJason King /* END CSTYLED */
10254226f635SJason King 
10264226f635SJason King #define	PA(cd, arg, fn) {	\
10274226f635SJason King 	.code = cd,		\
10284226f635SJason King 	.p.parse_expr_arg = fn,	\
10294226f635SJason King 	.fntype = EXPR_ARG,	\
10304226f635SJason King 	.val = arg		\
10314226f635SJason King }
10324226f635SJason King 
10334226f635SJason King #define	PN(cd, fn) {			\
10344226f635SJason King 	.code = cd,			\
10354226f635SJason King 	.p.parse_expr_noarg = fn,	\
10364226f635SJason King 	.fntype = EXPR_NOARG		\
10374226f635SJason King }
10384226f635SJason King 
10394226f635SJason King static struct {
10404226f635SJason King 	const char code[3];
10414226f635SJason King 	union {
10424226f635SJason King 		const char *(*parse_expr_arg)(const char *, const char *,
10434226f635SJason King 		    const char *, cpp_db_t *);
10444226f635SJason King 		const char *(*parse_expr_noarg)(const char *, const char *,
10454226f635SJason King 		    cpp_db_t *);
10464226f635SJason King 	} p;
10474226f635SJason King 	enum {
10484226f635SJason King 		EXPR_ARG,
10494226f635SJason King 		EXPR_NOARG
10504226f635SJason King 	} fntype;
10514226f635SJason King 	const char val[4];
10524226f635SJason King } expr_tbl[] = {
10534226f635SJason King 	PA("aN", "&=", parse_binary_expr),
10544226f635SJason King 	PA("aS", "=", parse_binary_expr),
10554226f635SJason King 	PA("aa", "&&", parse_binary_expr),
10564226f635SJason King 	PA("ad", "&", parse_prefix_expr),
10574226f635SJason King 	PA("an", "&", parse_binary_expr),
10584226f635SJason King 	PN("at", parse_alignof),
10594226f635SJason King 	PN("az", parse_alignof),
10604226f635SJason King 	PN("cc", parse_cast_expr),
10614226f635SJason King 	PN("cl", parse_call_expr),
10624226f635SJason King 	PA("cm", ",", parse_binary_expr),
10634226f635SJason King 	PA("co", "~", parse_prefix_expr),
10644226f635SJason King 	PN("cv", parse_conv_expr),
10654226f635SJason King 	PN("da", parse_del_expr),
10664226f635SJason King 	PA("dV", "/=", parse_binary_expr),
10674226f635SJason King 	PN("dc", parse_cast_expr),
10684226f635SJason King 	PA("de", "*", parse_prefix_expr),
10694226f635SJason King 	PN("dl", parse_del_expr),
10704226f635SJason King 	PN("dn", parse_unresolved_name),
10714226f635SJason King 	PN("ds", parse_dot_star_expr),
10724226f635SJason King 	PN("dt", parse_dot_expr),
10734226f635SJason King 	PA("dv", "/", parse_binary_expr),
10744226f635SJason King 	PA("eO", "^=", parse_binary_expr),
10754226f635SJason King 	PA("eo", "^", parse_binary_expr),
10764226f635SJason King 	PA("eq", "==", parse_binary_expr),
10774226f635SJason King 	PA("ge", ">=", parse_binary_expr),
10784226f635SJason King 	PN("gs", parse_gs),
10794226f635SJason King 	PA("gt", ">", parse_binary_expr),
10804226f635SJason King 	PN("ix", parse_idx_expr),
10814226f635SJason King 	PA("lS", "<<=", parse_binary_expr),
10824226f635SJason King 	PA("le", "<=", parse_binary_expr),
10834226f635SJason King 	PA("ls", "<<", parse_binary_expr),
10844226f635SJason King 	PA("lt", "<", parse_binary_expr),
10854226f635SJason King 	PA("mI", "-=", parse_binary_expr),
10864226f635SJason King 	PA("mL", "*=", parse_binary_expr),
10874226f635SJason King 	PN("mm", parse_mm_expr),
10884226f635SJason King 	PA("mi", "-", parse_binary_expr),
10894226f635SJason King 	PA("ml", "*", parse_binary_expr),
10904226f635SJason King 	PN("na", parse_new_expr),
10914226f635SJason King 	PA("ne", "!=", parse_binary_expr),
10924226f635SJason King 	PA("ng", "-", parse_prefix_expr),
10934226f635SJason King 	PA("nt", "!", parse_prefix_expr),
10944226f635SJason King 	PN("nw", parse_new_expr),
10954226f635SJason King 	PN("nx", parse_noexcept_expr),
10964226f635SJason King 	PA("oR", "|=", parse_binary_expr),
10974226f635SJason King 	PN("on", parse_unresolved_name),
10984226f635SJason King 	PA("oo", "||", parse_binary_expr),
10994226f635SJason King 	PA("or", "|", parse_binary_expr),
11004226f635SJason King 	PA("pL", "+=", parse_binary_expr),
11014226f635SJason King 	PA("pl", "+", parse_binary_expr),
11024226f635SJason King 	PA("pm", "->*", parse_binary_expr),
11034226f635SJason King 	PN("pp", parse_pp_expr),
11044226f635SJason King 	PA("ps", "+", parse_prefix_expr),
11054226f635SJason King 	PN("pt", parse_arrow_expr),
11064226f635SJason King 	PN("qu", parse_trinary_expr),
11074226f635SJason King 	PA("rM", "%=", parse_binary_expr),
11084226f635SJason King 	PA("rS", ">>=", parse_binary_expr),
11094226f635SJason King 	PN("rc", parse_cast_expr),
11104226f635SJason King 	PA("rm", "%", parse_binary_expr),
11114226f635SJason King 	PA("rs", ">>", parse_binary_expr),
11124226f635SJason King 	PN("sc", parse_cast_expr),
11134226f635SJason King 	PN("sp", parse_pack_expansion),
11144226f635SJason King 	PN("sr", parse_unresolved_name),
11154226f635SJason King 	PN("st", parse_sizeof),
11164226f635SJason King 	PN("sz", parse_sizeof),
11174226f635SJason King 	PN("sZ", parse_sizeof_param_pack_expr),
11184226f635SJason King 	PN("te", parse_typeid_expr),
11194226f635SJason King 	PN("tr", parse_throw_expr),
11204226f635SJason King 	PN("tw", parse_throw_expr)
11214226f635SJason King };
11224226f635SJason King #undef PA
11234226f635SJason King #undef PN
11244226f635SJason King 
11254226f635SJason King static const char *
parse_expression(const char * first,const char * last,cpp_db_t * db)11264226f635SJason King parse_expression(const char *first, const char *last, cpp_db_t *db)
11274226f635SJason King {
11284226f635SJason King 	VERIFY3P(first, <=, last);
11294226f635SJason King 
11304226f635SJason King 	if (last - first < 2)
11314226f635SJason King 		return (first);
11324226f635SJason King 
11334226f635SJason King 	for (size_t i = 0; i < ARRAY_SIZE(expr_tbl); i++) {
11344226f635SJason King 		if (strncmp(expr_tbl[i].code, first, 2) != 0)
11354226f635SJason King 			continue;
11364226f635SJason King 		switch (expr_tbl[i].fntype) {
11374226f635SJason King 		case EXPR_ARG:
11384226f635SJason King 			return (expr_tbl[i].p.parse_expr_arg(first, last,
11394226f635SJason King 			    expr_tbl[i].val, db));
11404226f635SJason King 		case EXPR_NOARG:
11414226f635SJason King 			return (expr_tbl[i].p.parse_expr_noarg(first, last,
11424226f635SJason King 			    db));
11434226f635SJason King 		}
11444226f635SJason King 	}
11454226f635SJason King 
11464226f635SJason King 	switch (first[0]) {
11474226f635SJason King 	case 'L':
11484226f635SJason King 		return (parse_expr_primary(first, last, db));
11494226f635SJason King 	case 'T':
11504226f635SJason King 		return (parse_template_param(first, last, db));
11514226f635SJason King 	case 'f':
11524226f635SJason King 		return (parse_function_param(first, last, db));
11534226f635SJason King 	case '1':
11544226f635SJason King 	case '2':
11554226f635SJason King 	case '3':
11564226f635SJason King 	case '4':
11574226f635SJason King 	case '5':
11584226f635SJason King 	case '6':
11594226f635SJason King 	case '7':
11604226f635SJason King 	case '8':
11614226f635SJason King 	case '9':
11624226f635SJason King 		return (parse_unresolved_name(first, last, db));
11634226f635SJason King 	}
11644226f635SJason King 
11654226f635SJason King 	return (first);
11664226f635SJason King }
11674226f635SJason King 
11684226f635SJason King static const char *
parse_binary_expr(const char * first,const char * last,const char * op,cpp_db_t * db)11694226f635SJason King parse_binary_expr(const char *first, const char *last, const char *op,
11704226f635SJason King     cpp_db_t *db)
11714226f635SJason King {
11724226f635SJason King 	VERIFY3P(first, <=, last);
11734226f635SJason King 
11744226f635SJason King 	if (last - first < 2)
11754226f635SJason King 		return (first);
11764226f635SJason King 
11774226f635SJason King 	size_t n = nlen(db);
11784226f635SJason King 
11794226f635SJason King 	const char *t1 = parse_expression(first + 2, last, db);
11804226f635SJason King 	if (t1 == first + 2)
11814226f635SJason King 		return (first);
11824226f635SJason King 
11834226f635SJason King 	nadd_l(db, op, 0);
11844226f635SJason King 
11854226f635SJason King 	const char *t2 = parse_expression(t1, last, db);
11864226f635SJason King 	if (t2 == t1)
11874226f635SJason King 		return (first);
11884226f635SJason King 
11894226f635SJason King 	if (NAMT(db, n) != 3)
11904226f635SJason King 		return (first);
11914226f635SJason King 
11924226f635SJason King 	VERIFY3U(nlen(db), >, 2);
11934226f635SJason King 
11944226f635SJason King 	nfmt(db, "({2}) {1} ({0})", NULL);
11954226f635SJason King 	if (strcmp(op, ">") == 0)
11964226f635SJason King 		nfmt(db, "({0})", NULL);
11974226f635SJason King 
11984226f635SJason King 	return (t2);
11994226f635SJason King }
12004226f635SJason King 
12014226f635SJason King static const char *
parse_prefix_expr(const char * first,const char * last,const char * op,cpp_db_t * db)12024226f635SJason King parse_prefix_expr(const char *first, const char *last, const char *op,
12034226f635SJason King     cpp_db_t *db)
12044226f635SJason King {
12054226f635SJason King 	VERIFY3P(first, <=, last);
12064226f635SJason King 
12074226f635SJason King 	if (last - first < 2)
12084226f635SJason King 		return (first);
12094226f635SJason King 
12104226f635SJason King 	nadd_l(db, op, 0);
12114226f635SJason King 
12124226f635SJason King 	const char *t = parse_expression(first + 2, last, db);
12134226f635SJason King 	if (t == first + 2) {
12144226f635SJason King 		return (first);
12154226f635SJason King 	}
12164226f635SJason King 
12174226f635SJason King 	VERIFY3U(nlen(db), >, 1);
12184226f635SJason King 
12194226f635SJason King 	nfmt(db, "{1}({0})", NULL);
12204226f635SJason King 	return (t);
12214226f635SJason King }
12224226f635SJason King 
12234226f635SJason King static const char *
parse_gs(const char * first,const char * last,cpp_db_t * db)12244226f635SJason King parse_gs(const char *first, const char *last, cpp_db_t *db)
12254226f635SJason King {
12264226f635SJason King 	VERIFY3P(first, <=, last);
12274226f635SJason King 
12284226f635SJason King 	const char *t = NULL;
12294226f635SJason King 
12304226f635SJason King 	if (last - first < 4)
12314226f635SJason King 		return (first);
12324226f635SJason King 
12334226f635SJason King 	if (first[2] == 'n' && (first[3] == 'a' || first[3] == 'w'))
12344226f635SJason King 		t = parse_new_expr(first + 2, last, db);
12354226f635SJason King 	else if (first[2] == 'd' && (first[3] == 'l' || first[3] == 'a'))
12364226f635SJason King 		t = parse_del_expr(first + 2, last, db);
12374226f635SJason King 	else
12384226f635SJason King 		return (first);
12394226f635SJason King 
12404226f635SJason King 	if (t == first + 2)
12414226f635SJason King 		return (first);
12424226f635SJason King 
12434226f635SJason King 	VERIFY3U(nlen(db), >, 0);
12444226f635SJason King 
12454226f635SJason King 	nfmt(db, "::{0}", NULL);
12464226f635SJason King 	return (t);
12474226f635SJason King }
12484226f635SJason King 
12494226f635SJason King /*
12504226f635SJason King  * [gs] nw <expression>* _ <type> E		# new (expr-list) type
12514226f635SJason King  * [gs] nw <expression>* _ <type> <initializer>	# new (expr-list) type (init)
12524226f635SJason King  * [gs] na <expression>* _ <type> E		# new[] (expr-list) type
12534226f635SJason King  * [gs] na <expression>* _ <type> <initializer>	# new[] (expr-list) type (init)
12544226f635SJason King  * <initializer> ::= pi <expression>* E		# parenthesized initialization
12554226f635SJason King  */
12564226f635SJason King static const char *
parse_new_expr(const char * first,const char * last,cpp_db_t * db)12574226f635SJason King parse_new_expr(const char *first, const char *last, cpp_db_t *db)
12584226f635SJason King {
12594226f635SJason King 	VERIFY3P(first, <=, last);
12604226f635SJason King 
12614226f635SJason King 	/* note [gs] is already handled by parse_gs() */
12624226f635SJason King 	if (last - first < 3)
12634226f635SJason King 		return (first);
12644226f635SJason King 
12654226f635SJason King 	VERIFY3U(first[0], ==, 'n');
12664226f635SJason King 	VERIFY(first[1] == 'a' || first[1] == 'w');
12674226f635SJason King 
12684226f635SJason King 	const char *t1 = first + 2;
12694226f635SJason King 	const char *t2 = NULL;
12704226f635SJason King 	size_t n = nlen(db);
12714226f635SJason King 
12724226f635SJason King 	nadd_l(db, (first[1] == 'w') ? "new" : "new[]", 0);
12734226f635SJason King 
12744226f635SJason King 	while (t1 != last && t1[0] != '_') {
12754226f635SJason King 		t2 = parse_expression(t1, last, db);
12764226f635SJason King 		VERIFY3P(t2, !=, NULL);
12774226f635SJason King 		if (t2 == t1)
12784226f635SJason King 			return (first);
12794226f635SJason King 		t1 = t2;
12804226f635SJason King 	}
12814226f635SJason King 	if (t1 == last)
12824226f635SJason King 		return (first);
12834226f635SJason King 
12844226f635SJason King 	if (NAMT(db, n) > 1) {
12854226f635SJason King 		njoin(db, NAMT(db, n) - 1, ", ");
12864226f635SJason King 		nfmt(db, "({0})", NULL);
12874226f635SJason King 	}
12884226f635SJason King 
12894226f635SJason King 	t2 = parse_type(t1 + 1, last, db);
12904226f635SJason King 	if (t1 + 1 == t2)
12914226f635SJason King 		return (first);
12924226f635SJason King 
12934226f635SJason King 	if (t2[0] != 'E') {
12944226f635SJason King 		if (last - t2 < 3)
12954226f635SJason King 			return (first);
12964226f635SJason King 		if (t2[0] != 'p' && t2[1] != 'i')
12974226f635SJason King 			return (first);
12984226f635SJason King 
12994226f635SJason King 		t2 += 2;
13004226f635SJason King 		const char *t3 = t2;
13014226f635SJason King 		size_t n1 = nlen(db);
13024226f635SJason King 
13034226f635SJason King 		while (t2[0] != 'E' && t2 != last) {
13044226f635SJason King 			t3 = parse_expression(t2, last, db);
13054226f635SJason King 
13064226f635SJason King 			if (t2 == t3)
13074226f635SJason King 				return (first);
13084226f635SJason King 			t2 = t3;
13094226f635SJason King 		}
13104226f635SJason King 		if (t3 == last || t3[0] != 'E')
13114226f635SJason King 			return (first);
13124226f635SJason King 
13134226f635SJason King 		if (NAMT(db, n1) > 0) {
13144226f635SJason King 			njoin(db, NAMT(db, n1), ", ");
13154226f635SJason King 			nfmt(db, "({0})", NULL);
13164226f635SJason King 		}
13174226f635SJason King 	}
13184226f635SJason King 
13194226f635SJason King 	njoin(db, NAMT(db, n), " ");
13204226f635SJason King 	return (t2 + 1);
13214226f635SJason King }
13224226f635SJason King 
13234226f635SJason King static const char *
parse_del_expr(const char * first,const char * last,cpp_db_t * db)13244226f635SJason King parse_del_expr(const char *first, const char *last, cpp_db_t *db)
13254226f635SJason King {
13264226f635SJason King 	VERIFY3P(first, <=, last);
13274226f635SJason King 
13284226f635SJason King 	if (last - first < 3)
13294226f635SJason King 		return (first);
13304226f635SJason King 
13314226f635SJason King 	VERIFY3U(first[0], ==, 'd');
13324226f635SJason King 	VERIFY(first[1] == 'l' || first[1] == 'a');
13334226f635SJason King 
13344226f635SJason King 	size_t n = nlen(db);
13354226f635SJason King 	const char *t = parse_expression(first + 2, last, db);
13364226f635SJason King 	if (t == first + 2 || NAMT(db, n) != 1)
13374226f635SJason King 		return (first);
13384226f635SJason King 
13394226f635SJason King 	nfmt(db, (first[1] == 'a') ? "delete[] {0}" : "delete {0}", NULL);
13404226f635SJason King 	return (t);
13414226f635SJason King }
13424226f635SJason King 
13434226f635SJason King static const char *
parse_idx_expr(const char * first,const char * last,cpp_db_t * db)13444226f635SJason King parse_idx_expr(const char *first, const char *last, cpp_db_t *db)
13454226f635SJason King {
13464226f635SJason King 	VERIFY3P(first, <=, last);
13474226f635SJason King 	VERIFY3U(first[0], ==, 'i');
13484226f635SJason King 	VERIFY3U(first[1], ==, 'x');
13494226f635SJason King 
13504226f635SJason King 	size_t n = nlen(db);
13514226f635SJason King 	const char *t1 = parse_expression(first + 2, last, db);
13524226f635SJason King 	if (t1 == first + 2)
13534226f635SJason King 		return (first);
13544226f635SJason King 
13554226f635SJason King 	const char *t2 = parse_expression(t1, last, db);
13564226f635SJason King 	if (t2 == t1 || NAMT(db, n) != 2)
13574226f635SJason King 		return (first);
13584226f635SJason King 
13594226f635SJason King 	nfmt(db, "({0})[{1}]", NULL);
13604226f635SJason King 	return (t2);
13614226f635SJason King }
13624226f635SJason King 
13634226f635SJason King static const char *
parse_ppmm_expr(const char * first,const char * last,const char * fmt,cpp_db_t * db)13644226f635SJason King parse_ppmm_expr(const char *first, const char *last, const char *fmt,
13654226f635SJason King     cpp_db_t *db)
13664226f635SJason King {
13674226f635SJason King 	VERIFY3P(first, <=, last);
13684226f635SJason King 
13694226f635SJason King 	if (last - first < 3)
13704226f635SJason King 		return (first);
13714226f635SJason King 
13724226f635SJason King 	const char *t = NULL;
13734226f635SJason King 	size_t n = nlen(db);
13744226f635SJason King 
13754226f635SJason King 	if (first[2] == '_') {
13764226f635SJason King 		t = parse_binary_expr(first + 3, last, "--", db);
13774226f635SJason King 		if (t == first + 3)
13784226f635SJason King 			return (first);
13794226f635SJason King 		return (t);
13804226f635SJason King 	}
13814226f635SJason King 
13824226f635SJason King 	t = parse_expression(first + 2, last, db);
13834226f635SJason King 	if (t == first + 2 || NAMT(db, n) < 1)
13844226f635SJason King 		return (first);
13854226f635SJason King 
13864226f635SJason King 	nfmt(db, fmt, NULL);
13874226f635SJason King 	return (t);
13884226f635SJason King }
13894226f635SJason King 
13904226f635SJason King static const char *
parse_mm_expr(const char * first,const char * last,cpp_db_t * db)13914226f635SJason King parse_mm_expr(const char *first, const char *last, cpp_db_t *db)
13924226f635SJason King {
13934226f635SJason King 	VERIFY3P(first, <=, last);
13944226f635SJason King 	VERIFY3U(first[0], ==, 'm');
13954226f635SJason King 	VERIFY3U(first[1], ==, 'm');
13964226f635SJason King 
13974226f635SJason King 	return (parse_ppmm_expr(first, last, "({0})--", db));
13984226f635SJason King }
13994226f635SJason King 
14004226f635SJason King static const char *
parse_pp_expr(const char * first,const char * last,cpp_db_t * db)14014226f635SJason King parse_pp_expr(const char *first, const char *last, cpp_db_t *db)
14024226f635SJason King {
14034226f635SJason King 	VERIFY3P(first, <=, last);
14044226f635SJason King 
14054226f635SJason King 	VERIFY3U(first[0], ==, 'p');
14064226f635SJason King 	VERIFY3U(first[0], ==, 'p');
14074226f635SJason King 
14084226f635SJason King 	return (parse_ppmm_expr(first, last, "({0})++", db));
14094226f635SJason King }
14104226f635SJason King 
14114226f635SJason King static const char *
parse_trinary_expr(const char * first,const char * last,cpp_db_t * db)14124226f635SJason King parse_trinary_expr(const char *first, const char *last, cpp_db_t *db)
14134226f635SJason King {
14144226f635SJason King 	VERIFY3P(first, <=, last);
14154226f635SJason King 
14164226f635SJason King 	const char *t1, *t2, *t3;
14174226f635SJason King 	size_t n = nlen(db);
14184226f635SJason King 
14194226f635SJason King 	if (last - first < 2)
14204226f635SJason King 		return (first);
14214226f635SJason King 
14224226f635SJason King 	t1 = parse_expression(first + 2, last, db);
14234226f635SJason King 	if (t1 == first + 2)
14244226f635SJason King 		return (first);
14254226f635SJason King 	t2 = parse_expression(t1, last, db);
14264226f635SJason King 	if (t1 == t2)
14274226f635SJason King 		return (first);
14284226f635SJason King 	t3 = parse_expression(t2, last, db);
14294226f635SJason King 	if (t3 == t2)
14304226f635SJason King 		return (first);
14314226f635SJason King 
14324226f635SJason King 	if (NAMT(db, n) != 3)
14334226f635SJason King 		return (first);
14344226f635SJason King 
14354226f635SJason King 	nfmt(db, "({2}) ? ({1}) : ({0})", NULL);
14364226f635SJason King 	return (t3);
14374226f635SJason King }
14384226f635SJason King 
14394226f635SJason King static const char *
parse_noexcept_expr(const char * first,const char * last,cpp_db_t * db)14404226f635SJason King parse_noexcept_expr(const char *first, const char *last, cpp_db_t *db)
14414226f635SJason King {
14424226f635SJason King 	VERIFY3P(first, <=, last);
14434226f635SJason King 
14444226f635SJason King 	if (last - first < 2)
14454226f635SJason King 		return (first);
14464226f635SJason King 
14474226f635SJason King 	size_t n = nlen(db);
14484226f635SJason King 	const char *t = parse_expression(first + 2, last, db);
14494226f635SJason King 	if (t == first + 2 || NAMT(db, n) != 1)
14504226f635SJason King 		return (first);
14514226f635SJason King 
14524226f635SJason King 	nfmt(db, "noexcept ({0})", NULL);
14534226f635SJason King 	return (t);
14544226f635SJason King }
14554226f635SJason King 
14564226f635SJason King /*
14574226f635SJason King  * cc <type> <expression>	# const_cast<type> (expression)
14584226f635SJason King  * dc <type> <expression>	# dynamic_cast<type> (expression)
14594226f635SJason King  * rc <type> <expression>	# reinterpret_cast<type> (expression)
14604226f635SJason King  * sc <type> <expression>	# static_cast<type> (expression)
14614226f635SJason King  */
14624226f635SJason King static const char *
parse_cast_expr(const char * first,const char * last,cpp_db_t * db)14634226f635SJason King parse_cast_expr(const char *first, const char *last, cpp_db_t *db)
14644226f635SJason King {
14654226f635SJason King 	VERIFY3P(first, <=, last);
14664226f635SJason King 
14674226f635SJason King 	if (last - first < 2)
14684226f635SJason King 		return (first);
14694226f635SJason King 
14704226f635SJason King 	const char *fmt = NULL;
14714226f635SJason King 	switch (first[0]) {
14724226f635SJason King 	case 'c':
14734226f635SJason King 		fmt = "const_cast<{1}> ({0})";
14744226f635SJason King 		break;
14754226f635SJason King 	case 'd':
14764226f635SJason King 		fmt = "dynamic_cast<{1}> ({0})";
14774226f635SJason King 		break;
14784226f635SJason King 	case 'r':
14794226f635SJason King 		fmt = "reinterpret_cast<{1}> ({0})";
14804226f635SJason King 		break;
14814226f635SJason King 	case 's':
14824226f635SJason King 		fmt = "static_cast<{1}> ({0})";
14834226f635SJason King 		break;
14844226f635SJason King 	default:
14854226f635SJason King 		return (first);
14864226f635SJason King 	}
14874226f635SJason King 
14884226f635SJason King 	VERIFY3U(first[1], ==, 'c');
14894226f635SJason King 
14904226f635SJason King 	const char *t1 = parse_type(first + 2, last, db);
14914226f635SJason King 	if (t1 == first + 2)
14924226f635SJason King 		return (first);
14934226f635SJason King 
14944226f635SJason King 	const char *t2 = parse_expression(t1, last, db);
14954226f635SJason King 	if (t2 == t1)
14964226f635SJason King 		return (first);
14974226f635SJason King 
14984226f635SJason King 	VERIFY3U(nlen(db), >, 1);
14994226f635SJason King 
15004226f635SJason King 	nfmt(db, fmt, NULL);
15014226f635SJason King 	return (t2);
15024226f635SJason King }
15034226f635SJason King 
15044226f635SJason King /* pt <expression> <expression>		# expr->name */
15054226f635SJason King static const char *
parse_arrow_expr(const char * first,const char * last,cpp_db_t * db)15064226f635SJason King parse_arrow_expr(const char *first, const char *last, cpp_db_t *db)
15074226f635SJason King {
15084226f635SJason King 	VERIFY3P(first, <=, last);
15094226f635SJason King 
15104226f635SJason King 	if (last - first < 4)
15114226f635SJason King 		return (first);
15124226f635SJason King 
15134226f635SJason King 	size_t n = nlen(db);
15144226f635SJason King 
15154226f635SJason King 	const char *t1 = parse_expression(first + 2, last, db);
15164226f635SJason King 	if (t1 == first + 2)
15174226f635SJason King 		return (first);
15184226f635SJason King 
15194226f635SJason King 	const char *t2 = parse_expression(t1, last, db);
15204226f635SJason King 	if (t2 == t1 || NAMT(db, n) != 2)
15214226f635SJason King 		return (first);
15224226f635SJason King 
15234226f635SJason King 	nfmt(db, "{1}->{0}", NULL);
15244226f635SJason King 	return (t2);
15254226f635SJason King }
15264226f635SJason King 
15274226f635SJason King /* wrap value in () when necessary */
15284226f635SJason King static void
paren(str_pair_t * sp)15294226f635SJason King paren(str_pair_t *sp)
15304226f635SJason King {
15314226f635SJason King 	str_t *l = &sp->strp_l;
15324226f635SJason King 	str_t *r = &sp->strp_r;
15334226f635SJason King 
15344226f635SJason King 	if (str_length(r) > 1 &&
15354226f635SJason King 	    r->str_s[0] == ' ' && r->str_s[1] == '[') {
15364226f635SJason King 		(void) str_append(l, " (", 2);
15374226f635SJason King 		(void) str_insert(r, 0, ")", 1);
15384226f635SJason King 	} else if (str_length(r) > 0 && r->str_s[0] == '(') {
15394226f635SJason King 		(void) str_append(l, "(", 1);
15404226f635SJason King 		(void) str_insert(r, 0, ")", 1);
15414226f635SJason King 	}
15424226f635SJason King }
15434226f635SJason King 
15444226f635SJason King /* BEGIN CSTYLED */
15454226f635SJason King /*
15464226f635SJason King  * <type> ::= <builtin-type>
15474226f635SJason King  *        ::= <function-type>
15484226f635SJason King  *        ::= <class-enum-type>
15494226f635SJason King  *        ::= <array-type>
15504226f635SJason King  *        ::= <pointer-to-member-type>
15514226f635SJason King  *        ::= <template-param>
15524226f635SJason King  *        ::= <template-template-param> <template-args>
15534226f635SJason King  *        ::= <decltype>
15544226f635SJason King  *        ::= <substitution>
15554226f635SJason King  *        ::= <CV-qualifiers> <type>
15564226f635SJason King  *        ::= P <type>        # pointer-to
15574226f635SJason King  *        ::= R <type>        # reference-to
15584226f635SJason King  *        ::= O <type>        # rvalue reference-to (C++0x)
15594226f635SJason King  *        ::= C <type>        # complex pair (C 2000)
15604226f635SJason King  *        ::= G <type>        # imaginary (C 2000)
15614226f635SJason King  *        ::= Dp <type>       # pack expansion (C++0x)
15624226f635SJason King  *        ::= U <source-name> <type>  # vendor extended type qualifier
15634226f635SJason King  * extension := U <objc-name> <objc-type>  # objc-type<identifier>
15644226f635SJason King  * extension := <vector-type> # <vector-type> starts with Dv
15654226f635SJason King  *
15664226f635SJason King  * <objc-name> ::= <k0 number> objcproto <k1 number> <identifier>  # k0 = 9 + <number of digits in k1> + k1
15674226f635SJason King  * <objc-type> := <source-name>  # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>
15684226f635SJason King  */
15694226f635SJason King /* END CSTYLED */
15704226f635SJason King static const char *
parse_type(const char * first,const char * last,cpp_db_t * db)15714226f635SJason King parse_type(const char *first, const char *last, cpp_db_t *db)
15724226f635SJason King {
15734226f635SJason King 	VERIFY3P(first, <=, last);
15744226f635SJason King 
15754226f635SJason King 	if (first == last)
15764226f635SJason King 		return (first);
15774226f635SJason King 
15784226f635SJason King 	switch (first[0]) {
15794226f635SJason King 	case 'r':
15804226f635SJason King 	case 'V':
15814226f635SJason King 	case 'K':
15824226f635SJason King 		return (parse_qual_type(first, last, db));
15834226f635SJason King 	}
15844226f635SJason King 
15854226f635SJason King 	const char *t = first;
15864226f635SJason King 	const char *t1 = NULL;
15874226f635SJason King 	str_pair_t *sp = NULL;
15884226f635SJason King 	size_t n = nlen(db);
15894226f635SJason King 	size_t amt = 0;
15904226f635SJason King 
15914226f635SJason King 	t = parse_builtin_type(first, last, db);
15924226f635SJason King 	if (t != first)
15934226f635SJason King 		return (t);
15944226f635SJason King 
15954226f635SJason King 	switch (first[0]) {
15964226f635SJason King 	case 'A':
15974226f635SJason King 		t = parse_array_type(first, last, db);
15984226f635SJason King 		if (t == first || NAMT(db, n) == 0)
15994226f635SJason King 			return (first);
16004226f635SJason King 		save_top(db, 1);
16014226f635SJason King 		return (t);
16024226f635SJason King 
16034226f635SJason King 	case 'C':
16044226f635SJason King 		t = parse_type(first + 1, last, db);
16054226f635SJason King 		if (t == first + 1 || NAMT(db, n) == 0)
16064226f635SJason King 			return (first);
16074226f635SJason King 
16084226f635SJason King 		(void) str_append(TOP_L(db), " complex", 8);
16094226f635SJason King 		save_top(db, 1);
16104226f635SJason King 		return (t);
16114226f635SJason King 
16124226f635SJason King 	case 'F':
16134226f635SJason King 		t = parse_function_type(first, last, db);
16144226f635SJason King 		if (t == first || NAMT(db, n) == 0)
16154226f635SJason King 			return (first);
16164226f635SJason King 		save_top(db, 1);
16174226f635SJason King 		return (t);
16184226f635SJason King 
16194226f635SJason King 	case 'G':
16204226f635SJason King 		t = parse_type(first + 1, last, db);
16214226f635SJason King 		if (t == first + 1 || NAMT(db, n) == 0)
16224226f635SJason King 			return (first);
16234226f635SJason King 
16244226f635SJason King 		(void) str_append(TOP_L(db), " imaginary", 10);
16254226f635SJason King 		save_top(db, 1);
16264226f635SJason King 		return (t);
16274226f635SJason King 
16284226f635SJason King 	case 'M':
16294226f635SJason King 		t = parse_pointer_to_member_type(first, last, db);
16304226f635SJason King 		if (t == first || NAMT(db, n) == 0)
16314226f635SJason King 			return (first);
16324226f635SJason King 		save_top(db, 1);
16334226f635SJason King 		return (t);
16344226f635SJason King 
16354226f635SJason King 	case 'O':
16364226f635SJason King 		t = parse_type(first + 1, last, db);
16374226f635SJason King 		amt = NAMT(db, n);
16384226f635SJason King 		if (t == first + 1 || amt == 0)
16394226f635SJason King 			return (first);
16404226f635SJason King 
16414226f635SJason King 		sp = name_at(&db->cpp_name, amt - 1);
16424226f635SJason King 		for (size_t i = 0; i < amt; i++, sp++) {
16434226f635SJason King 			paren(sp);
16444226f635SJason King 			if (str_pair_len(sp) > 0)
16454226f635SJason King 				(void) str_append(&sp->strp_l, "&&", 2);
16464226f635SJason King 		}
16474226f635SJason King 
16484226f635SJason King 		save_top(db, amt);
16494226f635SJason King 		return (t);
16504226f635SJason King 
16514226f635SJason King 	case 'P':
16524226f635SJason King 		t = parse_type(first + 1, last, db);
16534226f635SJason King 		amt = NAMT(db, n);
16544226f635SJason King 		if (t == first + 1 || amt == 0)
16554226f635SJason King 			return (first);
16564226f635SJason King 
16574226f635SJason King 		sp = name_at(&db->cpp_name, amt - 1);
16584226f635SJason King 		for (size_t i = 0; i < amt; i++, sp++) {
16594226f635SJason King 			str_t *l = &sp->strp_l;
16604226f635SJason King 
16614226f635SJason King 			if (str_pair_len(sp) == 0)
16624226f635SJason King 				continue;
16634226f635SJason King 
16644226f635SJason King 			paren(sp);
16654226f635SJason King 			if (first[1] != 'U' ||
16664226f635SJason King 			    strncmp(l->str_s, "objc_object<", 12) != 0) {
16674226f635SJason King 				(void) str_append(l, "*", 1);
16684226f635SJason King 			} else {
16694226f635SJason King 				(void) str_erase(l, 0, 11);
16704226f635SJason King 				(void) str_insert(l, 0, "id", 2);
16714226f635SJason King 			}
16724226f635SJason King 		}
16734226f635SJason King 		save_top(db, amt);
16744226f635SJason King 		return (t);
16754226f635SJason King 
16764226f635SJason King 	case 'R':
16774226f635SJason King 		t = parse_type(first + 1, last, db);
16784226f635SJason King 		amt = NAMT(db, n);
16794226f635SJason King 		if (t == first + 1 || amt == 0)
16804226f635SJason King 			return (first);
16814226f635SJason King 
16824226f635SJason King 		sp = name_at(&db->cpp_name, amt - 1);
16834226f635SJason King 		for (size_t i = 0; i < amt; i++, sp++) {
16844226f635SJason King 			if (str_length(&sp->strp_l) == 0 &&
16854226f635SJason King 			    str_length(&sp->strp_r) == 0)
16864226f635SJason King 				continue;
16874226f635SJason King 
16884226f635SJason King 			paren(sp);
16894226f635SJason King 			(void) str_append(&sp->strp_l, "&", 1);
16904226f635SJason King 		}
16914226f635SJason King 
16924226f635SJason King 		save_top(db, amt);
16934226f635SJason King 		return (t);
16944226f635SJason King 
16954226f635SJason King 	case 'T':
16964226f635SJason King 		t = parse_template_param(first, last, db);
16974226f635SJason King 		if (t == first)
16984226f635SJason King 			return (first);
16994226f635SJason King 
17004226f635SJason King 		amt = NAMT(db, n);
17014226f635SJason King 		save_top(db, amt);
17024226f635SJason King 		if (!db->cpp_try_to_parse_template_args || amt != 1)
17034226f635SJason King 			return (t);
17044226f635SJason King 
17054226f635SJason King 		t1 = parse_template_args(t, last, db);
17064226f635SJason King 		if (t1 == t)
17074226f635SJason King 			return (t);
17084226f635SJason King 
17094226f635SJason King 		nfmt(db, "{1:L}{0}", "{1:R}");
17104226f635SJason King 		save_top(db, 1);
17114226f635SJason King 		return (t1);
17124226f635SJason King 
17134226f635SJason King 	case 'U':
17144226f635SJason King 		if (first + 1 == last)
17154226f635SJason King 			return (first);
17164226f635SJason King 
17174226f635SJason King 		t = parse_source_name(first + 1, last, db);
17184226f635SJason King 		if (t == first + 1)
17194226f635SJason King 			return (first);
17204226f635SJason King 
17214226f635SJason King 		nfmt(db, "{0}", NULL);
17224226f635SJason King 
17234226f635SJason King 		t1 = parse_type(t, last, db);
17244226f635SJason King 		if (t1 == t || NAMT(db, n) < 2)
17254226f635SJason King 			return (first);
17264226f635SJason King 
17274226f635SJason King 		const str_t *name = &name_at(&db->cpp_name, 1)->strp_l;
17284226f635SJason King 
17294226f635SJason King 		if (str_length(name) > 0 &&
17304226f635SJason King 		    strncmp(name->str_s, "objcproto", 9) != 0) {
17314226f635SJason King 			nfmt(db, "{0} {1}", NULL);
17324226f635SJason King 		} else {
17334226f635SJason King 			t = parse_source_name(name->str_s + 9,
17344226f635SJason King 			    name->str_s + name->str_len, db);
17354226f635SJason King 			if (t != name->str_s + 9) {
17364226f635SJason King 				nfmt(db, "{1}<{0}>", NULL);
17374226f635SJason King 
17384226f635SJason King 				str_pair_t save = {0};
17394226f635SJason King 
17404226f635SJason King 				name_pop(&db->cpp_name, &save);
17414226f635SJason King 
17424226f635SJason King 				/* get rid of 'objcproto' */
17434226f635SJason King 				name_pop(&db->cpp_name, NULL);
17444226f635SJason King 				CK(name_add_str(&db->cpp_name, &save.strp_l,
17454226f635SJason King 				    &save.strp_r));
17464226f635SJason King 			} else {
17474226f635SJason King 				nfmt(db, "{1} {0}", NULL);
17484226f635SJason King 			}
17494226f635SJason King 		}
17504226f635SJason King 
17514226f635SJason King 		save_top(db, 1);
17524226f635SJason King 		return (t1);
17534226f635SJason King 
17544226f635SJason King 	case 'S':
17554226f635SJason King 		if (first + 1 != last && first[1] == 't') {
17564226f635SJason King 			t = parse_name(first, last, NULL, db);
17574226f635SJason King 			if (t == first || NAMT(db, n) == 0)
17584226f635SJason King 				return (first);
17594226f635SJason King 
17604226f635SJason King 			save_top(db, 1);
17614226f635SJason King 			return (t);
17624226f635SJason King 		}
17634226f635SJason King 
17644226f635SJason King 		t = parse_substitution(first, last, db);
17654226f635SJason King 		if (t == first)
17664226f635SJason King 			return (first);
17674226f635SJason King 
17684226f635SJason King 		/*
17694226f635SJason King 		 * If the substitution is a <template-param>, it might
17704226f635SJason King 		 * be followed by <template-args>
17714226f635SJason King 		 */
17724226f635SJason King 		t1 = parse_template_args(t, last, db);
17734226f635SJason King 		if (t1 == t)
17744226f635SJason King 			return (t);
17754226f635SJason King 
17764226f635SJason King 		if (NAMT(db, n) < 2)
17774226f635SJason King 			return (t);
17784226f635SJason King 
17794226f635SJason King 		nfmt(db, "{1:L}{0}", "{1:R}");
17804226f635SJason King 		save_top(db, 1);
17814226f635SJason King 		return (t1);
17824226f635SJason King 
17834226f635SJason King 	case 'D':
17844226f635SJason King 		if (first + 1 == last)
17854226f635SJason King 			return (first);
17864226f635SJason King 
17874226f635SJason King 		switch (first[1]) {
17884226f635SJason King 		case 'p':
17894226f635SJason King 			t = parse_type(first + 2, last, db);
17904226f635SJason King 			if (t == first + 2)
17914226f635SJason King 				break;
17924226f635SJason King 
17934226f635SJason King 			save_top(db, NAMT(db, n));
17944226f635SJason King 			return (t);
17954226f635SJason King 
17964226f635SJason King 		case 't':
17974226f635SJason King 		case 'T':
17984226f635SJason King 			t = parse_decltype(first, last, db);
17994226f635SJason King 			if (first == t)
18004226f635SJason King 				break;
18014226f635SJason King 
18024226f635SJason King 			save_top(db, 1);
18034226f635SJason King 			return (t);
18044226f635SJason King 
18054226f635SJason King 		case 'v':
18064226f635SJason King 			t = parse_vector_type(first, last, db);
18074226f635SJason King 			if (first == t)
18084226f635SJason King 				break;
18094226f635SJason King 
18104226f635SJason King 			if (NAMT(db, n) == 0)
18114226f635SJason King 				return (first);
18124226f635SJason King 
18134226f635SJason King 			save_top(db, 1);
18144226f635SJason King 			return (t);
18154226f635SJason King 		}
18164226f635SJason King 		break;
18174226f635SJason King 	}
18184226f635SJason King 
18194226f635SJason King 	/*
18204226f635SJason King 	 * must check for builtin-types before class-enum-types to avoid
18214226f635SJason King 	 * ambiguities with operator-names
18224226f635SJason King 	 */
18234226f635SJason King 	t = parse_builtin_type(first, last, db);
18244226f635SJason King 	if (t != first)
18254226f635SJason King 		return (t);
18264226f635SJason King 
18274226f635SJason King 	t = parse_name(first, last, NULL, db);
18284226f635SJason King 	if (t == first || NAMT(db, n) == 0)
18294226f635SJason King 		return (first);
18304226f635SJason King 
18314226f635SJason King 	save_top(db, 1);
18324226f635SJason King 	return (t);
18334226f635SJason King }
18344226f635SJason King 
18354226f635SJason King static const char *
parse_qual_type(const char * first,const char * last,cpp_db_t * db)18364226f635SJason King parse_qual_type(const char *first, const char *last, cpp_db_t *db)
18374226f635SJason King {
18384226f635SJason King 	VERIFY3P(first, <=, last);
18394226f635SJason King 
18404226f635SJason King 	const char *t = NULL;
18414226f635SJason King 	const char *t1 = NULL;
18424226f635SJason King 	unsigned cv = 0;
18434226f635SJason King 
18444226f635SJason King 	t = parse_cv_qualifiers(first, last, &cv);
18454226f635SJason King 	if (t == first)
18464226f635SJason King 		return (first);
18474226f635SJason King 
18484226f635SJason King 	size_t n = nlen(db);
18494226f635SJason King 	boolean_t is_func = !!(t[0] == 'F');
18504226f635SJason King 
18514226f635SJason King 	t1 = parse_type(t, last, db);
18524226f635SJason King 	size_t amt = NAMT(db, n);
18534226f635SJason King 	if (t == t1 || amt == 0)
18544226f635SJason King 		return (first);
18554226f635SJason King 
18564226f635SJason King 	if (is_func)
18574226f635SJason King 		sub_pop(&db->cpp_subs);
18584226f635SJason King 
18594226f635SJason King 	str_pair_t *sp = name_at(&db->cpp_name, amt - 1);
18604226f635SJason King 
18614226f635SJason King 	for (size_t i = 0; i < amt; i++, sp++) {
18624226f635SJason King 		str_t *s = NULL;
18634226f635SJason King 
18644226f635SJason King 		if (!is_func) {
18654226f635SJason King 			s = &sp->strp_l;
18664226f635SJason King 
18674226f635SJason King 			if (str_length(s) == 0)
18684226f635SJason King 				continue;
18694226f635SJason King 
18704226f635SJason King 			if (cv & 1)
18714226f635SJason King 				(void) str_append(s, " const", 6);
18724226f635SJason King 			if (cv & 2)
18734226f635SJason King 				(void) str_append(s, " volatile", 9);
18744226f635SJason King 			if (cv & 4)
18754226f635SJason King 				(void) str_append(s, " restrict", 9);
18764226f635SJason King 
18774226f635SJason King 			continue;
18784226f635SJason King 		}
18794226f635SJason King 
18804226f635SJason King 		s = &sp->strp_r;
18814226f635SJason King 		size_t pos = str_length(s);
18824226f635SJason King 
18834226f635SJason King 		if (pos > 0 && s->str_s[pos - 1] == '&') {
18844226f635SJason King 			pos--;
18854226f635SJason King 			if (s->str_s[pos - 1] == '&')
18864226f635SJason King 				pos--;
18874226f635SJason King 		}
18884226f635SJason King 
18894226f635SJason King 		if (cv & 1) {
18904226f635SJason King 			(void) str_insert(s, pos, " const", 6);
18914226f635SJason King 			pos += 6;
18924226f635SJason King 		}
18934226f635SJason King 		if (cv & 2) {
18944226f635SJason King 			(void) str_insert(s, pos, " volatile", 9);
18954226f635SJason King 			pos += 9;
18964226f635SJason King 		}
18974226f635SJason King 		if (cv & 4) {
18984226f635SJason King 			(void) str_insert(s, pos, " restrict", 9);
18994226f635SJason King 		}
19004226f635SJason King 	}
19014226f635SJason King 
19024226f635SJason King 	save_top(db, amt);
19034226f635SJason King 	return (t1);
19044226f635SJason King }
19054226f635SJason King 
19064226f635SJason King /*
19074226f635SJason King  * at <type>		# alignof (a type)
19084226f635SJason King  * az <expression>	# alignof (a expression)
19094226f635SJason King  */
19104226f635SJason King static const char *
parse_alignof(const char * first,const char * last,cpp_db_t * db)19114226f635SJason King parse_alignof(const char *first, const char *last, cpp_db_t *db)
19124226f635SJason King {
19134226f635SJason King 	VERIFY3P(first, <=, last);
19144226f635SJason King 
19154226f635SJason King 	if (last - first < 2)
19164226f635SJason King 		return (first);
19174226f635SJason King 
19184226f635SJason King 	const char *(*fn)(const char *, const char *, cpp_db_t *);
19194226f635SJason King 
19204226f635SJason King 	fn = (first[1] == 't') ? parse_type : parse_expression;
19214226f635SJason King 
19224226f635SJason King 	size_t n = nlen(db);
19234226f635SJason King 	const char *t = fn(first + 2, last, db);
19244226f635SJason King 	if (t == first + 2 || NAMT(db, n) != 1)
19254226f635SJason King 		return (first);
19264226f635SJason King 
19274226f635SJason King 	nfmt(db, "alignof ({0})", NULL);
19284226f635SJason King 	return (t);
19294226f635SJason King }
19304226f635SJason King 
19314226f635SJason King /*
19324226f635SJason King  * st <type>	# sizeof (a type)
19334226f635SJason King  * sz <expr>	# sizeof (a expression)
19344226f635SJason King  */
19354226f635SJason King static const char *
parse_sizeof(const char * first,const char * last,cpp_db_t * db)19364226f635SJason King parse_sizeof(const char *first, const char *last, cpp_db_t *db)
19374226f635SJason King {
19384226f635SJason King 	VERIFY3P(first, <=, last);
19394226f635SJason King 
19404226f635SJason King 	if (last - first < 2)
19414226f635SJason King 		return (first);
19424226f635SJason King 
19434226f635SJason King 	VERIFY3U(first[0], ==, 's');
19444226f635SJason King 
19454226f635SJason King 	const char *t = NULL;
19464226f635SJason King 	size_t n = nlen(db);
19474226f635SJason King 
19484226f635SJason King 	switch (first[1]) {
19494226f635SJason King 	case 't':
19504226f635SJason King 		t = parse_type(first + 2, last, db);
19514226f635SJason King 		break;
19524226f635SJason King 	case 'z':
19534226f635SJason King 		t = parse_expression(first + 2, last, db);
19544226f635SJason King 		break;
19554226f635SJason King 	default:
19564226f635SJason King 		return (first);
19574226f635SJason King 	}
19584226f635SJason King 	if (t == first + 2 || NAMT(db, n) != 1)
19594226f635SJason King 		return (first);
19604226f635SJason King 
19614226f635SJason King 	nfmt(db, "sizeof ({0})", NULL);
19624226f635SJason King 	return (t);
19634226f635SJason King }
19644226f635SJason King 
19654226f635SJason King /* BEGIN CSTYLED */
19664226f635SJason King /*
19674226f635SJason King  * <function-param> ::= fp <top-level CV-qualifiers> _                                     # L == 0, first parameter
19684226f635SJason King  *                  ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _   # L == 0, second and later parameters
19694226f635SJason King  *                  ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _         # L > 0, first parameter
19704226f635SJason King  *                  ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> <parameter-2 non-negative number> _   # L > 0, second and later parameters
19714226f635SJason King  */
19724226f635SJason King /* END CSTYLED */
19734226f635SJason King static const char *
parse_function_param(const char * first,const char * last,cpp_db_t * db)19744226f635SJason King parse_function_param(const char *first, const char *last, cpp_db_t *db)
19754226f635SJason King {
19764226f635SJason King 	VERIFY3P(first, <=, last);
19774226f635SJason King 
19784226f635SJason King 	if (last - first < 3 || first[0] != 'f')
19794226f635SJason King 		return (first);
19804226f635SJason King 
19814226f635SJason King 	const char *t1 = first + 2;
19824226f635SJason King 	const char *t2 = NULL;
19834226f635SJason King 	unsigned cv = 0;
19844226f635SJason King 
19854226f635SJason King 	if (first[1] == 'L') {
1986*1cd08393SJason King 		t2 = parse_number(t1, last);
19874226f635SJason King 		if (t2 == last || t2[0] != 'p')
19884226f635SJason King 			return (first);
19894226f635SJason King 		t1 = t2;
19904226f635SJason King 	}
19914226f635SJason King 
19924226f635SJason King 	if (first[1] != 'p')
19934226f635SJason King 		return (first);
19944226f635SJason King 
19954226f635SJason King 	t1 = parse_cv_qualifiers(t1, last, &cv);
1996*1cd08393SJason King 	t2 = parse_number(t1, last);
19974226f635SJason King 	if (t2 == last || t2[0] != '_')
19984226f635SJason King 		return (first);
19994226f635SJason King 
20004226f635SJason King 	if (t2 - t1 > 0)
20014226f635SJason King 		nadd_l(db, t1, (size_t)(t2 - t1));
20024226f635SJason King 	else
20034226f635SJason King 		nadd_l(db, "", 0);
20044226f635SJason King 
20054226f635SJason King 	nfmt(db, "fp{0}", NULL);
20064226f635SJason King 	return (t2 + 1);
20074226f635SJason King }
20084226f635SJason King 
20094226f635SJason King /*
20104226f635SJason King  * sZ <template-param>		# size of a parameter pack
20114226f635SJason King  * sZ <function-param>		# size of a function parameter pack
20124226f635SJason King  */
20134226f635SJason King static const char *
parse_sizeof_param_pack_expr(const char * first,const char * last,cpp_db_t * db)20144226f635SJason King parse_sizeof_param_pack_expr(const char *first, const char *last, cpp_db_t *db)
20154226f635SJason King {
20164226f635SJason King 	VERIFY3P(first, <=, last);
20174226f635SJason King 
20184226f635SJason King 	if (last - first < 3)
20194226f635SJason King 		return (first);
20204226f635SJason King 
20214226f635SJason King 	VERIFY3U(first[0], ==, 's');
20224226f635SJason King 	VERIFY3U(first[1], ==, 'Z');
20234226f635SJason King 
20244226f635SJason King 	if (first[2] != 'T' && first[2] != 'f')
20254226f635SJason King 		return (first);
20264226f635SJason King 
20274226f635SJason King 	const char *t = NULL;
20284226f635SJason King 	size_t n = nlen(db);
20294226f635SJason King 
20304226f635SJason King 	if (first[2] == 'T')
20314226f635SJason King 		t = parse_template_param(first + 2, last, db);
20324226f635SJason King 	else
20334226f635SJason King 		t = parse_function_param(first + 2, last, db);
20344226f635SJason King 
20354226f635SJason King 	if (t == first + 2)
20364226f635SJason King 		return (first);
20374226f635SJason King 
20384226f635SJason King 	njoin(db, NAMT(db, n), ", ");
20394226f635SJason King 	nfmt(db, "sizeof...({0})", NULL);
20404226f635SJason King 	return (t);
20414226f635SJason King }
20424226f635SJason King 
20434226f635SJason King /*
20444226f635SJason King  * te <expression>                                      # typeid (expression)
20454226f635SJason King  * ti <type>                                            # typeid (type)
20464226f635SJason King  */
20474226f635SJason King static const char *
parse_typeid_expr(const char * first,const char * last,cpp_db_t * db)20484226f635SJason King parse_typeid_expr(const char *first, const char *last, cpp_db_t *db)
20494226f635SJason King {
20504226f635SJason King 	VERIFY3P(first, <=, last);
20514226f635SJason King 
20524226f635SJason King 	if (last - first < 3)
20534226f635SJason King 		return (first);
20544226f635SJason King 
20554226f635SJason King 	VERIFY3U(first[0], ==, 't');
20564226f635SJason King 	VERIFY(first[1] == 'e' || first[1] == 'i');
20574226f635SJason King 
20584226f635SJason King 	const char *t = NULL;
20594226f635SJason King 	size_t n = nlen(db);
20604226f635SJason King 
20614226f635SJason King 	if (first[1] == 'e')
20624226f635SJason King 		t = parse_expression(first + 2, last, db);
20634226f635SJason King 	else
20644226f635SJason King 		t = parse_type(first + 2, last, db);
20654226f635SJason King 
20664226f635SJason King 	if (t == first + 2 || NAMT(db, n) != 1)
20674226f635SJason King 		return (first);
20684226f635SJason King 
20694226f635SJason King 	nfmt(db, "typeid ({0})", NULL);
20704226f635SJason King 	return (t);
20714226f635SJason King }
20724226f635SJason King 
20734226f635SJason King /*
20744226f635SJason King  * tr							# throw
20754226f635SJason King  * tw <expression>					# throw expression
20764226f635SJason King  */
20774226f635SJason King static const char *
parse_throw_expr(const char * first,const char * last,cpp_db_t * db)20784226f635SJason King parse_throw_expr(const char *first, const char *last, cpp_db_t *db)
20794226f635SJason King {
20804226f635SJason King 	VERIFY3P(first, <=, last);
20814226f635SJason King 
20824226f635SJason King 	if (last - first < 3)
20834226f635SJason King 		return (first);
20844226f635SJason King 
20854226f635SJason King 	VERIFY3U(first[0], ==, 't');
20864226f635SJason King 	VERIFY(first[1] == 'w' || first[1] == 'r');
20874226f635SJason King 
20884226f635SJason King 	if (first[1] == 'r') {
20894226f635SJason King 		nadd_l(db, "throw", 0);
20904226f635SJason King 		return (first + 2);
20914226f635SJason King 	}
20924226f635SJason King 
20934226f635SJason King 	size_t n = nlen(db);
20944226f635SJason King 	const char *t = parse_expression(first + 2, last, db);
20954226f635SJason King 	if (t == first + 2 || NAMT(db, n) != 1)
20964226f635SJason King 		return (first);
20974226f635SJason King 
20984226f635SJason King 	nfmt(db, "throw {0}", NULL);
20994226f635SJason King 	return (t);
21004226f635SJason King }
21014226f635SJason King 
21024226f635SJason King /* ds <expression> <expression>		# expr.*expr */
21034226f635SJason King static const char *
parse_dot_star_expr(const char * first,const char * last,cpp_db_t * db)21044226f635SJason King parse_dot_star_expr(const char *first, const char *last, cpp_db_t *db)
21054226f635SJason King {
21064226f635SJason King 	VERIFY3P(first, <=, last);
21074226f635SJason King 
21084226f635SJason King 	if (last - first < 3)
21094226f635SJason King 		return (first);
21104226f635SJason King 
21114226f635SJason King 	VERIFY3U(first[0], ==, 'd');
21124226f635SJason King 	VERIFY3U(first[1], ==, 's');
21134226f635SJason King 
21144226f635SJason King 	size_t n = nlen(db);
21154226f635SJason King 	const char *t = parse_expression(first + 2, last, db);
21164226f635SJason King 	if (t == first + 2)
21174226f635SJason King 		return (first);
21184226f635SJason King 
21194226f635SJason King 	const char *t2 = parse_expression(t, last, db);
21204226f635SJason King 	if (t == t2 || NAMT(db, n) != 2)
21214226f635SJason King 		return (first);
21224226f635SJason King 
21234226f635SJason King 	nfmt(db, "{1}.*{0}", NULL);
21244226f635SJason King 	return (t2);
21254226f635SJason King }
21264226f635SJason King 
21274226f635SJason King /* dt <expression> <unresolved-name>		# expr.name */
21284226f635SJason King static const char *
parse_dot_expr(const char * first,const char * last,cpp_db_t * db)21294226f635SJason King parse_dot_expr(const char *first, const char *last, cpp_db_t *db)
21304226f635SJason King {
21314226f635SJason King 	VERIFY3P(first, <=, last);
21324226f635SJason King 
21334226f635SJason King 	if (last - first < 3)
21344226f635SJason King 		return (first);
21354226f635SJason King 
21364226f635SJason King 	VERIFY3U(first[0], ==, 'd');
21374226f635SJason King 	VERIFY3U(first[1], ==, 't');
21384226f635SJason King 
21394226f635SJason King 	const char *t = parse_expression(first + 2, last, db);
21404226f635SJason King 	if (t == first + 2)
21414226f635SJason King 		return (first);
21424226f635SJason King 
21434226f635SJason King 	const char *t1 = parse_unresolved_name(t, last, db);
21444226f635SJason King 	if (t1 == t)
21454226f635SJason King 		return (first);
21464226f635SJason King 
21474226f635SJason King 	nfmt(db, "{1}.{0}", NULL);
21484226f635SJason King 	return (t1);
21494226f635SJason King }
21504226f635SJason King 
21514226f635SJason King /* cl <expression>+ E		# call */
21524226f635SJason King static const char *
parse_call_expr(const char * first,const char * last,cpp_db_t * db)21534226f635SJason King parse_call_expr(const char *first, const char *last, cpp_db_t *db)
21544226f635SJason King {
21554226f635SJason King 	VERIFY3P(first, <=, last);
21564226f635SJason King 
21574226f635SJason King 	if (last - first < 4)
21584226f635SJason King 		return (first);
21594226f635SJason King 
21604226f635SJason King 	VERIFY3U(first[0], ==, 'c');
21614226f635SJason King 	VERIFY3U(first[1], ==, 'l');
21624226f635SJason King 
21634226f635SJason King 	const char *t = first + 2;
21644226f635SJason King 	const char *t1 = NULL;
21654226f635SJason King 	size_t n = nlen(db);
21664226f635SJason King 
21674226f635SJason King 	for (t = first + 2; t != last && t[0] != 'E'; t = t1) {
21684226f635SJason King 		t1 = parse_expression(t, last, db);
21694226f635SJason King 		if (t1 == t)
21704226f635SJason King 			return (first);
21714226f635SJason King 	}
21724226f635SJason King 
21734226f635SJason King 	size_t amt = NAMT(db, n);
21744226f635SJason King 
21754226f635SJason King 	if (t == last || amt == 0)
21764226f635SJason King 		return (first);
21774226f635SJason King 
21784226f635SJason King 	njoin(db, amt - 1, ", ");
21794226f635SJason King 	nfmt(db, "{1}({0})", NULL);
21804226f635SJason King 
21814226f635SJason King 	VERIFY3U(t[0], ==, 'E');
21824226f635SJason King 	return (t + 1);
21834226f635SJason King }
21844226f635SJason King 
21854226f635SJason King /* BEGIN CSTYLED */
21864226f635SJason King /*
21874226f635SJason King  * cv <type> <expression>	# conversion with one argument
21884226f635SJason King  * cv <type> _ <expression>* E	# conversion with a different number of arguments
21894226f635SJason King  */
21904226f635SJason King /* END CSTYLED */
21914226f635SJason King static const char *
parse_conv_expr(const char * first,const char * last,cpp_db_t * db)21924226f635SJason King parse_conv_expr(const char *first, const char *last, cpp_db_t *db)
21934226f635SJason King {
21944226f635SJason King 	VERIFY3P(first, <=, last);
21954226f635SJason King 
21964226f635SJason King 	if (last - first < 3)
21974226f635SJason King 		return (first);
21984226f635SJason King 
21994226f635SJason King 	VERIFY3U(first[0], ==, 'c');
22004226f635SJason King 	VERIFY3U(first[1], ==, 'v');
22014226f635SJason King 
22024226f635SJason King 	const char *t = NULL;
22034226f635SJason King 	const char *t1 = NULL;
22044226f635SJason King 	size_t n = nlen(db);
22054226f635SJason King 
22064226f635SJason King 	boolean_t try_to_parse_template_args =
22074226f635SJason King 	    db->cpp_try_to_parse_template_args;
22084226f635SJason King 
22094226f635SJason King 	db->cpp_try_to_parse_template_args = B_FALSE;
22104226f635SJason King 	t = parse_type(first + 2, last, db);
22114226f635SJason King 	db->cpp_try_to_parse_template_args = try_to_parse_template_args;
22124226f635SJason King 
22134226f635SJason King 	if (t == first + 2)
22144226f635SJason King 		return (first);
22154226f635SJason King 
22164226f635SJason King 	if (t[0] != '_') {
22174226f635SJason King 		t1 = parse_expression(t, last, db);
22184226f635SJason King 		if (t1 == t)
22194226f635SJason King 			return (first);
22204226f635SJason King 
22214226f635SJason King 		t = t1;
22224226f635SJason King 	} else {
22234226f635SJason King 		size_t n1 = nlen(db);
22244226f635SJason King 
22254226f635SJason King 		/* skip _ */
22264226f635SJason King 		t++;
22274226f635SJason King 		while (t[0] != 'E' && t != last) {
22284226f635SJason King 			t1 = parse_expression(t, last, db);
22294226f635SJason King 			if (t1 == t)
22304226f635SJason King 				return (first);
22314226f635SJason King 			t1 = t;
22324226f635SJason King 		}
22334226f635SJason King 
22344226f635SJason King 		/* E */
22354226f635SJason King 		t++;
22364226f635SJason King 
22374226f635SJason King 		njoin(db, NAMT(db, n1), ", ");
22384226f635SJason King 	}
22394226f635SJason King 
22404226f635SJason King 	if (NAMT(db, n) < 2)
22414226f635SJason King 		return (first);
22424226f635SJason King 
22434226f635SJason King 	nfmt(db, "({1})({0})", NULL);
22444226f635SJason King 	return (t);
22454226f635SJason King }
22464226f635SJason King 
22474226f635SJason King /* <simple-id> ::= <source-name> [ <template-args> ] */
22484226f635SJason King static const char *
parse_simple_id(const char * first,const char * last,cpp_db_t * db)22494226f635SJason King parse_simple_id(const char *first, const char *last, cpp_db_t *db)
22504226f635SJason King {
22514226f635SJason King 	VERIFY3P(first, <=, last);
22524226f635SJason King 
22534226f635SJason King 	const char *t = parse_source_name(first, last, db);
22544226f635SJason King 	if (t == first)
22554226f635SJason King 		return (t);
22564226f635SJason King 
22574226f635SJason King 	const char *t1 = parse_template_args(t, last, db);
22584226f635SJason King 	if (t == t1)
22594226f635SJason King 		return (t);
22604226f635SJason King 
22614226f635SJason King 	nfmt(db, "{1}{0}", NULL);
22624226f635SJason King 	return (t1);
22634226f635SJason King }
22644226f635SJason King 
22654226f635SJason King /*
22664226f635SJason King  * <unresolved-type> ::= <template-param>
22674226f635SJason King  *                   ::= <decltype>
22684226f635SJason King  *                   ::= <substitution>
22694226f635SJason King  */
22704226f635SJason King static const char *
parse_unresolved_type(const char * first,const char * last,cpp_db_t * db)22714226f635SJason King parse_unresolved_type(const char *first, const char *last, cpp_db_t *db)
22724226f635SJason King {
22734226f635SJason King 	VERIFY3P(first, <=, last);
22744226f635SJason King 
22754226f635SJason King 	if (first == last)
22764226f635SJason King 		return (first);
22774226f635SJason King 
22784226f635SJason King 	const char *t = first;
22794226f635SJason King 	size_t n = nlen(db);
22804226f635SJason King 
22814226f635SJason King 	switch (first[0]) {
22824226f635SJason King 	case 'T':
22834226f635SJason King 		t = parse_template_param(first, last, db);
22844226f635SJason King 		if (t == first || NAMT(db, n) != 1) {
22854226f635SJason King 			for (size_t i = 0; i < NAMT(db, n); i++)
22864226f635SJason King 				name_pop(&db->cpp_name, NULL);
22874226f635SJason King 			return (first);
22884226f635SJason King 		}
22894226f635SJason King 		save_top(db, 1);
22904226f635SJason King 		return (t);
22914226f635SJason King 
22924226f635SJason King 	case 'D':
22934226f635SJason King 		t = parse_decltype(first, last, db);
22944226f635SJason King 		if (t == first || NAMT(db, n) == 0)
22954226f635SJason King 			return (first);
22964226f635SJason King 		save_top(db, 1);
22974226f635SJason King 		return (t);
22984226f635SJason King 
22994226f635SJason King 	case 'S':
23004226f635SJason King 		t = parse_substitution(first, last, db);
23014226f635SJason King 		if (t != first)
23024226f635SJason King 			return (t);
23034226f635SJason King 
23044226f635SJason King 		if (last - first < 2 || first[1] != 't')
23054226f635SJason King 			return (first);
23064226f635SJason King 
23074226f635SJason King 		t = parse_unqualified_name(first + 2, last, db);
23084226f635SJason King 		if (t == first + 2 || NAMT(db, n) == 0)
23094226f635SJason King 			return (first);
23104226f635SJason King 
23114226f635SJason King 		nfmt(db, "std::{0:L}", "{0:R}");
23124226f635SJason King 		save_top(db, 1);
23134226f635SJason King 		return (t);
23144226f635SJason King 	}
23154226f635SJason King 
23164226f635SJason King 	return (first);
23174226f635SJason King }
23184226f635SJason King 
23194226f635SJason King /* sp <expression>		# pack expansion */
23204226f635SJason King static const char *
parse_pack_expansion(const char * first,const char * last,cpp_db_t * db)23214226f635SJason King parse_pack_expansion(const char *first, const char *last, cpp_db_t *db)
23224226f635SJason King {
23234226f635SJason King 	VERIFY3P(first, <=, last);
23244226f635SJason King 
23254226f635SJason King 	if (last - first < 3)
23264226f635SJason King 		return (first);
23274226f635SJason King 
23284226f635SJason King 	VERIFY3U(first[0], ==, 's');
23294226f635SJason King 	VERIFY3U(first[1], ==, 'p');
23304226f635SJason King 
23314226f635SJason King 	const char *t = parse_expression(first + 2, last, db);
23324226f635SJason King 	if (t == first +2)
23334226f635SJason King 		return (first);
23344226f635SJason King 
23354226f635SJason King 	return (t);
23364226f635SJason King }
23374226f635SJason King 
23384226f635SJason King /*
23394226f635SJason King  * <unscoped-name> ::= <unqualified-name>
23404226f635SJason King  *                 ::= St <unqualified-name>   # ::std::
23414226f635SJason King  * extension       ::= StL<unqualified-name>
23424226f635SJason King  */
23434226f635SJason King static const char *
parse_unscoped_name(const char * first,const char * last,cpp_db_t * db)23444226f635SJason King parse_unscoped_name(const char *first, const char *last, cpp_db_t *db)
23454226f635SJason King {
23464226f635SJason King 	VERIFY3P(first, <=, last);
23474226f635SJason King 
23484226f635SJason King 	if (last - first < 2)
23494226f635SJason King 		return (first);
23504226f635SJason King 
23514226f635SJason King 	const char *t = first;
23524226f635SJason King 	const char *t1 = NULL;
23534226f635SJason King 	boolean_t st = B_FALSE;
23544226f635SJason King 
23554226f635SJason King 	if (first[0] == 'S' && first[1] == 't') {
23564226f635SJason King 		st = B_TRUE;
23574226f635SJason King 		t = first + 2;
23584226f635SJason King 
23594226f635SJason King 		if (first + 3 != last && first[2] == 'L')
23604226f635SJason King 			t++;
23614226f635SJason King 	}
23624226f635SJason King 
23634226f635SJason King 	t1 = parse_unqualified_name(t, last, db);
23644226f635SJason King 	if (t == t1)
23654226f635SJason King 		return (first);
23664226f635SJason King 
23674226f635SJason King 	if (st)
23684226f635SJason King 		nfmt(db, "std::{0}", NULL);
23694226f635SJason King 
23704226f635SJason King 	return (t1);
23714226f635SJason King }
23724226f635SJason King 
23734226f635SJason King /*
23744226f635SJason King  * <unqualified-name> ::= <operator-name>
23754226f635SJason King  *                    ::= <ctor-dtor-name>
23764226f635SJason King  *                    ::= <source-name>
23774226f635SJason King  *                    ::= <unnamed-type-name>
23784226f635SJason King  */
23794226f635SJason King const char *
parse_unqualified_name(const char * first,const char * last,cpp_db_t * db)23804226f635SJason King parse_unqualified_name(const char *first, const char *last, cpp_db_t *db)
23814226f635SJason King {
23824226f635SJason King 	VERIFY3P(first, <=, last);
23834226f635SJason King 
23844226f635SJason King 	if (first == last)
23854226f635SJason King 		return (first);
23864226f635SJason King 
23874226f635SJason King 	switch (*first) {
23884226f635SJason King 	case 'C':
23894226f635SJason King 	case 'D':
23904226f635SJason King 		return (parse_ctor_dtor_name(first, last, db));
23914226f635SJason King 	case 'U':
23924226f635SJason King 		return (parse_unnamed_type_name(first, last, db));
23934226f635SJason King 
23944226f635SJason King 	case '1':
23954226f635SJason King 	case '2':
23964226f635SJason King 	case '3':
23974226f635SJason King 	case '4':
23984226f635SJason King 	case '5':
23994226f635SJason King 	case '6':
24004226f635SJason King 	case '7':
24014226f635SJason King 	case '8':
24024226f635SJason King 	case '9':
24034226f635SJason King 		return (parse_source_name(first, last, db));
24044226f635SJason King 	default:
24054226f635SJason King 		return (parse_operator_name(first, last, db));
24064226f635SJason King 	}
24074226f635SJason King }
24084226f635SJason King 
24094226f635SJason King /*
24104226f635SJason King  * <unnamed-type-name> ::= Ut [ <nonnegative number> ] _
24114226f635SJason King  *                     ::= <closure-type-name>
24124226f635SJason King  *
24134226f635SJason King  * <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
24144226f635SJason King  *
24154226f635SJason King  * <lambda-sig> ::= <parameter type>+
24164226f635SJason King  *			# Parameter types or "v" if the lambda has no parameters
24174226f635SJason King  */
24184226f635SJason King static const char *
parse_unnamed_type_name(const char * first,const char * last,cpp_db_t * db)24194226f635SJason King parse_unnamed_type_name(const char *first, const char *last, cpp_db_t *db)
24204226f635SJason King {
24214226f635SJason King 	VERIFY3P(first, <=, last);
24224226f635SJason King 
24234226f635SJason King 	if (last - first < 2 || first[0] != 'U')
24244226f635SJason King 		return (first);
24254226f635SJason King 
24264226f635SJason King 	if (first[1] != 't' && first[1] != 'l')
24274226f635SJason King 		return (first);
24284226f635SJason King 
24294226f635SJason King 	const char *t1 = first + 2;
24304226f635SJason King 	const char *t2 = NULL;
24314226f635SJason King 
24324226f635SJason King 	if (first[1] == 't') {
2433*1cd08393SJason King 		while (t1 != last && t1[0] != '_' && ISDIGIT(t1[0]))
24344226f635SJason King 			t1++;
24354226f635SJason King 
24364226f635SJason King 		if (t1[0] != '_')
24374226f635SJason King 			return (first);
24384226f635SJason King 
24394226f635SJason King 		if (t1 == first + 2)
24404226f635SJason King 			nadd_l(db, "", 0);
24414226f635SJason King 		else
24424226f635SJason King 			nadd_l(db, first + 2, (size_t)(t1 - first - 2));
24434226f635SJason King 
24444226f635SJason King 		nfmt(db, "'unnamed{0}'", NULL);
24454226f635SJason King 		return (t1 + 1);
24464226f635SJason King 	}
24474226f635SJason King 
24484226f635SJason King 	size_t n = nlen(db);
24494226f635SJason King 
24504226f635SJason King 	if (first[2] != 'v') {
24514226f635SJason King 		do {
24524226f635SJason King 			t2 = parse_type(t1, last, db);
24534226f635SJason King 			if (t1 == t2)
24544226f635SJason King 				return (first);
24554226f635SJason King 			t1 = t2;
24564226f635SJason King 		} while (t1 != last && t1[0] != 'E');
24574226f635SJason King 
24584226f635SJason King 		if (t1 == last || NAMT(db, n) < 1)
24594226f635SJason King 			return (first);
24604226f635SJason King 
24614226f635SJason King 		if (NAMT(db, n) < 1)
24624226f635SJason King 			return (first);
24634226f635SJason King 	} else {
24644226f635SJason King 		t1++;
24654226f635SJason King 		if (t1[0] != 'E')
24664226f635SJason King 			return (first);
24674226f635SJason King 	}
24684226f635SJason King 
24694226f635SJason King 	njoin(db, NAMT(db, n), ", ");
24704226f635SJason King 
24714226f635SJason King 	/* E */
24724226f635SJason King 	t1++;
24734226f635SJason King 
24744226f635SJason King 	t2 = t1;
24754226f635SJason King 	while (t2 != last && t2[0] != '_') {
2476*1cd08393SJason King 		char c = *t2++;
2477*1cd08393SJason King 		if (!ISDIGIT(c))
24784226f635SJason King 			return (first);
24794226f635SJason King 	}
24804226f635SJason King 
24814226f635SJason King 	if (t2[0] != '_')
24824226f635SJason King 		return (first);
24834226f635SJason King 
24844226f635SJason King 	if (t2 - t1 > 0)
24854226f635SJason King 		nadd_l(db, t1, (size_t)(t2 - t1));
24864226f635SJason King 	else
24874226f635SJason King 		nadd_l(db, "", 0);
24884226f635SJason King 
24894226f635SJason King 	nfmt(db, "'lambda{0}'({1})", NULL);
24904226f635SJason King 
24914226f635SJason King 	/* _ */
24924226f635SJason King 	return (t2 + 1);
24934226f635SJason King }
24944226f635SJason King 
24954226f635SJason King static struct {
24964226f635SJason King 	const char *alias;
24974226f635SJason King 	const char *fullname;
24984226f635SJason King 	const char *basename;
24994226f635SJason King } aliases[] = {
25004226f635SJason King 	{
25014226f635SJason King 		"std::string",
25024226f635SJason King 		"std::basic_string<char, std::char_traits<char>, "
25034226f635SJason King 		    "std::allocator<char> >",
25044226f635SJason King 		"basic_string"
25054226f635SJason King 	},
25064226f635SJason King 	{
25074226f635SJason King 		"std::istream",
25084226f635SJason King 		"std::basic_istream<char, std::char_traits<char> >",
25094226f635SJason King 		"basic_istream"
25104226f635SJason King 	},
25114226f635SJason King 	{
25124226f635SJason King 		"std::ostream",
25134226f635SJason King 		"std::basic_ostream<char, std::char_traits<char> >",
25144226f635SJason King 		"basic_ostream"
25154226f635SJason King 	},
25164226f635SJason King 	{
25174226f635SJason King 		"std::iostream",
25184226f635SJason King 		"std::basic_iostream<char, std::char_traits<char> >",
25194226f635SJason King 		"basic_iostream"
25204226f635SJason King 	}
25214226f635SJason King };
25224226f635SJason King 
25234226f635SJason King static void
basename(cpp_db_t * db)25244226f635SJason King basename(cpp_db_t *db)
25254226f635SJason King {
25264226f635SJason King 	str_t *s = TOP_L(db);
25274226f635SJason King 
25284226f635SJason King 	for (size_t i = 0; i < ARRAY_SIZE(aliases); i++) {
25294226f635SJason King 		if (str_length(s) != strlen(aliases[i].alias))
25304226f635SJason King 			continue;
25314226f635SJason King 		if (strncmp(aliases[i].alias, s->str_s, str_length(s)) != 0)
25324226f635SJason King 			continue;
25334226f635SJason King 
25344226f635SJason King 		/* swap out alias for full name */
25354226f635SJason King 		sysdem_ops_t *ops = s->str_ops;
25364226f635SJason King 		str_fini(s);
25374226f635SJason King 		str_init(s, ops);
25384226f635SJason King 		str_set(s, aliases[i].fullname, 0);
25394226f635SJason King 
25404226f635SJason King 		nadd_l(db, aliases[i].basename, 0);
25414226f635SJason King 		return;
25424226f635SJason King 	}
25434226f635SJason King 
25444226f635SJason King 	const char *start = s->str_s;
25454226f635SJason King 	const char *end = s->str_s + s->str_len;
25464226f635SJason King 
25474226f635SJason King 	/*
25484226f635SJason King 	 * if name ends with a template i.e. <.....> back up to start
25494226f635SJason King 	 * of outermost template
25504226f635SJason King 	 */
25514226f635SJason King 	unsigned c = 0;
25524226f635SJason King 
25534226f635SJason King 	if (end[-1] == '>') {
25544226f635SJason King 		for (; end > start; end--) {
25554226f635SJason King 			switch (end[-1]) {
25564226f635SJason King 			case '<':
25574226f635SJason King 				if (--c == 0) {
25584226f635SJason King 					end--;
25594226f635SJason King 					goto out;
25604226f635SJason King 				}
25614226f635SJason King 				break;
25624226f635SJason King 			case '>':
25634226f635SJason King 				c++;
25644226f635SJason King 				break;
25654226f635SJason King 			}
25664226f635SJason King 		}
25674226f635SJason King 	}
25684226f635SJason King 
25694226f635SJason King out:
25704226f635SJason King 	VERIFY3P(end, >=, start);
25714226f635SJason King 
25724226f635SJason King 	if (end - start < 2) {
25734226f635SJason King 		nadd_l(db, "", 0);
25744226f635SJason King 		return;
25754226f635SJason King 	}
25764226f635SJason King 
25774226f635SJason King 	for (start = end - 1; start > s->str_s; start--) {
25784226f635SJason King 		if (start[0] == ':') {
25794226f635SJason King 			start++;
25804226f635SJason King 			break;
25814226f635SJason King 		}
25824226f635SJason King 	}
25834226f635SJason King 
25844226f635SJason King 	VERIFY3P(end, >=, start);
25854226f635SJason King 
25864226f635SJason King 	nadd_l(db, start, (size_t)(end - start));
25874226f635SJason King }
25884226f635SJason King 
25894226f635SJason King /*
25904226f635SJason King  * <ctor-dtor-name> ::= C1    # complete object constructor
25914226f635SJason King  *                  ::= C2    # base object constructor
25924226f635SJason King  *                  ::= C3    # complete object allocating constructor
25934226f635SJason King  *   extension      ::= C5    # ?
25944226f635SJason King  *                  ::= D0    # deleting destructor
25954226f635SJason King  *                  ::= D1    # complete object destructor
25964226f635SJason King  *                  ::= D2    # base object destructor
25974226f635SJason King  *   extension      ::= D5    # ?
25984226f635SJason King  */
25994226f635SJason King static const char *
parse_ctor_dtor_name(const char * first,const char * last,cpp_db_t * db)26004226f635SJason King parse_ctor_dtor_name(const char *first, const char *last, cpp_db_t *db)
26014226f635SJason King {
26024226f635SJason King 	VERIFY3P(first, <=, last);
26034226f635SJason King 
26044226f635SJason King 	if (last - first < 2 || nempty(db) || str_length(TOP_L(db)) == 0)
26054226f635SJason King 		return (first);
26064226f635SJason King 
26074226f635SJason King 	switch (first[0]) {
26084226f635SJason King 	case 'C':
26094226f635SJason King 		switch (first[1]) {
26104226f635SJason King 		case '1':
26114226f635SJason King 		case '2':
26124226f635SJason King 		case '3':
26134226f635SJason King 		case '5':
26144226f635SJason King 			basename(db);
26154226f635SJason King 			break;
26164226f635SJason King 		default:
26174226f635SJason King 			return (first);
26184226f635SJason King 		}
26194226f635SJason King 		break;
26204226f635SJason King 	case 'D':
26214226f635SJason King 		switch (first[1]) {
26224226f635SJason King 		case '0':
26234226f635SJason King 		case '1':
26244226f635SJason King 		case '2':
26254226f635SJason King 		case '5':
26264226f635SJason King 			basename(db);
26274226f635SJason King 			(void) str_insert(TOP_L(db), 0, "~", 1);
26284226f635SJason King 			break;
26294226f635SJason King 		default:
26304226f635SJason King 			return (first);
26314226f635SJason King 		}
26324226f635SJason King 		break;
26334226f635SJason King 	default:
26344226f635SJason King 		return (first);
26354226f635SJason King 	}
26364226f635SJason King 
26374226f635SJason King 	db->cpp_parsed_ctor_dtor_cv = B_TRUE;
26384226f635SJason King 	return (first + 2);
26394226f635SJason King }
26404226f635SJason King 
26414226f635SJason King static const char *
parse_integer_literal(const char * first,const char * last,const char * fmt,cpp_db_t * db)26424226f635SJason King parse_integer_literal(const char *first, const char *last, const char *fmt,
26434226f635SJason King     cpp_db_t *db)
26444226f635SJason King {
26454226f635SJason King 	VERIFY3P(first, <=, last);
26464226f635SJason King 
2647*1cd08393SJason King 	const char *t = parse_number(first, last);
26484226f635SJason King 	const char *start = first;
26494226f635SJason King 
26504226f635SJason King 	if (t == first || t == last || t[0] != 'E')
26514226f635SJason King 		return (first);
26524226f635SJason King 
26534226f635SJason King 	if (first[0] == 'n')
26544226f635SJason King 		start++;
26554226f635SJason King 
26564226f635SJason King 	nadd_l(db, start, (size_t)(t - start));
26574226f635SJason King 	if (start != first)
26584226f635SJason King 		nfmt(db, "-{0}", NULL);
26594226f635SJason King 
26604226f635SJason King 	nfmt(db, fmt, NULL);
26614226f635SJason King 	return (t + 1);
26624226f635SJason King }
26634226f635SJason King 
26644226f635SJason King static struct float_data_s {
26654226f635SJason King 	const char *spec;
26664226f635SJason King 	size_t mangled_size;
26674226f635SJason King 	size_t max_demangled_size;
26684226f635SJason King 	char type;
26694226f635SJason King } float_info[] = {
26704226f635SJason King 	{ "%af", 8, 24, 'f' },		/* float */
26714226f635SJason King 	{ "%a", 16, 32, 'd' },		/* double */
26724226f635SJason King 	{ "%LaL", 20, 40, 'e' }		/* long double */
26734226f635SJason King };
26744226f635SJason King 
26754226f635SJason King static const char *
parse_floating_literal(const char * first,const char * last,cpp_db_t * db)26764226f635SJason King parse_floating_literal(const char *first, const char *last, cpp_db_t *db)
26774226f635SJason King {
26784226f635SJason King 	VERIFY3P(first, <=, last);
26794226f635SJason King 	VERIFY(first[0] == 'f' || first[0] == 'd' || first[0] == 'e');
26804226f635SJason King 
26814226f635SJason King 	const struct float_data_s *fd = NULL;
26824226f635SJason King 
26834226f635SJason King 	for (size_t i = 0; i < ARRAY_SIZE(float_info); i++) {
26844226f635SJason King 		if (float_info[i].type != first[0])
26854226f635SJason King 			continue;
26864226f635SJason King 
26874226f635SJason King 		fd = &float_info[i];
26884226f635SJason King 		break;
26894226f635SJason King 	}
26904226f635SJason King 
26914226f635SJason King 	if (fd == NULL || (size_t)(last - first) < fd->mangled_size)
26924226f635SJason King 		return (first);
26934226f635SJason King 
26944226f635SJason King 	union {
26954226f635SJason King 		union {
26964226f635SJason King 			float v;
26974226f635SJason King 			char buf[sizeof (float)];
26984226f635SJason King 		} f;
26994226f635SJason King 		union {
27004226f635SJason King 			double v;
27014226f635SJason King 			char buf[sizeof (double)];
27024226f635SJason King 		} d;
27034226f635SJason King 		union {
27044226f635SJason King 			long double v;
27054226f635SJason King 			char buf[sizeof (long double)];
27064226f635SJason King 		} ld;
27074226f635SJason King 	} conv;
27084226f635SJason King 
27094226f635SJason King 	const char *t = NULL;
27104226f635SJason King 	char *e = NULL;
27114226f635SJason King 
27124226f635SJason King 	switch (first[0]) {
27134226f635SJason King 	case 'f':
27144226f635SJason King 		e = conv.f.buf;
27154226f635SJason King 		break;
27164226f635SJason King 	case 'd':
27174226f635SJason King 		e = conv.d.buf;
27184226f635SJason King 		break;
27194226f635SJason King 	case 'e':
27204226f635SJason King 		e = conv.ld.buf;
27214226f635SJason King 		break;
27224226f635SJason King 	}
27234226f635SJason King 	last = first + fd->mangled_size + 1;
27244226f635SJason King 
27254226f635SJason King #if defined(_BIG_ENDIAN)
27264226f635SJason King 	for (t = first + 1; t != last; t++, e++) {
27274226f635SJason King 		if (!is_xdigit(t[0]))
27284226f635SJason King 			return (first);
27294226f635SJason King 
2730*1cd08393SJason King 		unsigned d1 = ISDIGIT(t[0]) ?  t[0] - '0' : t[0] - 'a' + 10;
27314226f635SJason King 		t++;
2732*1cd08393SJason King 		unsigned d0 = ISDIGIT(t[0]) ?  t[0] - '0' : t[0] - 'a' + 10;
27334226f635SJason King 
27344226f635SJason King 		*e = (d1 << 4) + d0;
27354226f635SJason King 	}
27364226f635SJason King #elif defined(_LITTLE_ENDIAN)
27374226f635SJason King 	for (t = last - 1; t > first; t--, e++) {
27384226f635SJason King 		if (!is_xdigit(t[0]))
27394226f635SJason King 			return (first);
27404226f635SJason King 
2741*1cd08393SJason King 		unsigned d0 = ISDIGIT(t[0]) ?  t[0] - '0' : t[0] - 'a' + 10;
27424226f635SJason King 		t--;
2743*1cd08393SJason King 		unsigned d1 = ISDIGIT(t[0]) ?  t[0] - '0' : t[0] - 'a' + 10;
27444226f635SJason King 
27454226f635SJason King 		*e = (d1 << 4) + d0;
27464226f635SJason King 	}
27474226f635SJason King 	t = last;
27484226f635SJason King #else
27494226f635SJason King #error One of _BIG_ENDIAN or _LITTLE_ENDIAN must be defined
27504226f635SJason King #endif
27514226f635SJason King 
27524226f635SJason King 	if (t[0] != 'E')
27534226f635SJason King 		return (first);
27544226f635SJason King 
27554226f635SJason King 	str_t num = { 0 };
27564226f635SJason King 	str_init(&num, db->cpp_ops);
27574226f635SJason King 
27584226f635SJason King 	num.str_size = fd->max_demangled_size + 1;
27594226f635SJason King 	num.str_s = zalloc(db->cpp_ops, num.str_size);
27604226f635SJason King 	CK(num.str_s != NULL);
27614226f635SJason King 
27624226f635SJason King 	int n = 0;
27634226f635SJason King 
27644226f635SJason King 	switch (first[0]) {
27654226f635SJason King 	case 'f':
27664226f635SJason King 		n = snprintf(num.str_s, fd->max_demangled_size, fd->spec,
27674226f635SJason King 		    conv.f.v);
27684226f635SJason King 		break;
27694226f635SJason King 	case 'd':
27704226f635SJason King 		n = snprintf(num.str_s, fd->max_demangled_size, fd->spec,
27714226f635SJason King 		    conv.d.v);
27724226f635SJason King 		break;
27734226f635SJason King 	case 'e':
27744226f635SJason King 		n = snprintf(num.str_s, fd->max_demangled_size, fd->spec,
27754226f635SJason King 		    conv.ld.v);
27764226f635SJason King 	}
27774226f635SJason King 
27784226f635SJason King 	if (n >= fd->max_demangled_size || n <= 0) {
27794226f635SJason King 		str_fini(&num);
27804226f635SJason King 		return (first);
27814226f635SJason King 	}
27824226f635SJason King 
27834226f635SJason King 	num.str_len = n;
27844226f635SJason King 	(void) name_add_str(&db->cpp_name, &num, NULL);
27854226f635SJason King 
27864226f635SJason King 	return (t + 1);
27874226f635SJason King }
27884226f635SJason King 
27894226f635SJason King /*
27904226f635SJason King  * <expr-primary> ::= L <type> <value number> E	# integer literal
27914226f635SJason King  *                ::= L <type> <value float> E	# floating literal
27924226f635SJason King  *                ::= L <string type> E		# string literal
27934226f635SJason King  *                ::= L <nullptr type> E	# nullptr literal (i.e., "LDnE")
27944226f635SJason King  *
27954226f635SJason King  *                ::= L <type> <real-part float> _ <imag-part float> E
27964226f635SJason King  *						# complex floating point
27974226f635SJason King  *						# literal (C 2000)
27984226f635SJason King  *
27994226f635SJason King  *                ::= L <mangled-name> E	# external name
28004226f635SJason King  */
28014226f635SJason King static struct {
28024226f635SJason King 	int		c;
28034226f635SJason King 	const char	*fmt;
28044226f635SJason King } int_lits[] = {
28054226f635SJason King 	{ 'a', "(signed char){0}" },
28064226f635SJason King 	{ 'c', "(char){0}" },
28074226f635SJason King 	{ 'h', "(unsigned char){0}" },
28084226f635SJason King 	{ 'i', "{0}" },
28094226f635SJason King 	{ 'j', "{0}u" },
28104226f635SJason King 	{ 'l', "{0}l" },
28114226f635SJason King 	{ 'm', "{0}ul" },
28124226f635SJason King 	{ 'n', "(__int128){0}" },
28134226f635SJason King 	{ 'o', "(unsigned __int128){0}" },
28144226f635SJason King 	{ 's', "(short){0}" },
28154226f635SJason King 	{ 't', "(unsigned short){0}" },
28164226f635SJason King 	{ 'w', "(wchar_t){0}" },
28174226f635SJason King 	{ 'x', "{0}ll" },
28184226f635SJason King 	{ 'y', "{0}ull" }
28194226f635SJason King };
28204226f635SJason King 
28214226f635SJason King static const char *
parse_expr_primary(const char * first,const char * last,cpp_db_t * db)28224226f635SJason King parse_expr_primary(const char *first, const char *last, cpp_db_t *db)
28234226f635SJason King {
28244226f635SJason King 	VERIFY3P(first, <=, last);
28254226f635SJason King 
28264226f635SJason King 	if (last - first < 4 || first[0] != 'L')
28274226f635SJason King 		return (first);
28284226f635SJason King 
28294226f635SJason King 	const char *t = NULL;
28304226f635SJason King 
28314226f635SJason King 	for (size_t i = 0; i < ARRAY_SIZE(int_lits); i++) {
28324226f635SJason King 		if (first[1] == int_lits[i].c) {
28334226f635SJason King 			t = parse_integer_literal(first + 2, last,
28344226f635SJason King 			    int_lits[i].fmt, db);
28354226f635SJason King 			return ((t == first + 2) ? first : t);
28364226f635SJason King 		}
28374226f635SJason King 	}
28384226f635SJason King 
28394226f635SJason King 	switch (first[1]) {
28404226f635SJason King 	case 'b':
28414226f635SJason King 		if (first[3] != 'E')
28424226f635SJason King 			return (first);
28434226f635SJason King 
28444226f635SJason King 		switch (first[2]) {
28454226f635SJason King 		case '0':
28464226f635SJason King 			nadd_l(db, "false", 5);
28474226f635SJason King 			break;
28484226f635SJason King 		case '1':
28494226f635SJason King 			nadd_l(db, "true", 4);
28504226f635SJason King 			break;
28514226f635SJason King 		default:
28524226f635SJason King 			return (first);
28534226f635SJason King 		}
28544226f635SJason King 		return (first + 4);
28554226f635SJason King 	case 'd':	/* double */
28564226f635SJason King 	case 'e':	/* long double */
28574226f635SJason King 	case 'f':	/* float */
28584226f635SJason King 		t = parse_floating_literal(first + 1, last, db);
28594226f635SJason King 		return ((t == first + 1) ? first : t);
28604226f635SJason King 	case 'T':
28614226f635SJason King /* BEGIN CSTYLED */
28624226f635SJason King 		/*
28634226f635SJason King 		 * Invalid mangled name per
28644226f635SJason King 		 *   http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
28654226f635SJason King 		 *
28664226f635SJason King 		 */
28674226f635SJason King /* END CSTYLED */
28684226f635SJason King 		return (first);
28694226f635SJason King 	case '_':
28704226f635SJason King 		if (first[2] != 'Z')
28714226f635SJason King 			return (first);
28724226f635SJason King 
28734226f635SJason King 		t = parse_encoding(first + 3, last, db);
28744226f635SJason King 		if (t == first + 3 || t == last || t[0] != 'E')
28754226f635SJason King 			return (first);
28764226f635SJason King 
28774226f635SJason King 		/* skip E */
28784226f635SJason King 		return (t + 1);
28794226f635SJason King 	default:
28804226f635SJason King 		t = parse_type(first + 1, last, db);
28814226f635SJason King 		if (t == first + 1 || t == last)
28824226f635SJason King 			return (first);
28834226f635SJason King 
28844226f635SJason King 		if (t[0] == 'E')
28854226f635SJason King 			return (t + 1);
28864226f635SJason King 
28874226f635SJason King 		const char *n;
2888*1cd08393SJason King 		for (n = t; n != last && ISDIGIT(n[0]); n++)
28894226f635SJason King 			;
28904226f635SJason King 		if (n == last || nempty(db) || n[0] != 'E')
28914226f635SJason King 			return (first);
28924226f635SJason King 		if (n == t)
28934226f635SJason King 			return (t);
28944226f635SJason King 
28954226f635SJason King 		nadd_l(db, t, (size_t)(n - t));
28964226f635SJason King 		nfmt(db, "({1}){0}", NULL);
28974226f635SJason King 
28984226f635SJason King 		return (n + 1);
28994226f635SJason King 	}
29004226f635SJason King }
29014226f635SJason King 
29024226f635SJason King /*
29034226f635SJason King  *   <operator-name>
29044226f635SJason King  *                   ::= aa    # &&
29054226f635SJason King  *                   ::= ad    # & (unary)
29064226f635SJason King  *                   ::= an    # &
29074226f635SJason King  *                   ::= aN    # &=
29084226f635SJason King  *                   ::= aS    # =
29094226f635SJason King  *                   ::= cl    # ()
29104226f635SJason King  *                   ::= cm    # ,
29114226f635SJason King  *                   ::= co    # ~
29124226f635SJason King  *                   ::= cv <type>    # (cast)
29134226f635SJason King  *                   ::= da    # delete[]
29144226f635SJason King  *                   ::= de    # * (unary)
29154226f635SJason King  *                   ::= dl    # delete
29164226f635SJason King  *                   ::= dv    # /
29174226f635SJason King  *                   ::= dV    # /=
29184226f635SJason King  *                   ::= eo    # ^
29194226f635SJason King  *                   ::= eO    # ^=
29204226f635SJason King  *                   ::= eq    # ==
29214226f635SJason King  *                   ::= ge    # >=
29224226f635SJason King  *                   ::= gt    # >
29234226f635SJason King  *                   ::= ix    # []
29244226f635SJason King  *                   ::= le    # <=
29254226f635SJason King  *                   ::= li <source-name>	# operator ""
29264226f635SJason King  *                   ::= ls    # <<
29274226f635SJason King  *                   ::= lS    # <<=
29284226f635SJason King  *                   ::= lt    # <
29294226f635SJason King  *                   ::= mi    # -
29304226f635SJason King  *                   ::= mI    # -=
29314226f635SJason King  *                   ::= ml    # *
29324226f635SJason King  *                   ::= mL    # *=
29334226f635SJason King  *                   ::= mm    # -- (postfix in <expression> context)
29344226f635SJason King  *                   ::= na    # new[]
29354226f635SJason King  *                   ::= ne    # !=
29364226f635SJason King  *                   ::= ng    # - (unary)
29374226f635SJason King  *                   ::= nt    # !
29384226f635SJason King  *                   ::= nw    # new
29394226f635SJason King  *                   ::= oo    # ||
29404226f635SJason King  *                   ::= or    # |
29414226f635SJason King  *                   ::= oR    # |=
29424226f635SJason King  *                   ::= pm    # ->*
29434226f635SJason King  *                   ::= pl    # +
29444226f635SJason King  *                   ::= pL    # +=
29454226f635SJason King  *                   ::= pp    # ++ (postfix in <expression> context)
29464226f635SJason King  *                   ::= ps    # + (unary)
29474226f635SJason King  *                   ::= pt    # ->
29484226f635SJason King  *                   ::= qu    # ?
29494226f635SJason King  *                   ::= rm    # %
29504226f635SJason King  *                   ::= rM    # %=
29514226f635SJason King  *                   ::= rs    # >>
29524226f635SJason King  *                   ::= rS    # >>=
29534226f635SJason King  *                   ::= v <digit> <source-name> # vendor extended operator
29544226f635SJason King  */
29554226f635SJason King static struct {
29564226f635SJason King 	const char code[3];
29574226f635SJason King 	const char *op;
29584226f635SJason King } op_tbl[] = {
29594226f635SJason King 	{ "aa", "operator&&" },
29604226f635SJason King 	{ "ad", "operator&" },
29614226f635SJason King 	{ "an", "operator&" },
29624226f635SJason King 	{ "aN", "operator&=" },
29634226f635SJason King 	{ "aS", "operator=" },
29644226f635SJason King 	{ "cl", "operator()" },
29654226f635SJason King 	{ "cm", "operator," },
29664226f635SJason King 	{ "co", "operator~" },
29674226f635SJason King 	{ "da", "operator delete[]" },
29684226f635SJason King 	{ "de", "operator*" },
29694226f635SJason King 	{ "dl", "operator delete" },
29704226f635SJason King 	{ "dv", "operator/" },
29714226f635SJason King 	{ "dV", "operator/=" },
29724226f635SJason King 	{ "eo", "operator^" },
29734226f635SJason King 	{ "eO", "operator^=" },
29744226f635SJason King 	{ "eq", "operator==" },
29754226f635SJason King 	{ "ge", "operator>=" },
29764226f635SJason King 	{ "gt", "operator>" },
29774226f635SJason King 	{ "ix", "operator[]" },
29784226f635SJason King 	{ "le", "operator<=" },
29794226f635SJason King 	{ "ls", "operator<<" },
29804226f635SJason King 	{ "lS", "operator<<=" },
29814226f635SJason King 	{ "lt", "operator<" },
29824226f635SJason King 	{ "mi", "operator-" },
29834226f635SJason King 	{ "mI", "operator-=" },
29844226f635SJason King 	{ "ml", "operator*" },
29854226f635SJason King 	{ "mL", "operator*=" },
29864226f635SJason King 	{ "mm", "operator--" },
29874226f635SJason King 	{ "na", "operator new[]" },
29884226f635SJason King 	{ "ne", "operator!=" },
29894226f635SJason King 	{ "ng", "operator-" },
29904226f635SJason King 	{ "nt", "operator!" },
29914226f635SJason King 	{ "nw", "operator new" },
29924226f635SJason King 	{ "oo", "operator||" },
29934226f635SJason King 	{ "or", "operator|" },
29944226f635SJason King 	{ "oR", "operator|=" },
29954226f635SJason King 	{ "pm", "operator->*" },
29964226f635SJason King 	{ "pl", "operator+" },
29974226f635SJason King 	{ "pL", "operator+=" },
29984226f635SJason King 	{ "pp", "operator++" },
29994226f635SJason King 	{ "ps", "operator+" },
30004226f635SJason King 	{ "pt", "operator->" },
30014226f635SJason King 	{ "qu", "operator?" },
30024226f635SJason King 	{ "rm", "operator%" },
30034226f635SJason King 	{ "rM", "operator%=" },
30044226f635SJason King 	{ "rs", "operator>>" },
30054226f635SJason King 	{ "rS", "operator>>=" }
30064226f635SJason King };
30074226f635SJason King 
30084226f635SJason King static const char *
parse_operator_name(const char * first,const char * last,cpp_db_t * db)30094226f635SJason King parse_operator_name(const char *first, const char *last, cpp_db_t *db)
30104226f635SJason King {
30114226f635SJason King 	VERIFY3P(first, <=, last);
30124226f635SJason King 
30134226f635SJason King 	if (last - first < 2)
30144226f635SJason King 		return (first);
30154226f635SJason King 
30164226f635SJason King 	for (size_t i = 0; i < ARRAY_SIZE(op_tbl); i++) {
30174226f635SJason King 		if (strncmp(first, op_tbl[i].code, 2) != 0)
30184226f635SJason King 			continue;
30194226f635SJason King 
30204226f635SJason King 		nadd_l(db, op_tbl[i].op, 0);
30214226f635SJason King 		return (first + 2);
30224226f635SJason King 	}
30234226f635SJason King 
30244226f635SJason King 	const char *t = NULL;
30254226f635SJason King 
30264226f635SJason King 	if (first[0] == 'l' && first[1] == 'i') {
30274226f635SJason King 		t = parse_source_name(first + 2, last, db);
30284226f635SJason King 		if (t == first + 2 || nempty(db))
30294226f635SJason King 			return (first);
30304226f635SJason King 
30314226f635SJason King 		nfmt(db, "operator\"\" {0}", NULL);
30324226f635SJason King 		return (t);
30334226f635SJason King 	}
30344226f635SJason King 
30354226f635SJason King 	if (first[0] == 'v') {
3036*1cd08393SJason King 		if (!ISDIGIT(first[1]))
30374226f635SJason King 			return (first);
30384226f635SJason King 
30394226f635SJason King 		t = parse_source_name(first + 2, last, db);
30404226f635SJason King 		if (t == first + 2)
30414226f635SJason King 			return (first);
30424226f635SJason King 
30434226f635SJason King 		nfmt(db, "operator {0}", NULL);
30444226f635SJason King 		return (t);
30454226f635SJason King 	}
30464226f635SJason King 
30474226f635SJason King 	if (first[0] != 'c' && first[1] != 'v')
30484226f635SJason King 		return (first);
30494226f635SJason King 
30504226f635SJason King 	boolean_t try_to_parse_template_args =
30514226f635SJason King 	    db->cpp_try_to_parse_template_args;
30524226f635SJason King 
30534226f635SJason King 	db->cpp_try_to_parse_template_args = B_FALSE;
30544226f635SJason King 	t = parse_type(first + 2, last, db);
30554226f635SJason King 	db->cpp_try_to_parse_template_args = try_to_parse_template_args;
30564226f635SJason King 
30574226f635SJason King 	if (t == first + 2 || nempty(db))
30584226f635SJason King 		return (first);
30594226f635SJason King 
30604226f635SJason King 	nfmt(db, "operator {0}", NULL);
30614226f635SJason King 	db->cpp_parsed_ctor_dtor_cv = B_TRUE;
30624226f635SJason King 	return (t);
30634226f635SJason King }
30644226f635SJason King 
30654226f635SJason King struct type_tbl_s {
30664226f635SJason King 	int code;
30674226f635SJason King 	const char *name;
30684226f635SJason King };
30694226f635SJason King 
30704226f635SJason King static struct type_tbl_s type_tbl1[] = {
30714226f635SJason King 	{ 'a', "signed char" },
30724226f635SJason King 	{ 'b', "bool" },
30734226f635SJason King 	{ 'c', "char" },
30744226f635SJason King 	{ 'd', "double" },
30754226f635SJason King 	{ 'e', "long double" },
30764226f635SJason King 	{ 'f', "float" },
30774226f635SJason King 	{ 'g', "__float128" },
30784226f635SJason King 	{ 'h', "unsigned char" },
30794226f635SJason King 	{ 'i', "int" },
30804226f635SJason King 	{ 'j', "unsigned int" },
30814226f635SJason King 	{ 'l', "long" },
30824226f635SJason King 	{ 'm', "unsigned long" },
30834226f635SJason King 	{ 'n', "__int128" },
30844226f635SJason King 	{ 'o', "unsigned __int128" },
30854226f635SJason King 	{ 's', "short" },
30864226f635SJason King 	{ 't', "unsigned short" },
30874226f635SJason King 	{ 'v', "void" },
30884226f635SJason King 	{ 'w', "wchar_t" },
30894226f635SJason King 	{ 'x', "long long" },
30904226f635SJason King 	{ 'y', "unsigned long long" },
30914226f635SJason King 	{ 'z', "..." }
30924226f635SJason King };
30934226f635SJason King 
30944226f635SJason King static struct type_tbl_s type_tbl2[] = {
30954226f635SJason King 	{ 'a', "auto" },
30964226f635SJason King 	{ 'c', "decltype(auto)" },
30974226f635SJason King 	{ 'd', "decimal64" },
30984226f635SJason King 	{ 'e', "decimal128" },
30994226f635SJason King 	{ 'f', "decimal32" },
31004226f635SJason King 	{ 'h', "decimal16" },
31014226f635SJason King 	{ 'i', "char32_t" },
31024226f635SJason King 	{ 'n', "std::nullptr_t" },
31034226f635SJason King 	{ 's', "char16_t" }
31044226f635SJason King };
31054226f635SJason King 
31064226f635SJason King static const char *
parse_builtin_type(const char * first,const char * last,cpp_db_t * db)31074226f635SJason King parse_builtin_type(const char *first, const char *last, cpp_db_t *db)
31084226f635SJason King {
31094226f635SJason King 	VERIFY3P(first, <=, last);
31104226f635SJason King 
31114226f635SJason King 	if (first == last)
31124226f635SJason King 		return (first);
31134226f635SJason King 
31144226f635SJason King 	size_t i;
31154226f635SJason King 
31164226f635SJason King 	for (i = 0; i < ARRAY_SIZE(type_tbl1); i++) {
31174226f635SJason King 		if (first[0] == type_tbl1[i].code) {
31184226f635SJason King 			nadd_l(db, type_tbl1[i].name, 0);
31194226f635SJason King 			return (first + 1);
31204226f635SJason King 		}
31214226f635SJason King 	}
31224226f635SJason King 
31234226f635SJason King 	if (first[0] == 'D') {
31244226f635SJason King 		if (first + 1 == last)
31254226f635SJason King 			return (first);
31264226f635SJason King 		for (i = 0; i < ARRAY_SIZE(type_tbl2); i++) {
31274226f635SJason King 			if (first[1] == type_tbl2[i].code) {
31284226f635SJason King 				nadd_l(db, type_tbl2[i].name, 0);
31294226f635SJason King 				return (first + 2);
31304226f635SJason King 			}
31314226f635SJason King 		}
31324226f635SJason King 	}
31334226f635SJason King 
31344226f635SJason King 	if (first[0] == 'u') {
31354226f635SJason King 		const char *t = parse_source_name(first + 1, last, db);
31364226f635SJason King 		if (t == first + 1)
31374226f635SJason King 			return (first);
31384226f635SJason King 		return (t);
31394226f635SJason King 	}
31404226f635SJason King 
31414226f635SJason King 	return (first);
31424226f635SJason King }
31434226f635SJason King 
31444226f635SJason King static const char *
parse_base36(const char * first,const char * last,size_t * val)3145*1cd08393SJason King parse_base36(const char *first, const char *last, size_t *val)
31464226f635SJason King {
31474226f635SJason King 	VERIFY3P(first, <=, last);
31484226f635SJason King 
31494226f635SJason King 	const char *t;
31504226f635SJason King 
31514226f635SJason King 	for (t = first, *val = 0; t != last; t++) {
3152*1cd08393SJason King 		if (!ISDIGIT(t[0]) && !ISUPPER(t[0]))
31534226f635SJason King 			return (t);
31544226f635SJason King 
31554226f635SJason King 		*val *= 36;
31564226f635SJason King 
3157*1cd08393SJason King 		if (ISDIGIT(t[0]))
31584226f635SJason King 			*val += t[0] - '0';
31594226f635SJason King 		else
31604226f635SJason King 			*val += t[0] - 'A' + 10;
31614226f635SJason King 	}
31624226f635SJason King 	return (t);
31634226f635SJason King }
31644226f635SJason King 
31654226f635SJason King static struct type_tbl_s sub_tbl[] = {
31664226f635SJason King 	{ 'a', "std::allocator" },
31674226f635SJason King 	{ 'b', "std::basic_string" },
31684226f635SJason King 	{ 's', "std::string" },
31694226f635SJason King 	{ 'i', "std::istream" },
31704226f635SJason King 	{ 'o', "std::ostream" },
31714226f635SJason King 	{ 'd', "std::iostream" }
31724226f635SJason King };
31734226f635SJason King 
31744226f635SJason King static const char *
parse_substitution(const char * first,const char * last,cpp_db_t * db)31754226f635SJason King parse_substitution(const char *first, const char *last, cpp_db_t *db)
31764226f635SJason King {
31774226f635SJason King 	VERIFY3P(first, <=, last);
31784226f635SJason King 
31794226f635SJason King 	if (first == last || last - first < 2)
31804226f635SJason King 		return (first);
31814226f635SJason King 
31824226f635SJason King 	if (first[0] != 'S')
31834226f635SJason King 		return (first);
31844226f635SJason King 
31854226f635SJason King 	for (size_t i = 0; i < ARRAY_SIZE(sub_tbl); i++) {
31864226f635SJason King 		if (first[1] == sub_tbl[i].code) {
31874226f635SJason King 			nadd_l(db, sub_tbl[i].name, 0);
31884226f635SJason King 			return (first + 2);
31894226f635SJason King 		}
31904226f635SJason King 	}
31914226f635SJason King 
31924226f635SJason King 	const char *t = first + 1;
31934226f635SJason King 	size_t n = 0;
31944226f635SJason King 
31954226f635SJason King 	if (t[0] != '_') {
3196*1cd08393SJason King 		t = parse_base36(first + 1, last, &n);
31974226f635SJason King 		if (t == first + 1 || t[0] != '_')
31984226f635SJason King 			return (first);
31994226f635SJason King 
32004226f635SJason King 		/*
32014226f635SJason King 		 * S_ == substitution 0,
32024226f635SJason King 		 * S0_ == substituion 1,
32034226f635SJason King 		 * ...
32044226f635SJason King 		 */
32054226f635SJason King 		n++;
32064226f635SJason King 	}
32074226f635SJason King 
32084226f635SJason King 	if (n >= sub_len(&db->cpp_subs))
32094226f635SJason King 		return (first);
32104226f635SJason King 
32114226f635SJason King 	sub(db, n);
32124226f635SJason King 
32134226f635SJason King 	/* skip _ */
32144226f635SJason King 	VERIFY3U(t[0], ==, '_');
32154226f635SJason King 
32164226f635SJason King 	return (t + 1);
32174226f635SJason King }
32184226f635SJason King 
32194226f635SJason King static const char *
parse_source_name(const char * first,const char * last,cpp_db_t * db)32204226f635SJason King parse_source_name(const char *first, const char *last, cpp_db_t *db)
32214226f635SJason King {
32224226f635SJason King 	VERIFY3P(first, <=, last);
32234226f635SJason King 
32244226f635SJason King 	if (first == last)
32254226f635SJason King 		return (first);
32264226f635SJason King 
32274226f635SJason King 	const char *t = NULL;
32284226f635SJason King 	size_t n = 0;
32294226f635SJason King 
3230*1cd08393SJason King 	for (t = first; t != last && ISDIGIT(t[0]); t++) {
32314226f635SJason King 		/* make sure we don't overflow */
32324226f635SJason King 		size_t nn = n * 10;
32334226f635SJason King 		if (nn < n)
32344226f635SJason King 			return (first);
32354226f635SJason King 
32364226f635SJason King 		nn += t[0] - '0';
32374226f635SJason King 		if (nn < n)
32384226f635SJason King 			return (first);
32394226f635SJason King 
32404226f635SJason King 		n = nn;
32414226f635SJason King 	}
32424226f635SJason King 
32434226f635SJason King 	if (n == 0 || t == last || t + n > last ||
32444226f635SJason King 	    (uintptr_t)t + n < (uintptr_t)t)
32454226f635SJason King 		return (first);
32464226f635SJason King 
32474226f635SJason King 	if (strncmp(t, "_GLOBAL__N", 10) == 0)
32484226f635SJason King 		nadd_l(db, "(anonymous namespace)", 0);
32494226f635SJason King 	else
32504226f635SJason King 		nadd_l(db, t, n);
32514226f635SJason King 
32524226f635SJason King 	return (t + n);
32534226f635SJason King }
32544226f635SJason King 
32554226f635SJason King /*
32564226f635SJason King  * extension:
32574226f635SJason King  * <vector-type>           ::= Dv <positive dimension number> _
32584226f635SJason King  *                                    <extended element type>
32594226f635SJason King  *                         ::= Dv [<dimension expression>] _ <element type>
32604226f635SJason King  * <extended element type> ::= <element type>
32614226f635SJason King  *                         ::= p # AltiVec vector pixel
32624226f635SJason King  */
32634226f635SJason King static const char *
parse_vector_type(const char * first,const char * last,cpp_db_t * db)32644226f635SJason King parse_vector_type(const char *first, const char *last, cpp_db_t *db)
32654226f635SJason King {
32664226f635SJason King 	VERIFY3P(first, <=, last);
32674226f635SJason King 
32684226f635SJason King 	if (last - first < 3)
32694226f635SJason King 		return (first);
32704226f635SJason King 
32714226f635SJason King 	VERIFY3U(first[0], ==, 'D');
32724226f635SJason King 	VERIFY3U(first[1], ==, 'v');
32734226f635SJason King 
32744226f635SJason King 	const char *t = first + 2;
32754226f635SJason King 	const char *t1 = NULL;
32764226f635SJason King 
3277*1cd08393SJason King 	if (ISDIGIT(first[2]) && first[2] != '0') {
3278*1cd08393SJason King 		t1 = parse_number(t, last);
32794226f635SJason King 		if (t1 == last || t1 + 1 == last || t1[0] != '_')
32804226f635SJason King 			return (first);
32814226f635SJason King 
32824226f635SJason King 		nadd_l(db, t, (size_t)(t1 - t));
32834226f635SJason King 
32844226f635SJason King 		/* skip _ */
32854226f635SJason King 		t = t1 + 1;
32864226f635SJason King 
32874226f635SJason King 		if (t[0] != 'p') {
32884226f635SJason King 			t1 = parse_type(t, last, db);
32894226f635SJason King 			if (t1 == t)
32904226f635SJason King 				return (first);
32914226f635SJason King 
32924226f635SJason King 			nfmt(db, "{0} vector[{1}]", NULL);
32934226f635SJason King 			return (t1);
32944226f635SJason King 		}
32954226f635SJason King 		nfmt(db, "{0} pixel vector[{1}]", NULL);
32964226f635SJason King 		return (t1);
32974226f635SJason King 	}
32984226f635SJason King 
32994226f635SJason King 	if (first[2] != '_') {
33004226f635SJason King 		t1 = parse_expression(first + 2, last, db);
33014226f635SJason King 		if (first == last || t1 == first + 2 || t1[0] != '_')
33024226f635SJason King 			return (first);
33034226f635SJason King 
33044226f635SJason King 		/* skip _ */
33054226f635SJason King 		t = t1 + 1;
33064226f635SJason King 	} else {
33074226f635SJason King 		nadd_l(db, "", 0);
33084226f635SJason King 	}
33094226f635SJason King 
33104226f635SJason King 	t1 = parse_type(t, last, db);
33114226f635SJason King 	if (t == t1)
33124226f635SJason King 		return (first);
33134226f635SJason King 
33144226f635SJason King 	nfmt(db, "{1:L} vector[{0}]", "{1:R}");
33154226f635SJason King 	return (t1);
33164226f635SJason King }
33174226f635SJason King 
33184226f635SJason King /* BEGIN CSTYLED */
33194226f635SJason King /*
33204226f635SJason King  * <decltype>  ::= Dt <expression> E  # decltype of an id-expression or class member access (C++0x)
33214226f635SJason King  *             ::= DT <expression> E  # decltype of an expression (C++0x)
33224226f635SJason King  */
33234226f635SJason King /* END CSTYLED */
33244226f635SJason King static const char *
parse_decltype(const char * first,const char * last,cpp_db_t * db)33254226f635SJason King parse_decltype(const char *first, const char *last, cpp_db_t *db)
33264226f635SJason King {
33274226f635SJason King 	VERIFY3P(first, <=, last);
33284226f635SJason King 
33294226f635SJason King 	if (last - first < 4)
33304226f635SJason King 		return (first);
33314226f635SJason King 
33324226f635SJason King 	VERIFY3U(first[0], ==, 'D');
33334226f635SJason King 
33344226f635SJason King 	if (first[1] != 't' && first[1] != 'T')
33354226f635SJason King 		return (first);
33364226f635SJason King 
33374226f635SJason King 	size_t n = nlen(db);
33384226f635SJason King 	const char *t = parse_expression(first + 2, last, db);
33394226f635SJason King 	if (NAMT(db, n) != 1 || t == first + 2 || t == last || t[0] != 'E')
33404226f635SJason King 		return (first);
33414226f635SJason King 
33424226f635SJason King 	nfmt(db, "decltype({0})", NULL);
33434226f635SJason King 
33444226f635SJason King 	/* skip E */
33454226f635SJason King 	return (t + 1);
33464226f635SJason King }
33474226f635SJason King 
33484226f635SJason King /*
33494226f635SJason King  * <array-type> ::= A <positive dimension number> _ <element type>
33504226f635SJason King  *              ::= A [<dimension expression>] _ <element type>
33514226f635SJason King  */
33524226f635SJason King static const char *
parse_array_type(const char * first,const char * last,cpp_db_t * db)33534226f635SJason King parse_array_type(const char *first, const char *last, cpp_db_t *db)
33544226f635SJason King {
33554226f635SJason King 	VERIFY3P(first, <=, last);
33564226f635SJason King 	VERIFY3U(first[0], ==, 'A');
33574226f635SJason King 
33584226f635SJason King 	if (last - first < 3)
33594226f635SJason King 		return (first);
33604226f635SJason King 
33614226f635SJason King 	const char *t = first + 1;
33624226f635SJason King 	const char *t1 = NULL;
33634226f635SJason King 	size_t n = nlen(db);
33644226f635SJason King 
33654226f635SJason King 	if (t[0] != '_') {
3366*1cd08393SJason King 		if (ISDIGIT(t[0]) && t[0] != '0') {
3367*1cd08393SJason King 			t1 = parse_number(t, last);
33684226f635SJason King 			if (t1 == last)
33694226f635SJason King 				return (first);
33704226f635SJason King 
33714226f635SJason King 			nadd_l(db, t, (size_t)(t1 - t));
33724226f635SJason King 		} else {
33734226f635SJason King 			t1 = parse_expression(t, last, db);
33744226f635SJason King 			if (t1 == last || t == t1)
33754226f635SJason King 				return (first);
33764226f635SJason King 		}
33774226f635SJason King 
33784226f635SJason King 		if (t1[0] != '_')
33794226f635SJason King 			return (first);
33804226f635SJason King 
33814226f635SJason King 		t = t1;
33824226f635SJason King 	} else {
33834226f635SJason King 		nadd_l(db, "", 0);
33844226f635SJason King 	}
33854226f635SJason King 
33864226f635SJason King 	VERIFY3U(t[0], ==, '_');
33874226f635SJason King 
33884226f635SJason King 	t1 = parse_type(t + 1, last, db);
33894226f635SJason King 	if (t1 == t + 1 || NAMT(db, n) != 2)
33904226f635SJason King 		return (first);
33914226f635SJason King 
33924226f635SJason King 	/*
33934226f635SJason King 	 * if we have  " [xxx]" already, want new result to be
33944226f635SJason King 	 * " [yyy][xxx]"
33954226f635SJason King 	 */
33964226f635SJason King 	str_t *r = &name_top(&db->cpp_name)->strp_r;
33974226f635SJason King 	if (r->str_len > 1 && r->str_s[0] == ' ' && r->str_s[1] == '[')
33984226f635SJason King 		(void) str_erase(r, 0, 1);
33994226f635SJason King 
34004226f635SJason King 	nfmt(db, "{0:L}", " [{1}]{0:R}");
34014226f635SJason King 	return (t1);
34024226f635SJason King }
34034226f635SJason King 
34044226f635SJason King /* <pointer-to-member-type> ::= M <class type> <member type> */
34054226f635SJason King static const char *
parse_pointer_to_member_type(const char * first,const char * last,cpp_db_t * db)34064226f635SJason King parse_pointer_to_member_type(const char *first, const char *last, cpp_db_t *db)
34074226f635SJason King {
34084226f635SJason King 	VERIFY3P(first, <=, last);
34094226f635SJason King 
34104226f635SJason King 	if (last - first < 3)
34114226f635SJason King 		return (first);
34124226f635SJason King 
34134226f635SJason King 	VERIFY3U(first[0], ==, 'M');
34144226f635SJason King 
34154226f635SJason King 	const char *t1 = first + 1;
34164226f635SJason King 	const char *t2 = NULL;
34174226f635SJason King 	size_t n = nlen(db);
34184226f635SJason King 
34194226f635SJason King 	t2 = parse_type(t1, last, db);
34204226f635SJason King 	if (t1 == t2)
34214226f635SJason King 		return (first);
34224226f635SJason King 
34234226f635SJason King 	t1 = t2;
34244226f635SJason King 	t2 = parse_type(t1, last, db);
34254226f635SJason King 	if (t1 == t2)
34264226f635SJason King 		return (first);
34274226f635SJason King 
34284226f635SJason King 	if (NAMT(db, n) != 2)
34294226f635SJason King 		return (first);
34304226f635SJason King 
34314226f635SJason King 	str_pair_t *func = name_top(&db->cpp_name);
34324226f635SJason King 
34334226f635SJason King 	if (str_length(&func->strp_r) > 0 && func->strp_r.str_s[0] == '(')
34344226f635SJason King 		nfmt(db, "{0:L}({1}::*", "){0:R}");
34354226f635SJason King 	else
34364226f635SJason King 		nfmt(db, "{0:L} {1}::*", "{0:R}");
34374226f635SJason King 
34384226f635SJason King 	return (t2);
34394226f635SJason King }
34404226f635SJason King 
34414226f635SJason King /* BEGIN CSTYLED */
34424226f635SJason King /*
34434226f635SJason King  * <unresolved-name>
34444226f635SJason King  *  extension        ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
34454226f635SJason King  *                   ::= [gs] <base-unresolved-name>                     # x or (with "gs") ::x
34464226f635SJason King  *                   ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
34474226f635SJason King  *                                                                       # A::x, N::y, A<T>::z; "gs" means leading "::"
34484226f635SJason King  *                   ::= sr <unresolved-type> <base-unresolved-name>     # T::x / decltype(p)::x
34494226f635SJason King  *  extension        ::= sr <unresolved-type> <template-args> <base-unresolved-name>
34504226f635SJason King  *                                                                       # T::N::x /decltype(p)::N::x
34514226f635SJason King  *  (ignored)        ::= srN <unresolved-type>  <unresolved-qualifier-level>+ E <base-unresolved-name>
34524226f635SJason King  */
34534226f635SJason King /* END CSTYLED */
34544226f635SJason King static const char *
parse_unresolved_name(const char * first,const char * last,cpp_db_t * db)34554226f635SJason King parse_unresolved_name(const char *first, const char *last, cpp_db_t *db)
34564226f635SJason King {
34574226f635SJason King 	VERIFY3P(first, <=, last);
34584226f635SJason King 
34594226f635SJason King 	if (last - first < 2)
34604226f635SJason King 		return (first);
34614226f635SJason King 
34624226f635SJason King 	const char *t = first;
34634226f635SJason King 	const char *t2 = NULL;
34644226f635SJason King 	boolean_t global = B_FALSE;
34654226f635SJason King 	size_t n;
34664226f635SJason King 
34674226f635SJason King 	if (t[0] == 'g' && t[1] == 's') {
34684226f635SJason King 		global = B_TRUE;
34694226f635SJason King 		t += 2;
34704226f635SJason King 	}
34714226f635SJason King 	if (t == last)
34724226f635SJason King 		return (first);
34734226f635SJason King 
34744226f635SJason King 	t2 = parse_base_unresolved_name(t, last, db);
34754226f635SJason King 	if (t != t2) {
34764226f635SJason King 		if (global) {
34774226f635SJason King 			if (nempty(db))
34784226f635SJason King 				return (first);
34794226f635SJason King 
34804226f635SJason King 			(void) str_insert(TOP_L(db), 0, "::", 2);
34814226f635SJason King 		}
34824226f635SJason King 		return (t2);
34834226f635SJason King 	}
34844226f635SJason King 
34854226f635SJason King 	if (t[0] != 's' || t[1] != 'r' || last - t < 2)
34864226f635SJason King 		return (first);
34874226f635SJason King 
34884226f635SJason King 	n = nlen(db);
34894226f635SJason King 	if (t[2] == 'N') {
34904226f635SJason King 		t += 3;
34914226f635SJason King 		t2 = parse_unresolved_type(t, last, db);
34924226f635SJason King 		if (t2 == t || t2 == last)
34934226f635SJason King 			return (first);
34944226f635SJason King 		t = t2;
34954226f635SJason King 
34964226f635SJason King 		t2 = parse_template_args(t, last, db);
34974226f635SJason King 		if (t2 != t) {
34984226f635SJason King 			if (NAMT(db, n) < 2 || t2 == last)
34994226f635SJason King 				return (first);
35004226f635SJason King 
35014226f635SJason King 			nfmt(db, "{1:L}{0}", "{1:R}");
35024226f635SJason King 			t = t2;
35034226f635SJason King 		}
35044226f635SJason King 
35054226f635SJason King 		VERIFY3U(NAMT(db, n), ==, 1);
35064226f635SJason King 
35074226f635SJason King 		while (t[0] != 'E') {
35084226f635SJason King 			size_t nn = nlen(db);
35094226f635SJason King 			t2 = parse_unresolved_qualifier_level(t, last, db);
35104226f635SJason King 			if (t == t2 || t == last || NAMT(db, nn) != 1)
35114226f635SJason King 				return (first);
35124226f635SJason King 
35134226f635SJason King 			t = t2;
35144226f635SJason King 		}
35154226f635SJason King 
35164226f635SJason King 		/* skip E */
35174226f635SJason King 		t++;
35184226f635SJason King 
35194226f635SJason King 		t2 = parse_base_unresolved_name(t, last, db);
35204226f635SJason King 		if (t == t2 || NAMT(db, n) < 2)
35214226f635SJason King 			return (first);
35224226f635SJason King 
35234226f635SJason King 		njoin(db, NAMT(db, n), "::");
35244226f635SJason King 		return (t2);
35254226f635SJason King 	}
35264226f635SJason King 
35274226f635SJason King 	t += 2;
35284226f635SJason King 
35294226f635SJason King 	t2 = parse_unresolved_type(t, last, db);
35304226f635SJason King 	if (t != t2) {
35314226f635SJason King 		t = t2;
35324226f635SJason King 		t2 = parse_template_args(t, last, db);
35334226f635SJason King 		if (t2 != t)
35344226f635SJason King 			nfmt(db, "{1:L}{0}", "{1:R}");
35354226f635SJason King 		t = t2;
35364226f635SJason King 
35374226f635SJason King 		t2 = parse_base_unresolved_name(t, last, db);
35384226f635SJason King 		if (t == t2 || nlen(db) < 2)
35394226f635SJason King 			return (first);
35404226f635SJason King 
35414226f635SJason King 		nfmt(db, "{1:L}::{0}", "{1:R}");
35424226f635SJason King 		return (t2);
35434226f635SJason King 	}
35444226f635SJason King 
35454226f635SJason King 	t2 = parse_unresolved_qualifier_level(t, last, db);
35464226f635SJason King 	if (t2 == t || t2 == last)
35474226f635SJason King 		return (first);
35484226f635SJason King 
35494226f635SJason King 	t = t2;
35504226f635SJason King 	if (global && nlen(db) > 0)
35514226f635SJason King 		nfmt(db, "::{0:L}", "{0:R}");
35524226f635SJason King 
35534226f635SJason King 	while (t[0] != 'E') {
35544226f635SJason King 		t2 = parse_unresolved_qualifier_level(t, last, db);
35554226f635SJason King 		if (t == t2 || t == last || nlen(db) < 2)
35564226f635SJason King 			return (first);
35574226f635SJason King 
35584226f635SJason King 		t = t2;
35594226f635SJason King 	}
35604226f635SJason King 
35614226f635SJason King 	/* skip E */
35624226f635SJason King 	t++;
35634226f635SJason King 
35644226f635SJason King 	t2 = parse_base_unresolved_name(t, last, db);
35654226f635SJason King 	if (t == t2 || nlen(db) < 2)
35664226f635SJason King 		return (first);
35674226f635SJason King 
35684226f635SJason King 	njoin(db, NAMT(db, n), "::");
35694226f635SJason King 	return (t2);
35704226f635SJason King }
35714226f635SJason King 
35724226f635SJason King /* <unresolved-qualifier-level> ::= <simple-id> */
35734226f635SJason King static const char *
parse_unresolved_qualifier_level(const char * first,const char * last,cpp_db_t * db)35744226f635SJason King parse_unresolved_qualifier_level(const char *first, const char *last,
35754226f635SJason King     cpp_db_t *db)
35764226f635SJason King {
35774226f635SJason King 	VERIFY3P(first, <=, last);
35784226f635SJason King 	return (parse_simple_id(first, last, db));
35794226f635SJason King }
35804226f635SJason King 
35814226f635SJason King /* BEGIN CSTYLED */
35824226f635SJason King /*
35834226f635SJason King  * <base-unresolved-name> ::= <simple-id>                                # unresolved name
35844226f635SJason King  *          extension     ::= <operator-name>                            # unresolved operator-function-id
35854226f635SJason King  *          extension     ::= <operator-name> <template-args>            # unresolved operator template-id
35864226f635SJason King  *                        ::= on <operator-name>                         # unresolved operator-function-id
35874226f635SJason King  *                        ::= on <operator-name> <template-args>         # unresolved operator template-id
35884226f635SJason King  *                        ::= dn <destructor-name>                       # destructor or pseudo-destructor;
35894226f635SJason King  *                                                                       # e.g. ~X or ~X<N-1>
35904226f635SJason King  */
35914226f635SJason King /* END CSTYLED */
35924226f635SJason King static const char *
parse_base_unresolved_name(const char * first,const char * last,cpp_db_t * db)35934226f635SJason King parse_base_unresolved_name(const char *first, const char *last, cpp_db_t *db)
35944226f635SJason King {
35954226f635SJason King 	VERIFY3P(first, <=, last);
35964226f635SJason King 
35974226f635SJason King 	if (last - first < 2)
35984226f635SJason King 		return (first);
35994226f635SJason King 
36004226f635SJason King 	const char *t = NULL;
36014226f635SJason King 	const char *t1 = NULL;
36024226f635SJason King 
36034226f635SJason King 	if ((first[0] != 'o' && first[0] != 'd') || first[1] != 'n') {
36044226f635SJason King 		t = parse_simple_id(first, last, db);
36054226f635SJason King 		if (t != first)
36064226f635SJason King 			return (t);
36074226f635SJason King 
36084226f635SJason King 		t = parse_operator_name(first, last, db);
36094226f635SJason King 		if (t == first)
36104226f635SJason King 			return (first);
36114226f635SJason King 
36124226f635SJason King 		t1 = parse_template_args(t, last, db);
36134226f635SJason King 		if (t1 != t) {
36144226f635SJason King 			if (nlen(db) < 2)
36154226f635SJason King 				return (first);
36164226f635SJason King 			nfmt(db, "{1:L}{0}", "{1:R}");
36174226f635SJason King 		}
36184226f635SJason King 
36194226f635SJason King 		return (t1);
36204226f635SJason King 	}
36214226f635SJason King 
36224226f635SJason King 	if (first[0] == 'd') {
36234226f635SJason King 		t = parse_destructor_name(first + 2, last, db);
36244226f635SJason King 		return ((t != first + 2) ? t : first);
36254226f635SJason King 	}
36264226f635SJason King 
36274226f635SJason King 	t = parse_operator_name(first + 2, last, db);
36284226f635SJason King 	if (t == first + 2)
36294226f635SJason King 		return (first);
36304226f635SJason King 
36314226f635SJason King 	t1 = parse_template_args(t, last, db);
36324226f635SJason King 	if (t1 != t)
36334226f635SJason King 		nfmt(db, "{1:L}{0}", "{1:R}");
36344226f635SJason King 	return (t1);
36354226f635SJason King }
36364226f635SJason King 
36374226f635SJason King /*
36384226f635SJason King  * <destructor-name> ::= <unresolved-type>	# e.g., ~T or ~decltype(f())
36394226f635SJason King  *                   ::= <simple-id>		# e.g., ~A<2*N>
36404226f635SJason King  */
36414226f635SJason King static const char *
parse_destructor_name(const char * first,const char * last,cpp_db_t * db)36424226f635SJason King parse_destructor_name(const char *first, const char *last, cpp_db_t *db)
36434226f635SJason King {
36444226f635SJason King 	VERIFY3P(first, <=, last);
36454226f635SJason King 
36464226f635SJason King 	if (first == last)
36474226f635SJason King 		return (first);
36484226f635SJason King 
36494226f635SJason King 	const char *t = parse_unresolved_type(first, last, db);
36504226f635SJason King 
36514226f635SJason King 	if (t == first)
36524226f635SJason King 		t = parse_simple_id(first, last, db);
36534226f635SJason King 
36544226f635SJason King 	if (t == first)
36554226f635SJason King 		return (first);
36564226f635SJason King 
36574226f635SJason King 	nfmt(db, "~{0:L}", "{0:R}");
36584226f635SJason King 	return (t);
36594226f635SJason King }
36604226f635SJason King 
36614226f635SJason King /*
36624226f635SJason King  *  <ref-qualifier> ::= R                   # & ref-qualifier
36634226f635SJason King  *  <ref-qualifier> ::= O                   # && ref-qualifier
36644226f635SJason King  *
36654226f635SJason King  * <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
36664226f635SJason King  */
36674226f635SJason King static const char *
parse_function_type(const char * first,const char * last,cpp_db_t * db)36684226f635SJason King parse_function_type(const char *first, const char *last, cpp_db_t *db)
36694226f635SJason King {
36704226f635SJason King 	VERIFY3P(first, <=, last);
36714226f635SJason King 
36724226f635SJason King 	if (last - first < 2)
36734226f635SJason King 		return (first);
36744226f635SJason King 
36754226f635SJason King 	VERIFY3U(first[0], ==, 'F');
36764226f635SJason King 
36774226f635SJason King 	const char *t = first + 1;
36784226f635SJason King 
36794226f635SJason King 	/* extern "C" */
36804226f635SJason King 	if (t[0] == 'Y')
36814226f635SJason King 		t++;
36824226f635SJason King 
36834226f635SJason King 	const char *t1 = parse_type(t, last, db);
36844226f635SJason King 	if (t1 == t)
36854226f635SJason King 		return (first);
36864226f635SJason King 
36874226f635SJason King 	size_t n = nlen(db);
36884226f635SJason King 	int ref_qual = 0;
36894226f635SJason King 
36904226f635SJason King 	t = t1;
36914226f635SJason King 
36924226f635SJason King 	while (t != last && t[0] != 'E') {
36934226f635SJason King 		if (t[0] == 'v') {
36944226f635SJason King 			t++;
36954226f635SJason King 			continue;
36964226f635SJason King 		}
36974226f635SJason King 
36984226f635SJason King 		if (t[0] == 'R' && t + 1 != last && t[1] == 'E') {
36994226f635SJason King 			ref_qual = 1;
37004226f635SJason King 			t++;
37014226f635SJason King 			continue;
37024226f635SJason King 		}
37034226f635SJason King 
37044226f635SJason King 		if (t[0] == 'O' && t + 1 != last && t[1] == 'E') {
37054226f635SJason King 			ref_qual = 2;
37064226f635SJason King 			t++;
37074226f635SJason King 			continue;
37084226f635SJason King 		}
37094226f635SJason King 
37104226f635SJason King 
37114226f635SJason King 		t1 = parse_type(t, last, db);
37124226f635SJason King 		if (t1 == t || t == last)
37134226f635SJason King 			return (first);
37144226f635SJason King 
37154226f635SJason King 		t = t1;
37164226f635SJason King 	}
37174226f635SJason King 
37184226f635SJason King 	if (t == last)
37194226f635SJason King 		return (first);
37204226f635SJason King 
37214226f635SJason King 	njoin(db, NAMT(db, n), ", ");
37224226f635SJason King 	nfmt(db, "({0})", NULL);
37234226f635SJason King 
37244226f635SJason King 	switch (ref_qual) {
37254226f635SJason King 	case 1:
37264226f635SJason King 		nfmt(db, "{0} &", NULL);
37274226f635SJason King 		break;
37284226f635SJason King 	case 2:
37294226f635SJason King 		nfmt(db, "{0} &&", NULL);
37304226f635SJason King 		break;
37314226f635SJason King 	}
37324226f635SJason King 
37334226f635SJason King 	nfmt(db, "{1:L} ", "{0}{1:R}");
37344226f635SJason King 
37354226f635SJason King 	/* skip E */
37364226f635SJason King 	return (t + 1);
37374226f635SJason King }
37384226f635SJason King 
37394226f635SJason King /*
37404226f635SJason King  * <template-param> ::= T_    # first template parameter
37414226f635SJason King  *                  ::= T <parameter-2 non-negative number> _
37424226f635SJason King  */
37434226f635SJason King static const char *
parse_template_param(const char * first,const char * last,cpp_db_t * db)37444226f635SJason King parse_template_param(const char *first, const char *last, cpp_db_t *db)
37454226f635SJason King {
37464226f635SJason King 	VERIFY3P(first, <=, last);
37474226f635SJason King 
37484226f635SJason King 	if (last - first < 2 || first[0] != 'T')
37494226f635SJason King 		return (first);
37504226f635SJason King 
37514226f635SJason King 	const char *t = first + 1;
37524226f635SJason King 	size_t idx = 0;
37534226f635SJason King 
37544226f635SJason King 	while (t != last && t[0] != '_') {
3755*1cd08393SJason King 		if (!ISDIGIT(t[0]))
37564226f635SJason King 			return (first);
37574226f635SJason King 
37584226f635SJason King 		idx *= 10;
37594226f635SJason King 		idx += t[0] - '0';
37604226f635SJason King 		t++;
37614226f635SJason King 	}
37624226f635SJason King 
37634226f635SJason King 	if (t == last)
37644226f635SJason King 		return (first);
37654226f635SJason King 
37664226f635SJason King 	VERIFY3U(t[0], ==, '_');
37674226f635SJason King 
37684226f635SJason King 	/*
37694226f635SJason King 	 * T_ -> idx 0
37704226f635SJason King 	 * T0 -> idx 1
37714226f635SJason King 	 * T1 -> idx 2
37724226f635SJason King 	 * ...
37734226f635SJason King 	 */
37744226f635SJason King 	if (first[1] != '_')
37754226f635SJason King 		idx++;
37764226f635SJason King 
37774226f635SJason King 	/* skip _ */
37784226f635SJason King 	t++;
37794226f635SJason King 
37804226f635SJason King 	if (tempty(db))
37814226f635SJason King 		return (first);
37824226f635SJason King 
37834226f635SJason King 	if (idx >= ttlen(db)) {
37844226f635SJason King 		nadd_l(db, first, (size_t)(t - first));
37854226f635SJason King 		db->cpp_fix_forward_references = B_TRUE;
37864226f635SJason King 		return (t);
37874226f635SJason King 	}
37884226f635SJason King 
37894226f635SJason King 	tsub(db, idx);
37904226f635SJason King 	return (t);
37914226f635SJason King }
37924226f635SJason King 
37934226f635SJason King /*
37944226f635SJason King  * <template-args> ::= I <template-arg>* E
37954226f635SJason King  *     extension, the abi says <template-arg>+
37964226f635SJason King  */
37974226f635SJason King static const char *
parse_template_args(const char * first,const char * last,cpp_db_t * db)37984226f635SJason King parse_template_args(const char *first, const char *last, cpp_db_t *db)
37994226f635SJason King {
38004226f635SJason King 	VERIFY3P(first, <=, last);
38014226f635SJason King 
38024226f635SJason King 	if (last - first < 2 || first[0] != 'I')
38034226f635SJason King 		return (first);
38044226f635SJason King 
38054226f635SJason King 	if (db->cpp_tag_templates)
38064226f635SJason King 		sub_clear(templ_top(&db->cpp_templ));
38074226f635SJason King 
38084226f635SJason King 	const char *t = first + 1;
38094226f635SJason King 	size_t n = nlen(db);
38104226f635SJason King 
38114226f635SJason King 	while (t[0] != 'E') {
38124226f635SJason King 		if (db->cpp_tag_templates)
38134226f635SJason King 			tpush(db);
38144226f635SJason King 
38154226f635SJason King 		size_t n1 = nlen(db);
38164226f635SJason King 		const char *t1 = parse_template_arg(t, last, db);
38174226f635SJason King 
38184226f635SJason King 		if (db->cpp_tag_templates)
38194226f635SJason King 			tpop(db);
38204226f635SJason King 
38214226f635SJason King 		if (t1 == t || t == last)
38224226f635SJason King 			return (first);
38234226f635SJason King 
38244226f635SJason King 		if (db->cpp_tag_templates)
38254226f635SJason King 			tsave(db, NAMT(db, n1));
38264226f635SJason King 
38274226f635SJason King 		t = t1;
38284226f635SJason King 	}
38294226f635SJason King 
38304226f635SJason King 	/*
38314226f635SJason King 	 * ugly, but if the last thing pushed was an empty string,
38324226f635SJason King 	 * get rid of it so we dont get "<..., >"
38334226f635SJason King 	 */
38344226f635SJason King 	if (NAMT(db, n) > 1 &&
38354226f635SJason King 	    str_pair_len(name_top(&db->cpp_name)) == 0)
38364226f635SJason King 		name_pop(&db->cpp_name, NULL);
38374226f635SJason King 
38384226f635SJason King 	njoin(db, NAMT(db, n), ", ");
38394226f635SJason King 
38404226f635SJason King 	VERIFY3U(nlen(db), >, 0);
38414226f635SJason King 
38424226f635SJason King 	/* make sure we don't bitshift ourselves into oblivion */
38434226f635SJason King 	str_t *top = TOP_L(db);
38444226f635SJason King 	if (str_length(top) > 0 &&
38454226f635SJason King 	    top->str_s[top->str_len - 1] == '>')
38464226f635SJason King 		nfmt(db, "<{0} >", NULL);
38474226f635SJason King 	else
38484226f635SJason King 		nfmt(db, "<{0}>", NULL);
38494226f635SJason King 
38504226f635SJason King 	/* skip E */
38514226f635SJason King 	return (t + 1);
38524226f635SJason King }
38534226f635SJason King 
38544226f635SJason King /*
38554226f635SJason King  * <discriminator> := _ <non-negative number>      # when number < 10
38564226f635SJason King  *                 := __ <non-negative number> _   # when number >= 10
38574226f635SJason King  *  extension      := decimal-digit+               # at the end of string
38584226f635SJason King  */
38594226f635SJason King static const char *
parse_discriminator(const char * first,const char * last)3860*1cd08393SJason King parse_discriminator(const char *first, const char *last)
38614226f635SJason King {
38624226f635SJason King 	VERIFY3P(first, <=, last);
38634226f635SJason King 
38644226f635SJason King 	const char *t = NULL;
38654226f635SJason King 
38664226f635SJason King 	if (first == last)
38674226f635SJason King 		return (first);
38684226f635SJason King 
3869*1cd08393SJason King 	if (ISDIGIT(first[0])) {
3870*1cd08393SJason King 		for (t = first; t != last && ISDIGIT(t[0]); t++)
38714226f635SJason King 			;
38724226f635SJason King 
38734226f635SJason King 		/* not at the end of the string */
38744226f635SJason King 		if (t != last)
38754226f635SJason King 			return (first);
38764226f635SJason King 
38774226f635SJason King 		return (t);
38784226f635SJason King 	} else if (first[0] != '_' || first + 1 == last) {
38794226f635SJason King 		return (first);
38804226f635SJason King 	}
38814226f635SJason King 
38824226f635SJason King 	t = first + 1;
3883*1cd08393SJason King 	if (ISDIGIT(t[0]))
38844226f635SJason King 		return (t + 1);
38854226f635SJason King 
38864226f635SJason King 	if (t[0] != '_' || t + 1 == last)
38874226f635SJason King 		return (first);
38884226f635SJason King 
3889*1cd08393SJason King 	for (t++; t != last && ISDIGIT(t[0]); t++)
38904226f635SJason King 		;
38914226f635SJason King 	if (t == last || t[0] != '_')
38924226f635SJason King 		return (first);
38934226f635SJason King 
38944226f635SJason King 	return (t);
38954226f635SJason King }
38964226f635SJason King 
38974226f635SJason King /* <CV-qualifiers> ::= [r] [V] [K] */
38984226f635SJason King const char *
parse_cv_qualifiers(const char * first,const char * last,unsigned * cv)38994226f635SJason King parse_cv_qualifiers(const char *first, const char *last, unsigned *cv)
39004226f635SJason King {
39014226f635SJason King 	VERIFY3P(first, <=, last);
39024226f635SJason King 
39034226f635SJason King 	if (first == last)
39044226f635SJason King 		return (first);
39054226f635SJason King 
39064226f635SJason King 	*cv = 0;
39074226f635SJason King 	if (first[0] == 'r') {
39084226f635SJason King 		*cv |= CPP_QUAL_RESTRICT;
39094226f635SJason King 		first++;
39104226f635SJason King 	}
39114226f635SJason King 	if (first != last && first[0] == 'V') {
39124226f635SJason King 		*cv |= CPP_QUAL_VOLATILE;
39134226f635SJason King 		first++;
39144226f635SJason King 	}
39154226f635SJason King 	if (first != last && first[0] == 'K') {
39164226f635SJason King 		*cv |= CPP_QUAL_CONST;
39174226f635SJason King 		first++;
39184226f635SJason King 	}
39194226f635SJason King 
39204226f635SJason King 	return (first);
39214226f635SJason King }
39224226f635SJason King 
39234226f635SJason King /*
39244226f635SJason King  * <number> ::= [n] <non-negative decimal integer>
39254226f635SJason King  */
39264226f635SJason King static const char *
parse_number(const char * first,const char * last)3927*1cd08393SJason King parse_number(const char *first, const char *last)
39284226f635SJason King {
39294226f635SJason King 	VERIFY3P(first, <=, last);
39304226f635SJason King 
39314226f635SJason King 	const char *t = first;
39324226f635SJason King 
3933*1cd08393SJason King 	if (first == last || (first[0] != 'n' && !ISDIGIT(first[0])))
39344226f635SJason King 		return (first);
39354226f635SJason King 
39364226f635SJason King 	if (t[0] == 'n')
39374226f635SJason King 		t++;
39384226f635SJason King 
39394226f635SJason King 	if (t[0] == '0')
39404226f635SJason King 		return (t + 1);
39414226f635SJason King 
3942*1cd08393SJason King 	while (ISDIGIT(t[0]))
39434226f635SJason King 		t++;
39444226f635SJason King 
39454226f635SJason King 	return (t);
39464226f635SJason King }
39474226f635SJason King 
39484226f635SJason King /*
39494226f635SJason King  * Like isxdigit(3C), except we can only accept lower case letters as
39504226f635SJason King  * that's only what is allowed when [de]mangling floating point constants into
39514226f635SJason King  * their hex representation.
39524226f635SJason King  */
39534226f635SJason King static inline boolean_t
is_xdigit(int c)39544226f635SJason King is_xdigit(int c)
39554226f635SJason King {
39564226f635SJason King 	if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))
39574226f635SJason King 		return (B_TRUE);
39584226f635SJason King 	return (B_FALSE);
39594226f635SJason King }
39604226f635SJason King 
39614226f635SJason King static boolean_t
nempty(cpp_db_t * db)39624226f635SJason King nempty(cpp_db_t *db)
39634226f635SJason King {
39644226f635SJason King 	return (name_empty(&db->cpp_name));
39654226f635SJason King }
39664226f635SJason King 
39674226f635SJason King static size_t
nlen(cpp_db_t * db)39684226f635SJason King nlen(cpp_db_t *db)
39694226f635SJason King {
39704226f635SJason King 	return (name_len(&db->cpp_name));
39714226f635SJason King }
39724226f635SJason King 
39734226f635SJason King static void
nadd_l(cpp_db_t * db,const char * s,size_t len)39744226f635SJason King nadd_l(cpp_db_t *db, const char *s, size_t len)
39754226f635SJason King {
39764226f635SJason King 	CK(name_add(&db->cpp_name, s, len, NULL, 0));
39774226f635SJason King }
39784226f635SJason King 
39794226f635SJason King static void
njoin(cpp_db_t * db,size_t amt,const char * sep)39804226f635SJason King njoin(cpp_db_t *db, size_t amt, const char *sep)
39814226f635SJason King {
39824226f635SJason King 	name_t *nm = &db->cpp_name;
39834226f635SJason King 
39844226f635SJason King 	CK(name_join(nm, amt, sep));
39854226f635SJason King }
39864226f635SJason King 
39874226f635SJason King static void
nfmt(cpp_db_t * db,const char * fmt_l,const char * fmt_r)39884226f635SJason King nfmt(cpp_db_t *db, const char *fmt_l, const char *fmt_r)
39894226f635SJason King {
39904226f635SJason King 	CK(name_fmt(&db->cpp_name, fmt_l, fmt_r));
39914226f635SJason King }
39924226f635SJason King 
39934226f635SJason King static void
save_top(cpp_db_t * db,size_t amt)39944226f635SJason King save_top(cpp_db_t *db, size_t amt)
39954226f635SJason King {
39964226f635SJason King 	CK(sub_save(&db->cpp_subs, &db->cpp_name, amt));
39974226f635SJason King }
39984226f635SJason King 
39994226f635SJason King static void
sub(cpp_db_t * db,size_t n)40004226f635SJason King sub(cpp_db_t *db, size_t n)
40014226f635SJason King {
40024226f635SJason King 	CK(sub_substitute(&db->cpp_subs, n, &db->cpp_name));
40034226f635SJason King }
40044226f635SJason King 
40054226f635SJason King static boolean_t
tempty(const cpp_db_t * db)40064226f635SJason King tempty(const cpp_db_t *db)
40074226f635SJason King {
40084226f635SJason King 	return (templ_empty(&db->cpp_templ) ? B_TRUE : B_FALSE);
40094226f635SJason King }
40104226f635SJason King 
40114226f635SJason King static size_t
ttlen(const cpp_db_t * db)40124226f635SJason King ttlen(const cpp_db_t *db)
40134226f635SJason King {
40144226f635SJason King 	return (templ_top_len(&db->cpp_templ));
40154226f635SJason King }
40164226f635SJason King 
40174226f635SJason King static void
tsub(cpp_db_t * db,size_t n)40184226f635SJason King tsub(cpp_db_t *db, size_t n)
40194226f635SJason King {
40204226f635SJason King 	CK(templ_sub(&db->cpp_templ, n, &db->cpp_name));
40214226f635SJason King }
40224226f635SJason King 
40234226f635SJason King static void
tpush(cpp_db_t * db)40244226f635SJason King tpush(cpp_db_t *db)
40254226f635SJason King {
40264226f635SJason King 	CK(templ_push(&db->cpp_templ));
40274226f635SJason King }
40284226f635SJason King 
40294226f635SJason King static void
tpop(cpp_db_t * db)40304226f635SJason King tpop(cpp_db_t *db)
40314226f635SJason King {
40324226f635SJason King 	templ_pop(&db->cpp_templ);
40334226f635SJason King }
40344226f635SJason King 
40354226f635SJason King static void
tsave(cpp_db_t * db,size_t amt)40364226f635SJason King tsave(cpp_db_t *db, size_t amt)
40374226f635SJason King {
40384226f635SJason King 	CK(templ_save(&db->cpp_name, amt, &db->cpp_templ));
40394226f635SJason King }
40404226f635SJason King 
4041*1cd08393SJason King static void
db_init(cpp_db_t * db,sysdem_ops_t * ops)40424226f635SJason King db_init(cpp_db_t *db, sysdem_ops_t *ops)
40434226f635SJason King {
40444226f635SJason King 	(void) memset(db, 0, sizeof (*db));
40454226f635SJason King 	db->cpp_ops = ops;
40464226f635SJason King 	name_init(&db->cpp_name, ops);
40474226f635SJason King 	sub_init(&db->cpp_subs, ops);
40484226f635SJason King 	templ_init(&db->cpp_templ, ops);
40494226f635SJason King 	db->cpp_tag_templates = B_TRUE;
40504226f635SJason King 	db->cpp_try_to_parse_template_args = B_TRUE;
40514226f635SJason King 	tpush(db);
40524226f635SJason King }
40534226f635SJason King 
40544226f635SJason King static void
db_fini(cpp_db_t * db)40554226f635SJason King db_fini(cpp_db_t *db)
40564226f635SJason King {
40574226f635SJason King 	name_fini(&db->cpp_name);
40584226f635SJason King 	sub_fini(&db->cpp_subs);
40594226f635SJason King 	templ_fini(&db->cpp_templ);
40604226f635SJason King 	(void) memset(db, 0, sizeof (*db));
40614226f635SJason King }
40624226f635SJason King 
40634226f635SJason King static void
print_sp(const str_pair_t * sp,FILE * out)40644226f635SJason King print_sp(const str_pair_t *sp, FILE *out)
40654226f635SJason King {
40664226f635SJason King 	(void) fprintf(out, "{%.*s#%.*s}",
40674226f635SJason King 	    (int)sp->strp_l.str_len, sp->strp_l.str_s,
40684226f635SJason King 	    (int)sp->strp_r.str_len, sp->strp_r.str_s);
40694226f635SJason King }
40704226f635SJason King 
40714226f635SJason King static void
print_name(const name_t * n,FILE * out)40724226f635SJason King print_name(const name_t *n, FILE *out)
40734226f635SJason King {
40746bb387f3SJason King 	const str_pair_t *sp;
40754226f635SJason King 	size_t i;
40764226f635SJason King 
40774226f635SJason King 	(void) fprintf(out, "Name:\n");
40784226f635SJason King 
40794226f635SJason King 	if (name_len(n) == 0)
40804226f635SJason King 		return;
40814226f635SJason King 
40826bb387f3SJason King 	sp = name_top((name_t *)n);
40836bb387f3SJason King 
40844226f635SJason King 	for (i = 0; i < n->nm_len; i++, sp--) {
40854226f635SJason King 		(void) fprintf(out, "  [%02zu] ", i);
40864226f635SJason King 		print_sp(sp, out);
40874226f635SJason King 		(void) fputc('\n', out);
40884226f635SJason King 	}
40894226f635SJason King 
40904226f635SJason King 	(void) fputc('\n', out);
40914226f635SJason King }
40924226f635SJason King 
40934226f635SJason King /* Print a base-36 number (for substitutions) */
40944226f635SJason King static char *
base36(char * buf,size_t val)40954226f635SJason King base36(char *buf, size_t val)
40964226f635SJason King {
40974226f635SJason King 	char tmp[16] = { 0 };
40984226f635SJason King 	char *p = tmp;
40994226f635SJason King 
41004226f635SJason King 	if (val == 0) {
41014226f635SJason King 		buf[0] = '0';
41024226f635SJason King 		buf[1] = '\0';
41034226f635SJason King 		return (buf);
41044226f635SJason King 	}
41054226f635SJason King 
41064226f635SJason King 	while (val > 0) {
41074226f635SJason King 		size_t r = val % 36;
41084226f635SJason King 
41094226f635SJason King 		if (r < 10)
41104226f635SJason King 			*p++ = r + '0';
41114226f635SJason King 		else
41124226f635SJason King 			*p++ = r - 10 + 'A';
41134226f635SJason King 
41144226f635SJason King 		val /= 36;
41154226f635SJason King 	}
41164226f635SJason King 
41174226f635SJason King 	char *q = buf;
41184226f635SJason King 	while (--p >= tmp)
41194226f635SJason King 		*q++ = *p;
41204226f635SJason King 
41214226f635SJason King 	return (buf);
41224226f635SJason King }
41234226f635SJason King 
41244226f635SJason King static void
print_sub(const sub_t * sub,FILE * out)41254226f635SJason King print_sub(const sub_t *sub, FILE *out)
41264226f635SJason King {
41274226f635SJason King 	const name_t *n = sub->sub_items;
41284226f635SJason King 
41294226f635SJason King 	(void) fprintf(out, "Substitutions:\n");
41304226f635SJason King 
41314226f635SJason King 	if (sub->sub_len == 0)
41324226f635SJason King 		return;
41334226f635SJason King 
41344226f635SJason King 	for (size_t i = 0; i < sub->sub_len; i++, n++) {
41354226f635SJason King 		(void) printf("  ");
41364226f635SJason King 		if (i == 0) {
41374226f635SJason King 			(void) fprintf(out, "%-4s", "S_");
41384226f635SJason King 		} else {
41394226f635SJason King 			char buf[16] = { 0 };
41404226f635SJason King 			char buf2[16] = { 0 };
41414226f635SJason King 
41424226f635SJason King 			(void) snprintf(buf, sizeof (buf), "S%s_",
41434226f635SJason King 			    base36(buf2, i));
41444226f635SJason King 			(void) fprintf(out, "%-4s", buf);
41454226f635SJason King 		}
41464226f635SJason King 		(void) fprintf(out, " = ");
41474226f635SJason King 
41484226f635SJason King 		(void) fputc('{', out);
41494226f635SJason King 		for (size_t j = 0; j < n->nm_len; j++) {
41504226f635SJason King 			if (j > 0)
41514226f635SJason King 				(void) fputc(' ', out);
41524226f635SJason King 			print_sp(&n->nm_items[j], out);
41534226f635SJason King 		}
41544226f635SJason King 		(void) fputc('}', out);
41554226f635SJason King 
41564226f635SJason King 		(void) fputc('\n', out);
41574226f635SJason King 	}
41584226f635SJason King 	(void) fputc('\n', out);
41594226f635SJason King }
41604226f635SJason King 
41614226f635SJason King static void
print_templ(const templ_t * tpl,FILE * out)41624226f635SJason King print_templ(const templ_t *tpl, FILE *out)
41634226f635SJason King {
41644226f635SJason King 
41654226f635SJason King 	(void) fprintf(out, "Template\n");
41664226f635SJason King 
41674226f635SJason King 	const sub_t *s = templ_top((templ_t *)tpl);
41684226f635SJason King 
41694226f635SJason King 	for (size_t i = 0; i < s->sub_len; i++) {
41704226f635SJason King 		char buf[16] = { 0 };
41714226f635SJason King 
41724226f635SJason King 		if (i == 0)
41734226f635SJason King 			(void) snprintf(buf, sizeof (buf), "%s", "T_");
41744226f635SJason King 		else
41754226f635SJason King 			(void) snprintf(buf, sizeof (buf), "T%zu_", i - 1);
41764226f635SJason King 
41774226f635SJason King 		(void) fprintf(out, "  %-4s = ", buf);
41784226f635SJason King 
41794226f635SJason King 		(void) fputc('{', out);
41804226f635SJason King 
41814226f635SJason King 		const name_t *n = &s->sub_items[i];
41824226f635SJason King 		for (size_t j = 0; j < n->nm_len; j++) {
41834226f635SJason King 			const str_pair_t *sp = &n->nm_items[j];
41844226f635SJason King 
41854226f635SJason King 			if (j > 0)
41864226f635SJason King 				(void) fputc(' ', out);
41874226f635SJason King 
41884226f635SJason King 			(void) fprintf(out, "{%.*s#%.*s}",
41894226f635SJason King 			    (int)sp->strp_l.str_len, sp->strp_l.str_s,
41904226f635SJason King 			    (int)sp->strp_r.str_len, sp->strp_r.str_s);
41914226f635SJason King 		}
41924226f635SJason King 		(void) fprintf(out, "}\n");
41934226f635SJason King 	}
41944226f635SJason King 	(void) fprintf(out, "\n");
41954226f635SJason King }
41964226f635SJason King 
41974226f635SJason King static void
dump(cpp_db_t * db,FILE * out)41984226f635SJason King dump(cpp_db_t *db, FILE *out)
41994226f635SJason King {
42004226f635SJason King 	print_name(&db->cpp_name, out);
42014226f635SJason King 	print_sub(&db->cpp_subs, out);
42024226f635SJason King 	print_templ(&db->cpp_templ, out);
42034226f635SJason King }
4204