dt_pragma.c revision 178566
1178479Sjb/* 2178479Sjb * CDDL HEADER START 3178479Sjb * 4178479Sjb * The contents of this file are subject to the terms of the 5178479Sjb * Common Development and Distribution License (the "License"). 6178479Sjb * You may not use this file except in compliance with the License. 7178479Sjb * 8178479Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9178479Sjb * or http://www.opensolaris.org/os/licensing. 10178479Sjb * See the License for the specific language governing permissions 11178479Sjb * and limitations under the License. 12178479Sjb * 13178479Sjb * When distributing Covered Code, include this CDDL HEADER in each 14178479Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15178479Sjb * If applicable, add the following below this CDDL HEADER, with the 16178479Sjb * fields enclosed by brackets "[]" replaced with your own identifying 17178479Sjb * information: Portions Copyright [yyyy] [name of copyright owner] 18178479Sjb * 19178479Sjb * CDDL HEADER END 20178479Sjb */ 21178566Sjb 22178479Sjb/* 23178566Sjb * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24178479Sjb * Use is subject to license terms. 25178479Sjb */ 26178479Sjb 27178479Sjb#pragma ident "%Z%%M% %I% %E% SMI" 28178479Sjb 29178479Sjb#include <assert.h> 30178479Sjb#include <strings.h> 31178566Sjb#if defined(sun) 32178479Sjb#include <alloca.h> 33178566Sjb#endif 34178479Sjb#include <stdlib.h> 35178479Sjb#include <stdio.h> 36178479Sjb 37178479Sjb#include <dt_parser.h> 38178479Sjb#include <dt_impl.h> 39178479Sjb#include <dt_provider.h> 40178479Sjb#include <dt_module.h> 41178479Sjb 42178479Sjb/* 43178479Sjb * This callback function is installed in a given identifier hash to search for 44178479Sjb * and apply deferred pragmas that are pending for a given new identifier name. 45178479Sjb * Multiple pragmas may be pending for a given name; we processs all of them. 46178479Sjb */ 47178479Sjb/*ARGSUSED*/ 48178479Sjbstatic void 49178479Sjbdt_pragma_apply(dt_idhash_t *dhp, dt_ident_t *idp) 50178479Sjb{ 51178479Sjb dt_idhash_t *php; 52178479Sjb dt_ident_t *pdp; 53178479Sjb 54178479Sjb if ((php = yypcb->pcb_pragmas) == NULL) 55178479Sjb return; /* no pragmas pending for current compilation pass */ 56178479Sjb 57178479Sjb while ((pdp = dt_idhash_lookup(php, idp->di_name)) != NULL) { 58178479Sjb switch (pdp->di_kind) { 59178479Sjb case DT_IDENT_PRAGAT: 60178479Sjb idp->di_attr = pdp->di_attr; 61178479Sjb break; 62178479Sjb case DT_IDENT_PRAGBN: 63178479Sjb idp->di_vers = pdp->di_vers; 64178479Sjb break; 65178479Sjb } 66178479Sjb dt_idhash_delete(php, pdp); 67178479Sjb } 68178479Sjb} 69178479Sjb 70178479Sjb/* 71178479Sjb * The #pragma attributes directive can be used to reset stability attributes 72178479Sjb * on a global identifier or inline definition. If the identifier is already 73178479Sjb * defined, we can just change di_attr. If not, we insert the pragma into a 74178479Sjb * hash table of the current pcb's deferred pragmas for later processing. 75178479Sjb */ 76178479Sjbstatic void 77178479Sjbdt_pragma_attributes(const char *prname, dt_node_t *dnp) 78178479Sjb{ 79178479Sjb dtrace_hdl_t *dtp = yypcb->pcb_hdl; 80178479Sjb dtrace_attribute_t attr, *a; 81178479Sjb dt_provider_t *pvp; 82178479Sjb const char *name, *part; 83178479Sjb dt_ident_t *idp; 84178479Sjb 85178479Sjb if (dnp == NULL || dnp->dn_kind != DT_NODE_IDENT || 86178479Sjb dnp->dn_list == NULL || dnp->dn_list->dn_kind != DT_NODE_IDENT) { 87178479Sjb xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s " 88178479Sjb "<attributes> <ident>\n", prname); 89178479Sjb } 90178479Sjb 91178479Sjb if (dtrace_str2attr(dnp->dn_string, &attr) == -1) { 92178479Sjb xyerror(D_PRAGMA_INVAL, "invalid attributes " 93178479Sjb "specified by #pragma %s\n", prname); 94178479Sjb } 95178479Sjb 96178479Sjb dnp = dnp->dn_list; 97178479Sjb name = dnp->dn_string; 98178479Sjb 99178479Sjb if (strcmp(name, "provider") == 0) { 100178479Sjb dnp = dnp->dn_list; 101178479Sjb name = dnp->dn_string; 102178479Sjb 103178479Sjb dnp = dnp->dn_list; 104178479Sjb part = dnp->dn_string; 105178479Sjb 106178479Sjb if ((pvp = dt_provider_lookup(dtp, name)) != NULL) { 107178479Sjb if (strcmp(part, "provider") == 0) { 108178479Sjb a = &pvp->pv_desc.dtvd_attr.dtpa_provider; 109178479Sjb } else if (strcmp(part, "module") == 0) { 110178479Sjb a = &pvp->pv_desc.dtvd_attr.dtpa_mod; 111178479Sjb } else if (strcmp(part, "function") == 0) { 112178479Sjb a = &pvp->pv_desc.dtvd_attr.dtpa_func; 113178479Sjb } else if (strcmp(part, "name") == 0) { 114178479Sjb a = &pvp->pv_desc.dtvd_attr.dtpa_name; 115178479Sjb } else if (strcmp(part, "args") == 0) { 116178479Sjb a = &pvp->pv_desc.dtvd_attr.dtpa_args; 117178479Sjb } else { 118178479Sjb xyerror(D_PRAGMA_INVAL, "invalid component " 119178479Sjb "\"%s\" in attribute #pragma " 120178479Sjb "for provider %s\n", name, part); 121178479Sjb } 122178479Sjb 123178479Sjb *a = attr; 124178479Sjb return; 125178479Sjb } 126178479Sjb 127178479Sjb } else if ((idp = dt_idstack_lookup( 128178479Sjb &yypcb->pcb_globals, name)) != NULL) { 129178479Sjb 130178479Sjb if (idp->di_gen != dtp->dt_gen) { 131178479Sjb xyerror(D_PRAGMA_SCOPE, "#pragma %s cannot modify " 132178479Sjb "entity defined outside program scope\n", prname); 133178479Sjb } 134178479Sjb 135178479Sjb idp->di_attr = attr; 136178479Sjb return; 137178479Sjb } 138178479Sjb 139178479Sjb if (yypcb->pcb_pragmas == NULL && (yypcb->pcb_pragmas = 140178479Sjb dt_idhash_create("pragma", NULL, 0, 0)) == NULL) 141178479Sjb longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 142178479Sjb 143178479Sjb idp = dt_idhash_insert(yypcb->pcb_pragmas, name, DT_IDENT_PRAGAT, 0, 0, 144178479Sjb attr, 0, &dt_idops_thaw, (void *)prname, dtp->dt_gen); 145178479Sjb 146178479Sjb if (idp == NULL) 147178479Sjb longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 148178479Sjb 149178479Sjb if (dtp->dt_globals->dh_defer == NULL) 150178479Sjb dtp->dt_globals->dh_defer = &dt_pragma_apply; 151178479Sjb} 152178479Sjb 153178479Sjb/* 154178479Sjb * The #pragma binding directive can be used to reset the version binding 155178479Sjb * on a global identifier or inline definition. If the identifier is already 156178479Sjb * defined, we can just change di_vers. If not, we insert the pragma into a 157178479Sjb * hash table of the current pcb's deferred pragmas for later processing. 158178479Sjb */ 159178479Sjbstatic void 160178479Sjbdt_pragma_binding(const char *prname, dt_node_t *dnp) 161178479Sjb{ 162178479Sjb dtrace_hdl_t *dtp = yypcb->pcb_hdl; 163178479Sjb dt_version_t vers; 164178479Sjb const char *name; 165178479Sjb dt_ident_t *idp; 166178479Sjb 167178479Sjb if (dnp == NULL || dnp->dn_kind != DT_NODE_STRING || 168178479Sjb dnp->dn_list == NULL || dnp->dn_list->dn_kind != DT_NODE_IDENT) { 169178479Sjb xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s " 170178479Sjb "\"version\" <ident>\n", prname); 171178479Sjb } 172178479Sjb 173178479Sjb if (dt_version_str2num(dnp->dn_string, &vers) == -1) { 174178479Sjb xyerror(D_PRAGMA_INVAL, "invalid version string " 175178479Sjb "specified by #pragma %s\n", prname); 176178479Sjb } 177178479Sjb 178178479Sjb name = dnp->dn_list->dn_string; 179178479Sjb idp = dt_idstack_lookup(&yypcb->pcb_globals, name); 180178479Sjb 181178479Sjb if (idp != NULL) { 182178479Sjb if (idp->di_gen != dtp->dt_gen) { 183178479Sjb xyerror(D_PRAGMA_SCOPE, "#pragma %s cannot modify " 184178479Sjb "entity defined outside program scope\n", prname); 185178479Sjb } 186178479Sjb idp->di_vers = vers; 187178479Sjb return; 188178479Sjb } 189178479Sjb 190178479Sjb if (yypcb->pcb_pragmas == NULL && (yypcb->pcb_pragmas = 191178479Sjb dt_idhash_create("pragma", NULL, 0, 0)) == NULL) 192178479Sjb longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 193178479Sjb 194178479Sjb idp = dt_idhash_insert(yypcb->pcb_pragmas, name, DT_IDENT_PRAGBN, 0, 0, 195178479Sjb _dtrace_defattr, vers, &dt_idops_thaw, (void *)prname, dtp->dt_gen); 196178479Sjb 197178479Sjb if (idp == NULL) 198178479Sjb longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 199178479Sjb 200178479Sjb if (dtp->dt_globals->dh_defer == NULL) 201178479Sjb dtp->dt_globals->dh_defer = &dt_pragma_apply; 202178479Sjb} 203178479Sjb 204178479Sjb/* 205178479Sjb * The #pragma depends_on directive can be used to express a dependency on a 206178479Sjb * module, provider or library which if not present will cause processing to 207178479Sjb * abort. 208178479Sjb */ 209178479Sjbstatic void 210178479Sjbdt_pragma_depends(const char *prname, dt_node_t *cnp) 211178479Sjb{ 212178479Sjb dtrace_hdl_t *dtp = yypcb->pcb_hdl; 213178479Sjb dt_node_t *nnp = cnp ? cnp->dn_list : NULL; 214178479Sjb int found; 215178479Sjb dt_lib_depend_t *dld; 216178566Sjb char lib[MAXPATHLEN]; 217178479Sjb 218178479Sjb if (cnp == NULL || nnp == NULL || 219178479Sjb cnp->dn_kind != DT_NODE_IDENT || nnp->dn_kind != DT_NODE_IDENT) { 220178479Sjb xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s " 221178479Sjb "<class> <name>\n", prname); 222178479Sjb } 223178479Sjb 224178479Sjb if (strcmp(cnp->dn_string, "provider") == 0) 225178479Sjb found = dt_provider_lookup(dtp, nnp->dn_string) != NULL; 226178479Sjb else if (strcmp(cnp->dn_string, "module") == 0) { 227178479Sjb dt_module_t *mp = dt_module_lookup_by_name(dtp, nnp->dn_string); 228178479Sjb found = mp != NULL && dt_module_getctf(dtp, mp) != NULL; 229178479Sjb } else if (strcmp(cnp->dn_string, "library") == 0) { 230178479Sjb if (yypcb->pcb_cflags & DTRACE_C_CTL) { 231178566Sjb assert(dtp->dt_filetag != NULL); 232178479Sjb 233178566Sjb /* 234178566Sjb * We have the file we are working on in dtp->dt_filetag 235178566Sjb * so find that node and add the dependency in. 236178566Sjb */ 237178479Sjb dld = dt_lib_depend_lookup(&dtp->dt_lib_dep, 238178479Sjb dtp->dt_filetag); 239178479Sjb assert(dld != NULL); 240178479Sjb 241178566Sjb (void) snprintf(lib, sizeof (lib), "%s%s", 242178479Sjb dld->dtld_libpath, nnp->dn_string); 243178479Sjb if ((dt_lib_depend_add(dtp, &dld->dtld_dependencies, 244178479Sjb lib)) != 0) { 245178479Sjb xyerror(D_PRAGMA_DEPEND, 246178566Sjb "failed to add dependency %s:%s\n", lib, 247178479Sjb dtrace_errmsg(dtp, dtrace_errno(dtp))); 248178479Sjb } 249178566Sjb } else { 250178566Sjb /* 251178566Sjb * By this point we have already performed a topological 252178566Sjb * sort of the dependencies; we process this directive 253178566Sjb * as satisfied as long as the dependency was properly 254178566Sjb * loaded. 255178566Sjb */ 256178566Sjb if (dtp->dt_filetag == NULL) 257178566Sjb xyerror(D_PRAGMA_DEPEND, "main program may " 258178566Sjb "not explicitly depend on a library"); 259178566Sjb 260178566Sjb dld = dt_lib_depend_lookup(&dtp->dt_lib_dep, 261178566Sjb dtp->dt_filetag); 262178566Sjb assert(dld != NULL); 263178566Sjb 264178566Sjb (void) snprintf(lib, sizeof (lib), "%s%s", 265178566Sjb dld->dtld_libpath, nnp->dn_string); 266178566Sjb dld = dt_lib_depend_lookup(&dtp->dt_lib_dep_sorted, 267178566Sjb lib); 268178566Sjb assert(dld != NULL); 269178566Sjb 270178566Sjb if (!dld->dtld_loaded) 271178566Sjb xyerror(D_PRAGMA_DEPEND, "program requires " 272178566Sjb "library \"%s\" which failed to load", 273178566Sjb lib); 274178479Sjb } 275178566Sjb 276178566Sjb found = B_TRUE; 277178479Sjb } else { 278178479Sjb xyerror(D_PRAGMA_INVAL, "invalid class %s " 279178479Sjb "specified by #pragma %s\n", cnp->dn_string, prname); 280178479Sjb } 281178479Sjb 282178479Sjb if (!found) { 283178479Sjb xyerror(D_PRAGMA_DEPEND, "program requires %s %s\n", 284178479Sjb cnp->dn_string, nnp->dn_string); 285178479Sjb } 286178479Sjb} 287178479Sjb 288178479Sjb/* 289178479Sjb * The #pragma error directive can be followed by any list of tokens, which we 290178479Sjb * just concatenate and print as part of our error message. 291178479Sjb */ 292178479Sjbstatic void 293178479Sjbdt_pragma_error(const char *prname, dt_node_t *dnp) 294178479Sjb{ 295178479Sjb dt_node_t *enp; 296178479Sjb size_t n = 0; 297178479Sjb char *s; 298178479Sjb 299178479Sjb for (enp = dnp; enp != NULL; enp = enp->dn_list) { 300178479Sjb if (enp->dn_kind == DT_NODE_IDENT || 301178479Sjb enp->dn_kind == DT_NODE_STRING) 302178479Sjb n += strlen(enp->dn_string) + 1; 303178479Sjb } 304178479Sjb 305178479Sjb s = alloca(n + 1); 306178479Sjb s[0] = '\0'; 307178479Sjb 308178479Sjb for (enp = dnp; enp != NULL; enp = enp->dn_list) { 309178479Sjb if (enp->dn_kind == DT_NODE_IDENT || 310178479Sjb enp->dn_kind == DT_NODE_STRING) { 311178479Sjb (void) strcat(s, enp->dn_string); 312178479Sjb (void) strcat(s, " "); 313178479Sjb } 314178479Sjb } 315178479Sjb 316178479Sjb xyerror(D_PRAGERR, "#%s: %s\n", prname, s); 317178479Sjb} 318178479Sjb 319178479Sjb/*ARGSUSED*/ 320178479Sjbstatic void 321178479Sjbdt_pragma_ident(const char *prname, dt_node_t *dnp) 322178479Sjb{ 323178479Sjb /* ignore any #ident or #pragma ident lines */ 324178479Sjb} 325178479Sjb 326178479Sjbstatic void 327178479Sjbdt_pragma_option(const char *prname, dt_node_t *dnp) 328178479Sjb{ 329178479Sjb dtrace_hdl_t *dtp = yypcb->pcb_hdl; 330178479Sjb char *opt, *val; 331178479Sjb 332178479Sjb if (dnp == NULL || dnp->dn_kind != DT_NODE_IDENT) { 333178479Sjb xyerror(D_PRAGMA_MALFORM, 334178479Sjb "malformed #pragma %s <option>=<val>\n", prname); 335178479Sjb } 336178479Sjb 337178479Sjb if (dnp->dn_list != NULL) { 338178479Sjb xyerror(D_PRAGMA_MALFORM, 339178479Sjb "superfluous arguments specified for #pragma %s\n", prname); 340178479Sjb } 341178479Sjb 342178479Sjb opt = alloca(strlen(dnp->dn_string) + 1); 343178479Sjb (void) strcpy(opt, dnp->dn_string); 344178479Sjb 345178479Sjb if ((val = strchr(opt, '=')) != NULL) 346178479Sjb *val++ = '\0'; 347178479Sjb 348178479Sjb if (dtrace_setopt(dtp, opt, val) == -1) { 349178479Sjb if (val == NULL) { 350178479Sjb xyerror(D_PRAGMA_OPTSET, 351178479Sjb "failed to set option '%s': %s\n", opt, 352178479Sjb dtrace_errmsg(dtp, dtrace_errno(dtp))); 353178479Sjb } else { 354178479Sjb xyerror(D_PRAGMA_OPTSET, 355178479Sjb "failed to set option '%s' to '%s': %s\n", 356178479Sjb opt, val, dtrace_errmsg(dtp, dtrace_errno(dtp))); 357178479Sjb } 358178479Sjb } 359178479Sjb} 360178479Sjb 361178479Sjb/* 362178479Sjb * The #line directive is used to reset the input line number and to optionally 363178479Sjb * note the file name for use in error messages. Sun cpp(1) also produces a 364178479Sjb * third integer token after the filename which is one of the following: 365178479Sjb * 366178479Sjb * 0 - line change has nothing to do with an #include file 367178479Sjb * 1 - line change because we just entered a #include file 368178479Sjb * 2 - line change because we just exited a #include file 369178479Sjb * 370178479Sjb * We use these state tokens to adjust pcb_idepth, which in turn controls 371178479Sjb * whether type lookups access the global type space or not. 372178479Sjb */ 373178479Sjbstatic void 374178479Sjbdt_pragma_line(const char *prname, dt_node_t *dnp) 375178479Sjb{ 376178479Sjb dt_node_t *fnp = dnp ? dnp->dn_list : NULL; 377178479Sjb dt_node_t *inp = fnp ? fnp->dn_list : NULL; 378178479Sjb 379178479Sjb if ((dnp == NULL || dnp->dn_kind != DT_NODE_INT) || 380178479Sjb (fnp != NULL && fnp->dn_kind != DT_NODE_STRING) || 381178479Sjb (inp != NULL && inp->dn_kind != DT_NODE_INT)) { 382178479Sjb xyerror(D_PRAGMA_MALFORM, "malformed #%s " 383178479Sjb "<line> [ [\"file\"] state ]\n", prname); 384178479Sjb } 385178479Sjb 386178479Sjb /* 387178479Sjb * If a file is specified, free any old pcb_filetag and swap fnp's 388178479Sjb * dn_string into pcb_filetag as the new filename for error messages. 389178479Sjb */ 390178479Sjb if (fnp != NULL) { 391178479Sjb if (yypcb->pcb_filetag != NULL) 392178479Sjb free(yypcb->pcb_filetag); 393178479Sjb 394178479Sjb /* 395178479Sjb * This is not pretty, but is a necessary evil until we either 396178479Sjb * write "dpp" or get a useful standalone cpp from DevPro. If 397178479Sjb * the filename begins with /dev/fd, we know it's the master 398178479Sjb * input file (see dt_preproc() in dt_cc.c), so just clear the 399178479Sjb * dt_filetag pointer so error messages refer to the main file. 400178479Sjb */ 401178479Sjb if (strncmp(fnp->dn_string, "/dev/fd/", 8) != 0) { 402178479Sjb yypcb->pcb_filetag = fnp->dn_string; 403178479Sjb fnp->dn_string = NULL; 404178479Sjb } else 405178479Sjb yypcb->pcb_filetag = NULL; 406178479Sjb } 407178479Sjb 408178479Sjb if (inp != NULL) { 409178479Sjb if (inp->dn_value == 1) 410178479Sjb yypcb->pcb_idepth++; 411178479Sjb else if (inp->dn_value == 2 && yypcb->pcb_idepth != 0) 412178479Sjb yypcb->pcb_idepth--; 413178479Sjb } 414178479Sjb 415178479Sjb yylineno = dnp->dn_value; 416178479Sjb} 417178479Sjb 418178479Sjb/* 419178479Sjb * D compiler pragma types range from control directives to common pragmas to 420178479Sjb * D custom pragmas, in order of specificity. Similar to gcc, we use #pragma D 421178479Sjb * as a special prefix for our pragmas so they can be used in mixed headers. 422178479Sjb */ 423178479Sjb#define DT_PRAGMA_DIR 0 /* pragma directive may be used after naked # */ 424178479Sjb#define DT_PRAGMA_SUB 1 /* pragma directive may be used after #pragma */ 425178479Sjb#define DT_PRAGMA_DCP 2 /* pragma may only be used after #pragma D */ 426178479Sjb 427178479Sjbstatic const struct dt_pragmadesc { 428178479Sjb const char *dpd_name; 429178479Sjb void (*dpd_func)(const char *, dt_node_t *); 430178479Sjb int dpd_kind; 431178479Sjb} dt_pragmas[] = { 432178479Sjb { "attributes", dt_pragma_attributes, DT_PRAGMA_DCP }, 433178479Sjb { "binding", dt_pragma_binding, DT_PRAGMA_DCP }, 434178479Sjb { "depends_on", dt_pragma_depends, DT_PRAGMA_DCP }, 435178479Sjb { "error", dt_pragma_error, DT_PRAGMA_DIR }, 436178479Sjb { "ident", dt_pragma_ident, DT_PRAGMA_DIR }, 437178479Sjb { "line", dt_pragma_line, DT_PRAGMA_DIR }, 438178479Sjb { "option", dt_pragma_option, DT_PRAGMA_DCP }, 439178479Sjb { NULL, NULL } 440178479Sjb}; 441178479Sjb 442178479Sjb/* 443178479Sjb * Process a control line #directive by looking up the directive name in our 444178479Sjb * lookup table and invoking the corresponding function with the token list. 445178479Sjb * According to K&R[A12.9], we silently ignore null directive lines. 446178479Sjb */ 447178479Sjbvoid 448178479Sjbdt_pragma(dt_node_t *pnp) 449178479Sjb{ 450178479Sjb const struct dt_pragmadesc *dpd; 451178479Sjb dt_node_t *dnp; 452178479Sjb int kind = DT_PRAGMA_DIR; 453178479Sjb 454178479Sjb for (dnp = pnp; dnp != NULL; dnp = dnp->dn_list) { 455178479Sjb if (dnp->dn_kind == DT_NODE_INT) { 456178479Sjb dt_pragma_line("line", dnp); 457178479Sjb break; 458178479Sjb } 459178479Sjb 460178479Sjb if (dnp->dn_kind != DT_NODE_IDENT) 461178479Sjb xyerror(D_PRAGCTL_INVAL, "invalid control directive\n"); 462178479Sjb 463178479Sjb if (kind == DT_PRAGMA_DIR && 464178479Sjb strcmp(dnp->dn_string, "pragma") == 0) { 465178479Sjb kind = DT_PRAGMA_SUB; 466178479Sjb continue; 467178479Sjb } 468178479Sjb 469178479Sjb if (kind == DT_PRAGMA_SUB && 470178479Sjb strcmp(dnp->dn_string, "D") == 0) { 471178479Sjb kind = DT_PRAGMA_DCP; 472178479Sjb continue; 473178479Sjb } 474178479Sjb 475178479Sjb for (dpd = dt_pragmas; dpd->dpd_name != NULL; dpd++) { 476178479Sjb if (dpd->dpd_kind <= kind && 477178479Sjb strcmp(dpd->dpd_name, dnp->dn_string) == 0) 478178479Sjb break; 479178479Sjb } 480178479Sjb 481178479Sjb yylineno--; /* since we've already seen \n */ 482178479Sjb 483178479Sjb if (dpd->dpd_name != NULL) { 484178479Sjb dpd->dpd_func(dpd->dpd_name, dnp->dn_list); 485178479Sjb yylineno++; 486178479Sjb break; 487178479Sjb } 488178479Sjb 489178479Sjb switch (kind) { 490178479Sjb case DT_PRAGMA_DIR: 491178479Sjb xyerror(D_PRAGCTL_INVAL, "invalid control directive: " 492178479Sjb "#%s\n", dnp->dn_string); 493178479Sjb /*NOTREACHED*/ 494178479Sjb case DT_PRAGMA_SUB: 495178479Sjb break; /* K&R[A12.8] says to ignore unknown pragmas */ 496178479Sjb case DT_PRAGMA_DCP: 497178479Sjb default: 498178479Sjb xyerror(D_PRAGMA_INVAL, "invalid D pragma: %s\n", 499178479Sjb dnp->dn_string); 500178479Sjb } 501178479Sjb 502178479Sjb yylineno++; 503178479Sjb break; 504178479Sjb } 505178479Sjb 506178479Sjb dt_node_list_free(&pnp); 507178479Sjb} 508