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