diff options
author | chin <none@none> | 2007-08-17 12:01:52 -0700 |
---|---|---|
committer | chin <none@none> | 2007-08-17 12:01:52 -0700 |
commit | da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968 (patch) | |
tree | 5280d3b78e289fe9551371ab6e7f15ef9944ea14 /usr/src/lib/libpp | |
parent | 073dbf9103ef2a2b05d8a16e2d26db04e0374b0e (diff) | |
download | illumos-joyent-da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968.tar.gz |
6437624 RFE: Add ksh93 (as /usr/bin/ksh93) and libshell.so to OS/Net
6505835 AST tools and library (libpp) required for creating l10n messages for ksh93
PSARC/2006/550 Korn Shell 93 Integration
PSARC/2006/587 /etc/ksh.kshrc for ksh93
PSARC/2007/035 ksh93 Amendments
Contributed by Roland Mainz <roland.mainz@nrubsig.org>
--HG--
rename : usr/src/lib/libcmd/common/mapfile-vers => deleted_files/usr/src/lib/libcmd/common/mapfile-vers
rename : usr/src/lib/libcmd/common/placeholder.c => deleted_files/usr/src/lib/libcmd/common/placeholder.c
Diffstat (limited to 'usr/src/lib/libpp')
57 files changed, 22033 insertions, 0 deletions
diff --git a/usr/src/lib/libpp/Makefile b/usr/src/lib/libpp/Makefile new file mode 100644 index 0000000000..4091cfcbbf --- /dev/null +++ b/usr/src/lib/libpp/Makefile @@ -0,0 +1,66 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SHELL=/usr/bin/ksh + +include ../Makefile.lib + +SUBDIRS = $(MACH) +#$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint +_msg := TARGET= _msg + +.KEEP_STATE: + +all clean clobber install lint _msg: $(SUBDIRS) + +LIBRARY= libpp.a + +HDRS= \ + pp.h \ + ppkey.h + +HDRDIR32= common +HDRDIR64= common +include ../Makefile.asthdr + +install_h: $(ROOTHDRS) + +# We don't check these header files because they're owned by AT&T/AST +check: + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include ../Makefile.targ diff --git a/usr/src/lib/libpp/Makefile.com b/usr/src/lib/libpp/Makefile.com new file mode 100644 index 0000000000..f9a16b9af1 --- /dev/null +++ b/usr/src/lib/libpp/Makefile.com @@ -0,0 +1,121 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SHELL=/usr/bin/ksh + +LIBRARY= libpp.a +VERS= .1 + +OBJECTS= \ + ppargs.o \ + ppbuiltin.o \ + ppcall.o \ + ppcomment.o \ + ppcontext.o \ + ppcontrol.o \ + ppcpp.o \ + ppdata.o \ + pperror.o \ + ppexpr.o \ + ppfsm.o \ + ppincref.o \ + ppinput.o \ + ppkey.o \ + pplex.o \ + ppline.o \ + ppmacref.o \ + ppmisc.o \ + ppop.o \ + pppragma.o \ + ppprintf.o \ + ppproto.o \ + ppsearch.o \ + pptrace.o + +include ../../Makefile.astmsg + +include ../../Makefile.lib + +# mapfile-vers does not live with the sources in in common/ to make +# automated code updates easier. +MAPFILES= ../mapfile-vers + +# Set common AST build flags (e.g., needed to support the math stuff). +include ../../../Makefile.ast + +LIBS = $(DYNLIB) $(LINTLIB) +LDLIBS += -last -lc +$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) + +SRCDIR = ../common + +# We use "=" here since using $(CPPFLAGS.master) is very tricky in our +# case - it MUST come as the last element but future changes in -D options +# may then cause silent breakage in the AST sources because the last -D +# option specified overrides previous -D options so we prefer the current +# way to explicitly list each single flag. +CPPFLAGS = \ + $(DTEXTDOM) $(DTS_ERRNO) \ + -I. \ + -I$(ROOT)/usr/include/ast \ + -D_PACKAGE_ast \ + '-DUSAGE_LICENSE=\ + "[-author?Glenn Fowler <gsf@research.att.com>]"\ + "[-copyright?Copyright (c) 1986-2007 AT&T Knowledge Ventures]"\ + "[-license?http://www.opensource.org/licenses/cpl1.0.txt]"\ + "[--catalog?libpp]"' + +CFLAGS += \ + $(CCVERBOSE) \ + -xstrconst +CFLAGS64 += \ + $(CCVERBOSE) \ + -xstrconst + +pics/ppcall.o := CERRWARN += -erroff=E_INTEGER_OVERFLOW_DETECTED +pics/ppcontrol.o := CERRWARN += -erroff=E_INTEGER_OVERFLOW_DETECTED +pics/ppcpp.o := CERRWARN += -erroff=E_INTEGER_OVERFLOW_DETECTED +pics/pplex.o := CERRWARN += -erroff=E_INTEGER_OVERFLOW_DETECTED +pics/ppexpr.o := CERRWARN += -erroff=E_INTEGER_OVERFLOW_DETECTED +pics/ppop.o := CERRWARN += -erroff=E_INTEGER_OVERFLOW_DETECTED +pics/ppsearch.o := CERRWARN += -erroff=E_INTEGER_OVERFLOW_DETECTED +pics/ppsearch.o := CERRWARN += -_gcc=-Wno-sequence-point + +.KEEP_STATE: + +all: $(LIBS) + +# +# libpp is not lint-clean yet; fake up a target. (You can use +# "make lintcheck" to actually run lint; please send all lint fixes +# upstream (to AT&T) so the next update will pull them into ON.) +# +lint: + @ print "usr/src/lib/libpp is not lint-clean: skipping" + @ $(TRUE) + +include ../../Makefile.targ diff --git a/usr/src/lib/libpp/THIRDPARTYLICENSE b/usr/src/lib/libpp/THIRDPARTYLICENSE new file mode 100644 index 0000000000..50c6364c06 --- /dev/null +++ b/usr/src/lib/libpp/THIRDPARTYLICENSE @@ -0,0 +1,245 @@ ++------------------------------------------------------------------------------+ +| This license covers all software that refers to the URL | +| http://www.opensource.org/licenses/cpl1.0.txt | ++------------------------------------------------------------------------------+ + +Common Public License Version 1.0 + + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF + THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + + 1. DEFINITIONS + + "Contribution" means: + + a) in the case of the initial Contributor, the initial code and + documentation distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + + i) changes to the Program, and + + ii) additions to the Program; + + where such changes and/or additions to the Program originate from + and are distributed by that particular Contributor. A Contribution + 'originates' from a Contributor if it was added to the Program by + such Contributor itself or anyone acting on such Contributor's + behalf. Contributions do not include additions to the Program + which: (i) are separate modules of software distributed in + conjunction with the Program under their own license agreement, and + (ii) are not derivative works of the Program. + + "Contributor" means any person or entity that distributes the Program. + + "Licensed Patents " mean patent claims licensable by a Contributor + which are necessarily infringed by the use or sale of its Contribution + alone or when combined with the Program. + + "Program" means the Contributions distributed in accordance with this + Agreement. + + "Recipient" means anyone who receives the Program under this + Agreement, including all Contributors. + + 2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare derivative works of, publicly + display, publicly perform, distribute and sublicense the + Contribution of such Contributor, if any, and such derivative + works, in source code and object code form. + + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, + if any, in source code and object code form. This patent license + shall apply to the combination of the Contribution and the Program + if, at the time the Contribution is added by the Contributor, such + addition of the Contribution causes such combination to be covered + by the Licensed Patents. The patent license shall not apply to any + other combinations which include the Contribution. No hardware per + se is licensed hereunder. + + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. + Each Contributor disclaims any liability to Recipient for claims + brought by any other entity based on infringement of intellectual + property rights or otherwise. As a condition to exercising the + rights and licenses granted hereunder, each Recipient hereby + assumes sole responsibility to secure any other intellectual + property rights needed, if any. For example, if a third party + patent license is required to allow Recipient to distribute the + Program, it is Recipient's responsibility to acquire that license + before distributing the Program. + + d) Each Contributor represents that to its knowledge it has + sufficient copyright rights in its Contribution, if any, to grant + the copyright license set forth in this Agreement. + + 3. REQUIREMENTS + + A Contributor may choose to distribute the Program in object code form + under its own license agreement, provided that: + + a) it complies with the terms and conditions of this Agreement; and + + b) its license agreement: + + i) effectively disclaims on behalf of all Contributors all + warranties and conditions, express and implied, including + warranties or conditions of title and non-infringement, and implied + warranties or conditions of merchantability and fitness for a + particular purpose; + + ii) effectively excludes on behalf of all Contributors all + liability for damages, including direct, indirect, special, + incidental and consequential damages, such as lost profits; + + iii) states that any provisions which differ from this Agreement + are offered by that Contributor alone and not by any other party; + and + + iv) states that source code for the Program is available from such + Contributor, and informs licensees how to obtain it in a reasonable + manner on or through a medium customarily used for software + exchange. + + When the Program is made available in source code form: + + a) it must be made available under this Agreement; and + + b) a copy of this Agreement must be included with each copy of the + Program. + + Contributors may not remove or alter any copyright notices contained + within the Program. + + Each Contributor must identify itself as the originator of its + Contribution, if any, in a manner that reasonably allows subsequent + Recipients to identify the originator of the Contribution. + + 4. COMMERCIAL DISTRIBUTION + + Commercial distributors of software may accept certain + responsibilities with respect to end users, business partners and the + like. While this license is intended to facilitate the commercial use + of the Program, the Contributor who includes the Program in a + commercial product offering should do so in a manner which does not + create potential liability for other Contributors. Therefore, if a + Contributor includes the Program in a commercial product offering, + such Contributor ("Commercial Contributor") hereby agrees to defend + and indemnify every other Contributor ("Indemnified Contributor") + against any losses, damages and costs (collectively "Losses") arising + from claims, lawsuits and other legal actions brought by a third party + against the Indemnified Contributor to the extent caused by the acts + or omissions of such Commercial Contributor in connection with its + distribution of the Program in a commercial product offering. The + obligations in this section do not apply to any claims or Losses + relating to any actual or alleged intellectual property infringement. + In order to qualify, an Indemnified Contributor must: a) promptly + notify the Commercial Contributor in writing of such claim, and b) + allow the Commercial Contributor to control, and cooperate with the + Commercial Contributor in, the defense and any related settlement + negotiations. The Indemnified Contributor may participate in any such + claim at its own expense. + + For example, a Contributor might include the Program in a commercial + product offering, Product X. That Contributor is then a Commercial + Contributor. If that Commercial Contributor then makes performance + claims, or offers warranties related to Product X, those performance + claims and warranties are such Commercial Contributor's responsibility + alone. Under this section, the Commercial Contributor would have to + defend claims against the other Contributors related to those + performance claims and warranties, and if a court requires any other + Contributor to pay any damages as a result, the Commercial Contributor + must pay those damages. + + 5. NO WARRANTY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS + PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY + WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY + OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely + responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, compliance with applicable + laws, damage to or loss of data, programs or equipment, and + unavailability or interruption of operations. + + 6. DISCLAIMER OF LIABILITY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR + ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING + WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR + DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + 7. GENERAL + + If any provision of this Agreement is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this Agreement, and without further + action by the parties hereto, such provision shall be reformed to the + minimum extent necessary to make such provision valid and enforceable. + + If Recipient institutes patent litigation against a Contributor with + respect to a patent applicable to software (including a cross-claim or + counterclaim in a lawsuit), then any patent licenses granted by that + Contributor to such Recipient under this Agreement shall terminate as + of the date such litigation is filed. In addition, if Recipient + institutes patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Program + itself (excluding combinations of the Program with other software or + hardware) infringes such Recipient's patent(s), then such Recipient's + rights granted under Section 2(b) shall terminate as of the date such + litigation is filed. + + All Recipient's rights under this Agreement shall terminate if it + fails to comply with any of the material terms or conditions of this + Agreement and does not cure such failure in a reasonable period of + time after becoming aware of such noncompliance. If all Recipient's + rights under this Agreement terminate, Recipient agrees to cease use + and distribution of the Program as soon as reasonably practicable. + However, Recipient's obligations under this Agreement and any licenses + granted by Recipient relating to the Program shall continue and + survive. + + Everyone is permitted to copy and distribute copies of this Agreement, + but in order to avoid inconsistency the Agreement is copyrighted and + may only be modified in the following manner. The Agreement Steward + reserves the right to publish new versions (including revisions) of + this Agreement from time to time. No one other than the Agreement + Steward has the right to modify this Agreement. IBM is the initial + Agreement Steward. IBM may assign the responsibility to serve as the + Agreement Steward to a suitable separate entity. Each new version of + the Agreement will be given a distinguishing version number. The + Program (including Contributions) may always be distributed subject to + the version of the Agreement under which it was received. In addition, + after a new version of the Agreement is published, Contributor may + elect to distribute the Program (including its Contributions) under + the new version. Except as expressly stated in Sections 2(a) and 2(b) + above, Recipient receives no rights or licenses to the intellectual + property of any Contributor under this Agreement, whether expressly, + by implication, estoppel or otherwise. All rights in the Program not + expressly granted under this Agreement are reserved. + + This Agreement is governed by the laws of the State of New York and + the intellectual property laws of the United States of America. No + party to this Agreement will bring a legal action under this Agreement + more than one year after the cause of action arose. Each party waives + its rights to a jury trial in any resulting litigation. + +Copyright (c) 2004 by the Open Source Initiative +This is a copy of the license posted on 2004-10-06 at: + http://www.opensource.org/licenses/cpl diff --git a/usr/src/lib/libpp/THIRDPARTYLICENSE.descrip b/usr/src/lib/libpp/THIRDPARTYLICENSE.descrip new file mode 100644 index 0000000000..e82817ee4d --- /dev/null +++ b/usr/src/lib/libpp/THIRDPARTYLICENSE.descrip @@ -0,0 +1 @@ +AT&T ADVANCED SOFTWARE TECHNOLOGY PREPROCESSOR LIBRARY (LIBPP) diff --git a/usr/src/lib/libpp/common/BUGS b/usr/src/lib/libpp/common/BUGS new file mode 100644 index 0000000000..1d3304d103 --- /dev/null +++ b/usr/src/lib/libpp/common/BUGS @@ -0,0 +1,6 @@ +libpp bug list + +01/22/93 gsf "" join drops trailing newline of last token in last file +06/11/92 gsf spurious empty character constant warning for shipproto.c +02/29/92 gsf "" join bombs if next line is #ident +02/01/87 gsf a/**/b doesn't concatenate outside macro bodies (COMPATIBILITY) diff --git a/usr/src/lib/libpp/common/HISTORY b/usr/src/lib/libpp/common/HISTORY new file mode 100644 index 0000000000..37d9156541 --- /dev/null +++ b/usr/src/lib/libpp/common/HISTORY @@ -0,0 +1,220 @@ +libpp change history + + ----- minor sync release ----- +09/11/89 add extra sun style 1,2 arg to line syncs in ppline with pp:linetype + add pp:oldc to convert __STDC__ void* and prototypes to old C +08/11/89 fix <...> include dir bug +08/08/89 add SYM_INIT for #define during INIT +07/28/89 delete STRIPTOP, STRIP only T_STRING & T_CHARCONST at pp.level==1 + add ppcargs() compatibility command line argument parse +07/17/89 dialect: ANSI (default) or (Reiser) compatibility + style: extended (default) or strict + use pathprobe(3) for dynamic ppdefault.h + add PP_PROBE to specify pathprobe() processor + add -[DI]+ to invert options in ppargs() + delete PP_ANSI, PP_DIALECT, PP_INITDIR, PP_LANGUAGE + delete PP_NONHOSTED, PP_NOPASSTHROUGH, PP_PHASEOUT + add #pragma's for most ppargs() options + add #option(pragma-option) predicate test + PP_MACREF now called during initialization +07/11/89 add PP_BUILTIN for external #(...) handler + add line number to missing endif message + ignore errors in skipped ppexpr() &&, || and ?: subexpressions + add space before macro actual in replacement text +07/04/89 fix PP_TRUNCATE interaction with PP_COMPILE +06/30/89 #define x #; x was recognized as directive # +06/27/89 don't pass comments during #if skip +05/01/89 add L"..." and L'...' wide quoted constants + mixed "..." and L"..." ok -- L"..." for COMPILE, first otherwise + fix PASSCOMMENTS in directives + allow #define f(a,) for COMPATIBILITY + fix literal string concatenation bugs + fix header parsing in non-active if-blocks + #endmac now takes no arg +04/11/89 tone down unknown directive diagnostic in conditional +04/07/89 move macref call before arg processing +03/27/89 fix pplex bug that bombed line sync for last line == #include +03/15/89 fix PP_TRUNCATE macro id bit table checks + remove compatibility option s from ppargs() -- belongs in cmds +03/08/89 remove ``empty character constant'' warning for PASSTHROUGH +02/28/89 fix variable n usage conflict for DEFINE: in ppcontrol +02/22/89 fix -T conflict with __GNUC__ in ppargs +02/01/89 add -T (PP_TRUNCATE) for old non-flexname compiler compatibility +01/31/89 -I-M-<char><suffix> finds map file by mapping input file name + -I-H[directory] allowed for fine hosted control +01/24/89 fix #undef of SYM_READONLY macro message + add PPCOMPATIBLE for compatibility installation in /lib/cpp + add PP_MAP & -I-M to map include files for minimal including +01/18/89 fix pp.token setting by noting with pp.state|=TOKENSET +01/11/89 fix #if skip bug where quoted token set begin line state +12/11/88 add error checking wrappers to *alloc() +12/05/88 add PP_FILEDEPS (-M) and FILEDEPS mode for BSD compatibility +12/01/88 add #macdef-#endmac and change actualsync() char to SYNC ('\r') +11/30/88 TOKOUTBUF controls 11/28/88 STANDALONE speedup +11/28/88 speed up STANDALONE by avoiding pp.token copy +11/22/88 add comment removal to string_special +11/11/88 LIBEXPR enables expr(3) in ppexpr() (12K extra text) +10/11/88 move VARQUOTE to pp.mode +10/01/88 allow checkpoint files for !STANDALONE +08/31/88 add pp.undefsym for pp.macref's on undefined symbols +08/23/88 0xe+N -> `0xe' `+' `N' +08/16/88 fix ppckeys.c: T_DOUBLE->T_DOUBLE_T, T_FLOAT->T_FLOAT_T +07/17/88 add \newline to string_special + add line number arg to pp.comment call + move private stuff from pp.h to pplib.h + add ignored -v to ppargs() (GNU uses this) +06/22/88 move pp.macref check; stack pp.state in ppcontrol() + add PP_INCREF and (*pp.incref)(old-file, new-file, push|return) +06/11/88 add pp.macref + add ppckeys.h and C, C++ and pcc-based C keyword tables +06/01/88 convert to new hash library interface +05/31/88 pp:readonly in PP_INIT only for STRICT +05/11/88 T_MOREARGS -> T_VARIADIC; add SYM_VARIADIC for ... last macro arg +05/03/88 fix empty include file bug by omitting empty check +04/27/88 ignore space in pragma % maps to accomodate SCCS %.% expansion +04/19/88 change pp.h to check for old nmake cpp clash with ppsymbol +04/11/88 fix flag check bug in ppload() +02/29/88 add MAP_ECHO and %E for MAP_RESCAN + echo + PP_INITDIR inserted before PP_STANDARD during initialization +02/18/88 ignore malformed #'s in COMPATIBILITY macro definitions + add pp.prefix, PP_PREFIX and -I-P for prefix dir "..." includes +02/10/88 add NOQUOTE to disable ' and " and decouple from VARQUOTE + add keyword and quote pragmas +02/02/88 add strcmp builtin predicate for token string value comparison +01/24/88 fix <backslash><newline> handling in #define on bsd +01/20/88 add %T and fix %[...] pragma mapping formats +01/11/88 complete 12/11/87 COMPATIBILITY macro arg /**/ pasting bug fix + complete KEYWORD support +01/08/88 add PP_KEYWORD, (pp.state & KEYWORD), -D-K and #if KEYARGS +01/06/88 hex char constants are now variable length +01/04/88 do not add terminator for COMPATIBILITY " and ' constants +12/11/87 remove #multiple in lieu of #pragma multiple + add %R MAP_RESCAN option to rescan pragma/directive mapping + fix COMPATIBILITY macro arg /**/ pasting bug +12/08/87 recode for updated hash library interface + add T_PTRMEMREF ->* and T_DOTREF .* C++ operator tokens +12/01/87 reorganize pp token numbers to span 0401..0477 +11/22/87 add operand error checks to ppexpr() + add PP_DEFAULT and -I-Dfile for fine PPDEFAULT control +11/11/87 pppragma() now omits space after # for primitive passes (uts) +10/30/87 fix line count on `newline' in ['"] constant warning +10/29/87 add MAP_PLUSCOMMENT and %P to pragma|directive mapping +10/28/87 add head & tail args to ppcomment; pass // comments as is +10/23/87 add warning for multiple ppop(PP_LOCAL) calls +10/16/87 change PP_HOSTED to PP_HOSTDIR, add PP_HOSTED and PP_NONHOSTED + add #(BASE) that expands to base name of #(FILE) +10/15/87 for PASSTHROUGH each line of multi-line "..." or '...' is a token +10/14/87 add ppmultiple() for multiple include test ops +10/11/87 delete CONVERTASSIGN -> `=<op>' no longer recognized + delete C++ := -> = conversion + fix COMPATIBILITY macro recursion bug + add `#pragma multiple' equivalent to `#multiple' +10/06/87 split pplex.c adding ppdirective.c and ppbuiltin.c + don't recognize obsolete assignments for PLUSPLUS +10/05/87 fix PLUSPLUS PASSCOMMENTS bug `// */' -> `/* ***/' +10/01/87 allow newlines in ' and " constants for PASSTHROUGH +09/28/87 fix CONVERTCC STRICT bug that omitted octal character constants + add CATLITERAL compile switch for adjacent string literal concatenation + fix "\07" "3" -> "\073" string literal concatenation bug -> "\0073" +09/18/87 complete ppdump() and ppload() checkpoint support +09/17/87 fix macro formal bug that didn't update pointers after realloc() + add PP_DONE complement op to PP_INIT + add SYM_BUILTIN and #pragma pp:builtin to note builtin macros + add PP_DUMP, -D-D and #pragma pp:load checkpoint support +08/20/87 fix bug that omitted some actualsync() calls for '\n' in pp.in->actual +08/19/87 fix pp.linesync==0 && PASSTHROUGH bug that omitted '\n' after "token" +08/11/87 fix #($var) null pointer bug +07/31/87 fix linesync bug for comment after #include in PASSCOMMENTS +07/24/87 add PP_NOPASSTHROUGH +07/16/87 fix predicate missing # ambiguity warning +07/09/87 fix `macro("@*")' bug in expand_special() +06/17/87 fix comment error message check that was off by one line +06/16/87 remove #pragma pp:multiple; add #multiple; retain PP_MULTIPLE +06/08/87 add # operator to disambiguate predicate tests + inhibit more warnings on hosted files + make diagnostics more consistent -- a little more work + PP_READ files and their included files always marked hosted +06/05/87 fix macro actual arg collection with imbedded #include, #line +05/28/87 add `#pragma pp:multiple *' to mark all files multiple + add -D-M for command line equivalent to `#pragma pp:multiple *' +05/01/87 clarify HOSTED and SYM_PREDEFINED +04/24/87 split pplex.c into smaller files -- too big for some compilers + move common wrapper routines into the library + fix ppargs() to cooperate with other option parsers +04/22/87 remove getenv("PPSTANDARD") override of PP_STANDARD +04/21/87 replace yacc parser with recursive expr() from library streval() +04/20/87 add #((<expr>)) expression evaluation on (x) + add #(<sym>=<expr>) to dynamically evaluate macro values +04/11/87 home brew output buffering for PP_STANDALONE -- up to 10% + cleanup +04/10/87 change T_STRING concatenation in preparation for new output buffering +04/09/87 fix character constant conversion warnings +04/07/87 fix \\n and ??/\n bugs in comment scan +04/06/87 add DIGIT, HEX, OCTAL and NONOCTAL case classes to ppdefs.h + use GETCHR() and ISSPECIAL() in outer pplex() loop -- up to 10% + fix macro actual arg count test +04/03/87 add PP_TEST and TEST1, TEST2 to mode for internal tests +04/02/87 delete PPDEFAULT and generalize with PP_READ + note `# <line> "<file>"' as non-standard + add check for malloc() out of space +04/01/87 C specific error messages only if language="C" + C++ specific error messages only if language="C++" +03/31/87 delete command() predicate -- gateway for trojan horse +03/30/87 add dialect() and language() builtin predicates + change in->standard to in->hosted and STANDARD to HOSTED + add PP_HOSTED and change PP_NOSTANDARD to PP_NOHOSTED + ignore #pragma for non-hosted files in STRICT dialect +03/27/87 add predop(); delete pp:plusplus + pp:dialect and pp:language for verification only +03/24/87 ----- first release ----- +03/24/87 ----- first release ----- +03/23/87 allow WARN to apply to all dialects + fix pp:directive `...multiple...' warning + add MAP_NEWLINE to separate multiple pragmas +03/22/87 warn about null macro args for STRICT + add PP_LANGUAGE, `#pragma language [language]' + warn about newline in macro call arguments in directives + warn about directives in macro call arguments for STRICT + validate character constants in #if expressions +03/20/87 add PP_DIRECTIVE and PP_LOCAL + add %I (ignore) map format and allow %X for pragma args +03/19/87 change PP_DEFAULT to PP_STANDARD, add PP_DIALECT + add dialect arg to PP_COMPATIBILITY, PP_DIALECT and PP_STRICT + add `#pragma pp:pragma pass:option format' mapping +03/18/87 delete pp:obsolete; fix `#pragma version' + fixed macro stack frame bug during recursive macro arg expansion + change CONFORMING, PP_CONFORMING to STRICT, PP_STRICT + add `#pragma dialect [dialect]' verification +03/17/87 add PP_NOSTANDARD to disable any special handling of std files + refine mkdefault.sh for sun workstations + remove comma operator from pp.yacc since it implies side effects + add argument type checking for pp:directive and pp:obsolete +03/16/87 refine CONFORMING messages + disambiguate most #assert/#define clashes + add PASSCOMMENT and (*ppcomment)() for old lint fans +03/14/87 #undef in pp:readonly marks id as readonly macro +03/11/87 warn about macros that are predicates in #if expressions + add mode to handle uncoupled flag bit overflow from state +03/04/87 fix COMPATIBILITY to expand a macro in its definition +02/24/87 add gentab.sh and mkdefault.sh to Makefile +02/20/87 add IN_RECURSIVE for proper handling of #(...) +02/16/87 add #unassert; PP_WARN & WARN to note obsolete usage + only recognize directive if # is first char for (state&COMPATIBILITY) + generalize gentab.sh and retrofit pp.tab + change in->name.file to be the name of including file +02/13/87 add pp.tab; PP_PRAGMA "x=y" -> "#pragma x y" + add #(x y...) -> "#x y..." for recursive directive evaluation +02/12/87 #pragma [pass:] [no]option [arg ...] + #pragma pp:[no]directive [pass:]<new-directive> + #pragma pp:id <identifier-character> +02/11/87 distribute post-token switch in pplex() to individual cases (~5%) +02/09/87 clarify invalid numeric token gobble + add VARQUOTE & PP_VARQUOTE for `X...X vs. '...' & "..." constants +02/06/87 change STRICT to CONFORMING; add PP_CONFORMING +02/06/87 change PPBUILTIN to #(<id>) +02/05/87 clarify /*...*/ concatenation for (state&COMPATIBILITY) + add convertcc() to convert new char const to old style + rework # op to work with convertcc() +02/04/87 add =<op> obsolete operators for (state&COMPATIBILITY) +02/02/87 fix expand() to save and restore (state&DISABLE) +12/17/86 first code diff --git a/usr/src/lib/libpp/common/NOTES b/usr/src/lib/libpp/common/NOTES new file mode 100644 index 0000000000..85ab42e74b --- /dev/null +++ b/usr/src/lib/libpp/common/NOTES @@ -0,0 +1,83 @@ +C preprocessor features: + +(1) The preprocessor is centered around the libpp.a library. This + library provides a tokenizing implementation of the preprocessing + stages of ANSI standard C. The same library is used to construct + a standalone prepreprocessor as well as a C compiler front end + that, compiled with the library, eliminates the need for a + separate preprocessing pass. Other C tools requiring C tokenizing + can use this library, providing a common interface to C language + tokens. + +(2) The #pragma interface is exploited to allow the addition of new + directives and #pragma's without changing the preprocessor + executable. Most implementation details can be specified by + directives in the file "ppdefault.h" that is automatically included + (by the standalone cpp library wrapper) as an initialization step. + +(3) #assert, #unassert and corresponding #if predicate tests have been + added to relieve the conflicts introduced by predefined #define + macros (e.g., unix, vax, u3b, ...). This is the same feature + present in the extended Reiser cpp that has been included in the + nmake distribution. (NOTE: #assert is a failed experiment) + +(4) The implementation is sensitive to the incompatible differences + between the Reiser cpp (used by AT&T and BSD compilers) and the new + ANSI standard C. A compatibility dialect implements Reiser + features, allowing for a smooth transition to the ANSI standard. + +(5) To aid in the transition to ANSI, the preprocessor can do some + operations that would normally be done by the lexical analysis + stage of a compiler front end: + + (a) convert new-style character constants to a form + recognized by all current compilers + + (b) concatenate adjacent string literals + +(6) The preprocessor can also warn about obsolete constructs used + in the compatibility dialect and on non-standard constructs + used in the ANSI dialect. The latter is useful in writing + C code that is made to run through other implementations of + ANSI standard C. + +(7) The preprocessor allows a C language implementor to take + advantage of local extensions without invalidating the + conformance of the C language implementation. + +C9X additions: + +(1) #pragma STDC ... + special forms always accecpted + +(2) _Pragma unary operator for pragmas via macro expansion + _Pragma(string-literal) + #pragma a b c + _Pragma("a b c") + +(3) keywords + restrict inline _Bool _Complex _Imaginary + +(4) macros + __STDC_VERSION__ 199901L + __STDC_IEC_559__ 1 or undef + __STDC_IEC_559_COMPLEX__ 1 or udef + __STDC_ISO_10646__ yyyymmL + +(5) empty arguments allowed in function-like macros + +(6) variable arguments via ... + __VA_ARGS__ in replacement list only, expands to var args + only var args is ok (shall only appear in ...) + +(7) hex floating constant with binary exponents + xxxxxx[pP]dddd + +(8) // style comments + +(9) universal characters, even in identifiers! + \uxxxx \Uxxxxxxxx + +(10) LL ll ULL ull suffix for long long literals + +(11) <stdarg.h> has va_copy() diff --git a/usr/src/lib/libpp/common/RELEASE b/usr/src/lib/libpp/common/RELEASE new file mode 100644 index 0000000000..179930e147 --- /dev/null +++ b/usr/src/lib/libpp/common/RELEASE @@ -0,0 +1,432 @@ +06-09-23 ppop.c: check -I <dev,ino> for c and TYPE_HOSTED|TYPE_VENDOR attrs +06-09-23 pplex.c: add HOSTED check for "/* appears in // comment" -- doh +06-09-05 pp.probe: add version stamp comment +06-06-29 pp.probe: gcc pp:linefile probe (otherwise it can dump!) +06-06-28 ppproto.c: fix inappropriate __PARAM__ insertion +06-05-09 pp.tab,ppcontrol.c,ppproto.c: add externalize + ppfsm.c: handle compatibility ul numeric qualifiers +06-02-28 probe.win32: add wchar_t probe +06-01-11 pplex.c: fix rpcgen pp:passthrough header splice bug +05-12-16 pplex.c: fix imake pp:passthrough comment splice bug +05-09-16 pplib.h: add <string.h> for standalone proto +05-07-31 pplib.h: finally trust __STDC__ headers +05-04-11 pplex.c: fix '"a" #s' catliteral + stringize bug +05-03-29 pp.probe: check $? and stderr messages for pp:lineid +05-02-20 probe.win32: handle /platformsdk mount +05-01-11 ppargs.c: fix -I-S docs + ppinput.c: ppproto() only for COMPATIBILITY or PLUSPLUS +04-10-22 ppproto.c: handle `type var[x][y]' arg prototype +04-10-01 pplex.c: really fix directive hidden newline logic +04-08-31 pplex.c: fix directive hidden newline logic + ppcall.c: fix '(' peek bug that missed the MARK +04-08-30 add pragma pp:pragmaflags PP_PRAGMAFLAGS, pp:system_header +04-08-11 ppproto.c: intercept "#(define|undef) extern" for __(EX|IM)PORT__ +04-07-23 probe.win32: generalize #include dir order search +04-07-22 ppsearch.c: access() => eaccess() +04-05-20 ppproto.c: don't __PROTO__ `int fun __P((int));' +04-04-15 probe.win32: sync up with uwin 2003-08-06 master -- oops +04-04-01 pp.probe: add stdinclude usrinclude path cleanup +04-02-29 ppproto.c: fix bug that skipped prototyped check during notices check + ppproto.c: recognize `Copyright nn' +04-02-14 ppproto.c: comment[0]==0 => no notice +04-02-11 Makefile: fix %.yacc to handle cross-compile +04-01-28 pp.h,pplib.h,ppop.c: add PP_RESET to restore original pp.symtab scope +03-12-12 ppcall.c: missing macro actual warned but expanded +03-11-12 ppexpr.c: fix premature #if expression token strip +03-06-21 ppproto.c: fix T_INVALID ? splice bug that did 0?val => 0?vaL +03-06-10 ppargs.c: add -D-d and -D-m + ppargs.c: add gnu options { -dD -dM -imacros -include -lang-* -lint } +03-05-19 pplex.c: fix stray SKIPMACRO bug +03-05-18 ppcall.c: add SYM_FUNCTION '(' peek to avoid inappropriate ungetchr() +03-04-30 pp:mapinclude hosted <std.h>="." will search only hosted dirs + pp.probe: add pp:mapinclude probe for namespace incursions +03-04-29 ignore()=>ppmapinclude(), add pp:mapinclude +03-03-25 ppop.c: PP_RESERVED now deletes old symbol before redef with lex value +03-03-14 pp.probe: fix the #include_next probe +03-02-28 ppsearch.c: fix -MM bug that missed prefix include hosted mark +03-02-18 pplex.c: handle COMPATIBILITY \" and \' in macro actuals +03-01-23 probe.win32: mingw32 tweaks +02-12-17 ppargs.c: document -I-! +02-12-06 -I- pp:noprefix otherwise pp:prefix default +02-11-29 probe.win32: added __INTSIZE, drop dm pp:noallmultiple +02-11-26 pp.def: add STDC_HOSTED + probe.win32: add C95 and C99 STDC predefined macros +02-10-30 ppfsm.h: add boundary check to IDSTATE() +02-10-18 probe.win32: update for mingw +02-10-15 ppsearch.c: if PLUSPLUS && not found && no suffix then try with .h +02-10-10 pplex.c: fix does not end with `newline' bugs +02-10-01 ppop.c,ppargs.c: -I-I => -I-M with proper docs; -I-I for PP_IGNORE +02-09-21 pp.probe: add pp:nocatliteral test +02-09-10 pp.tab: add pp:passthrough to match -D-P docs +02-08-30 probe.win32: fix for borland cc -E +02-08-22 ppexpr.c: add __SOURCE__ and #match(string,pattern) +02-06-25 ppproto.c: fix pragma search bug that stopped after 8 comment lines +02-06-11 ppsearch.c: fix ... next include search to skip *all* intermediates +02-05-28 probe.win32: updates for { mingw } + ppsearch.c: don't use inherited prefix for <...> -- duh +02-05-24 ppcontrol.c: simplify getline() space canonicalization + probe.win32: updates for { digital-mars borland lcc } +02-05-20 ppcontrol.c: update to use regsubcomp(),regsubexec() +02-05-09 ppcontrol.c: inhibit `EOF in directive': newline warning will catch it + pplex.c: inhibit `newline in character constant' for hosted directives +02-05-06 probe.win32: add more win32 compilers +02-04-15 probe.win32: handle long long unsigned int +02-04-12 ppproto.c: fix NOTICED check +02-03-15 ppproto.c: fix cpp pp:compatibility double line sync memory fault +02-03-11 pplex.c: add pp:modern to emit \a \v instead of octal forms +02-02-14 ppargs.c: fix -D or -U as last arg core dump +02-01-24 pplib.h: use vmalloc(Vmregion) if _std_malloc +02-01-23 probe.win32: add more msvc predefined macro candidates +02-01-14 ppproto.c: #pragma prototyped noticed -- has notice comment +02-01-10 ppproto.c: fix PROTO_FORCE|PROTO_PASS bug that disabled PROTO_FORCE +02-01-08 pplex.c: fix HEADEREXPAND|HEADEREXPANDALL logic +01-11-22 pplex.c: add pp:headerexpandall for gcc vs. msvc <...> expand diff + pp.probe: add pp:headerexpandall test +01-10-20 pplex.c: fix pp:splicespace inside "..." +01-09-11 ppinput.c: use pathnative() for native fs representation +01-08-31 pp.probe: handle -Dmacro(args)=value +01-08-11 ppcontrol: fix ... and __VAR_ARGS__ for C99 + ppsearch: fix SEARCH_NEXT bug that skipped the include stack +01-08-06 ppproto: preserve #! first line for # comments +01-07-17 gentab.sh: fix ksh test to omit pdksh (typeset -u fails) +01-06-26 ppproto.c: fix another buffer boundary bug that didn't preserve OTHER +01-06-06 ppsearch.c: list PP_FILEDEPS headers once +01-06-01 pp.h,ppop.c,ppsearch.c: allow multiple PP_FILEDEPS (-M) +01-05-24 pp.probe: fix pp:hostedtransition probe: only suncc can __STDC__==1? +01-04-25 pp.probe: split macro probe files for compilers that have #line limits +01-04-19 pp.h,pplex.c,ppproto.c: fix { \a \E \v } EBCDIC translations +01-04-16 pp.tab: add pp:splicespace for mvs jcl decks -- the 60's live on +01-04-13 ppbuiltin: add __FUNCTION__ cache for functions that span the buffer +01-03-08 pp.tab,ppbuiltin,ppcontrol,probe: add pp:hostedtransition +01-02-22 pp.tab,ppfsm,pplex,pp.probe,probe.win32: add pp:zeof for ^Z => EOF +01-02-14 ppcall.c: fix macro(tuple*) bug that truncated macro arg expand buffer + pplex.c: fix # inside pp:pragmaexpand + gentab.sh: change ksh test for openbsd /bin/sh + ppproto.c: fix buffer boundary bug that lost call nesting + ppproto.c: add realloc prototype and memcpy=>memcopy strcpy=>strcopy +01-02-09 ppsearch.c: fix another pp.include null dereference +01-02-07 ppcall.c: fix stack inequality checks + ppcall.c: handle trailing \ in macro args +01-02-06 fix readonly buffer write (cpp test 07:2873) +01-02-04 fix -M* to properly handle .cxx .cpp .C input + fix IN_BUFFER pop bug that did not reset the token pointer +01-01-01 pp:headerexpand: space ok if not IN_MACRO + ppcall: hide if IN_FILE|IN_MACRO|IN_EXPAND + pplex: don't complain about ^L or ^Z as last char in file + ppsearch: fix #include <.../foo.h> loop + ppcontrol: manulally increment IN_RESCAN error_info.line +00-12-25 add EXPOSE to expose hidden macros (for #import ...) + probe.win32: add cc path *and* args to first line to avoid hash clash + pp.probe: filter out invalid symbols for predefined macro scan, duh + pp:headerexpand: limit expansion to IN_MACRO +00-10-31 __STDC__==0 if HOSTED && _UWIN +00-10-26 pplib.h: change SEEK_SET to O_RDONLY for aix +00-10-17 pp.probe: __IMPORT__ => __STDPP__IMPORT__ +00-09-18 add __FUNCTION__=#(FUNCTION), #define <a b> c + pp.probe: add probe_longlong + probe.win32: add #define <long long> +00-09-11 add pp:noproto (NOPROTO pp.option) to disable ppproto() +00-09-01 ppproto: fix buffer slide bug +00-08-11 pplb.h: check for <unistd.h> already included for PROTOMAIN + pragma: add pp:pragmaexpand to expand pragma args + ppcontrol: always disable pp:* pragma expansion + ppcall: fix pp:hide buffer clash +00-06-01 pplex: fix "\\U" and "\\u" +00-05-22 ppsearch: fix uwin #include <C:/foo/bar.h> +00-05-16 probe.win32: update reserved word list +00-05-09 ppcontrol: fix C++ macro >+> invalid fuse + ppcontrol: 'macro' expansion only for COMPATIBILITY | TRANSITION + c9x: up to date with proposed standard +00-04-01 pp.tab: add allpossible and ALLPOSSIBLE + ppmacref: fix ref inside literal catenation +00-02-14 pppopen(): general comments with "bme" (begin middle end) string +00-01-11 pp.probe: hosttype now in C.probe +99-11-19 is[a-z]*( => ppis[a-z]*( + ppproto: "..." [A-Z_]+ "..." ignores [A-Z_]+ if PROTOMAIN +99-11-11 ppproto: use astlicense() +99-10-31 ppproto: add PROTO_SHARP, update license parse + pplex: fix some MARK bugs seen by #define X "A B <C@D>" +99-10-01 add pp:stringsplit for "...\\n..." => "..."\n"..." + add pp:lineid to match PP_LINEID +99-07-17 ppbuiltin: fix getline() canon spacing for numbers + ppsearch: fix FILEDEPS not found \\n print + pplex: fix spurious FILEDEPS '.' empty character constant message + ppargs: fix usage error call and error_info.id default value + ppproto: fix up copyright notice for ksh93 style .author file + ppproto: check if notice text if file path +99-06-02 ppproto: add __MANGLE_package_DATA__ & __MANGLE_package_FUNC__ +99-05-26 ppcontrol: all pragmas but prototyped need pp: +99-05-25 ppargs: long options +99-05-22 ppproto: changes for full ast vs. PROTO_STANDALONE +99-05-09 ppinput: add #pragma pp:native and (pp.option&NATIVE) for native paths +99-04-22 ppproto: finish type=open notice +99-02-11 #define __STDC__ #(STDC); demote __STDC__ to 0 for HOSTED (thanks sun) +99-02-04 pplex: joined strings separated by \\\n +99-01-11 probe.win32: add _UWIN predef +98-10-20 pplex: a few more (HOSTED|RELAX) checks + -D:preserve throws a bunch of stuff -- great for imake (yuk) +98-05-11 pplex: fix "..." \n off by one line count +98-02-14 ppcontrol: fix HEADEREXPAND missing NUL +98-01-23 ppproto: add _GNUC_ to _WIN32 check + ppfsm: don't optimize for hp.pa +97-11-11 ppcontrol: fix recursive use of pp.hdrbuf for HEADEREXPAND +97-10-31 ppmacref,pp.h: add ppmacref sum arg -- some parts assumed it! +97-10-01 pplex: loosen HEADEREXPAND check +97-08-11 pplex: fix COMPILE pplex() bug that did not reset NEWLINE for S_MACRO + pplex: PP_PRESERVE does not pp.pragma <token> ... # <pragma-stuff> + pp.def: add UWIN + ppcall: fix macro actual arg error checks +97-07-17 ppproto.c: C++ __INLINE__ prefixed with extern __MANGLE__ + ppop.c: fix PP_RESERVED T_* lookup +97-05-09 pp.def: add MVS :architecture: + ppfsm.c: change C_* pseudo codes to not clash with ebcdic + pp.probe: fix stdc.$src sed script +97-04-01 ppcontrol.c: fix tokop() for PP_RESERVED +96-12-25 add ms #@ charize to complement # stringize + pp.probe now detects preincludes + ppproto: allow #ifdef'd function definions before { + ppproto: NoN() is not a function + pp.key,ppkey.h: add int64 + ppargs.c: fix -M{DGM}* +96-12-06 add pp:headerexpand for ms that expands macros in expanded <...> +96-10-31 a few more line sync tweaks for EDG C++ +96-10-11 fix pp:macref off by one for standalone pp (big suprise) +96-10-01 -D:macref -D-L -> #line (n-2)\n#pragma pp:macref ... +96-08-11 fix transition macro expansion + compatibility \" or \' does not start quote +96-02-29 use <hashkey.h> + drop ungetchr() in ppcall that modified macro values + tighten the DEBUG PANIC case in ppcontrol.c + unify #architecture() and #machine() probe + add POSIX,WIN32,X86 to pp.sym + tweak pp.probe +96-02-14 pp:noallmultiple works on hosted files too + fix #define /* EOF loop +96-01-31 fix ## as arg to stringize macro to have ## value, not # + add nonstopux and SYSTYPE_SVR4 to pp.def +96-01-01 AT&T Research now + fix catliteral line sync line number bug + ppproto() converts non-directive <num>u to (unsigned)<num> + switch to <regex.h> +95-10-31 fix PP_COMPILE PP_TRANSITION bug that didn't allow space before # + fix PP_TRANSITION \newline in definition complaint +95-10-11 fix ppproto() PROTO_PLUSPLUS bug + change ignored pp.incref PP_SYNC_POP to PP_SYNC_IGNORE + add PP_PEDANTIC to handle gnu oversights (can't beat em ...) + add memfatal() call + relax newline in quote semantics + proto inline -> __INLINE__ + fix __INLINE__ proto def for __GCC__>=2 +95-08-11 pp:preserve for easel (aka IFS) and imake + fix pp:reguard ## macro output + fix MARK PANIC with CATLITERAL + PP_INPUT *.(s|S|as|AS|asm|ASM) implies pp:nocatliteral pp:spaceout + ppargs() can't use isid() until after FSM_INIT + -D#... for assert, -D%... for directives + __STRICT_ANSI__ && __GNUC__ requires -pedantic for PP_STRICT + #include <.../x> for include_next +95-05-09 fix tokop() bug that concatenated adjacent strings + don't concatenate directive string literals in proto + split pp.mode into pp.mode and pp.option + restrict pp.probe hostinfo output to the first token + fix EOB/EOF pplex() nonterminating loop + unused var cleanup + add pp:reguard to emit #define and #undef (for C++ templates) + add a few ppproto '\r's for NT + fix T_BUILTIN ppsymbol -> ppsymkey pun + fix pp:stringspan `#define x "' hang +95-04-01 fix pp:hide for macros defined before the hide + fix pp:map getline space canonicalization + fix proto `<digits>[uU]' + proto does // comments by default (fixes bug introduced 07/17/94) + proto does "..." "..." string literal concatenation + spice up proto copyright comments for nonexclusive license + add hosttype assertion + fix proto `typedef type fun(args)' + proto copyright finishing touches + fix overzealous "empty character constant" message +95-02-14 pp:nopredefined probe info defines are now pp:builtin + clean up pp:hosted conflicts + tighten up unknown directive warning + PP_INPUT *.(s|as|AS|asm|ASM) implies pp:nocatliteral pp:spaceout + change newof(0,char,n,0) to newof(0,char,0,n) if 0 init not needed + don't emit unkown directives inside #if 0 ... #endif +95-01-19 *strict-* does not force STRICT + token##null-last-variadic-arg consumes token (to match gcc) + variadic actuals call be one less than arity (to match gcc) + fix PLUSPLUS digraph bug that lost comment state + tighten up PLUSPLUS //, /*, */ interaction warnings + macro formals in "..." for COMPATIBILITY|TRANSITION + macro formals in '...' for COMPATIBILITY|TRANSITION|!STRICT + STRINGSPAN allows '\n' in '... too + add PP_SYNC_* flags for pp.incref arg 3 + add PP_SYNC_INSERT for invented file references + fix C++ fsm bug that popped out of comment in // /* */ ... + PP_INPUT *.(s|S|asm|ASM) implies pp:nocatliteral pp:spaceout +95-01-01 avoid string literal concatenation in pp.probe #if #predicate() tests + fix pplib.h memcpy,strncmp PROTOMAIN prototypes (its a nop tho) +94-11-11 fix readonly memory reference in refill + add C++ digraphs (digraph = --trigraph) + add C++ T_EXPLICIT -- did dos take over C++? + fix improper ppproto() C++ __PARAM__ expansion +94-11-01 allow #include string header arg concatenation (yes, its not ansi) + #macdef macros are recursive +94-10-01 fix C++ } loop in ppfsm/refill + T_NOISES consumes symbol and optional paren group + __builtin_* T_NOISES by default + fix "..." "...MARK..." join + fix STANDALONE */*comment*/ +94-09-11 fix pp.probe cp+strip with chmod u+w +94-08-11 add -I<vdb-archive> to handle pax -x ppar header archives + fix -D-Q header checkpoints + add `pp:chop prefix' to chop prefix/ from include prefix/*/* + add pp:keyargs for key=value macro formals/actuals (not for C!) +94-06-01 fix ppcontrol/tokop() that botched pp:id, etc. + add pp:plussplice to handle cfront // \<newline> ignorance + inhibit trigraph conversion for pp:compatibility, duh + new C++ keywords enabled by pp:keyword + proto: int fun xxx((yyy)) is macro call, not decl + fix !ALLMULTIPLE pp:load to SKIP between duplicated line syncs + fix PP_DUMP for pp:noallmultiple, optimize pp:load format + fix CPP CACHEOUTX() buffer boundary bug +94-04-01 drop warnings for -X* + fix ppproto() %% in comment bug for yacc proto + PP_COMMENT now truncates comments to MAXTOKEN-4 +94-03-01 no pp:truncate for #pragma pp:macref +94-01-01 fix STANDALONE+PP_TRUNCATE fsm macro bug + drop __VOID__ from ppproto.c +93-12-01 release +93-11-11 fix PP_COMPILE+PP_TRUNCATE=8 bug for continue,unsigned,etc. + add PP_LINEBASE for compilers that botch long line sync paths + fix #if unsigned promotions + aggressive interactive line splice flush + fix #else inside multiline null dereference + fix "..." newline space # COMPATIBILITY CATLITERAL bug + fix m(a)b compatibility token pasting [cpp/test/ess.01.c] + fix nested @X mark bug [cpp/test/net.02.c] +93-10-11 add FSM_COMPATIBILITY for floating point hex -- yo ansi, anybody home + add #else if|ifdef|ifndef for COMPATIBILITY but with warning + drop PP_HOSTED, add ppop(PP_CDIR|PP_HOSTED,"-",n), -D-I for pp:cdir +93-10-01 add pp:opspace to tokenize <binop><space>= to <binop>= +93-08-11 drop ancient BCD constant (`...`) detection -- wake up cfront + fix PP_TRUNCATE macro fsm bug that missed some expansions + fix stringize bug that choked if space preceded # + fix <function-like-macro> <identifier> bug that omitted space +93-07-17 minor transition mode fix for string concatenation + fix standalone macdef line sync buffer bug + pp:noline turns off linesync, pp:line restores it +93-06-22 add pp:prefix to control prefix include compatibility +93-04-01 use probe_verbose in predefined symbol probe +93-03-11 close fd after last file block read -- relaxes open fd limit + remove pp.control nesting limit + add `#rename old new' + __STDC__ not defined for plusplus (until they figure it out) +93-01-22 fix ansi macro args recursion bug +93-01-11 fix '\377'<0 for signed char compilers + add RELAX for __STDPP__directive directives +92-12-25 fix #include guard test that omitted IN_tokens for CPP=1 +92-12-11 fix pp:truncate for STANDALONE and COMPILE + fix pp:allmultiple again! +92-11-30 add pp:final, pp:initial + add __STDPP__directive and #(directive) as ??= alternative + relax obsolete macro expand warning for _xxx||xxx + retain quoted \newline when PP_LINEID != "" + fix CATLITERAL hidden newline line sync +92-11-11 fix COMPATIBILITY EOF in macro arg list and # in macro body + fix [?\] on 4K buffer boundary bug that lost next refill() + fix ppproto bug that botched -ih comments +92-10-31 fix standalone -C bug that duplicated output buffer + add pp:stringspan to handle gnu "<newline>" extension +92-10-12 fix T_X_GROUP asm bug + allow `#define a "b' pp:compatibility hack +92-08-11 add PP_PLUSCOMMENT, pp:pluscomment probe + add #(default v,d) #(empty v) #(iterate m,...) + compatibility allows #define f(a,,b) for 2 args! + probe now handles gcc -E -g3 to get gnu predefines +92-07-17 fix pp:multiple again, fix ppproto() out of bounds + PP_STANDARD is always PP_CDIR and PP_HOSTED +92-07-11 add #import and #include_next probes +92-06-11 fix bug where comments dissappeared after disabled macro in standalone + COMPATIBILITY macro recursion bug fix may cause some to be missed + PP_MACREF or -D-L- ignores #line until #line with file arg +92-06-01 add pp:ignore + fix probe of stdpp to handle -I[-+][CH] +92-05-11 add pp:hide <id>, pp:note <id>, noticed(<id>), exists(<...>) + add defined(__STDPP__<pragma>) feature test + add PP_CDIR, pp:cdir for C++ extern "C" { ... } include wrapping + pp.probe now handles predefines with values other than 1 +92-04-11 add inverse proto (K&R -> prototype) to ppproto +92-04-01 release +92-02-29 #include <...> inside <xxx.h> gets next xxx.h on -I list + non-libpp generated symbols containing ' ' are not truncated +92-02-11 conversion to new lexer brings time close to reiser (esp. w/gcc -O) + combine standalone (ppcpp) tokenizing (pplex) and proto lex tables + recode ppproto for standalone operation via PROTOMAIN + add PP_NOHASH for PP_COMPILE front ends that rehash T_ID anyway + delete PP_NOQUOTE + delete #option(strict) test in probe in favor of non-hosted warnings + add unsigned to ppexpr() +91-10-11 add pp:truncate <len> for non-flexname compilers +91-09-11 fix ppproto aggression on f(*y); -> f __PROTO__((*y)); +91-08-11 switch seterror() to error_info.* + add pp:linefile to force file name in line sync + add pp:spaceout for probed compilers that don't allow pp override +91-06-11 fix ignored -I/usr/include bug +91-04-11 set SYM_INIT in pp.macref for -U on cmd line +91-01-31 replace pp:pragma and pp:directive with pp:map + replace #assert and #unassert with #define #... and #undef #... + #assert and #unassert compatibility retained via pp:map + replace -D#directive with -D%directive (because of #assert change) + add pp:splicecat for \<newline> #define token paste + fix \<newline> bug that added space in COMPATIBILITY quoted strings +90-12-11 fix #pragma pp:multiple +90-11-11 generalize handling of non-standard keywords for COMPILE + replace pp:identifier/PP_IDENTIFIER with pp:reserved/PP_RESERVED + pp*keys* -> ppkey + add PP_NOISE + (gag) handle msdos paths by changing \ to / and retrying on failure + (gag) handle msdos :> operator by pplex() '+' return + add #pragma prototyped and ppproto.c for prototype conversion + add unsigned long arg to PP_MACREF for hashed macro arity+value +90-10-11 0f is not a float constant + change -I-M to -I-I, file just lists include files to be ignored + fix ppprobe for __STDC__==0 hybrids + add pp.flags and PP_[a-z0-9]+ for exported state info +90-10-01 fix standalone ppmacref for directives + add `try' to C++ keywords + fine tune a few COMPILE error messages + privatize pp.h +90-08-11 use opt_again in cmdargs() option parsers + (gag) add pp:macref macro reference pragma to handle CC preprocessors + (gag) add pp:spaceout to handle ansi + asm hacks +90-07-17 remove spaces from macdef line sync (blew sun cc) +90-06-11 add internal ppsymkey to avoid ppsymbol.value pun for SYM_KEYWORD +90-05-01 fix catliteral bug of `"..." << ' -> `"..." <=' +90-04-01 fix `ifndef-define-endif' include wrapper test +90-03-27 add setpreroot() to ppop() [ sleazy but well hidden ] +90-03-22 pp.macref called for all undef's +90-03-20 add <prefix>cpp checks to ppprobe + add pp:hostdir before pp:include in ppprobe + fix PP_HOSTDIR op with no dir arg +90-03-15 System V CCS compatibility update + add PP_ASSERT + add -A for PP_ASSERT and -YI,dir for PP_STANDARD + add ppincref.c and -H to use it + -Xa defines __STDC__ to 0 (gak) +90-03-09 duplicate macro formals cause level 2 error +90-03-01 add #(ARGC) for (variadic) macro arg count +90-02-11 fix line sync number bug in pppush() +89-12-01 ignore leading = in pragma map for old pragma compatibility + check for NEWLINE on first macdef line sync +89-11-11 add -1 arg to pp.incref -- include skipped + STRICT 0x7e-macro is T_INVALID per standard +89-10-31 put all C keys in ppckeys.c, C++ keys in pppkeys.c + add pp:identifier pragma to selectively undo PP_COMPILE keywords + add tokop() to ppcontrol to support multi-valued pragmas + add #ifndef...#endif include optimization for STRICT +89-10-27 use REF_NORMAL, REF_IF, REF_UNDEF for pp.macref arg2 +89-10-17 fix c(x)y compatibility pasting bug + #line 1 "f" now marks "f" included +89-10-11 enable -I. during initialization +89-10-01 inhibit pp:linetype syncs for top level #line directives + ----- see HISTORY ----- diff --git a/usr/src/lib/libpp/common/gentab.sh b/usr/src/lib/libpp/common/gentab.sh new file mode 100644 index 0000000000..0234ce6c93 --- /dev/null +++ b/usr/src/lib/libpp/common/gentab.sh @@ -0,0 +1,234 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1986-2007 AT&T Knowledge Ventures # +# and is licensed under the # +# Common Public License, Version 1.0 # +# by AT&T Knowledge Ventures # +# # +# A copy of the License is available at # +# http://www.opensource.org/licenses/cpl1.0.txt # +# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# Glenn Fowler <gsf@research.att.com> # +# # +######################################################################## +: +# Glenn Fowler +# AT&T Bell Laboratories +# +# @(#)gentab (gsf@research.att.com) 07/17/94 +# +# C table generator +# +# %flags [ prefix=<prefix> ] [ index=<index> ] [ init=<init> ] +# +# %keyword <name> [ prefix=<prefix> ] [ index=<index> ] [ init=<init> ] [ first=<id> ] [ last=<id> ] +# +# %sequence [ prefix=<prefix> ] [ index=<index> ] [ init=<init> ] +# + +case `(typeset -u s=a n=0; ((n=n+1)); print $s$n) 2>/dev/null` in +A1) shell=ksh + typeset -u ID + typeset -i counter err_line + ;; +*) shell=bsh + ;; +esac +command=$0 +counter=0 +define=1 +err_line=0 +type="" +index="" +first="" +last="" +table=1 +while : +do case $1 in + -d) table=0 ;; + -t) define=0 ;; + *) break ;; + esac + shift +done +case $1 in +"") err_file="" + ;; +*) exec <$1 + err_file="\"$1\", " + ;; +esac +while read line +do case $shell in + ksh) ((err_line=err_line+1)) ;; + *) err_line=`expr $err_line + 1` ;; + esac + set '' $line + shift + case $1 in + [#]*) echo "/*" + while : + do case $1 in + [#]*) shift + echo " * $*" + read line + set '' $line + shift + ;; + *) break + ;; + esac + done + echo " */" + echo + ;; + esac + eval set '""' $line + shift + case $1 in + "") ;; + %flags|%keywords|%sequence) + case $define:$last in + 1:?*) case $shell in + ksh) ((n=counter-1)) ;; + *) n=`expr $counter - 1` ;; + esac + echo "#define $prefix$last $n" + ;; + esac + case $type in + %flags|%sequence) + if test $define = 1 + then echo + fi + ;; + %keywords) + if test $table = 1 + then echo " 0, 0" + echo "};" + echo + elif test $define = 1 + then echo + fi + ;; + esac + case $index in + ?*) eval $index=$counter ;; + esac + type=$1 + shift + name="" + prefix="" + index="" + init="" + first="" + last="" + case $type in + %keywords) + case $1 in + "") echo "$command: ${err_file}line $err_line: $type table name omitted" >&2 + exit 1 + ;; + esac + name=$1 + shift + if test $table = 1 + then echo "$name"'[] =' + echo "{" + fi + ;; + esac + eval "$@" + case $init in + "") case $type in + %flags|%sequence) + init=0 + ;; + *) init=1 + ;; + esac + ;; + esac + case $index in + "") counter=$init + ;; + *) eval value=\$$index + case $value in + "") counter=$init ;; + [0123456789]*) counter=$value ;; + esac + ;; + esac + case $define:$first in + 1:?*) echo "#define $prefix$first $counter" ;; + esac + ;; + %*) echo "$command: ${err_file}line $err_line: $1: unknown keyword" >&2 + exit 1 + ;; + *) while : + do case $1 in + "") break + ;; + *) case $shell in + ksh) ID=${1#[!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]} ;; + *) ID=`echo $1 | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ | sed 's/^[^ABCDEFGHIJKLMNOPQRSTUVWXYZ_]//'` ;; + esac + case $type in + %flags) if test $define = 1 + then case $counter in + 32) echo "$command: ${err_file}line $err_line: warning: $1: too many flag bits" >&2 ;; + 1[56789]|[23][0123456789]) long=L ;; + *) long= ;; + esac + echo "#define $prefix$ID (1$long<<$counter)" + fi + ;; + %keywords) + if test $define = 1 + then echo "#define $prefix$ID $counter" + fi + if test $table = 1 + then echo " \"$1\", $prefix$ID," + fi + ;; + %sequence) + if test $define = 1 + then echo "#define $prefix$ID $counter" + fi + ;; + esac + case $shell in + ksh) ((counter=counter+1)) ;; + *) counter=`expr $counter + 1` ;; + esac + shift + ;; + esac + done + ;; + esac +done +case $define:$last in +1:?*) case $shell in + ksh) ((n=counter-1)) ;; + *) n=`expr $counter - 1` ;; + esac + echo "#define $prefix$last $n" + ;; +esac +case $type in +%keywords) + if test $table = 1 + then echo " 0, 0" + echo "};" + fi + ;; +esac +exit 0 diff --git a/usr/src/lib/libpp/common/llib-lpp b/usr/src/lib/libpp/common/llib-lpp new file mode 100644 index 0000000000..d3df1ce176 --- /dev/null +++ b/usr/src/lib/libpp/common/llib-lpp @@ -0,0 +1,53 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * lib/libpp/common/llib-lpp + * + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/*LINTLIBRARY*/ +/*PROTOLIB1*/ + +#include "pp.h" + +/* automatically generated data start here */ +extern struct ppglobals pp; +extern char ppctype[]; +extern int ppargs(char**, int); +extern void ppcpp(void); +extern void ppcomment(char*, char*, char*, int); +extern void* ppcontext(void*, int); +extern void pperror(int, ...); +extern void ppincref(char*, char*, int, int); +extern void ppinput(char*, char*, int); +extern int pplex(void); +extern void ppline(int, char*); +extern void ppmacref(struct ppsymbol*, char*, int, int, unsigned long); +extern void ppop(int, ...); +extern void pppragma(char*, char*, char*, char*, int); +extern int ppprintf(char*, ...); +extern int ppsync(void); +/* end of automatically generated data */ diff --git a/usr/src/lib/libpp/common/pp.3 b/usr/src/lib/libpp/common/pp.3 new file mode 100644 index 0000000000..988185bd24 --- /dev/null +++ b/usr/src/lib/libpp/common/pp.3 @@ -0,0 +1,890 @@ +.fp 5 CW +.de L \" literal font +.ft 5 +.if !\\$1 \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \f1 +.. +.de LR +.}S 5 1 \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" +.. +.de RL +.}S 1 5 \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" +.. +.de EX \" start example +.ta 1i 2i 3i 4i 5i 6i +.PP +.RS +.PD 0 +.ft 5 +.nf +.. +.de EE \" end example +.fi +.ft +.PD +.RE +.PP +.. +.TH PP 3 +.SH NAME \" @(#)pp.3 (gsf@research.att.com) 04/01/92 +pp \- ANSI C preprocessor library +.SH SYNOPSIS +.EX +:PACKAGE: ast +#include <pp.h> +%include "pptokens.yacc +\-lpp +.EE +.SH DESCRIPTION +The +.I pp +library provides a tokenizing implementation of the C language preprocessor +and supports K&R (Reiser), ANSI and C++ dialects. +The preprocessor is comprised of 12 public functions, +a global character class table accessed by macros, and +a single global struct with 10 public elements. +.PP +.I pp +operates in two modes. +.I Standalone +mode is used to implement the traditional standalone C preprocessor. +.I Tokeinizing +mode provides a function interface to a stream of preprocessed tokens. +.I pp +is by default ANSI; the only default predefined symbols are +.L __STDC__ +and +.LR __STDPP__ . +Dialects (K&R, C++) and local conventions are determined by +compiler specific +.IR probe (1) +information that is included at runtime. +The +.I probe +information can be overridden by providing a file +.L pp_default.h +with pragmas and definitions for each compiler implementation. +This file is usually located in the compiler specific +default include directory. +.PP +Directive, command line argument, option and pragma syntax is described in +.IR cpp (1). +.I pp +specific semantics are described below. +Most semantic differences with standard or classic implementations are in the +form of optimizations. +.PP +Options and pragmas map to +.L ppop +function calls described below. +For the remaining descriptions, +``setting \f5ppop(PP_\fP\fIoperation\fP\f5)\fP'' +is a shorthand for calling +.L ppop +with the arguments appropriate for +\f5PP_\fP\fIoperation\fP. +.PP +The library interface describes only the public functions and struct elements. +Static structs and pointers to structs are provided by the library. +The user should not attempt to allocate structs. +In particular, +.L sizeof +is meaningless for +.I pp +supplied structs. +.PP +The global struct +.L pp +provides readonly information. +Any changes to +.L pp +must be done using the functions described below. +.L pp +has the following public elements: +.TP +.L "char* version" +The +.I pp +implementaion version string. +.TP +.L "char* lineid" +The current line sync directive name. +Used for standalone line sync output. +The default value is the empty string. +See the +.L ppline +function below. +.TP +.L "char* outfile" +The current output file name. +.TP +.L "char* pass" +The pragma pass name for +.I pp. +The default value is +.LR pp . +.TP +.L "char* token" +The string representation for the current input token. +.TP +.L "int flags" +The inclusive or of: +.RS +.TP +.L PP_comment +Set if +.L ppop(PP_COMMENT) +was set. +.TP +.L PP_compatibility +Set if +.L ppop(PP_COMPATIBILITY) +was set. +.TP +.L PP_linefile +Set if standalone line syncs require a file argument. +.TP +.L PP_linetype +Set if standalone line syncs require a third argument. +The third argument is +.L 1 +for include file push, +.L 2 +for include file pop and null otherwise. +.TP +.L PP_strict +Set if +.L ppop(PP_STRICT) +was set. +.TP +.L PP_transition +Set if +.L ppop(PP_TRANSITION) +was set. +.RE +.TP +.L "struct ppdirs* lcldirs" +The list of directories to be searched for "..." include files. +If the first directory name is "" then it is replaced by the +directory of the including file at include time. +The public elements of +.L "struct ppdirs" +are: +.RS +.TP +.L "char* name" +The directory pathname. +.TP +.L "struct ppdirs* next" +The next directory, +.L 0 +if it is the last in the list. +.RE +.TP +.L "struct ppdirs* stddirs" +.L pp.stddirs\->next +is the list of directories to be searched for <...> include files. +This list may be +.LR 0 . +.TP +.L "struct ppsymbol* symbol" +If +.L ppop(PP_COMPILE) +was set then +.L pp.symbol +points to the symbol table entry for the current identifier token. +.L pp.symbol +is undefined for non-identifier tokens. +Once defined, an identifier will always have the same +.L ppsymbol +pointer. +If +.L ppop(PP_NOHASH) +was also set then +.L pp.symbol +is defined for macro and keyword tokens and +.L 0 +for all other identifiers. +The elements of +.L "struct ppsymbol" +are: +.RS +.TP +.L "char* name" +The identifier name. +.TP +.L "int flags" +The inclusive or of the following flags: +.PD 0 +.RS +.TP +.L SYM_ACTIVE +Currently being expanded. +.TP +.L SYM_BUILTIN +Builtin macro. +.TP +.L SYM_DISABLED +Macro expansion currently disabled. +.TP +.L SYM_FUNCTION +Function-like macro. +.TP +.L SYM_INIT +Initialization macro. +.TP +.L SYM_KEYWORD +Keyword identifier. +.TP +.L SYM_LOADED +Loaded checkpoint macro. +.TP +.L SYM_MULTILINE +.L #macdef +macro. +.TP +.L SYM_NOEXPAND +No identifiers in macro body. +.TP +.L SYM_PREDEFINED +Predefined macro. +.TP +.L SYM_PREDICATE +Also a +.L #assert +predicate. +.TP +.L SYM_READONLY +Readonly macro. +.TP +.L SYM_REDEFINE +Ok to redefine. +.TP +.L SYM_VARIADIC +Variadic function-like macro. +.TP +.L SYM_UNUSED +First unused symbol flag bit index. +The bits from +.L (1<<SYM_UNUSED) +on are initially unset and may be set by the user. +.RE +.PD +.TP +.L "struct ppmacro* macro" +Non-zero if the identifier is a macro. +.L "int macro\->arity" +is the number of formal arguments for function-like macros and +.L "char* macro\->value" +is the macro definition value, a +.L 0 +terminated string that may contain internal mark sequences. +.TP +.L "char* value" +Initially set to +.L 0 +and never modified by +.IR pp . +This field may be set by the user. +.RE +.TP +.L "Hash_table_t* symtab" +The macro and identifier +.L "struct ppsymbol" +hash table. +The +.IR hash (3) +routines may be used to examine the table, with the exception that the +following macros must be used for individual +.L pp.symtab +symbol lookup: +.RS +.TP +.L "struct ppsymbol* ppsymget(Hash_table_t* table, char* name)" +Return the +.L ppsymbol +pointer for +.LR name , +0 if +.L name +not defined. +.TP +.L "struct ppsymbol* ppsymset(Hash_table_t* table, char* name)" +Return the +.L ppsymbol +pointer for +.LR name . +If +.L name +is not defined then allocate and return a new +.L ppsymbol +for it. +.RE +.RE +.PP +Error messages are reported using +.IR error (3) +and the following globals relate to +.IR pp : +.TP +.L "int error_info.errors" +The level 2 error count. +Error levels above 2 cause immediate exit. +If +.L error_info.errors +is non-zero then the user program exit status should also be non-zero. +.TP +.L "char* error_info.file" +The current input file name. +.TP +.L "int error_info.line" +The current input line number. +.TP +.L "int error_info.trace" +The debug trace level, +.L 0 +by default. +Larger negative numbers produce more trace information. +Enabled when the user program is linked with the +.B \-g +.IR cc (1) +option. +.TP +.L "int error_info.warnings" +The level 1 error count. +Warnings do not affect the exit status. +.PP +The functions are: +.TP +.L "extern int ppargs(char** argv, int last);" +Passed to +.IR optjoin (3) +to parse +.IR cpp (1) +style options and arguments. +The user may also supply application specific option parsers. +Also handles non-standard options like the sun +.L \-undef +and GNU +.LR \-trigraphs . +Hello in there, ever here of +.IR getopt (3)? +.TP +.L "extern void ppcpp(void);" +This is the standalone +.IR cpp (1) +entry point. +.L ppcpp +consumes all of the input and writes the preprocessed text to the output. +A single call to +.L ppcpp +is equivalent to, but more efficient than: +.EX + ppop(PP_SPACEOUT, 1); + while (pplex()) + ppprintf(" %s", pp.token); +.EE +.TP +.L "extern int ppcomment(char* head, char* comment, char* tail, int line);" +The default comment handler that passes comments to the output. +May be used as an argument to +.LR ppop(PP_COMMENT) , +or the user may supply an application specific handler. +.L head +is the comment head text, +.L "/*" +for C and +.L "//" +for C++, +.L comment +is the comment body, +.L tail +is the comment tail text, +.L "*/" +for C and +.B newline +for C++, and +.L line +is the comment starting line number. +.TP +.L "extern void pperror(int level, char* format, ...);" +Equivalent to +.IR error (3). +All +.I pp +error and warning messages pass through +.LR pperror . +The user may link with an application specific +.L pperror +to override the library default. +.TP +.L "extern int ppincref(char* parent, char* file, int line, int push);" +The default include reference handler that outputs +.L file +to the standard error. +May be used as an argument to the +.LR ppop(PP_INCREF) , +or the user may supply an application specific handler. +.L parent +is the including file name, +.L file +is the current include file name, +.L line +is the current line number in +.LR file , +and +.L push +is non-zero if +.L file +is being pushed or +.L 0 +if file is being popped. +.TP +.L "extern void ppinput(char* buffer, char* file, int line);" +Pushes the +.L 0 +terminated +.L buffer +on the +.I pp +input stack. +.L file +is the pseudo file name used in line syncs for +.L buffer +and +.L line +is the starting line number. +.TP +.L "int pplex(void)" +Returns the token type of the next input token. +.L pp.token +and where applicable +.L pp.symbol +are updated to refer to the new token. +The token type constants are defined in +.L pp.h +for +.L #include +and +.L pp.yacc +for +.IR yacc (1) +.LR %include . +The token constant names match +.LR T_[A-Z_]* ; +some are encoded by oring with +.L N_[A-Z_]* +tokens. +.sp +The numeric constant tokens and encodings are: +.EX + T_DOUBLE (N_NUMBER|N_REAL) + T_DOUBLE_L (N_NUMBER|N_REAL|N_LONG) + T_FLOAT (N_NUMBER|N_REAL|N_FLOAT) + T_DECIMAL (N_NUMBER) + T_DECIMAL_L (N_NUMBER|N_LONG) + T_DECIMAL_U (N_NUMBER|N_UNSIGNED) + T_DECIMAL_UL (N_NUMBER|N_UNSIGNED|N_LONG) + T_OCTAL (N_NUMBER|N_OCTAL) + T_OCTAL_L (N_NUMBER|N_OCTAL|N_LONG) + T_OCTAL_U (N_NUMBER|N_OCTAL|N_UNSIGNED) + T_OCTAL_UL (N_NUMBER|N_OCTAL|N_UNSIGNED|N_LONG) + T_HEXADECIMAL (N_NUMBER|N_HEXADECIMAL) + T_HEXADECIMAL_L (N_NUMBER|N_HEXADECIMAL|N_LONG) + T_HEXADECIMAL_U (N_NUMBER|N_HEXADECIMAL|N_UNSIGNED) + T_HEXADECIMAL_UL (N_NUMBER|N_HEXADECIMAL|N_UNSIGNED|N_LONG) +.EE +The normal C tokens are: +.EX + T_ID \fIC identifier\fP + T_INVALID \fIinvalid token\fP + T_HEADER <..> + T_CHARCONST '..' + T_WCHARCONST L'..' + T_STRING ".." + T_WSTRING L".." + T_PTRMEM -> + T_ADDADD ++ + T_SUBSUB -- + T_LSHIFT << + T_RSHIFT >> + T_LE <= + T_GE >= + T_EQ == + T_NE != + T_ANDAND && + T_OROR || + T_MPYEQ *= + T_DIVEQ /= + T_MODEQ %= + T_ADDEQ += + T_SUBEQ -= + T_LSHIFTEQ <<= + T_RSHIFTEQ >>= + T_ANDEQ &= + T_XOREQ ^= + T_OREQ |= + T_TOKCAT ## + T_VARIADIC ... + T_DOTREF .* [\fIif\fP PP_PLUSPLUS] + T_PTRMEMREF ->* [\fIif\fP PP_PLUSPLUS] + T_SCOPE :: [\fIif\fP PP_PLUSPLUS] + T_UMINUS \fIunary minus\fP +.EE +If +.L ppop(PP_COMPILE) +was set then the keyword tokens are also defined. +Compiler differences and dialects are detected by the +.I pp +.IR probe (1) +information, and only the appropriate keywords are enabled. +The ANSI keyword tokens are: +.EX +T_AUTO T_BREAK T_CASE T_CHAR +T_CONTINUE T_DEFAULT T_DO T_DOUBLE_T +T_ELSE T_EXTERN T_FLOAT_T T_FOR +T_GOTO T_IF T_INT T_LONG +T_REGISTER T_RETURN T_SHORT T_SIZEOF +T_STATIC T_STRUCT T_SWITCH T_TYPEDEF +T_UNION T_UNSIGNED T_WHILE T_CONST +T_ENUM T_SIGNED T_VOID T_VOLATILE +.EE +and the C++ keyword tokens are: +.EX +T_CATCH T_CLASS T_DELETE T_FRIEND +T_INLINE T_NEW T_OPERATOR T_OVERLOAD +T_PRIVATE T_PROTECTED T_PUBLIC T_TEMPLATE +T_THIS T_THROW T_TRY T_VIRTUAL +.EE +In addition, +.L T_ASM +is recognized where appropriate. +Additional keyword tokens +.L ">= T_KEYWORD" +may be added using +.LR ppop(PP_COMPILE) . +.sp +Many C implementations show no restraint in adding new keywords; some +PC compilers have tripled the number of keywords. +For the most part these new keywords introduce noise constructs that +can be ignored for standard +.RI ( reasonable ) +analysis and compilation. +The noise keywords fall in four syntactic categories that map into the two +noise keyword tokens +.L T_NOISE +and +.LR T_NOISES . +For +.L T_NOISES +.L pp.token +points to the entire noise construct, including the offending noise keyword. +The basic noise keyword categories are: +.RS +.TP +.L T_NOISE +The simplest noise: a single keyword that is noise in any context and maps to +.LR T_NOISE . +.TP +.L T_X_GROUP +A noise keyword that precedes an optional grouping construct, either +.L "(..)" +or +.L "{..}" +and maps to +.LR T_NOISES . +.TP +.L T_X_LINE +A noise keyword that consumes the remaining tokens in the line +and maps to +.LR T_NOISES . +.TP +.L T_X_STATEMENT +A noise keyword that consumes the tokens up to the next +.L ; +and maps to +.LR T_NOISES . +.RE +.sp +If +.L ppop(PP_NOISE) +is +.L "> 0" +then implementation specific noise constructs are mapped to either +.L T_NOISE +or +.L T_NOISES , +otherwise if +.L ppop(PP_NOISE) +is +.L "< 0" +then noise constructs are completely ignored, +otherwise the unmapped grouping noise tokens +.L T_X_.* +are returned. +.sp +Token encodings may be tested by the following macros: +.RS +.TP +.L "int isnumber(int token);" +Non-zero if +.L token +is an integral or floating point numeric constant. +.TP +.L "int isinteger(int token);" +Non-zero if +.L token +is an integral numeric constant. +.TP +.L "int isreal(int token);" +Non-zero if +.L token +is a floating point numeric constant. +.TP +.L "int isassignop(int token);" +Non-zero if +.L token +is a C assignment operator. +.TP +.L "int isseparate(int token);" +Non-zero if +.L token +must be separated from other tokens by +.BR space . +.TP +.L "int isnoise(int token);" +Non-zero if +.L token +is a noise keyword. +.RE +.TP +.L "extern int ppline(int line, char* file);" +The default line sync handler that outputs line sync pragmas for the C compiler +front end. +May be used as an argument to +.LR ppop(PP_LINE) , +or the user may supply an application specific handler. +.L line +is the line number and +.L file +is the file name. +If +.L ppop(PP_LINEID) +was set then the directive +\fB#\fP \fIlineid line \fP"\fIfile\fP" is output. +.TP +.L "extern int ppmacref(struct ppsymbol* symbol, char* file, int line, int type);" +The default macro reference handler that outputs a macro reference pragmas. +May be used as an argument to +.LR ppop(PP_MACREF) , +or the user may supply an application specific handler. +.L symbol +is the macro +.L ppsymbol +pointer, +.L file +is the reference file, +.L line +is the reference line, +and if +.L type +is non-zero a macro value checksum is also output. +The pragma syntax is +\fB#pragma pp:macref\fP "\fIsymbol\->name\fP" \fIline checksum\fP. +.TP +.L "int ppop(int op, ...)" +.L ppop +is the option control interface. +.L op +determines the type(s) of the remaining argument(s). +Options marked by +.L "/*INIT*/" +must be done before +.LR PP_INIT . +.RS +.TP +.L "(PP_ASSERT, char* string) /*INIT*/" +.L string +is asserted as if by +.LR #assert . +.TP +.L "(PP_BUILTIN, char*(*fun)(char* buf, char* name, char* args)) /*INIT*/" +Installs +.L fun +as the unknown builtin macro handler. +Builtin macros are of the form +.LR "#(name args)" . +.L fun +is called with +.L name +set to the unknown builtin macro name and +.L args +set to the arguments. +.L buf +is a +.L MAXTOKEN+1 +buffer that can be used for the +.L fun +return value. +.L 0 +should be returned on error. +.TP +.L "(PP_COMMENT,void (*fun)(char*head,char*body,char*tail,int line) /*INIT*/" +.TP +.L "(PP_COMPATIBILITY, char* string) /*INIT*/" +.TP +.L "(PP_COMPILE, char* string) /*INIT*/" +.TP +.L "(PP_DEBUG, char* string) /*INIT*/" +.TP +.L "(PP_DEFAULT, char* string) /*INIT*/" +.TP +.L "(PP_DEFINE, char* string) /*INIT*/" +.L string +is defined as if by +.LR #define . +.TP +.L "(PP_DIRECTIVE, char* string) /*INIT*/" +The directive +.BI # string +is executed. +.TP +.L "(PP_DONE, char* string) /*INIT*/" +.TP +.L "(PP_DUMP, char* string) /*INIT*/" +.TP +.L "(PP_FILEDEPS, char* string) /*INIT*/" +.TP +.L "(PP_FILENAME, char* string) /*INIT*/" +.TP +.L "(PP_HOSTDIR, char* string) /*INIT*/" +.TP +.L "(PP_HOSTED, char* string) /*INIT*/" +.TP +.L "(PP_ID, char* string) /*INIT*/" +.TP +.L "(PP_IGNORE, char* string) /*INIT*/" +.TP +.L "(PP_INCLUDE, char* string) /*INIT*/" +.TP +.L "(PP_INCREF, char* string) /*INIT*/" +.TP +.L "(PP_INIT, char* string) /*INIT*/" +.TP +.L "(PP_INPUT, char* string) /*INIT*/" +.TP +.L "(PP_LINE, char* string) /*INIT*/" +.TP +.L "(PP_LINEFILE, char* string) /*INIT*/" +.TP +.L "(PP_LINEID, char* string) /*INIT*/" +.TP +.L "(PP_LINETYPE, char* string) /*INIT*/" +.TP +.L "(PP_LOCAL, char* string) /*INIT*/" +.TP +.L "(PP_MACREF, char* string) /*INIT*/" +.TP +.L "(PP_MULTIPLE, char* string) /*INIT*/" +.TP +.L "(PP_NOHASH, char* string) /*INIT*/" +.TP +.L "(PP_NOID, char* string) /*INIT*/" +.TP +.L "(PP_NOISE, char* string) /*INIT*/" +.TP +.L "(PP_OPTION, char* string) /*INIT*/" +The directive +\fB#pragma pp:\fP\fIstring\fP +is executed. +.TP +.L "(PP_OPTARG, char* string) /*INIT*/" +.TP +.L "(PP_OUTPUT, char* string) /*INIT*/" +.TP +.L "(PP_PASSNEWLINE, char* string) /*INIT*/" +.TP +.L "(PP_PASSTHROUGH, char* string) /*INIT*/" +.TP +.L "(PP_PLUSPLUS, char* string) /*INIT*/" +.TP +.L "(PP_PRAGMA, char* string) /*INIT*/" +.TP +.L "(PP_PREFIX, char* string) /*INIT*/" +.TP +.L "(PP_PROBE, char* string) /*INIT*/" +.TP +.L "(PP_READ, char* string) /*INIT*/" +.TP +.L "(PP_RESERVED, char* string) /*INIT*/" +.TP +.L "(PP_SPACEOUT, char* string) /*INIT*/" +.TP +.L "(PP_STANDALONE, char* string) /*INIT*/" +.TP +.L "(PP_STANDARD, char* string) /*INIT*/" +.TP +.L "(PP_STRICT, char* string) /*INIT*/" +.TP +.L "(PP_TEST, char* string) /*INIT*/" +.TP +.L "(PP_TRUNCATE, char* string) /*INIT*/" +.TP +.L "(PP_UNDEF, char* string) /*INIT*/" +.TP +.L "(PP_WARN, char* string) /*INIT*/" +.RE +.TP +.L "int pppragma(char* dir, char* pass, char* name, char* value, int nl);" +The default handler that +copies unknown directives and pragmas to the output. +May be used as an argument to +.LR ppop(PP_PRAGMA) , +or the user may supply an application specific handler. +This function is most often called after directive and pragma mapping. +Any of the arguments may be +.LR 0 . +.L dir +is the directive name, +.L pass +is the pragma pass name, +.L name +is the pragma option name, +.L value +is the pragma option value, and +.L nl +is non-zero +if a trailing newline is required if the pragma is copied to the output. +.TP +.L "int ppprintf(char* format, ...);" +A +.IR printf (3) +interface to the standalone +.I pp +output buffer. +Macros provide limited control over output buffering: +.L "void ppflushout()" +flushes the output buffer, +.L "void ppcheckout()" +flushes the output buffer if over +.L PPBUFSIZ +character are buffered, +.L "int pppendout()" +returns the number of pending character in the output buffer, and +.L "void ppputchar(int c)" +places the character +.L c +in the output buffer. +.SH CAVEATS +The ANSI mode is intended to be true to the standard. +The compatibility mode has been proven in practice, but there are +surely dark corners of some implementations that may have been omitted. +.SH "SEE ALSO" +cc(1), cpp(1), nmake(1), probe(1), yacc(1), +.br +ast(3), error(3), hash(3), optjoin(3) +.SH AUTHOR +Glenn Fowler +.br +(Dennis Ritchie provided the original table driven lexer.) +.br +AT&T Bell Laboratories diff --git a/usr/src/lib/libpp/common/pp.def b/usr/src/lib/libpp/common/pp.def new file mode 100644 index 0000000000..f2d679f3af --- /dev/null +++ b/usr/src/lib/libpp/common/pp.def @@ -0,0 +1,282 @@ +# +# list of known old cpp predefined symbols +# +# @(#)pp.def (gsf@research.att.com) 2002-11-26 +# +# symbols will be tested for the common `_' permutations +# qualifiers may be combinations of +# +# architecture cpu architecture +# dialect C dialect +# machine bundled package name +# release system release name +# source *_SOURCE baggage +# system default is unix +# vendor compiler vendor +# +ABI_SOURCE :source: +AES_SOURCE :source: +AIX :architecture: +AIX32 :architecture: +AIX64 :architecture: +ALL_SOURCE :source: +AM29000 :architecture: +AM29K :architecture: +ANSI_CPP :dialect: +AOSVS :release: +APPLE :vendor: +APPLE_CC :dialect: +ATT :release: +ATT4 :release: +BIG_ENDIAN +BSD :release: +BSD_COMPAT :source: +BSD_TYPES :source: +CDECL +CI +CLASSIFY_TYPE +COMPACT :architecture: +COMPILER_VER +CRAY :machine: +CRAY1 :machine: +CRAY2 :machine: +DATAGENERAL :machine: +DGUX :release: +DLL +DMERT :release: +DYNAMIC :dialect: +EXTENSIONS :dialect: +FreeBSD :release: +GNUC :dialect:vendor: +GNUC_MINOR +GNUG :dialect:vendor: +HFS :vendor: +HIGHC +HOST_MIPS +HPUX_SOURCE :source: +HUGE :architecture: +IBMR2 :architecture: +ISIS +LANGUAGE_C :dialect: +LANGUAGE_CPLUS :dialect: +LANGUAGE_C_PLUS_PLUS :dialect: +LARGE :architecture: +LARGE_M +LATTICE :vendor: +LONGLONG :dialect: +LONG_LONG :dialect: +M68010 :machine: +M68020 :machine: +MACH :release: +MEDIUM :architecture: +MIPSEB +MIPSEL +MIPS_FPSET +MIPS_ISA +MIPS_ISA_MIPS1 +MIPS_ISA_MIPS2 +MIPS_SIM +MIPS_SIM_ABI16 +MIPS_SIM_ABI32 +MIPS_SZINT +MIPS_SZLONG +MIPS_SZPTR +MODERN_C :dialect: +MOXIE :release: +MSC_VER :release: +MSDOS :system: +MSNT :system: +MVS :architecture: +M_ALPHA :architecture: +M_BITFIELDS +M_I186 :architecture: +M_I286 :architecture: +M_I386 :architecture: +M_I8086 :architecture: +M_I86 :architecture: +M_I86LM +M_I86MM +M_I86SM +M_IX86 :architecture: +M_LDATA +M_LTEXT +M_MRX000 :architecture: +M_PPC :architecture: +M_SDATA +M_STEXT +M_SYS3 +M_SYS5 +M_SYSIII +M_SYSV +M_WDSWAP +M_XENIX +NATURAL_ALIGNMENT +NEXT :release: +NeXT :release: +ON_SEL +OSK +OVERLAY +PASCAL +PDP11 :architecture: +POSIX +POSIX2_SOURCE :source: +POSIX_C_SOURCE :source: +POSIX_SOURCE :source: +POWER :architecture: +PTRDIFF_TYPE +PWB +RES +RT +SGI_MP_SOURCE :source: +SGI_REENTRANT_FUNCTIONS :dialect: +SGI_SOURCE :source: +SIZE_TYPE +SMALL :architecture: +SMALL_M +STDC_HOSTED +STDC_IEC_559 +STDC_IEC_559_COMPLEX +STDC_ISO_10646 +STDC_VERSION +STD_INCLUDE_DIR +SVR3 +SVR4 +SVR4_SOURCE :source: +SYSTYPE_BSD +SYSTYPE_SVR4 +SYSTYPE_SYSV +TARGET_LIB +TINY :architecture: +TM_DPS6 +TM_L66 +TS +TS_GCOS +TS_MOD400 +TURBOC +UTS :release: +UWIN :release: +V9 :release: +VAX :architecture: +VAX11C :vendor: +VAXC :vendor: +VMS :system: +WCHAR_TYPE +WIN32 :release: +X86 :architecture: +XOPEN_SOURCE :source: +XPG2 :source: +XPG3 :source: +XPG4 :source: +_50SERIES +alliant :machine: +aosvs :release: +apollo :machine: +c_plusplus :dialect: +cpc :machine: +cplusplus :dialect: +cpm :system: +cpm68k :machine: +cpm80 :machine: +cpm86 :machine: +cray :machine: +datageneral :machine: +decus +dgux :release: +dmert :release: +fpcc +ftx +gcos :release: +gimpel :release: +gnu +gould :machine: +hobbit :architecture: +host_mips +hp9000s200 :architecture: +hp9000s300 :architecture: +hp9000s500 :architecture: +hp9000s700 :architecture: +hp9000s800 :architecture: +hppa :architecture:machine: +hpux :release: +i286 :architecture: +i386 :architecture: +i80186 :architecture: +i80286 :architecture: +i8080 :architecture: +i8086 :architecture: +i860 :architecture: +iAPX286 :architecture: +iAPX386 :architecture: +ibm :architecture: +ibm032 :architecture: +interdata :architecture: +kl10 +linux :release: +m68000 :architecture: +m68k :architecture: +m88000 :architecture: +m88k :architecture: +mbb +mc300 :architecture: +mc500 :architecture: +mc68000 :architecture: +mc68008 :architecture: +mc68010 :architecture: +mc68020 :architecture: +mc68k32 :architecture: +mc700 :architecture: +mert :release: +mips :architecture: +mpm +msdos :system: +n16 :architecture: +n32032 :architecture: +n32332 :architecture: +news800 +nomacarg +nonstopux :system: +ns1600 :architecture: +ns16000 :architecture: +ns32000 :architecture: +orion :release: +os :release: +pcdos :system: +pdp11 :architecture: +ppc :architecture: +pyr :architecture: +rsx :release: +sel :architecture: +selport +sequent :machine: +sequoia :machine: +sparc :architecture: +spectrum :machine: +sun :machine: +sun2 :machine: +sun3 :machine: +svr4 :release: +tahoe :architecture: +topix :release: +tops20 :machine: +tss :system: +u370 :architecture: +u3b :architecture: +u3b15 :architecture: +u3b2 :architecture: +u3b20 :architecture: +u3b200 :architecture: +u3b20d :architecture: +u3b4000 :architecture: +u3b5 :architecture: +univac :machine: +unix :system: +unixpc :machine: +uts :release: +vax :architecture: +vax11c :vendor: +vaxc :vendor: +vms :system: +xinu :release: +z80 :architecture: +z800 :architecture: +z8000 :architecture: diff --git a/usr/src/lib/libpp/common/pp.h b/usr/src/lib/libpp/common/pp.h new file mode 100644 index 0000000000..2b91c8e435 --- /dev/null +++ b/usr/src/lib/libpp/common/pp.h @@ -0,0 +1,452 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor library public definitions + */ + +#ifndef _PP_H +#define _PP_H + +#ifdef ppsymbol +/* + * undo old nmake cpp name-space intrusion + * this disables __LINE__, __FILE__, __DATE__ and __TIME__ + */ +#undef ppsymbol +#undef __LINE__ +#define __LINE__ 0 +#undef __FILE__ +#define __FILE__ "libpp" +#undef __DATE__ +#define __DATE__ "MMM DD YYYY" +#undef __TIME__ +#define __TIME__ "HH:MM:SS" +#endif + + +#if PROTOMAIN +#define HASH_HEADER int hash_header +#define Hash_table_t char +#define Sfio_t char +#define CC_bel (('A'==0301)?0057:0007) +#define CC_esc (('A'==0301)?0047:0033) +#define CC_vt 0013 +#else +#include <limits.h> +#include <hash.h> +#include <error.h> +#include <ccode.h> +#endif + +#define PPDEFAULT "pp_default.h" /* runtime definitions */ +#define PPPROBE "cc" /* default probe key */ +#define PPSTANDARD "/usr/include" /* standard include dir */ + +#define PPBLKSIZ 1024 /* unit block size */ +#define PPBAKSIZ (1*PPBLKSIZ) /* input pushback size */ +#define PPBUFSIZ (32*PPBLKSIZ) /* io buffer size */ +#define PPTOKSIZ ((PPBUFSIZ/2)-1) /* max token size */ + +#define PPWRITE(n) do{if(write(1,pp.outbuf,n)!=(n))pperror(ERROR_SYSTEM|3,"%s: write error",pp.outfile);pp.offset+=(n);pp.lastout=pp.outbuf[n-1];}while(0) + +#define pplastout() ((pp.outp>pp.outbuf)?*(pp.outp-1):pp.lastout) +#define ppoffset() (pp.offset+pppendout()) +#define pppendout() (pp.outp-pp.outbuf) +#define ppputchar(c) (*pp.outp++=(c)) +#define ppflushout() do{if(pp.outp>pp.outbuf){PPWRITE(pp.outp-pp.outbuf);pp.outp=pp.outbuf;}}while(0) +#define ppcheckout() do{if(pp.outp>pp.oute){PPWRITE(PPBUFSIZ);if(pp.outbuf==pp.outb){pp.outbuf+=PPBUFSIZ;pp.oute+=PPBUFSIZ;}else{pp.outbuf-=PPBUFSIZ;memcpy(pp.outbuf,pp.oute,pp.outp-pp.oute);pp.oute-=PPBUFSIZ;pp.outp-=2*PPBUFSIZ;}}}while(0) + +#define ppsymget(t,n) (struct ppsymbol*)hashlook(t,n,HASH_LOOKUP,NiL) +#define ppsymref(t,n) (struct ppsymbol*)hashlook(t,n,pp.truncate?HASH_LOOKUP:HASH_LOOKUP|HASH_INTERNAL,NiL) +#define ppsymset(t,n) (struct ppsymbol*)hashlook(t,n,HASH_CREATE|HASH_SIZE(sizeof(struct ppsymbol)),NiL) + +#if CHAR_MIN < 0 +#define pptype (ppctype-(CHAR_MIN)+1) +#else +#define pptype (ppctype) +#endif + +#define C_ID (1<<0) +#define C_DIG (1<<1) +#define C_SPLICE (1<<2) + +#define ppisdig(c) ((pptype)[c]&C_DIG) +#define ppisid(c) ((pptype)[c]&C_ID) +#define ppisidig(c) ((pptype)[c]&(C_ID|C_DIG)) +#define ppismac(c) ((pptype)[c]&(C_ID|C_DIG|C_SPLICE)) +#define ppissplice(c) ((pptype)[c]&C_SPLICE) + +#define setid(c) ((pptype)[c]|=C_ID) +#define clrid(c) ((pptype)[c]&=~C_ID) +#define setdig(c) ((pptype)[c]|=C_DIG) +#define setsplice(c) ((pptype)[c]|=C_SPLICE) + +#define REF_CREATE (REF_NORMAL+1) /* include wrapper (internal) */ +#define REF_DELETE (REF_NORMAL+2) /* macro definition (internal) */ +#define REF_NORMAL 0 /* normal macro reference */ +#define REF_IF (-1) /* if, ifdef, ifndef, elif */ +#define REF_UNDEF (-2) /* undef */ + +#define SYM_ACTIVE (1L<<0) /* active macro lock */ +#define SYM_BUILTIN (1L<<1) /* builtin macro */ +#define SYM_DISABLED (1L<<2) /* macro expansion disabled */ +#define SYM_EMPTY (1L<<3) /* allow empty/missing actuals */ +#define SYM_FINAL (1L<<4) /* final hosted value */ +#define SYM_FUNCTION (1L<<5) /* macro with args */ +#define SYM_INIT (1L<<6) /* initialization macro */ +#define SYM_INITIAL (1L<<7) /* initial hosted value */ +#define SYM_KEYWORD (1L<<8) /* keyword identifier */ +#define SYM_LEX (1L<<9) /* ppsymkey with lex field */ +#define SYM_MULTILINE (1L<<10) /* multi-line macro */ +#define SYM_NOEXPAND (1L<<11) /* no identifiers in macro body */ +#define SYM_NOTICED (1L<<12) /* symbol noticed in output */ +#define SYM_PREDEFINED (1L<<13) /* predefined macro */ +#define SYM_PREDICATE (1L<<14) /* also a predicate */ +#define SYM_READONLY (1L<<15) /* readonly macro */ +#define SYM_REDEFINE (1L<<16) /* ok to redefine */ +#define SYM_VARIADIC (1L<<17) /* variadic macro with args */ +#define SYM_UNUSED 24 /* first unused symbol flag bit */ + +#define PP_ASSERT 1 /* preassert symbol */ +#define PP_BUILTIN 2 /* #(<id>) handler */ +#define PP_CDIR 3 /* C (vs. C++) file dirs follow */ +#define PP_CHOP 4 /* include prefix chop */ +#define PP_COMMENT 5 /* passed comment handler */ +#define PP_COMPATIBILITY 6 /* old (Reiser) dialect */ +#define PP_COMPILE 7 /* tokenize for front end */ +#define PP_DEBUG 8 /* set debug trace level */ +#define PP_DEFINE 9 /* predefine symbol */ +#define PP_DEFAULT 10 /* read default include files */ +#define PP_DIRECTIVE 11 /* initialization directive */ +#define PP_DONE 12 /* all processing done */ +#define PP_DUMP 13 /* do checkpoint dump */ +#define PP_FILEDEPS 14 /* output file dependencies */ +#define PP_FILENAME 15 /* set input file name */ +#define PP_HOSTDIR 16 /* hosted file dirs follow */ +#define PP_ID 17 /* add to identifier set */ +#define PP_IGNORE 18 /* ignore this include file */ +#define PP_IGNORELIST 19 /* include ignore list file */ +#define PP_INCLUDE 20 /* add dir to include search */ +#define PP_INCREF 21 /* include file push/ret handler*/ +#define PP_INIT 22 /* one time initialization */ +#define PP_INPUT 23 /* set input source file */ +#define PP_KEYARGS 24 /* name=value macro args */ +#define PP_LINE 25 /* line sync handler */ +#define PP_LINEBASE 26 /* base name in line sync */ +#define PP_LINEFILE 27 /* line sync requires file arg */ +#define PP_LINEID 28 /* PP_LINE directive id */ +#define PP_LINETYPE 29 /* # extra line sync type args */ +#define PP_LOCAL 30 /* previous PP_INCLUDE for "" */ +#define PP_MACREF 31 /* macro def/ref handler */ +#define PP_MULTIPLE 32 /* set all files multiple */ +#define PP_NOHASH 33 /* don't hash PP_COMPILE T_ID's */ +#define PP_NOISE 34 /* convert T_X_* to T_NOISE */ +#define PP_OPTION 35 /* set pragma option */ +#define PP_OPTARG 36 /* unknown option arg handler */ +#define PP_OUTPUT 37 /* set output file sink */ +#define PP_PASSTHROUGH 38 /* ppcpp() expands # lines only */ +#define PP_PEDANTIC 39 /* pedantic non-hosted warnings */ +#define PP_PLUSCOMMENT 40 /* enable C++ comments */ +#define PP_PLUSPLUS 41 /* tokenize for C++ */ +#define PP_POOL 42 /* pool for multiple io passes */ +#define PP_PRAGMA 43 /* passed pragma handler */ +#define PP_PRAGMAFLAGS 44 /* global pragma flags */ +#define PP_PROBE 45 /* ppdefault probe key */ +#define PP_QUOTE 46 /* add to quote set */ +#define PP_READ 47 /* include file without output */ +#define PP_REGUARD 48 /* file pop emits guard define */ +#define PP_RESERVED 49 /* COMPILE reserved keyword */ +#define PP_RESET 50 /* reset to initiali predefs */ +#define PP_SPACEOUT 51 /* pplex returns space,newline */ +#define PP_STANDALONE 52 /* standalone preprocessor */ +#define PP_STANDARD 53 /* standard include dir */ +#define PP_STRICT 54 /* strict implementation */ +#define PP_TEST 55 /* enable (undocumented) tests */ +#define PP_TEXT 56 /* include file with output */ +#define PP_TRANSITION 57 /* on COMPATIBILITY boundary */ +#define PP_TRUNCATE 58 /* truncate macro names */ +#define PP_UNDEF 59 /* undef symbol after ppdefault */ +#define PP_VENDOR 60 /* vendor file dirs follow */ +#define PP_WARN 61 /* enable annoying warnings */ + +#define PP_comment (1<<0) /* PP_COMMENT is set */ +#define PP_compatibility (1<<1) /* PP_COMPATIBILITY is set */ +#define PP_hosted (1<<2) /* current file is hosted */ +#define PP_linebase (1<<3) /* base name in line sync */ +#define PP_linefile (1<<4) /* line sync file arg required */ +#define PP_linehosted (1<<5) /* line sync hosted arg required*/ +#define PP_lineignore (1<<6) /* line sync for ignored file */ +#define PP_linetype (1<<7) /* line sync type arg required */ +#define PP_strict (1<<8) /* PP_STRICT is set */ +#define PP_transition (1<<9) /* PP_TRANSITION is set */ + +#define PP_deps (1<<0) /* generate header deps */ +#define PP_deps_file (1<<1) /* write deps to separate file */ +#define PP_deps_generated (1<<2) /* missing deps are generated */ +#define PP_deps_local (1<<3) /* only local header deps */ + +#define PP_sync 0 /* normal line sync */ +#define PP_sync_push '1' /* [3] include file push */ +#define PP_sync_pop '2' /* [3] include file pop */ +#define PP_sync_ignore '3' /* [3] ignored include file */ +#define PP_sync_hosted '3' /* [4] hosted include file */ + +#define PP_SYNC_PUSH (1<<0) /* pp.incref PP_sync_push type */ +#define PP_SYNC_POP (1<<1) /* pp.incref PP_sync_pop type */ +#define PP_SYNC_IGNORE (1<<2) /* pp.incref PP_sync_ignore type*/ +#define PP_SYNC_HOSTED (1<<3) /* pp.incref PP_sync_hosted type*/ +#define PP_SYNC_INSERT (1<<4) /* pinserted by other means */ + +/* + * numeric modifiers + * + * NOTE: 0400 is claimed by error in yacc + * (N_PP+30) is the largest valid pp token + * free tokens start at T_TOKEN + */ + +#define N_PP 0401 /* pp tokens 0401..0437 */ +#define N_NUMBER 0440 /* numbers 0440..0477 */ +#define N_TEST (N_NUMBER|07700)/* number test mask */ +#define N_TOKEN 0500 /* free 0500..07777 */ +#define N_WIDE 1 /* wide quoted constant */ + +/* + * NOTE: preserve the token ranges and encodings for is*(x) + */ + +#define ppisnumber(x) (((x)&N_TEST)==N_NUMBER) +#define ppisinteger(x) (((x)&(N_TEST|N_REAL))==N_NUMBER) +#define ppisreal(x) (((x)&(N_TEST|N_REAL))==(N_NUMBER|N_REAL)) +#define ppisassignop(x) (((x)>=T_MPYEQ)&&((x)<=T_OREQ)) +#define ppisseparate(x) (((x)>=N_PP)&&((x)<=T_WSTRING)||((x)>=N_NUMBER)||((x)=='+')||((x)=='-')) + +#define N_LONG 0001 +#define N_UNSIGNED 0002 /* if ppisinteger(x) */ +#define N_FLOAT 0002 /* if ppisreal(x) */ + +#define N_REAL 0004 +#define N_OCTAL 0010 +#define N_HEXADECIMAL 0020 + +#define N_EXPONENT 010000 /* for lexing only */ +#define N_SIGN 020000 /* for lexing only */ +#define N_TRAILING 040000 /* for lexing only */ + +#if !defined(T_DOUBLE) + +/* + * numeric constants + */ + +#define T_DOUBLE (N_NUMBER|N_REAL) +#define T_DOUBLE_L (N_NUMBER|N_REAL|N_LONG) +#define T_FLOAT (N_NUMBER|N_REAL|N_FLOAT) +#define T_DECIMAL (N_NUMBER) +#define T_DECIMAL_L (N_NUMBER|N_LONG) +#define T_DECIMAL_U (N_NUMBER|N_UNSIGNED) +#define T_DECIMAL_UL (N_NUMBER|N_UNSIGNED|N_LONG) +#define T_OCTAL (N_NUMBER|N_OCTAL) +#define T_OCTAL_L (N_NUMBER|N_OCTAL|N_LONG) +#define T_OCTAL_U (N_NUMBER|N_OCTAL|N_UNSIGNED) +#define T_OCTAL_UL (N_NUMBER|N_OCTAL|N_UNSIGNED|N_LONG) +#define T_HEXADECIMAL (N_NUMBER|N_HEXADECIMAL) +#define T_HEXADECIMAL_L (N_NUMBER|N_HEXADECIMAL|N_LONG) +#define T_HEXADECIMAL_U (N_NUMBER|N_HEXADECIMAL|N_UNSIGNED) +#define T_HEXADECIMAL_UL (N_NUMBER|N_HEXADECIMAL|N_UNSIGNED|N_LONG) +#define T_HEXDOUBLE (N_NUMBER|N_HEXADECIMAL|N_REAL) +#define T_HEXDOUBLE_L (N_NUMBER|N_HEXADECIMAL|N_REAL|N_LONG) + +/* + * identifier and invalid token + */ + +#define T_ID (N_PP+0) +#define T_INVALID (N_PP+1) + +/* + * quoted constants + */ + +#define T_HEADER (N_PP+2) /* <..> */ +#define T_CHARCONST (N_PP+3) /* '..' */ +#define T_WCHARCONST (T_CHARCONST|N_WIDE) /* L'..' */ +#define T_STRING (N_PP+5) /* ".." */ +#define T_WSTRING (T_STRING|N_WIDE) /* L".." */ + +/* + * multichar operators + */ + +#define T_PTRMEM (N_PP+7) /* -> */ +#define T_ADDADD (N_PP+8) /* ++ */ +#define T_SUBSUB (N_PP+9) /* -- */ +#define T_LSHIFT (N_PP+10) /* << */ +#define T_RSHIFT (N_PP+11) /* >> */ +#define T_LE (N_PP+12) /* <= */ +#define T_GE (N_PP+13) /* >= */ +#define T_EQ (N_PP+14) /* == */ +#define T_NE (N_PP+15) /* != */ +#define T_ANDAND (N_PP+16) /* && */ +#define T_OROR (N_PP+17) /* || */ +#define T_MPYEQ (N_PP+18) /* *= */ +#define T_DIVEQ (N_PP+19) /* /= */ +#define T_MODEQ (N_PP+20) /* %= */ +#define T_ADDEQ (N_PP+21) /* += */ +#define T_SUBEQ (N_PP+22) /* -= */ +#define T_LSHIFTEQ (N_PP+23) /* <<= */ +#define T_RSHIFTEQ (N_PP+24) /* >>= */ +#define T_ANDEQ (N_PP+25) /* &= */ +#define T_XOREQ (N_PP+26) /* ^= */ +#define T_OREQ (N_PP+27) /* |= */ +#define T_TOKCAT (N_PP+28) /* ## */ +#define T_VARIADIC (N_PP+29) /* ... */ + +/* + * C++ tokens + */ + +#define T_DOTREF (N_TOKEN+0) /* .* */ +#define T_PTRMEMREF (N_TOKEN+1) /* ->* */ +#define T_SCOPE (N_TOKEN+2) /* :: */ + +/* + * compiler tokens + */ + +#define T_UMINUS (N_TOKEN+3) + +#endif + +/* + * start of free tokens + */ + +#define T_TOKEN (N_TOKEN+4) + +struct ppdirs /* directory list */ +{ + char* name; /* directory name */ + struct ppdirs* next; /* next in list */ + +#ifdef _PP_DIRS_PRIVATE_ + _PP_DIRS_PRIVATE_ +#endif + +}; + +struct ppkeyword /* pp keyword info */ +{ + char* name; /* keyword name */ + int value; /* keyword token value */ +}; + +struct ppmacro /* pp macro info */ +{ + int arity; /* # formal arguments */ + char* value; /* definition value */ + +#ifdef _PP_MACRO_PRIVATE_ + _PP_MACRO_PRIVATE_ +#endif + +}; + +struct ppsymbol /* pp symbol info */ +{ + HASH_HEADER; /* hash stuff and symbol name */ + unsigned long flags; /* SYM_* status */ + struct ppmacro* macro; /* macro info */ + void* value; /* value (for other passes) */ + +#ifdef _PP_SYMBOL_PRIVATE_ + _PP_SYMBOL_PRIVATE_ +#endif + +}; + +#define _PP_CONTEXT_BASE_ ((char*)&pp.lcldirs) + +#define _PP_CONTEXT_PUBLIC_ \ + struct ppdirs* lcldirs; /* the "..." dir list */ \ + struct ppdirs* stddirs; /* next is the <...> dir list */ \ + int flags; /* PP_[a-z]* flags */ \ + Hash_table_t* symtab; /* macro and id hash table */ + +struct ppglobals /* globals accessed by pp.* */ +{ + const char* version; /* version stamp */ + char* lineid; /* line sync directive id */ + char* outfile; /* output file name */ + char* pass; /* pass name */ + char* token; /* pplex() token name */ + struct ppsymbol* symbol; /* last symbol if PP_COMPILE */ + + /* exposed for the output macros */ + + char* outb; /* output buffer base */ + char* outbuf; /* output buffer */ + char* outp; /* outbuf pointer */ + char* oute; /* outbuf end */ + unsigned long offset; /* output offset */ + +#ifdef _PP_CONTEXT_PUBLIC_ + _PP_CONTEXT_PUBLIC_ /* public context */ +#endif + +#ifdef _PP_CONTEXT_PRIVATE_ + _PP_CONTEXT_PRIVATE_ /* library private context */ +#endif + +#ifdef _PP_GLOBALS_PRIVATE_ + _PP_GLOBALS_PRIVATE_ /* library private additions */ +#endif + +}; + +/* + * library interface globals + */ + +#define ppctype _pp_ctype + +extern struct ppglobals pp; +extern char ppctype[]; + +extern int ppargs(char**, int); +extern void ppcpp(void); +extern void ppcomment(char*, char*, char*, int); +extern void* ppcontext(void*, int); +extern void pperror(int, ...); +extern void ppincref(char*, char*, int, int); +extern void ppinput(char*, char*, int); +extern int pplex(void); +extern void ppline(int, char*); +extern void ppmacref(struct ppsymbol*, char*, int, int, unsigned long); +extern void ppop(int, ...); +extern void pppragma(char*, char*, char*, char*, int); +extern int ppprintf(char*, ...); +extern int ppsync(void); + +#endif diff --git a/usr/src/lib/libpp/common/pp.key b/usr/src/lib/libpp/common/pp.key new file mode 100644 index 0000000000..36de339f36 --- /dev/null +++ b/usr/src/lib/libpp/common/pp.key @@ -0,0 +1,117 @@ +# +# list of known non-classic keywords +# +# @(#)pp.key (AT&T Labs Research) 2000-05-09 +# +# keyword type alternate comment +# +# . either T_<keyword> or T_NOISE +# GROUP balanced (), optional {} group +# LINE upto newline +# STATEMENT upto ; +# [pre][.[suf]] [pre]<keyword>[suf] +# + +_Bool . . c9x +_Complex . . c9x +_Imaginary . . c9x +__alignof GROUP .__ gnu +__attribute GROUP .__ gnu +__extension GROUP .__ gnu +__null . .__ gnu +asm GROUP _,__,__.__ common +const . __,__.__ ansi +entry . . ancient +enum . . pcc,ansi +fortran . _ ancient +inline . __,__.__ c9x +int8 . _,__,__.__ common +int16 . _,__,__.__ common +int32 . _,__,__.__ common +int64 . _,__,__.__ common +restrict . __,__.__ c9x +signed . __,__.__ ansi +typeof GROUP __,__.__ gnu +void . . pcc,ansi +volatile . __,__.__ ansi + +# new C++ keywords -- is any identifier safe? + +and . . C++ (no left_parenthesis?) +and_eq . . C++ +bitand . . C++ +bitor . . C++ +bool . . C++ +catch . . C++ +compl . . C++ +const_cast . . C++ +dynamic_cast . . C++ +explicit . . C++ +false . . C++ +mutable . . C++ +namespace . . C++ +not . . C++ +not_eq . . C++ +or . . C++ +or_eq . . C++ +protected . . C++ +reinterpret_cast . . C++ +static_cast . . C++ +template . . C++ +throw . . C++ +true . . C++ +try . . C++ +typeid . . C++ +using . . C++ +wchar_t . _,__ C++ ughlee and strange +xor . . C++ +xor_eq . . C++ + +# these are typically found in pc compilers, but may be in cross compilers + +based GROUP _,__ microsoft +cdecl . _,__ microsoft +declspec GROUP _,__ microsoft +except . _,__ microsoft +export . _,__ microsoft +far . _,__ microsoft +fastcall . _,__ microsoft +finally . _,__ microsoft +huge . _,__ microsoft +interrupt . _,__ microsoft +leave . _,__ microsoft +loadds . _,__ microsoft +near . _,__ microsoft +novtordisp . _,__ microsoft +oldcall . _,__ microsoft +pascal . _,__ microsoft +saveregs . _,__ microsoft +segment . _,__ microsoft +segname . _,__ microsoft +self . _,__ microsoft +stdcall . _,__ microsoft +syscall . _,__ microsoft +try . _,__ microsoft + +cs . _,__ turbo +ds . _,__ turbo +es . _,__ turbo +regparam . _,__ turbo +seg . _,__ turbo +ss . _,__ turbo + +# these must have been a vms edict + +align . _,__,__.__ dec +f_float . _,__,__.__ dec +g_float . _,__,__.__ dec +globaldef . _,__,__.__ dec +globalref . _,__,__.__ dec +globalvalue . _,__,__.__ dec +noshare . _,__,__.__ dec +readonly . _,__,__.__ dec +s_float . _,__,__.__ dec +t_float . _,__,__.__ dec +unaligned . _,__,__.__ dec +variant_struct . _,__,__.__ dec +variant_union . _,__,__.__ dec diff --git a/usr/src/lib/libpp/common/pp.probe b/usr/src/lib/libpp/common/pp.probe new file mode 100644 index 0000000000..285f23da71 --- /dev/null +++ b/usr/src/lib/libpp/common/pp.probe @@ -0,0 +1,1210 @@ +: +# Glenn Fowler +# AT&T Research +# +# @(#)pp.probe (AT&T Research) 2006-09-05 +# +# C probe for libpp +# +# NOTE: C.probe must be included or .'d here +# + +ppdef=$dir/pp.def +ppkey=$dir/pp.key +ppsym=$dir/ppsym +for f in $ppdef $ppkey $ppsym +do test -f $f || { echo "$0: $f: not found" >&4; exit 1 ;} +done + +sed -e "/^#/d" -e "s/[ ].*//" < $ppdef > all.pp + +system= +release= +version= +architecture= +cpu= +model= +machine= + +# +# path cleanup +# + +for i in stdinclude usrinclude +do eval o='$'$i + v=$o + case $v in + *//*) v=`echo $v | sed 's,///*,/,g'` ;; + esac + if (test . -ef "`pwd`") + then k= + for x in $v + do case $x in + */../*|*/..) + case $x in + /*) a=/ ;; + *) a= ;; + esac + IFS=/ + set '' $x + IFS=$ifs + r= + for d + do r="$d $r" + done + p= + g= + for d in $r + do case $d in + ..) g="$g $d" ;; + *) case $g in + '') case $p in + '') p=$d ;; + *) p=$d/$p ;; + esac + ;; + *) set $g + shift + g=$* + ;; + esac + ;; + esac + done + case $a in + '') for d in $g + do p=$d/$p + done + ;; + *) p=$a$p + ;; + esac + case $p in + /) continue ;; + esac + test $x -ef $p && x=$p + ;; + esac + k="$k $x" + done + set '' $k + shift + v=$1 + case $# in + 0) ;; + *) shift + while : + do case $# in + 0) break ;; + esac + k= + for d + do for j in $v + do test $d -ef $j && continue 2 + done + k="$k $d" + done + set '' $k + case $# in + 1) break ;; + esac + shift + v="$v $1" + shift + done + ;; + esac + fi + case $v in + $o) ;; + *) eval $i='$'v ;; + esac +done + +id="::IDENT::`date`::IDENT::" +echo '#assert test(ok) +#if #test(ok) +#else +( +#endif' > assert.$src +echo '#ifdef __BASE_FILE__ +int ok; +#else +( +#endif' > basefile.$src +cat > catlit1.i <<'!' +char test[] = "te" +"st"; +! +cat > catlit2.i <<'!' +char test[] = "te\ +st"; +! +echo '#define g(a,b) a ## b +volatile int a; +const int g(x,y)=1; +extern int c(int);' > compat.$src +echo > cpp.$src +echo "#defincl <x.h>" > defincl.$src +echo 'int a$b;' > dollar.$src +echo "#eject" > eject.$src +echo "#if 0 +( +#else if 1 +int x; +#else +( +#endif" > elseif.$src +echo "#define _CAT(a,b,c) a##b##c +#define hdra hdrx +#define hdr _CAT(<,hdra,.h>) +#include hdr" > hdra.$src +echo "#define _XAT(a,b,c) a##b##c +#define _CAT(a,b,c) _XAT(a,b,c) +#define hdra hdrx +#define hdr _CAT(<,hdra,.h>) +#include hdr" > hdrx.$src +echo "int f(){return 0;}" > hdrx.h +echo "#ident \"$id\"" > ident.$src +echo "#import \"import.h\"" > import.$src +echo "int aaa;" > import.h +echo "#include <inc_next.h>" > inc_next.$src +mkdir inc0 inc1 +echo "#include_next <inc_next.h>" > inc0/inc_next.h +echo 'char s[] = "INCLUDE_NEXT";' > inc1/inc_next.h +echo '# 1 "linefile.i" + +# 1 "linefile.i" + +int i;' > linefile1.i +echo '# 1 "linefile.i" + +# 1 + +int i;' > linefile2.i +echo "int i = 0;" > lineid1.i +echo '# 1 "t.c" +int i = 0;' > lineid2.i +echo '# 1 "t.c" +int i = 0;' > lineid3.$src +echo "#include <stdio.h>" > linetype.$src +echo '#include <sys/types.h> +main() +{ + return sizeof(LONGLONG) != 8; +}' > longlong.$src +echo '#include "once.h" +#include "once.h"' > once.$src +echo '#ifdef once +allmultiple +#else +#define once +#endif' > once.h +echo "extern int a,b;int f(){return a + = b;}" > opspace.$src +echo "int f(){return(0);} // ((" > pluscom.$src +echo "class x {int n;} m;" > plusplus.$src +echo > preinc.$src +echo '// splice \ +( +int x = 1;' > plusspl.$src +echo "int stdc_default_value = __STDC__ ;" > stdc.$src +echo 'char xxx[] = "abc +(";' > span.$src +echo '#define g(a,b) a\ +b +int ab,xy; +#define xy XY +char* g(x,y);' > splice.$src +{ +echo 'int a\ ' +echo 'b = 1;' +} > splicesp.$src +echo '#define g(a,b) a/**/b +int g(x,y)=1;' > trans.$src +echo '#define m 65 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 65 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 64 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 63 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 62 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 61 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 60 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 59 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 58 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 57 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 56 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 55 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 54 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 53 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 52 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 51 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 50 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 49 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 48 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 47 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 46 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 45 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 44 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 43 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 42 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 41 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 40 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 39 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 38 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 37 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 36 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 35 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 34 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 33 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 32 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 31 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 30 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxxx 29 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxxx 28 +#define xxxxxxxxxxxxxxxxxxxxxxxxxxx 27 +#define xxxxxxxxxxxxxxxxxxxxxxxxxx 26 +#define xxxxxxxxxxxxxxxxxxxxxxxxx 25 +#define xxxxxxxxxxxxxxxxxxxxxxxx 24 +#define xxxxxxxxxxxxxxxxxxxxxxx 23 +#define xxxxxxxxxxxxxxxxxxxxxx 22 +#define xxxxxxxxxxxxxxxxxxxxx 21 +#define xxxxxxxxxxxxxxxxxxxx 20 +#define xxxxxxxxxxxxxxxxxxx 19 +#define xxxxxxxxxxxxxxxxxx 18 +#define xxxxxxxxxxxxxxxxx 17 +#define xxxxxxxxxxxxxxxx 16 +#define xxxxxxxxxxxxxxx 15 +#define xxxxxxxxxxxxxx 14 +#define xxxxxxxxxxxxx 13 +#define xxxxxxxxxxxx 12 +#define xxxxxxxxxxx 11 +#define xxxxxxxxxx 10 +#define xxxxxxxxx 9 +#define xxxxxxxx 8 +#define xxxxxxx 7 +#define xxxxxx 6 +#define xxxxx 5 +#define xxxx 4 +#define xxx 3 +#define xx 2 +#define x 1 +#if xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx != m +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +#endif' > truncate.$src +cat > zeof.c <<'!' +char* foo = "az"; +! + +allmultiple= +assert= +basefile= +compatibility=1 +defincl= +dollar= +eject= +elseif= +headerexpand= +headerexpandall= +hostedtransition= +ident= +import= +include_next= +linefile= +lineid= +linetype= +nocatliteral= +opspace= +pluscom= +plusplus= +plussplice= +redef= +reguard= +reserved= +spaceout= +splicecat= +splicespace= +strict= +stringspan= +transition= +truncate= +zeof= + +$cc -c assert.$src && assert=1 + +$cc -c basefile.$src && basefile=__BASE_FILE__ + +if $cc -E defincl.$src +then case "`$cc -E defincl.$src | grep -c 'defincl'`" in + 0) defincl=1 ;; + esac +fi + +if $cc -c catlit1.i 2>e +then if $cc -c catlit2.i 2>f + then if test `wc -c < f` -gt `wc -c < e` + then nocatliteral=1 + fi + else nocatliteral=1 + fi +fi + +$cc -c dollar.$src && dollar=1 + +$cc -c elseif.$src && elseif=1 + +if $cc -I. -c hdra.$src +then headerexpandall=1 +elif $cc -I. -c hdrx.$src +then headerexpand=1 +fi + +if $cc -E eject.$src +then case "`$cc -E eject.$src | grep -c 'eject'`" in + 0) eject=1 ;; + esac +fi + +$cc -S ident.$src && grep "$id" ident.s && ident=1 + +{ $cc -E import.$src | grep aaa ;} && import=1 + +{ $cc -E -Iinc0 -Iinc1 inc_next.$src | grep INCLUDE_NEXT ;} && include_next=1 + +if $cc -c linefile1.i +then $cc -c linefile2.i + case $? in + 0) ;; + *) linefile=1 ;; + esac +fi + +if $cc -c lineid1.i 2>b +then $cc -c lineid2.i 2>e + c=$? +else $cc -c lineid3.c 2>e + c=$? +fi +case $c in +0) case `wc -l < b` in + `wc -l < e`) ;; + *) lineid=line ;; + esac + ;; +*) lineid=line + ;; +esac + +if $cc -E linetype.$src | grep '^[ ]*#[ ]*[0123456789]*[ ]*".*"[ ]*[12]' > linetype +then if grep '^[ ]*#[ ]*[0123456789]*[ ]*".*"[ ]*[12][ ][ ]*3' linetype + then linetype=2 + else linetype=1 + fi +fi + +{ $cc -E once.$src | grep allmultiple ;} && allmultiple=1 + +$cc -c plusplus.$src && plusplus=1 + +$cc -c span.$src && stringspan=1 + +$cc -c splice.$src && splicecat=1 + +$cc -c splicesp.$src && splicespace=1 + +exec < $ppkey +while read keyword type alternate comment +do case $keyword in + .) break ;; + ""|"#") continue ;; + esac + case $type in + ""|".") type= ;; + *) type="=$type" ;; + esac + for pre in '' _ __ + do for suf in '' _ __ + do case $suf in + '') sep= ;; + *) sep=. ;; + esac + case ,,$alternate, in + *,$pre$sep$suf,*) + key=$pre$keyword$suf + undef="$undef $key" + echo "int f(){ + int $key = 0; + return $key; +} +#undef $key +int g(){ + int $key = 0; + return $key; +}" > key.$src + $cc -c key.$src >/dev/null 2>&1 || reserved="$reserved $key$type" + ;; + esac + done + done +done + +$cc -c opspace.$src && opspace=1 + +case $plusplus in +"") $cc -c compat.$src && compatibility= + $cc -c pluscom.$src && pluscom=1 + ;; +esac +case $plusplus$pluscom in +?*) $cc -c plusspl.$src || plussplice=1 ;; +esac +case $plusplus in +?*) mkdir reguard + cd reguard + echo '#include "ptrone.h" +#include "ptrdef.h" +int main () { return gt(2,1) + gt(2.0,1.0); }' > ptr.$src + echo '#include "ptrone.h" +template<class T> int gt(T a, T b) { return a > b; }' > ptrdef.$src + echo 'template<class T> int gt(T a, T b);' > ptrdef.h + echo '/* empty */' > ptrone.h + if $cc -E ptr.$src > x.i && $cc x.i + then echo '#ifndef _PTRONE_H +#define _PTRONE_H +static int xxx; +#endif' > ptrone.h + if $cc -E ptr.$src > x.i && echo "#define _PTRONE_H" >> x.i && $cc x.i + then reguard=1 + fi + fi + cd .. + rm -rf reguard + ;; +esac + +stdc=`$cc -E stdc.$src | sed -e '/stdc_default_value/!d' -e 's/.*=[ ]*//' -e 's/[ ]*;.*//'` +case $stdc in +0) $cc -c trans.$src && transition=1 ;; +[0123456789]*) ;; +*) stdc= ;; +esac + +truncate=`$cc -E truncate.$src | grep '^[ ]*[0123456789]'` +$cc -c zeof.c || zeof=1 + +echo "$predef" >> all.pp +{ + case $ppopt$ppenv in + ?*) ppcmd=cpp + ppdir=. + eval $ppenv '$'cc -Dmycpp -E '$'ppopt cpp.$src + ;; + esac + eval set x $probe_verbose + shift + x= + for o in "$@" + do set x `$cc $o -c cpp.$src 2>&1` + while : + do shift + case $# in + 0) break ;; + esac + case $1 in + *[\\/]rm) + ;; + [\\/]*) case " $x " in + *" $1 "*) ;; + *) test -x $1 && x="$x $1" ;; + esac + ;; + esac + done + case $x in + ?*) for f in $x + do cp $f x && chmod u+w x && strip x && f=x + $ppsym < $f + done + break + ;; + esac + done +} 3>&- 3>&1 >/dev/null | + sed -e '/^ppsymbol$/d' -e '/^.$/d' -e '/^..$/d' -e '/[ABCDEFGHIJKLMNOPQRSTUVWXYZ].*[abcdefghijklmnopqrstuvwxyz]/d' -e '/[abcdefghijklmnopqrstuvwxyz].*[ABCDEFGHIJKLMNOPQRSTUVWXYZ]/d' | + cat - all.pp | + sort -u | + { + for i in 0 1 2 3 4 5 + do echo "struct { char* name; long value; } predef[] = {" > cpp$i.$src + done + while read sym junk + do case $sym in + _*) set 0 ${sym} + ;; + *_) continue + ;; + [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]*) + set 1 ${sym} 2 _${sym} 3 _${sym}_ 4 __${sym} 5 __${sym}__ + ;; + *) continue + ;; + esac + while : + do case $# in + 0|1) break ;; + esac + { + echo "#ifdef $2" + echo "\"$2\" , (long) $2 -1," + echo "#endif" + } >> cpp$1.$src + shift + shift + done + done + for i in 0 1 2 3 4 5 + do echo "\"\", 0 };" >> cpp$i.$src + done + } +preval="`for i in 0 1 2 3 4 5;do $cc -E cpp$i.$src;done | sed -e '/\".*\".*,.*,/!d' -e 's/[^\"]*\"\\([^\"]*\\)\"[ ]*,[ ]*([ ]*long[ ]*)[ ]*\\(.*\\)[ ]*-[ ]*1[ ]*,[ ]*\$/\\1 \\2 =/g'` `$cc -dM -E stdc.$src | sed -e '/[ ]*#[ ]*define/!d' -e '/\"/d' -e 's/[ ]*#[ ]*define[ ]*\\([abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]*\\)[ ]*\\(.*\\)/\\1 \\2 =/'`" + +for i in bufld namei quota reboot utsname vfs +do echo "#include <sys/$i.h>" > t.$src + if $cc -E t.$src + then x=1 + else x=0 + fi + eval sys_$i=$x +done + +case "`grep -c '__STDC__[-0 ]*[=!]=[ ]*0' $usrinclude/stdio.h 2>/dev/null`" in +0) ;; +*) hostedtransition=1 ;; +esac + +mapinclude= +for i in builtins +do echo "#include <$i.h>" > t.$src + if $cc -E t.$src + then mapinclude="$mapinclude <$i.h>=\".\"" + fi +done + +# +# the payoff +# + +exec >&3 + +case "$compatibility:$transition:$dollar" in +::) strict=1 ;; +esac +case $version_stamp in +?*) echo "/* $version_stamp" ;; +*) echo "/* $cc" ;; +esac +echo "*/" +case $plusplus:$stdc in +1:?*) preval="$preval = __STDC__ $stdc =" + redef="$redef __STDC__" + ;; +esac +ppbuiltin=0 +set x $preval +shift +case $# in +0) ;; +*) echo + echo "#pragma pp:predefined" + predef= + while : + do case $# in + 0) break ;; + esac + m=$1 + shift + case $m in + *'('*) i=`echo "$m" | sed 's,(.*,,'` ;; + *) i=$m ;; + esac + predef="$predef +$i" + eval predef_$i=0 + while : + do case $1 in + '=') break ;; + *) shift ;; + esac + done + while : + do case $1 in + '=') shift ;; + *) break ;; + esac + done + done + for i in $undef + do case " $redef " in + *" $i "*) ;; + *) eval predef_$i=3 ;; + esac + done + set $preval + while : + do case $# in + 0) break ;; + esac + m=$1 + shift + case $m in + *'('*) i=`echo "$m" | sed 's,(.*,,'` ;; + *) i=$m ;; + esac + case $i in + '=') continue ;; + esac + v= + while : + do case $1 in + '=') break ;; + esac + v="$v $1" + shift + done + while : + do case $1 in + '=') shift ;; + *) break ;; + esac + done + case $i in + __LCC__)strict=2 ;; + _*) ;; + *) eval j=\$predef_$i + case $j in + 0) eval predef_$i=1 + echo "#define $m$v" + case $strict in + 1) strict= ;; + esac + ;; + esac + ;; + esac + done + nopredef=0 + while : + do set $preval + while : + do case $# in + 0) break ;; + esac + m=$1 + shift + case $m in + *'('*) i=`echo "$m" | sed 's,(.*,,'` ;; + *) i=$m ;; + esac + v= + while : + do case $1 in + '=') break ;; + esac + v="$v $1" + shift + done + while : + do case $1 in + '=') shift ;; + *) break ;; + esac + done + case $nopredef in + 2) ;; + *) case $v in + ' '*' '*) + nopredef=1 + continue + ;; + ' '[0123456789]*|' '"'"*"'"*) + ;; + *) case $1 in + _*) ;; + *) nopredef=1 + continue + ;; + esac + ;; + esac + ;; + esac + eval j=\$predef_$i + case $j in + 0) case $ppbuiltin in + 2) echo "#pragma pp:builtin" + ppbuiltin=1 + ;; + esac + eval predef_$i=2 + echo "#define $m$v" + ;; + 1) case $m in + $i) eval predef_$i=2 + eval j=\$predef___${i}__ + case $j in + [12]) ;; + *) case $ppbuiltin in + 2) echo "#pragma pp:builtin" + ppbuiltin=1 + ;; + esac + eval predef___${i}__=2 + echo "#define __${i}__$v" + ;; + esac + ;; + esac + ;; + esac + done + case $nopredef in + 2) break ;; + esac + echo "#pragma pp:nopredefined" + case $nopredef in + 0) break ;; + esac + ppbuiltin=2 + nopredef=2 + done + ;; +esac +case $basefile in +?*) case $ppbuiltin in + 0|2) ppbuiltin=1 + echo "#pragma pp:builtin" + ;; + esac + echo "#define $basefile #(BASE)" + ;; +esac +case $ppbuiltin in +1) echo "#pragma pp:nobuiltin" ;; +esac + +eval set x $probe_longlong +shift +x= +for o in "$@" +do rm -f longlong.$exe + if $cc -DLONGLONG="$o" -o longlong.$exe longlong.$src && + ./longlong.$exe + then x=1 + break + fi +done +case $x in +'') eval set x $probe_longlong_t + shift + for o in "$@" + do rm -f longlong.$exe + if $cc -DLONGLONG="$o" -o longlong.$exe longlong.$src && + ./longlong.$exe + then echo "#define <long long> $o" + break + fi + done + ;; +esac + +echo +for i in `echo "$predef" | sed -e 's/^__*\(.*\)_*\$/\1/' -e '/^[abcdefghijklmnopqrstuvwxyz][abcdefghijklmnopqrstuvwxyz]*[0123456789][abcdefghijklmnopqrstuvwxyz0123456789]*\$/!d'` `echo "$predef" | sed -e 's/^__*\(.*\)_*\$/\1/' -e '/^[abcdefghijklmnopqrstuvwxyz][abcdefghijklmnopqrstuvwxyz]*\$/!d'` +do case $i in + *ix) ;; + *) architecture=$i + break + ;; + esac +done +for i in `sed -e '/^#/d' -e '/:architecture:/!d' -e 's/[ ].*//' < $ppdef` +do eval j="\" \$predef_$i \$predef__${i} \$predef__${i}_ \$predef___${i} \$predef___${i}__ \"" + case $j in + *" 2 "*)architecture=$i + break + ;; + esac +done +for i in `sed -e '/^#/d' -e '/:machine:/!d' -e 's/[ ].*//' < $ppdef` +do eval j="\" \$predef_$i \$predef__${i} \$predef__${i}_ \$predef___${i} \$predef___${i}__ \"" + case $j in + *" 2 "*)machine="$machine $i" ;; + esac +done +case $sys_bufld$sys_reboot$sys_utsname in +1??) release=research + version=9 + ;; +01?) release=bsd + case $sys_quota in + 0) case $sys_vfs in + 0) version=4.1 + ;; + esac + ;; + 1) case $sys_namei in + 0) version=4.2 + ;; + 1) version=4.3 + ;; + esac + ;; + esac + ;; +001) release=V + ;; +esac +for i in `sed -e '/^#/d' -e '/:release:/!d' -e 's/[ ].*//' < $ppdef` +do eval j=\$predef_$i + case $j in + 2) release="$release $i" ;; + esac +done +for i in `sed -e '/^#/d' -e '/:system:/!d' -e 's/[ ].*//' < $ppdef` +do eval j=\$predef_$i + case $j in + 2) system="$system $i" ;; + esac +done +case $release in +topix) release="$release V" + ;; +esac +case $assert in +?*) for i in $predef + do case $i in + _*|*_) ;; + *) for p in architecture cpu machine system + do echo "#if #$p($i) +eval \"case \\\" \$$p \\\" in *\\\" $i \\\"*) ;; *) $p=\\\"$i \$$p\\\" ;; esac\" +: avoid string literal concatenation +#endif" + done + ;; + esac + done > t.$src + eval "`$cc -E t.$src`" + set x x $prepred + while : + do shift + shift + case $# in + [01]) break ;; + esac + eval " + case \" \$$1 \" in + *\" $2 \"*) ;; + *) $1=\"$2 \$$1\" ;; + esac + " + done + ;; +esac +case $system in +"") system=unix ;; +esac +case $architecture in +ibm|uts|u370) model=370 + architecture=ibm + ;; +m*68*) architecture=m68000 + for i in $predef + do case $i in + m*68*[123456789][0123456789]) + model=`echo $i | sed 's/.*\(..\)/\1/'` + break + ;; + esac + done + ;; +u3b?*) model=`echo $architecture | sed 's/u3b//'` + architecture=3b + ;; +u3b) case $model in + "") model=20 ;; + esac + architecture=3b + ;; +vax[0123456789]*) + model=`echo $architecture | sed 's/vax//'` + architecture=vax + ;; +hp[0123456789]*s[0123456789]) + case $release in + [abcdefghijklmnopqrstuvwxyz]*.[abcdefghijklmnopqrstuvwxyz]*.*) + version=$release + release=V + ;; + esac + architecture="$architecture `echo $architecture | sed 's/s.*//'`" + ;; +esac +case $hosttype in +*.*) i=`echo $hosttype | sed -e 's,.*\.,,'` ;; +*) i=$hosttype ;; +esac +case $i in +unknown);; +?*) case " $architecture " in + *" $i "*) ;; + *) architecture="$architecture $i" ;; + esac + ;; +esac +case $architecture in +"") echo "$cc: warning: architecture not determined" >&4 + set x $machine + architecture=$2 + ;; +esac +echo "#define #hosttype($hosttype)" +for i in $system +do echo "#define #system($i)" +done +case $release in +"") echo "#define #release()" ;; +*) for i in $release + do echo "#define #release($i)" + case $i in + V) echo "#define #release(system5)" ;; # compatibility + esac + done + ;; +esac +echo "#define #version($version)" +case $architecture in +"") echo "#define #architecture()" ;; +*) for i in `echo $architecture | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + do echo "#define #architecture($i)" + done + ;; +esac +echo "#define #model($model)" +case $machine in +"") case $architecture:$model in + ?*:?*) set x $architecture; machine="$2/$model $architecture" ;; + *) machine=$architecture ;; + esac + ;; +*) machine="$machine $architecture" + ;; +esac +case $machine in +"") echo "#define #machine()" ;; +*) j= + for i in `echo $machine | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + do case " $i " in + *" $j "*) + ;; + *) j="$j $i" + echo "#define #machine($i)" + ;; + esac + done + ;; +esac +for i in $cpu +do echo "#define #cpu($i)" +done +echo "#define #addressing()" +for i in $ATTRIBUTES +do eval d=\$$i + n=`echo $i | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + echo "#define #$n($d)" +done +case $stdc in +?*) echo "#define #dialect(ansi)" ;; +esac +case $plusplus in +?*) echo "#define #dialect(C++)" ;; +esac +case $hosted in +"") echo "#define #dialect(cross)" ;; +esac +case $so:$dynamic:$static in +::) ;; +*) echo "#define #dialect(dynamic)" ;; +esac +echo +case $plusplus in +?*) echo "#pragma pp:plusplus" ;; +esac +case $reserved in +?*) echo "#pragma pp:reserved" $reserved ;; +esac +case $nocatliteral in +?*) echo "#pragma pp:nocatliteral" ;; +esac +case $opspace in +?*) echo "#pragma pp:opspace" ;; +esac +case $pluscom in +?*) echo "#pragma pp:pluscomment" ;; +esac +case $plussplice in +?*) echo "#pragma pp:plussplice" ;; +esac +case $reguard in +?*) echo "#pragma pp:reguard" ;; +esac +case $splicecat in +?*) echo "#pragma pp:splicecat" ;; +esac +case $splicespace in +?*) echo "#pragma pp:splicespace" ;; +esac +case $stringspan in +?*) echo "#pragma pp:stringspan" ;; +esac +case $stdc in +"") echo "#pragma pp:compatibility" + ;; +0) echo "#pragma pp:transition" + ;; +1) case $strict in + ?*) echo "#pragma pp:strict" ;; + esac + ;; +esac +case $hostedtransition in +1) echo "#pragma pp:hostedtransition" ;; +esac +case $stdc in +?*) case $ppopt$ppenv in + "") spaceout=1 + echo "#pragma pp:spaceout" + ;; + esac + ;; +esac +case $truncate in +?*) echo "#pragma pp:truncate $truncate" ;; +esac +case $zeof in +?*) echo "#pragma pp:zeof" ;; +esac +case $dollar in +1) echo '#pragma pp:id "$"' ;; +esac +cdir=-I+C +hdir=-I+H +set x $stdinclude +while : +do shift + case $# in + 0) break ;; + esac + case $1 in + $cdir|$hdir) + ;; + -I+C) cdir=$1 + echo "#pragma pp:nocdir" + ;; + -I-C) cdir=$1 + echo "#pragma pp:cdir" + ;; + -I+H) hdir=$1 + echo "#pragma pp:nohostdir" + ;; + -I-H) hdir=$1 + echo "#pragma pp:hostdir" + ;; + -I*) ;; + *) echo "#pragma pp:include \"$1\"" + ;; + esac +done +case $usrinclude in +/usr/include) + ;; +?*) echo "#pragma pp:standard \"$usrinclude\"" + ;; +esac +case $plusplus in +?*) case $usrinclude in + ?*) if grep plusplus $usrinclude/ctype.h >/dev/null 2>&1 + then echo '#pragma pp:nocdir "-"' + fi + ;; + esac + ;; +esac +case $mapinclude in +?*) echo "#pragma pp:mapinclude hosted$mapinclude" ;; +esac +case $linefile in +?*) echo "#pragma pp:linefile" ;; +esac +case $lineid in +?*) echo "#pragma pp:lineid line" ;; +esac +case $linetype in +1) echo "#pragma pp:linetype" ;; +?*) echo "#pragma pp:linetype $linetype" ;; +esac +case $allmultiple in +"") echo "#pragma pp:noallmultiple" ;; +esac +case $defincl in +1) echo '#pragma pp:map "/#(pragma )?defincl>/"' ;; +esac +case $eject in +1) echo '#pragma pp:map "/#(pragma )?eject>/"' ;; +esac +case $elseif in +1) echo "#pragma pp:elseif" ;; +esac +case $headerexpand in +1) echo "#pragma pp:headerexpand" ;; +esac +case $headerexpandall in +1) echo "#pragma pp:headerexpandall" ;; +esac +case $ident in +1) echo '#pragma pp:map "/#(pragma )?ident>/" "/#(pragma )?/###/"' ;; +*) echo '#pragma pp:map "/#(pragma )?ident>/"' ;; +esac +case $import in +1) echo '#pragma pp:map "/#(pragma )?import>/" "/#(pragma )?import(.*)/__STDPP__IMPORT__(\2)/" +#macdef __STDPP__IMPORT__(x) +#pragma pp:noallmultiple +#include x +#pragma pp:allmultiple +#endmac' ;; +esac +case $include_next in +1) echo '#pragma pp:map "/#include_next>/" ",[^\<]*\<,#include <.../,"' ;; +esac +echo '#pragma pp:map "/#pragma lint:/" ",#pragma lint:(.*),##/*\1*/,u"' +echo '#pragma pp:map "/#(pragma )?sccs>/"' + +case $stdc:$spaceout in +1:) case ' '$reserved' ' in + *' 'asm' '*|*' 'asm=*) + echo "#macdef asm" + echo "#pragma pp:spaceout" + echo "#undef asm" + echo "asm" + echo "#endmac" + ;; + esac + ;; +esac + +if $cc -E preinc.$src > preinc.out +then for f in `sed -e 's,\\\\,/,g' -e 's,"[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]:/,"/,g' -e '/^#[line ]*[0123456789][0123456789]*[ ][ ]*"[\\/]/!d' -e 's/^#[line ]*[0123456789][0123456789]*[ ][ ]*".*[\\/]\(.*\)".*/\1/' preinc.out | sort -u` + do case $f in + *preinc.$src*) + ;; + *) echo "#include <$f>" + ;; + esac + done +fi diff --git a/usr/src/lib/libpp/common/pp.tab b/usr/src/lib/libpp/common/pp.tab new file mode 100644 index 0000000000..30a576d404 --- /dev/null +++ b/usr/src/lib/libpp/common/pp.tab @@ -0,0 +1,233 @@ +# +# Glenn Fowler +# AT&T Research +# +# @(#)pp.tab (AT&T Labs Research) 2006-05-09 +# +# C preprocessor tables and states +# +# + marks extensions to the standard +# + +%keywords "static struct ppkeyword directives" + + define + elif + else + endif + +endmac + error + if + ifdef + ifndef + include + +let + line + +macdef + pragma + +rename + undef + +warning + +%keywords "static struct ppkeyword options" prefix=X_ index=optindex last=last_option + + allmultiple + allpossible + builtin + catliteral + cdir + checkpoint + chop + compatibility + debug + elseif + externalize + final + hide + headerexpand + headerexpandall + hosted + hostedtransition + hostdir + id + ignore + include + initial + keyargs + line + linebase + linefile + lineid + linetype + macref + map + mapinclude + modern + multiple + native + note + opspace + passthrough + pedantic + pluscomment + plusplus + plussplice + pragmaflags + pragmaexpand + predefined + prefix + preserve + proto + prototyped + quote + readonly + reguard + reserved + spaceout + splicecat + splicespace + standard + statement + strict + stringspan + stringsplit + system_header + test + text + transition + truncate + vendor + version + warn + zeof + +%keywords "static struct ppkeyword predicates" prefix=X_ index=optindex + + defined + +exists + +included + +match + +noticed + +option + sizeof + +strcmp + +%keywords "static struct ppkeyword readonlys" prefix=R_ + + defined + +%flags # state : coupled, high frequency + + ADD # add pp.addbuf into output buffer + COLLECTING # collecting macro call arguments + COMPATIBILITY # compatibility (Reiser) dialect + COMPILE # tokenize for compiler + CONDITIONAL # processing #[el]if directive + DEFINITION # processing macro definition + DIRECTIVE # processing directive + DISABLE # disable macro evaluation + EOF2NL # pass eof as newline token + ESCAPE # \ -> \\ in QUOTE|SQUOTE + FILEPOP # 0 on IN_FILE pop - no popin + HEADER # processing include statement + HIDDEN # hidden lines encountered + JOINING # joining adjacent strings + NEWLINE # last non-space was newline + NOEXPAND # no macro expansions or disables + NOSPACE # don't pass space+ as token + NOTEXT # don't output text + NOVERTICAL # vertical space invalid + PASSEOF # pass EOF as 0 without pop + PASSTHROUGH # ppcpp expands # lines only + QUOTE # processing "..." token + SKIPCONTROL # skip until # control or EOF + SKIPMACRO # disable next macro + SPACEOUT # output spaces in STANDALONE + SQUOTE # processing '...' token + STANDALONE # output tokens on stdout + STRICT # strict implementation + STRIP # strip quotes from T_STRING and T_CHARCONST + SYNCLINE # output line sync soon + TRANSITION # on the COMPATIBILITY boundary + WARN # note obnoxious incompatibilities + +%flags # mode : coupled, low frequency + + ALLMULTIPLE # all files can be included more than once + BUILTIN # mark macro definitions builtin + CATLITERAL # concatenate adjacent "..." + DUMP # do a checkpoint dump + EXPOSE # expose hidden macros + EXTERNALIZE # set PROTO_EXTERNALIZE + FILEDEPS # output file dependencies + GENDEPS # missings FILEDEPS are generated + HEADERDEPS # <...> too for FILEDEPS + HOSTED # hosted include file + HOSTEDTRANSITION # hosted include files get __STDC__=0 + INACTIVE # inactive conditional branch + INIT # initialization phase + LOADING # loading a checkpoint file + MARKC # last ppsearch() file was in C language + MARKHOSTED # last ppsearch() file was hosted + MARKMACRO # mark macro to disable later + PEDANTIC # pedantic non-hosted non-standard warnings + READONLY # mark macro definitions readonly + RELAX # relax complaints for this directive + +%flags # options : uncoupled, low frequency + + ALLPOSSIBLE # ignore top level conditionals + DEFINITIONS # output macro definitions + ELSEIF # #else if|ifdef|ifndef ok + FINAL # final hosted macro value + HEADEREXPAND # HEADEREXPANDALL but macro args not expanded + HEADEREXPANDALL # expanded < does not quote #include macros + IGNORELINE # ignore #line until first file arg + INITIAL # initial hosted macro value + KEEPNOTEXT # keep NOTEXT setting + KEYARGS # name=value macro arguments + MODERN # generate modern output (\a instead of \007) + NATIVE # report native paths + NOHASH # don't hash PP_COMPILE T_ID's + NOISE # convert T_X_* to T_NOISES + NOISEFILTER # filter (ignore) NOISE + NOPROTO # disable ppproto() + PLUSCOMMENT # enable C++ comments + PLUSPLUS # preprocess for C++ + PLUSSPLICE # C++ // \<newline> does not splice + PRAGMAEXPAND # expand #pragma args + PREDEFINED # mark macro definitions predefined + PREDEFINITIONS # output predefined macro definitions + PREFIX # prefix include for compatibility + PRESERVE # preserve input layout + PROTOTYPED # force all input to be prototyped + REGUARD # emit header guard define at file pop + SPLICECAT # \<newline> ok for COMPATIBILITY catenation + SPLICESPACE # \<space>+<newline> == \<newline> for jcl + STRINGSPAN # <newline> in string ok + STRINGSPLIT # "...\\n..." => "..."\n"..." + TRUNCATE # truncate identifiers + ZEOF # ^Z anywhere in file => EOF + +%keywords "static struct ppkeyword variables" prefix=V_ index=optindex + + _Pragma + +ARGC + +BASE + DATE + FILE + +FUNCTION + LINE + +PATH + +SOURCE + -STDC + TIME + +VERSION + -default + -directive + -empty + -getenv + -getmac + -getopt + -getprd + -iterate diff --git a/usr/src/lib/libpp/common/ppargs.c b/usr/src/lib/libpp/common/ppargs.c new file mode 100644 index 0000000000..0aaff3905e --- /dev/null +++ b/usr/src/lib/libpp/common/ppargs.c @@ -0,0 +1,603 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * common preprocessor command line argument parse + * called by optjoin() + */ + +static const char usage[] = +"[-?\n@(#)$Id: cpp (AT&T Research) 2006-01-11 $\n]" +USAGE_LICENSE +"[+NAME?cpp - C language preprocessor]" +"[+DESCRIPTION?\bcpp\b is the preprocessor for all C language dialects. It is" +" a standalone version of the \blibpp\b(3) preprocessor library. The" +" C dialect implemented by \bcpp\b is determined by probing \bcc\b(1)" +" using \bprobe\b(1). The path of the emulated compiler can be changed" +" by the \b-D-X\b command line option.]" +"[+?If \aoutput\a is omitted then the standard output is written; if \ainput\a" +" is also omitted then the standard input is read. NOTE: this is an" +" ancient, non-standard, non-intuitiive file operand syntax that is" +" required by \bcc\b(1); use shell file name expansion at your peril.]" +"[+?\bcpp\b specific options are set by the \b-D-\b and \b-I-\b options.]" + +"[C:comments?Pass comments to the output. By default comments are omitted.]" +"[D:define?Define the macro \aname\a to have \avalue\a; \b1\b is assumed if" +" \b=\b\avalue\a is omitted. If \aname\a begins with \b:\b then it is" +" interpreted as a \blibpp\b(3) \b#pragma pp:\b statement; if \aname\a" +" begins with \b%\b then it is interpreted as a \blibpp\b(3) \b#\b" +" directive statement; if \aname\a begins with \b-\b or \b+\b then it is" +" interpreted as a \blibpp\b(3) option; \b-\b turns the option on," +" \b+\b turns it off. Most options have a \b#pragma\b counterpart that" +" is listed with the option definition. Right, this is ugly, but its the" +" only portable way to pass options through \bcc\b(1) to" +" \bcpp\b:]:[name[=value]]]{" +" [+-D-C, pp::compatibility?Preprocess for K&R compatibility.]" +" [+-D-D\alevel\a, \bpp::debug\b \alevel\a?Set the debug trace level." +" Higher levels produce more output. Levels higher than 3" +" enabled only in \b-g\b compiled versions.]" +" [+-D-F\aname\a?Set the main input file name to \aname\a. This only" +" affects error message and line sync output.]" +" [+-D-H, pp::hosted?All directories are hosted; compatibility" +" warning messages from hosted directory headers are suppressed.]" +" [+-D-I, pp::cdir?All directories contain C headers; used only with" +" \b-D-+\b.]" +" [+-D-K, pp::keyargs?Enable the non-standard \aname=value\a macro" +" argument mode.]" +" [+-D-L\b[\aid\a]], \bpp::lineid\b [\aid\a]]?Set the line sync directive" +" id to \aid\a or null if omitted.]" +" [+-D-M, pp::nomultiple?Disable multiple include detection.]" +" [+-D-P, pp::passthrough?Enable the non-standard passthrough mode; may" +" be useful for processing non-C input.]" +" [+-D-Q, pp::dump?Dump macro definitions to the output so that the" +" output may be passed through \bcpp\b again. Used for" +" generating precompiled headers.]" +" [+-D-R, pp::transition?Enable the transition preprocessing mode. Used" +" for compilers that can't make up their semantics between" +" K&R and ISO.]" +" [+-D-S, pp::strict?Enable strict preprocessing semantics and warnings." +" Works with any mode (compatibiliy, transition," +" or the default ISO).]" +" [+-D-T\atest\a, \bpp::test\b \atest\a?Enable implementation specific" +" test code according to \atest\a.]" +" [+-D-W, pp::warn?Enable pedantic warnings in non-hosted files.]" +" [+-D-X\b[\acc\a]]?Preprocess for the compiler \acc\a which must be" +" an executable path or an executable on \b$PATH\b.]" +" [+-D-Z, pp::pool?Enable pool mode. See \blibpp\b(3).]" +" [+-D-d?List canonicalized \b#define\b statements for non-predefined" +" macros in the output. ]" +" [+-D-m?List canonicalized \b#define\b statements for all macros. All" +" other output is disabled.]" +" [+-D-+, pp::plusplus?Preprocess for the C++ dialect.]" +"}" +"[I:include?Append \adirectory\a to the list of directories searched for" +" \b#include\b files. If \adirectory\a is \b-\b then: (1) \b-I\b" +" directories before \b-I-\b are searched only for \"...\" include" +" files; (2) \b-I\b directories after \b-I-\b are searched for" +" \"...\" and <...> include files; (3) the directory \b.\b is searched" +" only if it is explicitly specified by a \b-I\b option.]:?[directory]{" +" [+-I-C\adirectory\a, \bpp::cdir\b \adirectory\a?Mark \adirectory\a" +" as a C header directory. Used with \bpp:plusplus\b.]" +" [+-I-D[\afile\a]]?Read the default \bprobe\b(1) definitions from" +" \afile\a, or ignore the default definitions if \afile\a" +" is omitted.]" +" [+-I-H\adirectory\a, \bpp::hostdir\b \adirectory\a?Mark \adirectory\a" +" as a hosted directory. Headers from hosted directories have" +" compatibility warnings disabled.]" +" [+-I-I\aheader\a, \bpp::ignore\b \aheader\a?Add \aheader\a to the" +" list of ignored headers.]" +" [+-I-M\afile\a?\afile\a contains a sequence of \aheader\a" +" [= \"\amap\a\" ]] lines, where \aheader\a is either <\aname\a>" +" or \"\aname\a\", and \"\amap\a\" is an explicit binding" +" for \aheader\a. \aheader\a is ignored if = \"\amap\a\" is" +" omitted.]" +" [+-I-R\afile\a?Include \afile\a but do not emit text or line syncs.]" +" [+-I-S\adirectory\a?Add \adirectory\a to the default standard include" +" directory list.]" +" [+-I-T\afile\a?Include \afile\a and emit text to the output file.]" +"}" +"[M:dependencies?Generate \bmake\b(1) dependencies. Not needed with" +" \bnmake\b(1). \b-M\b may be followed by optional \aflags\a to change" +" dependency output styles:]{" +" [+D?Generate dependencies in a separate \b.d\b file. Preprocessed" +" output is still written to \aoutput\a, or the standard output" +" if \aoutput\a is omitted.]" +" [+G?Generate missing dependencies too.]" +" [+M?Only generate local header dependencies; \ahosted\a headers are" +" omitted. Note that \ahosted\a headers are determined by" +" \b-I-H\b and the \bpp:hosted\b and \bpp:hostdir\b pragmas;" +" no special distiction is made between \"\" and <> \binclude\b" +" styles.]" +"}" +"[P!:sync?Emit line syncs.]" +"[U:undefine?Remove the definition for the macro \aname\a.]:[name]" + +"[A:assert?Enter the assertion via \b#assert\b for system V" +" compatibility.]:[assertion]" +"[E:preprocess?Ignored for compatibility with ancient compilers.]" +"[H:include-reference?Emit \b#include\b file paths on the standard error," +" one per line, indented to show nesting.]" +"[T?If not \bgcc\b(1) then truncate identifiers to \alength\a" +" characters for compatibility with old AT&T (I guess only Lucent needs" +" them now) compilers.]#?[length]" +"[V:version?Emit the \blibpp\b(3) version.]" +"[X:argmode?Enable \aname\a=\avalue\a macro arguments for \beasel\b(1)" +" compatibility.]" +"[Y:standard?Add \adirectory\a to the list searched for" +" \b#include\b \b<...>\b files.]:[directory]" + +"\n" +"\n[ input [ output ] ]\n" +"\n" + +"[+SEE ALSO?\bcc\b(1), \bgcc\b(1), \blibpp\b(3)]" +; + +#include "pplib.h" + +#include <ctype.h> + +/* + * convert lint comments to pragmas + */ + +static void +pplint(char* head, char* comment, char* tail, int line) +{ + NoP(line); + if (strmatch(comment, "(ARGSUSED|PRINTFLIKE|PROTOLIB|SCANFLIKE|VARARGS)*([0-9])|CONSTCOND|CONSTANTCOND|CONSTANTCONDITION|EMPTY|FALLTHRU|FALLTHROUGH|LINTLIBRARY|LINTED*|NOTREACHED")) + { + strncopy(pp.token, comment, MAXTOKEN); + ppprintf("\n#%s %s:%s\n", dirname(PRAGMA), pp.pass, pp.token); + ppline(error_info.line, NiL); + } +} + +/* + * if last!=0 then argv[opt_info.index]==0 with return(0) + * else if argv[opt_info.index]==0 then return(0) + * otherwise argv[opt_info.index] is the first unrecognized + * option with return(1) + * + * use last=0 if the preprocessor is combined with other passes + * so that unknown options may be interpreted for those passes + */ + +int +ppargs(char** argv, int last) +{ + register char* s; + register int c; + register int n; + char* p; + + /* + * check the args and initialize + */ + + if (!error_info.id) + error_info.id = "cpp"; + for (;;) + { + for (; c = optget(argv, usage); last = 0) switch (c) + { + case 'C': + ppop(PP_COMMENT, ppcomment); + break; + case 'D': + /* + * this allows single arg pp option extensions + * without touching cc + * (not all cc wrappers have -W...) + */ + + switch (*(s = opt_info.arg)) + { + case '-': + case '+': + n = (*s++ == '-'); + while (c = *s++) switch (c) + { + case 'C': + ppop(PP_COMPATIBILITY, n); + break; + case 'D': + if (n && ((c = strtol(s, &p, 0)) || p != s)) + { + s = p; + n = c; + } + ppop(PP_DEBUG, -n); + break; + case 'F': + ppop(PP_FILENAME, n ? s : NiL); + goto hasarg; + case 'H': + ppop(PP_HOSTDIR, "-", n); + break; + case 'I': + ppop(PP_CDIR, "-", n); + break; + case 'K': + ppop(PP_KEYARGS, n); + break; + case 'L': + ppop(PP_LINEID, n && *s ? s : "line"); + goto hasarg; + case 'M': + ppop(PP_MULTIPLE, !n); + break; + case 'P': + ppop(PP_PASSTHROUGH, n); + break; + case 'Q': + ppop(PP_DUMP, n); + break; + case 'R': + ppop(PP_TRANSITION, n); + break; + case 'S': + ppop(PP_STRICT, n); + break; + case 'T': + ppop(PP_TEST, s); + goto hasarg; + case 'V': + ppop(PP_VENDOR, "-", n); + break; + case 'W': + ppop(PP_WARN, n); + break; + case 'X': + ppop(PP_PROBE, n && *s ? s : 0); + goto hasarg; + case 'Z': + ppop(PP_POOL, n); + break; + case 'd': + pp.option |= DEFINITIONS; + break; + case 'm': + pp.state |= NOTEXT; + pp.option |= KEEPNOTEXT|DEFINITIONS|PREDEFINITIONS; + pp.linesync = 0; + break; + case '+': + ppop(PP_PLUSPLUS, n); + break; + default: + if (pp.optarg) + { + if ((c = (*pp.optarg)(n, c, s)) > 0) goto hasarg; + else if (!c) break; + } + error(1, "%c%s: unknown -D option overload", n ? '-' : '+', s - 1); + goto hasarg; + } + hasarg: + break; + case ':': + ppop(PP_OPTION, s + 1); + break; + case '%': + ppop(PP_DIRECTIVE, s + 1); + break; + case '_': + if (strmatch(s, "__GNUC__*")) + pp.arg_style |= STYLE_gnu; + else if (strmatch(s, "__(ANSI|STDC|STRICT)__*") || !(pp.arg_style & STYLE_gnu) && strmatch(s, "__STRICT_ANSI__*")) + ppop(PP_STRICT, 1); + else if (strmatch(s, "__cplusplus*")) + ppop(PP_PLUSPLUS, 1); + /*FALLTHROUGH*/ + default: + ppop(PP_DEFINE, s); + break; + } + break; + case 'E': + /* historically ignored */ + break; + case 'I': + if (!(s = opt_info.arg)) + { + /* + * some compilers interpret `-I ...' as + * `-I-S' and arg ... while others interpret + * it as `-I...' + */ + + p = "-S"; + if ((s = argv[opt_info.index]) && ((n = *s++) == '-' || n == '+') && *s++ == 'D') + { + if (isalpha(*s) || *s == '_') + while (isalnum(*++s) || *s == '_'); + if (*s && *s != '=' && *s != '-' && *s != '+') + p = argv[opt_info.index++]; + } + s = p; + } + switch (*s) + { + case '-': + case '+': + n = *(p = s++) == '-'; + c = *s++; + if (!n && !*s) s = 0; + switch (c) + { + case 0: + ppop(PP_LOCAL); + break; + case 'C': + ppop(PP_CDIR, s, n); + break; + case 'D': + ppop(PP_DEFAULT, s); + break; + case 'H': + ppop(PP_HOSTDIR, s, n); + break; + case 'I': + ppop(PP_IGNORE, s); + break; + case 'M': + ppop(PP_IGNORELIST, s); + break; + case 'R': + ppop(PP_READ, s); + break; + case 'S': + ppop(PP_STANDARD, s); + break; + case 'T': + ppop(PP_TEXT, s); + break; + case 'V': + ppop(PP_VENDOR, s, n); + break; + default: + error(1, "%s: unknown -I option overload", p); + break; + } + break; + default: + ppop(PP_INCLUDE, s); + break; + } + break; + case 'M': + for (n = PP_deps; argv[opt_info.index]; opt_info.offset++) + { + switch (argv[opt_info.index][opt_info.offset]) + { + case 'D': + n |= PP_deps_file; + continue; + case 'G': + n |= PP_deps_generated; + continue; + case 'M': + n |= PP_deps_local; + continue; + } + break; + } + ppop(PP_FILEDEPS, n); + break; + case 'P': + ppop(PP_LINE, (PPLINESYNC)0); + break; + case 'U': + ppop(PP_UNDEF, opt_info.arg); + break; + + /* + * System V CCS compatibility + */ + + case 'A': + if (isalpha(opt_info.arg[0]) || opt_info.arg[0] == '_' || opt_info.arg[0] == '$') + ppop(PP_ASSERT, opt_info.arg); + break; + case 'H': + ppop(PP_INCREF, ppincref); + break; + case 'T': + if (!(pp.arg_style & STYLE_gnu)) + ppop(PP_TRUNCATE, TRUNCLENGTH); + /* else enable ANSI trigraphs -- default */ + break; + case 'V': + error(0, "%s", pp.version); + break; + case 'X': + pp.arg_mode = (*(opt_info.arg + 1) || pp.arg_mode && pp.arg_mode != *opt_info.arg) ? '-' : *opt_info.arg; + break; + case 'Y': + if (*(s = opt_info.arg) && *(s + 1) == ',') + { + if (*s != 'I') break; + s += 2; + } + ppop(PP_STANDARD, s); + break; + + /* + * errors + */ + + case '?': + error(ERROR_USAGE|4, "%s", opt_info.arg); + break; + case ':': + if (!last) + { + opt_info.again = 1; + return(1); + } + + /* + * cross your fingers + */ + + if (!(s = argv[opt_info.index])) + error(3, "%s", opt_info.arg); + if (opt_info.offset == 2 && (pp.arg_style & STYLE_gnu)) + { + p = argv[opt_info.index + 1]; + if (streq(s, "-$")) + { + ppop(PP_OPTION, "noid \"$\""); + goto ignore; + } + else if (streq(s, "-dD")) + { + pp.option |= DEFINITIONS; + goto ignore; + } + else if (streq(s, "-dM")) + { + pp.state |= NOTEXT; + pp.option |= KEEPNOTEXT|DEFINITIONS|PREDEFINITIONS; + pp.linesync = 0; + goto ignore; + } + else if (streq(s, "-imacros")) + { + if (p) + { + ppop(PP_READ, p); + opt_info.index++; + opt_info.offset = 0; + } + goto ignore; + } + else if (streq(s, "-include")) + { + if (p) + { + ppop(PP_TEXT, p); + opt_info.index++; + opt_info.offset = 0; + } + opt_info.offset = 0; + goto ignore; + } + else if (strneq(s, "-lang-", 6)) + { + s += 6; + if (streq(s, "c")) + c = 0; + else if (streq(s, "c++")) + c = 1; + else if (streq(s, "objc")) + c = 2; + else if (streq(s, "objc++")) + c = 3; + ppop(PP_PLUSPLUS, c & 1); + if (c & 2) + ppop(PP_DIRECTIVE, "pragma pp:map \"/#(pragma )?import>/\" \"/#(pragma )?import(.*)/__STDPP__IMPORT__(\\2)/\"\n\ +#macdef __STDPP__IMPORT__(x)\n\ +#pragma pp:noallmultiple\n\ +#include x\n\ +#pragma pp:allmultiple\n\ +#endmac"); + goto ignore; + } + else if (streq(s, "-lint")) + { + ppop(PP_COMMENT, pplint); + goto ignore; + } + } + s += opt_info.offset - 1; + if (strmatch(s, "i*.h")) + ppop((pp.arg_style & STYLE_gnu) || s[1] == '/' ? PP_READ : PP_TEXT, s + 1); + else if (strmatch(s, "*@(nostandard|nostdinc)*")) + ppop(PP_STANDARD, ""); + else if (strmatch(s, "*@(exten|xansi)*|std")) + { + ppop(PP_COMPATIBILITY, 0); + ppop(PP_TRANSITION, 1); + } + else if (strmatch(s, "*@(ansi|conform|pedantic|stand|std1|strict[!-])*")) + { + ppop(PP_COMPATIBILITY, 0); + ppop(PP_STRICT, 1); + if (strmatch(s, "*pedantic*")) + ppop(PP_PEDANTIC, 1); + } + else if (strmatch(s, "*@(trans)*")) + { + ppop(PP_COMPATIBILITY, 1); + ppop(PP_TRANSITION, 1); + } + else if (strmatch(s, "*@(classic|compat|std0|tradition|[kK][n&+][rR])*")) + { + ppop(PP_COMPATIBILITY, 1); + ppop(PP_TRANSITION, 0); + } + else if (strmatch(s, "*@(plusplus|++)*")) + ppop(PP_PLUSPLUS, 1); + else if (strmatch(s, "*@(warn)*")) + ppop(PP_WARN, 1); + + /* + * ignore unknown options + * the probe info takes care of these + * fails if an option value is in the next arg + * and this is the last option + */ + + if (argv[opt_info.index + 1] && argv[opt_info.index + 1][0] != '-' && argv[opt_info.index + 2] && argv[opt_info.index + 2][0] == '-') + { + opt_info.index++; + opt_info.offset = 0; + } + ignore: + while (argv[opt_info.index][opt_info.offset]) opt_info.offset++; + break; + } + if (!(s = argv[opt_info.index])) return(0); + switch (pp.arg_file) + { + case 0: + if (*s != '-' || *(s + 1)) ppop(PP_INPUT, s); + break; + case 1: + if (*s != '-' || *(s + 1)) ppop(PP_OUTPUT, s); + break; + default: + if (!last) return(1); + error(1, "%s: extraneous argument ignored", s); + break; + } + pp.arg_file++; + if (!argv[++opt_info.index]) return(0); + + /* + * old versions allow options after file args + */ + } +} diff --git a/usr/src/lib/libpp/common/ppbuiltin.c b/usr/src/lib/libpp/common/ppbuiltin.c new file mode 100644 index 0000000000..b9a906f657 --- /dev/null +++ b/usr/src/lib/libpp/common/ppbuiltin.c @@ -0,0 +1,397 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor builtin macro support + */ + +#include "pplib.h" + +#include <times.h> + +/* + * process a #(...) builtin macro call + * `#(' has already been seen + */ + +void +ppbuiltin(void) +{ + register int c; + register char* p; + register char* a; + + int n; + int op; + char* token; + char* t; + long number; + struct ppinstk* in; + struct pplist* list; + struct ppsymbol* sym; + Sfio_t* sp; + + number = pp.state; + pp.state |= DISABLE|FILEPOP|NOSPACE; + token = pp.token; + p = pp.token = pp.tmpbuf; + *(a = pp.args) = 0; + if ((c = pplex()) != T_ID) + { + error(2, "%s: #(<identifier>...) expected", p); + *p = 0; + } + switch (op = (int)hashget(pp.strtab, p)) + { + case V_DEFAULT: + n = 0; + p = pp.token = pp.valbuf; + if ((c = pplex()) == ',') + { + op = -1; + c = pplex(); + } + pp.state &= ~NOSPACE; + for (;;) + { + if (!c) + { + error(2, "%s in #(...) argument", pptokchr(c)); + break; + } + if (c == '(') n++; + else if (c == ')' && !n--) break; + else if (c == ',' && !n && op > 0) op = 0; + if (op) pp.token = pp.toknxt; + c = pplex(); + } + *pp.token = 0; + pp.token = token; + pp.state = number; + break; + case V_EMPTY: + p = pp.valbuf; + if ((c = pplex()) == ')') *p = '1'; + else + { + *p = '0'; + n = 0; + for (;;) + { + if (!c) + { + error(2, "%s in #(...) argument", pptokchr(c)); + break; + } + if (c == '(') n++; + else if (c == ')' && !n--) break; + c = pplex(); + } + } + *(p + 1) = 0; + pp.token = token; + pp.state = number; + break; + case V_ITERATE: + n = 0; + pp.token = pp.valbuf; + if ((c = pplex()) != T_ID || !(sym = ppsymref(pp.symtab, pp.token)) || !sym->macro || sym->macro->arity != 1 || (c = pplex()) != ',') + { + error(2, "#(%s <macro(x)>, ...) expected", p); + for (;;) + { + if (!c) + { + error(2, "%s in #(...) argument", pptokchr(c)); + break; + } + if (c == '(') n++; + else if (c == ')' && !n--) break; + c = pplex(); + } + *pp.valbuf = 0; + } + else while (c != ')') + { + p = pp.token; + if (pp.token > pp.valbuf) *pp.token++ = ' '; + STRCOPY(pp.token, sym->name, a); + *pp.token++ = '('; + if (!c || !(c = pplex())) + { + pp.token = p; + error(2, "%s in #(...) argument", pptokchr(c)); + break; + } + pp.state &= ~NOSPACE; + while (c) + { + if (c == '(') n++; + else if (c == ')' && !n--) break; + else if (c == ',' && !n) break; + pp.token = pp.toknxt; + c = pplex(); + } + *pp.token++ = ')'; + pp.state |= NOSPACE; + } + p = pp.valbuf; + pp.token = token; + pp.state = number; + break; + default: + pp.token = token; + while (c != ')') + { + if (!c) + { + error(2, "%s in #(...) argument", pptokchr(c)); + break; + } + if ((c = pplex()) == T_ID && !*a) + strcpy(a, pp.token); + } + pp.state = number; + switch (op) + { + case V_ARGC: + c = -1; + for (in = pp.in; in; in = in->prev) + if ((in->type == IN_MACRO || in->type == IN_MULTILINE) && (in->symbol->flags & SYM_FUNCTION)) + { + c = *((unsigned char*)(pp.macp->arg[0] - 2)); + break; + } + sfsprintf(p = pp.valbuf, MAXTOKEN, "%d", c); + break; + case V_BASE: + p = (a = strrchr(error_info.file, '/')) ? a + 1 : error_info.file; + break; + case V_DATE: + if (!(p = pp.date)) + { + time_t tm; + + time(&tm); + a = p = ctime(&tm) + 4; + *(p + 20) = 0; + for (p += 7; *p = *(p + 9); p++); + pp.date = p = strdup(a); + } + break; + case V_FILE: + p = error_info.file; + break; + case V_LINE: + sfsprintf(p = pp.valbuf, MAXTOKEN, "%d", error_info.line); + break; + case V_PATH: + p = pp.path; + break; + case V_SOURCE: + p = error_info.file; + for (in = pp.in; in->prev; in = in->prev) + if (in->prev->type == IN_FILE && in->file) + p = in->file; + break; + case V_STDC: + p = pp.valbuf; + p[0] = ((pp.state & (COMPATIBILITY|TRANSITION)) || (pp.mode & (HOSTED|HOSTEDTRANSITION)) == (HOSTED|HOSTEDTRANSITION)) ? '0' : '1'; + p[1] = 0; + break; + case V_TIME: + if (!(p = pp.time)) + { + time_t tm; + + time(&tm); + p = ctime(&tm) + 11; + *(p + 8) = 0; + pp.time = p = strdup(p); + } + break; + case V_VERSION: + p = (char*)pp.version; + break; + case V_DIRECTIVE: + pp.state |= NEWLINE; + pp.mode |= RELAX; + strcpy(p = pp.valbuf, "#"); + break; + case V_GETENV: + if (!(p = getenv(a))) p = ""; + break; + case V_GETMAC: + p = (sym = pprefmac(a, REF_NORMAL)) ? sym->macro->value : ""; + break; + case V_GETOPT: + sfsprintf(p = pp.valbuf, MAXTOKEN, "%ld", ppoption(a)); + break; + case V_GETPRD: + p = (list = (struct pplist*)hashget(pp.prdtab, a)) ? list->value : ""; + break; + case V__PRAGMA: + if ((c = pplex()) == '(') + { + number = pp.state; + pp.state |= NOSPACE|STRIP; + c = pplex(); + pp.state = number; + if (c == T_STRING || c == T_WSTRING) + { + if (!(sp = sfstropen())) + error(3, "temporary buffer allocation error"); + sfprintf(sp, "#%s %s\n", dirname(PRAGMA), pp.token); + a = sfstruse(sp); + if ((c = pplex()) == ')') + { + pp.state |= NEWLINE; + PUSH_BUFFER(p, a, 1); + } + sfstrclose(sp); + } + } + if (c != ')') + error(2, "%s: (\"...\") expected", p); + return; + case V_FUNCTION: + +#define BACK(a,p) ((a>p)?*--a:(number++?0:((p=pp.outbuf+PPBUFSIZ),(a=pp.outbuf+2*PPBUFSIZ),*--a))) +#define PEEK(a,p) ((a>p)?*(a-1):(number?0:*(pp.outbuf+2*PPBUFSIZ-1))) + + number = pp.outbuf == pp.outb; + a = pp.outp; + p = pp.outb; + op = 0; + while (c = BACK(a, p)) + { + if (c == '"' || c == '\'') + { + op = 0; + while ((n = BACK(a, p)) && n != c || PEEK(a, p) == '\\'); + } + else if (c == '\n') + { + token = a; + while (c = BACK(a, p)) + if (c == '\n') + { + a = token; + break; + } + else if (c == '#' && PEEK(a, p) == '\n') + break; + } + else if (c == ' ') + /*ignore*/; + else if (c == '{') /* '}' */ + op = 1; + else if (op == 1) + { + if (c == ')') + { + op = 2; + n = 1; + } + else + op = 0; + } + else if (op == 2) + { + if (c == ')') + n++; + else if (c == '(' && !--n) + op = 3; + } + else if (op == 3) + { + if (ppisidig(c)) + { + for (t = p, token = a; ppisidig(PEEK(a, p)); a--); + for (p = pp.valbuf + 1; a <= token; *p++ = *a++); + *p = 0; + p = pp.valbuf + 1; + if (streq(p, "for") || streq(p, "if") || streq(p, "switch") || streq(p, "while")) + { + op = 0; + p = t; + continue; + } + } + else + op = 0; + break; + } + } + if (op == 3) + strncpy(pp.funbuf, p, sizeof(pp.funbuf) - 1); + else if (*pp.funbuf) + p = pp.funbuf; + else + p = "__FUNCTION__"; + break; + default: + if (pp.builtin && (a = (*pp.builtin)(pp.valbuf, p, a))) + p = a; + break; + } + break; + } + if (strchr(p, MARK)) + { + a = pp.tmpbuf; + strcpy(a, p); + c = p != pp.valbuf; + p = pp.valbuf + c; + for (;;) + { + if (p < pp.valbuf + MAXTOKEN - 2) + switch (*p++ = *a++) + { + case 0: + break; + case MARK: + *p++ = MARK; + /*FALLTHROUGH*/ + default: + continue; + } + break; + } + p = pp.valbuf + c; + } + if (p == pp.valbuf) + PUSH_STRING(p); + else + { + if (p == pp.valbuf + 1) + *pp.valbuf = '"'; + else + { + if (strlen(p) > MAXTOKEN - 2) + error(1, "%-.16s: builtin value truncated", p); + sfsprintf(pp.valbuf, MAXTOKEN, "\"%-.*s", MAXTOKEN - 2, p); + } + PUSH_QUOTE(pp.valbuf, 1); + } +} diff --git a/usr/src/lib/libpp/common/ppcall.c b/usr/src/lib/libpp/common/ppcall.c new file mode 100644 index 0000000000..8e273dc92f --- /dev/null +++ b/usr/src/lib/libpp/common/ppcall.c @@ -0,0 +1,452 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor macro call + */ + +#include "pplib.h" + +#include <ctype.h> + +/* + * call a macro by pushing its value on the input stream + * only the macro token itself has been consumed + * -1 returned if macro disabled + * 0 returned if tok==0 and sym->mac->value to be copied to output by caller + * 1 returned if value pushed on input + */ + +int +ppcall(register struct ppsymbol* sym, int tok) +{ + register int c; + register char* p; + register char* q; + register struct ppmacro* mac; + int n; + int m; + int ret; + int old_hidden; + int last_line; + long old_state; + char* last_file; + char* old_token; + struct ppmacstk* mp; + struct ppinstk* old_in; + struct ppinstk* kp; + struct pptuple* tp; + + ret = -1; + sym->flags |= SYM_NOTICED; + if (mac = sym->macro) + { + count(macro); + if ((sym->flags & SYM_PREDICATE) && (pp.state & (CONDITIONAL|WARN)) == (CONDITIONAL|WARN)) + error(1, "%s: macro definition overrides assertion: use #%s ...", sym->name, sym->name); + if (sym->flags & SYM_DISABLED) +#if COMPATIBLE + if ((pp.state & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY || !mac->arity) +#endif + { + pp.mode |= MARKMACRO; +#if COMPATIBLE + if ((pp.state & (COMPATIBILITY|STRICT)) == (COMPATIBILITY|STRICT)) + error(1, "%s: macro recursion inhibited", sym->name); +#endif + goto disable; + } + if ((sym->flags & SYM_PREDEFINED) && !(pp.mode & (HOSTED|INACTIVE))) + { +#if COMPATIBLE + if (*sym->name != '_' && !(pp.state & COMPATIBILITY)) +#else + if (*sym->name != '_') +#endif + { + if (pp.state & STRICT) + { + error(1, "%s: obsolete predefined symbol expansion disabled", sym->name); + goto disable; + } + error(1, "%s: obsolete predefined symbol expanded%s", sym->name, (pp.state & DIRECTIVE) ? "" : " outside of directive"); + } + else if (!(pp.state & DIRECTIVE) && mac->value && (ppisdig(*mac->value) || *mac->value == '#')) + error(1, "%s: predefined symbol expanded outside of directive", sym->name); + } + debug((-5, "macro %s = %s", sym->name, mac->value)); + if (pp.macref) + (*pp.macref)(sym, error_info.file, error_info.line, (pp.state & CONDITIONAL) ? REF_IF : REF_NORMAL, 0L); + if (tp = mac->tuple) + { + old_state = pp.state; + pp.state |= DEFINITION|NOSPACE; + old_token = pp.token; + n = 2 * MAXTOKEN; + pp.token = p = oldof(0, char, 0, n); + q = p + MAXTOKEN; + *pp.token++ = ' '; + old_hidden = pp.hidden; + while (c = pplex()) + { + if (c == '\n') + { + pp.hidden++; + pp.state |= HIDDEN|NEWLINE; + old_state |= HIDDEN|NEWLINE; + error_info.line++; + } + else if (c == '#') + { + ungetchr(c); + break; + } + else + { + for (;;) + { + if (streq(pp.token, tp->token)) + { + if (!(tp = tp->match)) + break; + if (!tp->nomatch) + { + free(p); + pp.state = old_state; + pp.token = old_token; + PUSH_TUPLE(sym, tp->token); + ret = 1; + goto disable; + } + } + else if (!(tp = tp->nomatch)) + break; + } + if (!tp) + { + pp.token = pp.toknxt; + break; + } + } + if ((pp.token = pp.toknxt) > q) + { + c = pp.token - p; + p = newof(p, char, n += MAXTOKEN, 0); + q = p + n - MAXTOKEN; + pp.token = p + c; + } + *pp.token++ = ' '; + } + if (pp.token > p && *(pp.token - 1) == ' ') + pp.token--; + if (pp.hidden != old_hidden) + *pp.token++ = '\n'; + else + *pp.token++ = ' '; + *pp.token = 0; + pp.state = old_state; + pp.token = old_token; + if (*p) + PUSH_RESCAN(p); + else + free(p); + if (!mac->value) + goto disable; + } + if (sym->flags & SYM_FUNCTION) + { + /* + * a quick and dirty '(' peek to avoid possibly + * inappropriate ungetchr()'s below + */ + + for (p = pp.in->nextchr; isspace(*p); p++); + if ((c = *p) != '(' && c != '/' && c != 0 && c != MARK) + goto disable; + old_token = pp.token; + mp = pp.macp->next; + if ((pp.token = (char*)&mp->arg[mac->arity + 1]) > pp.maxmac) + error(3, "%s: too many nested function-like macros", sym->name); + old_hidden = pp.hidden; + old_state = pp.state; + pp.state |= DEFINITION|FILEPOP|NOSPACE; + while ((c = pplex()) == '\n') + { + pp.hidden++; + pp.state |= HIDDEN|NEWLINE; + old_state |= HIDDEN|NEWLINE; + error_info.line++; + } + if (c != '(') + { + pp.state = old_state; + if (c) + { + p = pp.toknxt; + while (p > pp.token) + ungetchr(*--p); +#if COMPATIBLE + if ((pp.state & (COMPATIBILITY|STRICT)) == (COMPATIBILITY|STRICT)) + error(1, "%s: macro arguments omitted", sym->name); +#endif + if (c == T_ID && !(pp.state & HIDDEN)) + ungetchr(' '); + } + if (pp.hidden != old_hidden) + { + ungetchr('\n'); + error_info.line--; + if (pp.hidden && !--pp.hidden) + pp.state &= ~HIDDEN; + } + pp.token = old_token; + goto disable; + } + pp.state = old_state; + + /* + * arg[i][-1] is an extra char for each actual i + * for a possible ungetchr('"') during IN_QUOTE + * arg[i][-1]==0 if arg i need not be expanded + * arg[0][-2] holds the actual arg count + */ + + c = 0; + m = 0; + n = 0; + mp = pp.macp->next; + p = pp.token = (char*)&mp->arg[mac->arity + 1]; + pp.state |= COLLECTING|NOEXPAND; + pp.state &= ~FILEPOP; + sym->flags |= SYM_ACTIVE; + old_in = pp.in; + last_line = error_info.line; + last_file = error_info.file; + mp->line = error_info.line; +#if MACKEYARGS + if (pp.option & KEYARGS) + { + for (c = 0; c < mac->arity; c++) + mp->arg[c] = mac->args.key[c].value + 1; + mp->arg[0]++; + } + else +#endif + { + *++p = ' '; + mp->arg[0] = ++p; + } +#if MACKEYARGS + keyarg: + if (pp.option & KEYARGS) + { + pp.state |= NOSPACE; + switch (pplex()) + { + case T_ID: + break; + case ')': /* no actual key args */ + if (!(pp.state & NOEXPAND)) + pp.state |= NOEXPAND; + for (c = 0; c < mac->arity; c++) + mp->arg[c][-1] = 0; + c = 0; + goto endactuals; + default: + error(3, "%s: invalid keyword macro argument", pp.token); + break; + } + for (c = 0; c < mac->arity; c++) + if (streq(pp.token, mac->args.key[c].name)) break; + if (c >= mac->arity) + error(2, "%s: invalid macro argument keyword", pp.token); + if (pplex() != '=') + error(2, "= expected in keyword macro argument"); + pp.state &= ~NOSPACE; + if (!c) + p++; + pp.token = mp->arg[c] = ++p; + } +#endif + for (;;) + { + if ((pp.mactop = pp.token = p) >= pp.maxmac) + error(3, "%s: too many nested function-like macros", sym->name); + switch (pplex()) + { + case '(': + n++; + break; + case ')': + if (!n--) + { + if (p > mp->arg[c] && *(p - 1) == ' ') + p--; + if (p > mp->arg[c] && *(p - 1) == '\\') + { + for (q = mp->arg[c]; q < p; q++) + if (*q == '\\') + q++; + if (q > p) + *p++ = '\\'; + } +#if MACKEYARGS + *p = 0; + m++; +#endif + goto endactuals; + } + break; + case ',': + if (!n && (m++, (c < mac->arity - 1 || !(sym->flags & SYM_VARIADIC)))) + { + if (p > mp->arg[c] && *(p - 1) == ' ') + p--; + *p++ = 0; + if (!(pp.state & NOEXPAND)) + pp.state |= NOEXPAND; + else + mp->arg[c][-1] = 0; +#if MACKEYARGS + if (pp.option & KEYARGS) + { + pp.token = p + 1; + goto keyarg; + } +#endif + { + if ((pp.state & STRICT) && p == mp->arg[c]) + error(1, "%s: macro call argument %d is null", sym->name, c + 1); + if (c < mac->arity) + c++; + *p++ = ' '; + } + pp.toknxt = mp->arg[c] = p; + } + break; + case 0: + if (pp.in == old_in) + kp = 0; + else + for (kp = pp.in; kp && kp != old_in; kp = kp->prev); + if (!kp) + { + error( +#if COMPATIBLE + (pp.state & COMPATIBILITY) ? 3 : +#endif + 2, "%s: %s in macro argument list", sym->name, pptokchr(0)); + goto endactuals; + } + continue; + case '\n': + pp.state |= HIDDEN; + error_info.line++; + pp.hidden++; + /*FALLTHROUGH*/ + case ' ': + if (p > mp->arg[c] && *(p - 1) != ' ') *p++ = ' '; + continue; + } + p = pp.toknxt; + if (error_info.line != last_line) + { + SETLINE(p, error_info.line); + last_line = error_info.line; + } + if (error_info.file != last_file) + { + SETFILE(p, error_info.file); + last_file = error_info.file; + } + } + endactuals: + if (pp.state & NOEXPAND) + mp->arg[c][-1] = 0; + pp.token = old_token; + if (pp.in != old_in) + { + for (kp = pp.in; kp && kp != old_in; kp = kp->prev); + if (kp) + error(2, "%s: macro call starts and ends in different files", sym->name); + } + pp.state &= ~(COLLECTING|FILEPOP|NOEXPAND); + sym->flags &= ~SYM_ACTIVE; +#if MACKEYARGS + if (!(pp.option & KEYARGS)) +#endif + { + if (p > mp->arg[0] && ++m || (sym->flags & SYM_VARIADIC)) + c++; + if (c != mac->arity && !(sym->flags & SYM_EMPTY)) + { + n = mac->arity; + if (!(sym->flags & SYM_VARIADIC)) + error(1, "%s: %d actual argument%s expected", sym->name, n, n == 1 ? "" : "s"); + else if (c < --n) + error(1, "%s: at least %d actual argument%s expected", sym->name, n, n == 1 ? "" : "s"); +#if COMPATIBLE + if (!c && (pp.state & (COMPATIBILITY|STRICT)) == (COMPATIBILITY|STRICT)) + goto disable; +#endif + } + if (!c) + ++c; + while (c < mac->arity) + mp->arg[c++] = (char*)"\0" + 1; + } + mp->arg[0][-2] = m; + *p++ = 0; + nextframe(mp, p); + count(function); + } + if (!tok && (sym->flags & SYM_NOEXPAND)) + { + if (sym->flags & SYM_FUNCTION) + popframe(mp); + ret = !mac->size; + } + else if (!(pp.state & HEADER) || (pp.option & HEADEREXPANDALL) || pp.in->type != IN_COPY) + { + if (sym->flags & SYM_MULTILINE) + PUSH_MULTILINE(sym); + else + PUSH_MACRO(sym); + ret = 1; + } + } + disable: + if (ret < 0 && sym->hidden && !(pp.mode & EXPOSE) && !(pp.state & HEADER) && (pp.in->type == IN_FILE || pp.in->type == IN_MACRO || pp.in->type == IN_EXPAND)) + { + struct ppinstk* inp; + + for (inp = pp.in; inp->type != IN_FILE && inp->prev; inp = inp->prev); + sfsprintf(pp.hidebuf, MAXTOKEN, "_%d_%s_hIDe", inp->index, sym->name); + PUSH_STRING(pp.hidebuf); + ret = 1; + } + pp.state &= ~NEWLINE; + pp.in->flags |= IN_tokens; + count(token); + return ret; +} diff --git a/usr/src/lib/libpp/common/ppcomment.c b/usr/src/lib/libpp/common/ppcomment.c new file mode 100644 index 0000000000..c938bc2e67 --- /dev/null +++ b/usr/src/lib/libpp/common/ppcomment.c @@ -0,0 +1,35 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * common preprocessor comment handler + */ + +#include "pplib.h" + +void +ppcomment(char* head, char* comment, char* tail, int line) +{ + NoP(line); + ppprintf("%s%-.*s%s", head, MAXTOKEN - 4, comment, tail); +} diff --git a/usr/src/lib/libpp/common/ppcontext.c b/usr/src/lib/libpp/common/ppcontext.c new file mode 100644 index 0000000000..220481ab87 --- /dev/null +++ b/usr/src/lib/libpp/common/ppcontext.c @@ -0,0 +1,65 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor context switch + * + * args op return + * (0,0) free current context 0 + * (0,1) save current context current + * (p,0) free context p 0 + * (p,1) make p current context previous + */ + +#include "pplib.h" + +void* +ppcontext(void* context, int flags) +{ + struct ppcontext* np = (struct ppcontext*)context; + struct ppcontext* op; + + if (flags & 01) + { + if (!(op = pp.context)) op = pp.context = newof(0, struct ppcontext, 1, 0); + memcpy(op, _PP_CONTEXT_BASE_, sizeof(struct ppcontext)); + } + else + { + if (!(op = np)) op = (struct ppcontext*)_PP_CONTEXT_BASE_; + if (op->filtab) hashfree(op->filtab); + if (op->prdtab) hashfree(op->prdtab); + if (op->symtab) hashfree(op->symtab); + if (op->date) free(op->date); + if (op->time) free(op->time); + if (np) + { + free(np); + np = 0; + } + memzero(op, sizeof(struct ppcontext)); + op = 0; + } + if (np) memcpy(_PP_CONTEXT_BASE_, np, sizeof(struct ppcontext)); + return((void*)op); +} diff --git a/usr/src/lib/libpp/common/ppcontrol.c b/usr/src/lib/libpp/common/ppcontrol.c new file mode 100644 index 0000000000..a5d9974927 --- /dev/null +++ b/usr/src/lib/libpp/common/ppcontrol.c @@ -0,0 +1,2295 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor control directive support + */ + +#include "pplib.h" + +#include <regex.h> + +#define TOKOP_DUP (1<<0) +#define TOKOP_STRING (1<<1) +#define TOKOP_UNSET (1<<2) + +struct edit +{ + struct edit* next; + regex_t re; +}; + +struct map +{ + struct map* next; + regex_t re; + struct edit* edit; +}; + +#define RESTORE (COLLECTING|CONDITIONAL|DEFINITION|DIRECTIVE|DISABLE|EOF2NL|HEADER|NOSPACE|NOVERTICAL|PASSEOF|STRIP) + +/* + * common predicate assertion operations + * op is DEFINE or UNDEF + */ + +static void +assert(int op, char* pred, char* args) +{ + register struct pplist* a; + register struct ppsymbol* sym; + register struct pplist* p; + register struct pplist* q; + + if (!args) switch (op) + { + case DEFINE: + goto mark; + case UNDEF: + a = 0; + goto unmark; + } + if (a = (struct pplist*)hashget(pp.prdtab, pred)) + { + p = 0; + q = a; + while (q) + { + if (streq(q->value, args)) + { + if (op == DEFINE) return; + q = q->next; + if (p) p->next = q; + else a = q; + } + else + { + p = q; + q = q->next; + } + } + if (op == UNDEF) + { + unmark: + hashput(pp.prdtab, pred, a); + if (sym = ppsymref(pp.symtab, pred)) + sym->flags &= ~SYM_PREDICATE; + return; + } + } + if (op == DEFINE) + { + p = newof(0, struct pplist, 1, 0); + p->next = a; + p->value = strdup(args); + hashput(pp.prdtab, NiL, p); + mark: + if ((pp.state & COMPILE) && pp.truncate) return; + if (sym = ppsymset(pp.symtab, pred)) + sym->flags |= SYM_PREDICATE; + } +} + +/* + * tokenize string ppop() + * + * op PP_* op + * name option name + * s string of option values + * n option sense + * flags TOKOP_* flags + */ + +static void +tokop(int op, char* name, register char* s, register int n, int flags) +{ + register int c; + register char* t; + + if (!(flags & TOKOP_UNSET) && !n) error(2, "%s: option cannot be unset", name); + else if (!s) ppop(op, s, n); + else if (flags & TOKOP_STRING) + { + PUSH_LINE(s); + for (;;) + { + pp.state &= ~NOSPACE; + c = pplex(); + pp.state |= NOSPACE; + if (!c) break; + if (c != ' ') + ppop(op, (flags & TOKOP_DUP) ? strdup(pp.token) : pp.token, n); + } + POP_LINE(); + } + else do + { + while (*s == ' ') s++; + for (t = s; *t && *t != ' '; t++); + if (*t) *t++ = 0; + else t = 0; + if (*s) ppop(op, (flags & TOKOP_DUP) ? strdup(s) : s, n); + } while (s = t); +} + +/* + * return symbol pointer for next token macro (re)definition + */ + +static struct ppsymbol* +macsym(int tok) +{ + register struct ppsymbol* sym; + + if (tok != T_ID) + { + error(2, "%s: invalid macro name", pptokstr(pp.token, 0)); + return 0; + } + sym = pprefmac(pp.token, REF_CREATE); + if ((sym->flags & SYM_FINAL) && (pp.mode & HOSTED)) return 0; + if (sym->flags & (SYM_ACTIVE|SYM_READONLY)) + { + if (!(pp.option & ALLPOSSIBLE)) + error(2, "%s: macro is %s", sym->name, (sym->flags & SYM_READONLY) ? "readonly" : "active"); + return 0; + } + if (!sym->macro) sym->macro = newof(0, struct ppmacro, 1, 0); + return sym; +} + +/* + * get one space canonical pplex() line, sans '\n', and place in p + * x is max+1 pos in p + * 0 returned if line too large + * otherwise end of p ('\0') returned + */ + +static char* +getline(register char* p, char* x, int disable) +{ + register int c; + register char* s; + char* b; + long restore; + + restore = pp.state & (NOSPACE|STRIP); + pp.state &= ~(NEWLINE|NOSPACE|STRIP); + pp.state |= EOF2NL; + b = p; + while ((c = pplex()) != '\n') + { + if (disable) + { + if (c == ' ') + /*ignore*/; + else if (disable == 1) + disable = (c == T_ID && streq(pp.token, pp.pass)) ? 2 : 0; + else + { + disable = 0; + if (c == ':') + pp.state |= DISABLE; + } + } + s = pp.token; + while (*p = *s++) + if (++p >= x) + { + p = 0; + goto done; + } + } + if (p > b && *(p - 1) == ' ') + p--; + if (p >= x) + p = 0; + else + *p = 0; + done: + pp.state &= ~(NOSPACE|STRIP); + pp.state |= restore; + return p; +} + +/* + * regex error handler + */ + +void +regfatal(regex_t* p, int level, int code) +{ + char buf[128]; + + regerror(code, p, buf, sizeof(buf)); + regfree(p); + error(level, "regular expression: %s", buf); +} + +/* + * process a single directive line + */ + +int +ppcontrol(void) +{ + register char* p; + register int c; + register int n; + register char* s; + register struct ppmacro* mac; + register struct ppsymbol* sym; + struct edit* edit; + struct map* map; + struct ppfile* fp; + int o; + int directive; + long restore; + struct pptuple* rp; + struct pptuple* tp; + char* v; + int emitted; + + union + { + struct map* best; + struct ppinstk* inp; + struct pplist* list; + char* string; + struct ppsymbol* symbol; + int type; + PPLINESYNC linesync; + } var; + + static char __va_args__[] = "__VA_ARGS__"; + static int i0; + static int i1; + static int i2; + static int i3; + static int i4; + + static long n1; + static long n2; + static long n3; + + static char* p0; + static char* p1; + static char* p2; + static char* p3; + static char* p4; + static char* p5; + static char* p6; + + static struct ppmacro old; + static char* formargs[MAXFORMALS]; +#if MACKEYARGS + static char* formvals[MAXFORMALS]; +#endif + + emitted = 0; + if (pp.state & SKIPCONTROL) pp.level--; + restore = (pp.state & RESTORE)|NEWLINE; + if (pp.state & PASSTHROUGH) restore |= DISABLE; + else restore &= ~DISABLE; + pp.state &= ~(NEWLINE|RESTORE|SKIPCONTROL); + pp.state |= DIRECTIVE|DISABLE|EOF2NL|NOSPACE|NOVERTICAL; +#if COMPATIBLE + if ((pp.state & (COMPATIBILITY|STRICT)) == COMPATIBILITY || (pp.mode & HOSTED)) pp.state &= ~NOVERTICAL; +#else + if (pp.mode & HOSTED) pp.state &= ~NOVERTICAL; +#endif + switch (c = pplex()) + { + case T_DECIMAL: + case T_OCTAL: + if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX))) + error(1, "# <line> [ \"<file>\" [ <type> ] ]: non-standard directive"); + directive = INCLUDE; + goto linesync; + case T_ID: + switch (directive = (int)hashref(pp.dirtab, pp.token)) + { + case ELIF: + else_if: + if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev) + goto eatdirective; + if (pp.control <= pp.in->control) + { + error(2, "no matching #%s for #%s", dirname(IF), dirname(ELIF)); + goto eatdirective; + } + if (pp.control == (pp.in->control + 1)) pp.in->flags |= IN_noguard; + if (*pp.control & HADELSE) + { + error(2, "invalid #%s after #%s", dirname(ELIF), dirname(ELSE)); + *pp.control |= SKIP; + goto eatdirective; + } + if (*pp.control & KEPT) + { + *pp.control |= SKIP; + goto eatdirective; + } + if (directive == IFDEF || directive == IFNDEF) + { + *pp.control &= ~SKIP; + goto else_ifdef; + } + conditional: + if (ppexpr(&i1)) + { + *pp.control &= ~SKIP; + *pp.control |= KEPT; + } + else *pp.control |= SKIP; + c = (pp.state & NEWLINE) ? '\n' : ' '; + goto eatdirective; + case ELSE: + if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev) + goto eatdirective; + if ((pp.option & ELSEIF) && (c = pplex()) == T_ID && ((n = (int)hashref(pp.dirtab, pp.token)) == IF || n == IFDEF || n == IFNDEF)) + { + error(1, "#%s %s is non-standard -- use #%s", dirname(directive), dirname(n), dirname(ELIF)); + directive = n; + goto else_if; + } + if (pp.control <= pp.in->control) error(2, "no matching #%s for #%s", dirname(IF), dirname(ELSE)); + else + { + if (pp.control == (pp.in->control + 1)) pp.in->flags |= IN_noguard; + if (!(*pp.control & KEPT)) + { + *pp.control &= ~SKIP; + *pp.control |= HADELSE|KEPT; + } + else + { + if (*pp.control & HADELSE) error(2, "more than one #%s for #%s", dirname(ELSE), dirname(IF)); + *pp.control |= HADELSE|SKIP; + } + } + goto enddirective; + case ENDIF: + if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev) + goto eatdirective; + if (pp.control <= pp.in->control) error(2, "no matching #%s for #%s", dirname(IF), dirname(ENDIF)); + else if (--pp.control == pp.in->control && pp.in->symbol) + { + if (pp.in->flags & IN_endguard) pp.in->flags |= IN_noguard; + else + { + pp.in->flags &= ~IN_tokens; + pp.in->flags |= IN_endguard; + } + } + goto enddirective; + case IF: + case IFDEF: + case IFNDEF: + if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev) + goto eatdirective; + pushcontrol(); + SETIFBLOCK(pp.control); + if (*pp.control & SKIP) + { + *pp.control |= KEPT; + goto eatdirective; + } + if (directive == IF) goto conditional; + else_ifdef: + if ((c = pplex()) == T_ID) + { + sym = pprefmac(pp.token, REF_IF); + if (directive == IFNDEF && pp.control == pp.in->control + 1) + { + if (pp.in->flags & (IN_defguard|IN_endguard)) + pp.in->flags |= IN_noguard; + else + { + pp.in->flags |= IN_defguard; + if (!(pp.in->flags & IN_tokens)) + pp.in->symbol = sym ? sym : pprefmac(pp.token, REF_CREATE); + } + } + } + else + { + sym = 0; + if (!(pp.mode & HOSTED)) + error(1, "%s: invalid macro name", pptokstr(pp.token, 0)); + } + *pp.control |= ((sym != 0) == (directive == IFDEF)) ? KEPT : SKIP; + goto enddirective; + case INCLUDE: + if (*pp.control & SKIP) + { + pp.state |= HEADER; + c = pplex(); + pp.state &= ~HEADER; + goto eatdirective; + } + pp.state &= ~DISABLE; + pp.state |= HEADER|STRIP; + switch (c = pplex()) + { + case T_STRING: + p = pp.token; + do pp.token = pp.toknxt; while ((c = pplex()) == T_STRING); + *pp.token = 0; + pp.token = p; + /*FALLTHROUGH*/ + case T_HEADER: + header: + if (!*pp.token) + { + error(2, "#%s: null file name", dirname(INCLUDE)); + break; + } + if (*pp.token == '/' && !(pp.mode & (HOSTED|RELAX))) + error(1, "#%s: reference to %s is not portable", dirname(INCLUDE), pp.token); + n = ppsearch(pp.token, c, SEARCH_INCLUDE); + break; + case '<': + /* + * HEADEREXPAND|HEADEREXPANDALL gets us here + */ + + if (!(p = pp.hdrbuf) && !(p = pp.hdrbuf = newof(0, char, MAXTOKEN, 0))) + error(3, "out of space"); + pp.state &= ~NOSPACE; + while ((c = pplex()) && c != '>') + { + v = p + 1; + STRCOPY(p, pp.token, s); + if (p == v && *(p - 1) == ' ' && pp.in->type != IN_MACRO) + p--; + } + pp.state |= NOSPACE; + *p++ = 0; + memcpy(pp.token, pp.hdrbuf, p - pp.hdrbuf); + c = T_HEADER; + goto header; + default: + error(2, "#%s: \"...\" or <...> argument expected", dirname(INCLUDE)); + goto eatdirective; + } + goto enddirective; + case 0: + { + regmatch_t match[10]; + + /*UNDENT*/ + p = pp.valbuf; + *p++ = '#'; + STRCOPY(p, pp.token, s); + p0 = p; + pp.mode |= EXPOSE; + pp.state |= HEADER; + p6 = getline(p, &pp.valbuf[MAXTOKEN], 0); + pp.state &= ~HEADER; + pp.mode &= ~EXPOSE; + if (!p6) + { + *p0 = 0; + error(2, "%s: directive too long", pp.valbuf); + c = 0; + goto eatdirective; + } + p1 = p2 = p3 = p4 = 0; + p5 = *p ? p + 1 : 0; + checkmap: + i0 = *p0; + p = pp.valbuf; + var.best = 0; + n = 0; + for (map = (struct map*)pp.maps; map; map = map->next) + if (!(i1 = regexec(&map->re, p, elementsof(match), match, 0))) + { + if ((c = match[0].rm_eo - match[0].rm_so) > n) + { + n = c; + var.best = map; + } + } + else if (i1 != REG_NOMATCH) + regfatal(&map->re, 3, i1); + c = '\n'; + if (map = var.best) + { + if ((pp.state & (STRICT|WARN)) && !(pp.mode & (HOSTED|RELAX))) + { + *p0 = 0; + if (!(pp.state & WARN) || strcmp(p + 1, dirname(PRAGMA))) + error(1, "%s: non-standard directive", p); + *p0 = i0; + } + if (!(*pp.control & SKIP)) + { + n = 0; + for (edit = map->edit; edit; edit = edit->next) + if (!(i0 = regexec(&edit->re, p, elementsof(match), match, 0))) + { + n++; + if (i0 = regsubexec(&edit->re, p, elementsof(match), match)) + regfatal(&edit->re, 3, i0); + p = edit->re.re_sub->re_buf; + if (edit->re.re_sub->re_flags & REG_SUB_STOP) + break; + } + else if (i0 != REG_NOMATCH) + regfatal(&edit->re, 3, i0); + if (n && *p) + { + p1 = s = oldof(0, char, 0, strlen(p) + 32); + while (*s = *p++) s++; + debug((-4, "map: %s", p1)); + *s++ = '\n'; + *s = 0; + error_info.line++; + PUSH_RESCAN(p1); + error_info.line--; + directive = LINE; + } + } + goto donedirective; + } + if (directive != PRAGMA && (!(*pp.control & SKIP) || !(pp.mode & (HOSTED|RELAX)))) + { + *p0 = 0; + error(1, "%s: unknown directive", pptokstr(pp.valbuf, 0)); + *p0 = i0; + } + pass: + if (!(*pp.control & SKIP) && pp.pragma && !(pp.state & NOTEXT) && (directive == PRAGMA || !(pp.mode & INIT))) + { + *p0 = 0; + if (p2) *p2 = 0; + if (p4) + { + if (p4 == p5) + { + p5 = strcpy(pp.tmpbuf, p5); + if (p = strchr(p5, MARK)) + { + s = p; + while (*p) + if ((*s++ = *p++) == MARK && *p == MARK) p++; + *s = 0; + } + } + *p4 = 0; + } + if (p = (char*)memchr(pp.valbuf + 1, MARK, p6 - pp.valbuf - 1)) + { + s = p; + while (p < p6) switch (*s++ = *p++) + { + case 0: + s = p; + break; + case MARK: + p++; + break; + } + *s = 0; + } + (*pp.pragma)(pp.valbuf + 1, p1, p3, p5, (pp.state & COMPILE) || (pp.mode & INIT) != 0); + emitted = 1; + } + goto donedirective; + + /*INDENT*/ + } + } + if (*pp.control & SKIP) goto eatdirective; + switch (directive) + { +#if MACDEF + case ENDMAC: + c = pplex(); + error(2, "no matching #%s for #%s", dirname(MACDEF), dirname(ENDMAC)); + goto enddirective; +#endif +#if MACDEF + case MACDEF: + if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX))) + error(1, "#%s: non-standard directive", pp.token); + /*FALLTHROUGH*/ +#endif + case DEFINE: + n2 = error_info.line; + if ((c = pplex()) == '#' && directive == DEFINE) + goto assertion; + if (c == '<') + { + n = 1; + c = pplex(); + } + else + n = 0; + if (!(sym = macsym(c))) + goto eatdirective; + if (pp.truncate) + ppfsm(FSM_MACRO, pp.token); + mac = sym->macro; + if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev && mac->value) + goto eatdirective; + if (n) + goto tuple; + old = *mac; + i0 = sym->flags; + sym->flags &= ~(SYM_BUILTIN|SYM_EMPTY|SYM_FINAL|SYM_FUNCTION|SYM_INIT|SYM_INITIAL|SYM_MULTILINE|SYM_NOEXPAND|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC); +#if MACDEF + if (directive == MACDEF) + sym->flags |= SYM_MULTILINE; +#endif + mac->arity = 0; + mac->formals = 0; + mac->value = 0; + pp.state &= ~NOSPACE; + pp.state |= DEFINITION|NOEXPAND; + switch (c = pplex()) + { + case '(': + sym->flags |= SYM_FUNCTION; + pp.state |= NOSPACE; +#if MACKEYARGS + if (pp.option & KEYARGS) + { + n = 2 * MAXTOKEN; + p = mac->formals = oldof(0, char, 0, n); + if ((c = pplex()) == T_ID) for (;;) + { + if (mac->arity < MAXFORMALS) + { + if (mac->arity) p++; + formargs[mac->arity] = p; + STRAPP(p, pp.token, s); + formvals[mac->arity++] = p1 = p; + if (mac->arity == 1) *p++ = ' '; + *p++ = ' '; + *p = 0; + } + else error(2, "%s: formal argument %s ignored", sym->name, pp.token); + switch (c = pplex()) + { + case '=': + c = pplex(); + break; + case ',': + break; + default: + goto endformals; + } + pp.state &= ~NOSPACE; + p0 = 0; + for (;;) + { + switch (c) + { + case '\n': + goto endformals; + case '(': + p0++; + break; + case ')': + if (!p0--) + { + if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') *--p = 0; + goto endformals; + } + break; + case ',': + if (!p0) + { + if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') *--p = 0; + goto nextformal; + } + break; + case ' ': + if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') continue; + break; + } + STRCOPY(p, pp.token, s); + if (p > &mac->formals[n - MAXTOKEN] && (s = newof(mac->formals, char, n += MAXTOKEN, 0)) != mac->formals) + { + n1 = s - mac->formals; + for (n = 0; n < mac->arity; n++) + { + formargs[n] += n1; + formvals[n] += n1; + } + c = p - mac->formals; + mac->formals = s; + p = mac->formals + c; + } + c = pplex(); + } + nextformal: + pp.state |= NOSPACE; + if ((c = pplex()) != T_ID) + { + c = ','; + break; + } + } + endformals: /*NOP*/; + } + else +#endif + { + p = mac->formals = oldof(0, char, 0, MAXFORMALS * (MAXID + 1)); + c = pplex(); +#if COMPATIBLE + if ((pp.state & COMPATIBILITY) && c == ',') + { + if ((pp.state & WARN) && !(pp.mode & HOSTED)) + error(1, "%s: macro formal argument expected", sym->name); + while ((c = pplex()) == ','); + } +#endif + for (;;) + { + if (c == T_VARIADIC) + { + if (sym->flags & SYM_VARIADIC) + error(2, "%s: %s: duplicate macro formal argument", sym->name, pp.token); + sym->flags |= SYM_VARIADIC; + v = __va_args__; + } + else if (c == T_ID) + { + v = pp.token; + if (sym->flags & SYM_VARIADIC) + error(2, "%s: %s: macro formal argument cannot follow ...", sym->name, v); + else if (streq(v, __va_args__)) + error(2, "%s: %s: invalid macro formal argument", sym->name, v); + } + else + break; + if (mac->arity < MAXFORMALS) + { + for (n = 0; n < mac->arity; n++) + if (streq(formargs[n], v)) + error(2, "%s: %s: duplicate macro formal argument", sym->name, v); + formargs[mac->arity++] = p; + STRAPP(p, v, s); + } + else + error(2, "%s: %s: macro formal argument ignored", sym->name, v); + if ((c = pplex()) == ',') + { + c = pplex(); +#if COMPATIBLE + if ((pp.state & COMPATIBILITY) && c == ',') + { + if ((pp.state & WARN) && !(pp.mode & HOSTED)) + error(1, "%s: macro formal argument expected", sym->name); + while ((c = pplex()) == ','); + } +#endif + } + else if (c != T_VARIADIC) + break; + else + { + if (sym->flags & SYM_VARIADIC) + error(2, "%s: %s: duplicate macro formal argument", sym->name, pp.token); + sym->flags |= SYM_VARIADIC; + c = pplex(); + break; + } + } + if (mac->arity && (s = newof(mac->formals, char, p - mac->formals, 0)) != mac->formals) + { + n1 = s - mac->formals; + for (n = 0; n < mac->arity; n++) + formargs[n] += n1; + mac->formals = s; + } + } + if (!mac->arity) + { + free(mac->formals); + mac->formals = 0; + } + switch (c) + { + case ')': +#if MACKEYARGS + pp.state |= NOEXPAND|NOSPACE; +#else + pp.state |= NOEXPAND; +#endif + c = pplex(); + break; + default: + error(2, "%s: invalid macro formal argument list", sym->name); + if (mac->formals) + { + free(mac->formals); + mac->formals = 0; + mac->arity = 0; + } + free(mac); + sym->macro = 0; + goto eatdirective; + } + pp.state &= ~NOSPACE; + break; + case ' ': + case '\t': + c = pplex(); + break; + } + n = 2 * MAXTOKEN; +#if MACKEYARGS + p1 = p; +#endif + p = mac->value = oldof(0, char, 0, n); + var.type = 0; + n1 = 0; +#if MACDEF + i2 = i3 = 0; + n3 = pp.state; +#endif + if ((pp.option & PLUSPLUS) && (pp.state & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY) + switch (c) + { + case '+': + case '-': + case '&': + case '|': + case '<': + case '>': + case ':': + case '=': + *p++ = ' '; + break; + } + o = 0; + for (;;) + { + switch (c) + { + case T_ID: + for (c = 0; c < mac->arity; c++) + if (streq(formargs[c], pp.token)) + { +#if COMPATIBLE + if (!(pp.state & COMPATIBILITY)) +#endif + if (var.type != TOK_TOKCAT && p > mac->value && *(p - 1) != ' ' && !(pp.option & PRESERVE)) *p++ = ' '; + *p++ = MARK; +#if COMPATIBLE + if ((pp.state & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY) *p++ = 'C'; + else +#endif + *p++ = (n1 || var.type == TOK_TOKCAT) ? 'C' : 'A'; + *p++ = c + ARGOFFSET; + var.type = TOK_FORMAL|TOK_ID; + c = '>'; + goto checkvalue; + } + if (var.type == TOK_BUILTIN) switch ((int)hashget(pp.strtab, pp.token)) + { + case V_DEFAULT: + case V_EMPTY: + sym->flags |= SYM_EMPTY; + break; + } + else if (pp.hiding && (var.symbol = ppsymref(pp.symtab, pp.token)) && var.symbol->hidden) + { + for (var.inp = pp.in; var.inp->type != IN_FILE && var.inp->prev; var.inp = var.inp->prev); + p += sfsprintf(p, MAXTOKEN, "_%d_%s_hIDe", var.inp->hide, pp.token); + var.type = TOK_ID; + goto checkvalue; + } + var.type = TOK_ID; + break; + case '#': + var.type = 0; +#if MACDEF + if (!(sym->flags & (SYM_FUNCTION|SYM_MULTILINE))) break; +#else + if (!(sym->flags & SYM_FUNCTION)) break; +#endif + pp.state |= NOSPACE; + c = pplex(); + if (c == '@') + { + c = pplex(); + i4 = 'S'; + } + else i4 = 'Q'; + pp.state &= ~NOSPACE; + if (c != T_ID) c = mac->arity; + else for (c = 0; c < mac->arity; c++) + if (streq(formargs[c], pp.token)) + break; + if (c >= mac->arity) + { +#if MACDEF + if (sym->flags & SYM_MULTILINE) + { + if (n3 & NEWLINE) + { + pp.state &= ~NOEXPAND; + switch ((int)hashref(pp.dirtab, pp.token)) + { + case ENDMAC: + if (!i2--) goto gotdefinition; + break; + case INCLUDE: + /* PARSE HEADER constant */ + break; + case MACDEF: + i2++; + break; + } + *p++ = '#'; + } + } + else +#endif +#if COMPATIBLE + if (pp.state & COMPATIBILITY) *p++ = '#'; + else +#endif + error(2, "# must precede a formal parameter"); + } + else + { + if (p > mac->value && ppisidig(*(p - 1)) && !(pp.option & PRESERVE)) *p++ = ' '; + *p++ = MARK; + *p++ = i4; + *p++ = c + ARGOFFSET; + goto checkvalue; + } + break; + case T_TOKCAT: + if (p <= mac->value) error(2, "%s lhs operand omitted", pp.token); + else + { + if (*(p - 1) == ' ') p--; + if (var.type == (TOK_FORMAL|TOK_ID)) *(p - 2) = 'C'; + } + pp.state |= NOSPACE; + c = pplex(); + pp.state &= ~NOSPACE; + if (c == '\n') error(2, "%s rhs operand omitted", pptokchr(T_TOKCAT)); + var.type = TOK_TOKCAT; + continue; + case '(': + if (*pp.token == '#') + { + var.type = TOK_BUILTIN; + n1++; + } + else + { + var.type = 0; + if (n1) n1++; + } + break; + case ')': + var.type = 0; + if (n1) n1--; + break; + case T_STRING: + case T_CHARCONST: + pp.state &= ~NOEXPAND; + var.type = 0; + if (strchr(pp.token, MARK)) pp.state &= ~NOEXPAND; +#if COMPATIBLE + /*UNDENT*/ + + if ((sym->flags & SYM_FUNCTION) && (pp.state & (COMPATIBILITY|TRANSITION))) + { + char* v; + + s = pp.token; + for (;;) + { + if (!*s) goto checkvalue; + if (ppisid(*s)) + { + v = s; + while (ppisid(*++s)); + i1 = *s; + *s = 0; + for (c = 0; c < mac->arity; c++) + if (streq(formargs[c], v)) + { + *p++ = MARK; + *p++ = 'C'; + *p++ = c + ARGOFFSET; + if (!(pp.mode & HOSTED) && (!(pp.state & COMPATIBILITY) || (pp.state & WARN))) switch (*pp.token) + { + case '"': + error(1, "use the # operator to \"...\" quote macro arguments"); + break; + case '\'': + error(1, "macro arguments should be '...' quoted before substitution"); + break; + } + goto quotearg; + } + STRCOPY2(p, v); + quotearg: + *s = i1; + } + else *p++ = *s++; + } + } + /*INDENT*/ +#endif + break; + case '\n': +#if MACDEF + if (sym->flags & SYM_MULTILINE) + { + if (pp.state & EOF2NL) + { + error_info.line++; + pp.state |= HIDDEN; + pp.hidden++; + var.type = 0; + if (!i3++) + goto checkvalue; + break; + } + pp.state |= EOF2NL; + error(2, "%s: missing #%s", sym->name, dirname(ENDMAC)); + } +#endif + goto gotdefinition; + case 0: + c = '\n'; + goto gotdefinition; +#if COMPATIBLE + case ' ': + if (pp.state & COMPATIBILITY) var.type = 0; + if (pp.option & PRESERVE) break; + if (p > mac->value && *(p - 1) != ' ') *p++ = ' '; + goto checkvalue; + case '\t': + if (var.type & TOK_ID) + { + while ((c = pplex()) == '\t'); + if (c == T_ID) + { + if (var.type == (TOK_FORMAL|TOK_ID)) *(p - 2) = 'C'; + var.type = TOK_TOKCAT; + if (pp.state & WARN) error(1, "use the ## operator to concatenate macro arguments"); + } + else var.type = 0; + continue; + } + var.type = 0; + if (pp.option & PRESERVE) break; + if (p > mac->value && *(p - 1) != ' ') *p++ = ' '; + goto checkvalue; +#endif + case MARK: + pp.state &= ~NOEXPAND; + /*FALLTHROUGH*/ + + default: + var.type = 0; + break; + } + STRCOPY(p, pp.token, s); + checkvalue: + o = c; + if (p > &mac->value[n - MAXTOKEN] && (s = newof(mac->value, char, n += MAXTOKEN, 0)) != mac->value) + { + c = p - mac->value; + mac->value = s; + p = mac->value + c; + } +#if MACDEF + n3 = pp.state; +#endif + c = pplex(); + } + gotdefinition: + while (p > mac->value && *(p - 1) == ' ') p--; + if (p > mac->value && (pp.option & PLUSPLUS) && (pp.state & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY) + switch (o) + { + case '+': + case '-': + case '&': + case '|': + case '<': + case '>': + case ':': + case '=': + *p++ = ' '; + break; + } + *p = 0; +#if MACKEYARGS + if (!mac->arity) /* ok */; + else if (pp.option & KEYARGS) + { + p0 = mac->formals; + mac->formkeys = newof(0, struct ppkeyarg, n, p1 - p0 + 1); + s = (char*)&mac->formkeys[mac->arity]; + (void)memcpy(s, p0, p1 - p0 + 1); + free(p0); + for (n = 0; n < mac->arity; n++) + { + mac->formkeys[n].name = s + (formargs[n] - p0); + mac->formkeys[n].value = s + (formvals[n] - p0); + } + } + else +#endif + for (n = 1; n < mac->arity; n++) + *(formargs[n] - 1) = ','; + if (old.value) + { + if ((i0 & SYM_FUNCTION) != (sym->flags & SYM_FUNCTION) || old.arity != mac->arity || !streq(old.value, mac->value)) goto redefined; + if (!old.formals) + { + if (mac->formals) goto redefined; + } + else if (mac->formals) + { +#if MACKEYARGS + if (pp.option & KEYARGS) + { + for (n = 0; n < mac->arity; n++) + if (!streq(mac->formkeys[n].name, old.formkeys[n].name) || !streq(mac->formkeys[n].value, old.formkeys[n].value)) + goto redefined; + } + else +#endif + if (!streq(mac->formals, old.formals)) goto redefined; + } +#if MACKEYARGS + if (pp.option & KEYARGS) + { + if (mac->formkeys) free(mac->formkeys); + mac->formkeys = old.formkeys; + } + else +#endif + { + if (mac->formals) free(mac->formals); + mac->formals = old.formals; + } + free(mac->value); + mac->value = old.value; + goto benign; + redefined: + if (!(pp.mode & HOSTED) || !(i0 & SYM_INITIAL)) + error(1, "%s redefined", sym->name); +#if MACKEYARGS + if ((pp.option & KEYARGS) && mac->formkeys) + free(mac->formkeys); +#endif +#if MACKEYARGS + if (!(pp.option & KEYARGS)) +#endif + if (old.formals) free(old.formals); + free(old.value); + } + else if (!pp.truncate) ppfsm(FSM_MACRO, sym->name); + mac->value = newof(mac->value, char, (mac->size = p - mac->value) + 1, 0); + if ((pp.option & (DEFINITIONS|PREDEFINITIONS|REGUARD)) && !sym->hidden && !(sym->flags & SYM_MULTILINE) && ((pp.option & PREDEFINITIONS) || !(pp.mode & INIT)) && ((pp.option & (DEFINITIONS|PREDEFINITIONS)) || !(pp.state & NOTEXT))) + { + ppsync(); + ppprintf("#%s %s", dirname(DEFINE), sym->name); + if (sym->flags & SYM_FUNCTION) + { + ppputchar('('); + if (mac->formals) + ppprintf("%s", mac->formals); + ppputchar(')'); + } + if ((p = mac->value) && *p) + { + ppputchar(' '); + i0 = 0; + while (n = *p++) + { + if (n != MARK || (n = *p++) == MARK) + { + ppputchar(n); + i0 = ppisid(n); + } + else + { + if (n == 'Q') + ppputchar('#'); + else if (i0) + { + ppputchar('#'); + ppputchar('#'); + } + s = formargs[*p++ - ARGOFFSET]; + while ((n = *s++) && n != ',') + ppputchar(n); + if (ppisid(*p) || *p == MARK) + { + ppputchar('#'); + ppputchar('#'); + } + i0 = 0; + } + ppcheckout(); + } + } + emitted = 1; + } + benign: + if (pp.mode & BUILTIN) sym->flags |= SYM_BUILTIN; + if (pp.option & FINAL) sym->flags |= SYM_FINAL; + if (pp.mode & INIT) sym->flags |= SYM_INIT; + if (pp.option & INITIAL) sym->flags |= SYM_INITIAL; + if (pp.state & NOEXPAND) sym->flags |= SYM_NOEXPAND; + if (pp.option & PREDEFINED) sym->flags |= SYM_PREDEFINED; + if (pp.mode & READONLY) sym->flags |= SYM_READONLY; + if (pp.macref) (*pp.macref)(sym, error_info.file, n2, mac ? error_info.line - n2 + 1 : REF_UNDEF, mac ? strsum(mac->value, (long)mac->arity) : 0L); + break; + assertion: + c = pplex(); + if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX))) + error(1, "#%s #%s: assertions are non-standard", dirname(directive), pptokstr(pp.token, 0)); + if (c != T_ID) + { + error(2, "%s: invalid predicate name", pptokstr(pp.token, 0)); + goto eatdirective; + } + switch ((int)hashref(pp.strtab, pp.token)) + { + case X_DEFINED: + case X_EXISTS: + case X_STRCMP: + error(2, "%s is a builtin predicate", pp.token); + goto eatdirective; + case X_SIZEOF: + error(2, "%s cannot be a predicate", pp.token); + goto eatdirective; + } + strcpy(pp.tmpbuf, pp.token); + switch (pppredargs()) + { + case T_ID: + case T_STRING: + assert(directive, pp.tmpbuf, pp.args); + break; + case 0: + assert(directive, pp.tmpbuf, NiL); + break; + default: + error(2, "invalid predicate argument list"); + goto eatdirective; + } + break; + tuple: + pp.state |= DEFINITION|NOEXPAND|NOSPACE; + rp = 0; + tp = mac->tuple; + if (!tp && !mac->value) + ppfsm(FSM_MACRO, sym->name); + while ((c = pplex()) && c != '>' && c != '\n') + { + for (; tp; tp = tp->nomatch) + if (streq(tp->token, pp.token)) + break; + if (!tp) + { + if (!(tp = newof(0, struct pptuple, 1, strlen(pp.token)))) + error(3, "out of space"); + strcpy(tp->token, pp.token); + if (rp) + { + tp->nomatch = rp; + rp->nomatch = tp; + } + else + { + tp->nomatch = mac->tuple; + mac->tuple = tp; + } + } + rp = tp; + tp = tp->match; + } + pp.state &= ~NOSPACE; + if (!rp || c != '>') + error(2, "%s: > omitted in tuple macro definition", sym->name); + else + { + n = 2 * MAXTOKEN; + p = v = oldof(0, char, 0, n); + while ((c = pplex()) && c != '\n') + if (p > v || c != ' ') + { + STRCOPY(p, pp.token, s); + if (p > &v[n - MAXTOKEN] && (s = newof(v, char, n += MAXTOKEN, 0)) != v) + { + c = p - v; + v = s; + p = v + c; + } + } + while (p > v && *(p - 1) == ' ') + p--; + n = p - v; + tp = newof(0, struct pptuple, 1, n); + strcpy(tp->token, v); + tp->match = rp->match; + rp->match = tp; + } + goto benign; + case WARNING: + if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX))) + error(1, "#%s: non-standard directive", pp.token); + /*FALLTHROUGH*/ + case ERROR: + pp.state &= ~DISABLE; + p = pp.tmpbuf; + while ((c = pplex()) != '\n') + if (p + strlen(pp.token) < &pp.tmpbuf[MAXTOKEN]) + { + STRCOPY(p, pp.token, s); + pp.state &= ~NOSPACE; + } + *p = 0; + p = *pp.tmpbuf ? pp.tmpbuf : ((directive == WARNING) ? "user warning" : "user error"); + n = (directive == WARNING) ? 1 : 3; + error(n, "%s", p); + break; + case LET: + n2 = error_info.line; + if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX))) + error(1, "#%s: non-standard directive", pp.token); + if (!(sym = macsym(c = pplex()))) goto eatdirective; + if ((c = pplex()) != '=') + { + error(2, "%s: = expected", sym->name); + goto eatdirective; + } + sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_MULTILINE|SYM_PREDEFINED|SYM_VARIADIC); + mac = sym->macro; + mac->arity = 0; + if (mac->value) + { + if (!(sym->flags & SYM_REDEFINE) && !sym->hidden) + error(1, "%s: redefined", sym->name); +#if MACKEYARGS + if ((pp.option & KEYARGS) && mac->formkeys) free(mac->formkeys); + else +#endif + free(mac->formals); + mac->formals = 0; + n = strlen(mac->value) + 1; + } + else + { + ppfsm(FSM_MACRO, sym->name); + n = 0; + } + n1 = ppexpr(&i1); + if (i1) c = sfsprintf(pp.tmpbuf, MAXTOKEN, "%luU", n1); + else c = sfsprintf(pp.tmpbuf, MAXTOKEN, "%ld", n1); + if (n < ++c) + { + if (mac->value) free(mac->value); + mac->value = oldof(0, char, 0, c); + } + strcpy(mac->value, pp.tmpbuf); + sym->flags |= SYM_REDEFINE; + c = (pp.state & NEWLINE) ? '\n' : ' '; + goto benign; + case LINE: + pp.state &= ~DISABLE; + if ((c = pplex()) == '#') + { + c = pplex(); + directive = INCLUDE; + } + if (c != T_DECIMAL && c != T_OCTAL) + { + error(1, "#%s: line number expected", dirname(LINE)); + goto eatdirective; + } + linesync: + n = error_info.line; + error_info.line = strtol(pp.token, NiL, 0); + if (error_info.line == 0 && directive == LINE && (pp.state & STRICT) && !(pp.mode & HOSTED)) + error(1, "#%s: line number should be > 0", dirname(LINE)); + pp.state &= ~DISABLE; + pp.state |= STRIP; + switch (c = pplex()) + { + case T_STRING: + s = error_info.file; + if (*(p = pp.token)) pathcanon(p, 0); + fp = ppsetfile(p); + error_info.file = fp->name; + if (error_info.line == 1) + ppmultiple(fp, INC_TEST); + switch (c = pplex()) + { + case '\n': + break; + case T_DECIMAL: + case T_OCTAL: + if (directive == LINE && (pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX))) + error(1, "#%s: integer file type argument is non-standard", dirname(LINE)); + break; + default: + error(1, "#%s: integer file type argument expected", dirname(LINE)); + break; + } + if (directive == LINE) pp.in->flags &= ~IN_ignoreline; + else if (pp.incref) + { + if (error_info.file != s) + { + switch (*pp.token) + { + case PP_sync_push: + if (pp.insert) (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT); + else (*pp.incref)(s, error_info.file, n, PP_SYNC_PUSH); + break; + case PP_sync_pop: + if (pp.insert) (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT); + else (*pp.incref)(s, error_info.file, n - 1, PP_SYNC_POP); + break; + case PP_sync_ignore: + if (pp.insert) (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT); + else + { + (*pp.incref)(s, error_info.file, n, PP_SYNC_IGNORE); + error_info.file = s; + } + break; + default: + if (*s) + { + if (fp == pp.insert) + pp.insert = 0; + else if (error_info.line == 1 && !pp.insert) + (*pp.incref)(s, error_info.file, n, PP_SYNC_PUSH); + else + { + if (!pp.insert) pp.insert = ppgetfile(s); + (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT); + } + } + break; + } + } + } + break; + case '\n': + break; + default: + error(1, "#%s: \"file-name\" expected", dirname(LINE)); + break; + } + if (directive == LINE && (pp.in->flags & IN_ignoreline)) + error_info.line = n + 1; + else + { + pp.hidden = 0; + pp.state &= ~HIDDEN; + if (pp.linesync) + { +#if CATSTRINGS + if (pp.state & JOINING) pp.state |= HIDDEN|SYNCLINE; + else +#endif + { + s = pp.lineid; + n = pp.flags; + if (directive == LINE) + { + pp.flags &= ~PP_linetype; + if (pp.macref) pp.lineid = dirname(LINE); + } + (*pp.linesync)(error_info.line, error_info.file); + pp.flags = n; + pp.lineid = s; + } + } + } + directive = LINE; + break; + case PRAGMA: + /* + * #pragma [STDC] [pass:] [no]option [arg ...] + * + * pragma args are not expanded by default + * + * if STDC is present then it is silently passed on + * + * if pass is pp.pass then the option is used + * and verified but is not passed on + * + * if pass is omitted then the option is passed on + * + * otherwise if pass is non-null and not pp.pass then + * the option is passed on but not used + * + * if the line does not match this form then + * it is passed on unchanged + * + * #directive pass: option [...] + * ^ ^ ^ ^ ^ ^ ^ ^ + * pp.valbuf p0 p1 p2 p3 p4 p5 p6 + * + * p? 0 if component omitted + * i0 0 if ``no''option + */ + + p = pp.valbuf; + *p++ = '#'; + STRCOPY(p, pp.token, s); + p0 = p; + if (pp.option & PRAGMAEXPAND) + pp.state &= ~DISABLE; + if (!(p6 = getline(p, &pp.valbuf[MAXTOKEN], !!(pp.option & PRAGMAEXPAND)))) + { + *p0 = 0; + error(2, "%s: directive too long", pp.valbuf); + c = 0; + goto eatdirective; + } + p1 = ++p; + while (ppisid(*p)) + p++; + if (p == p1) + { + p5 = p; + p4 = 0; + p3 = 0; + p2 = 0; + p1 = 0; + } + else if (*p != ':') + { + p5 = *p ? p + (*p == ' ') : 0; + p4 = p; + p3 = p1; + p2 = 0; + p1 = 0; + } + else + { + p2 = p++; + p3 = p; + while (ppisid(*p)) + p++; + if (p == p3) + { + p4 = p1; + p3 = 0; + p2 = 0; + p1 = 0; + } + else + p4 = p; + p5 = *p4 ? p4 + (*p4 == ' ') : 0; + } + if (!p1 && p3 && (p4 - p3) == 4 && strneq(p3, "STDC", 4)) + goto pass; + if ((pp.state & WARN) && !(pp.mode & (HOSTED|RELAX))) + error(1, "#%s: non-standard directive", dirname(PRAGMA)); + i0 = !p3 || *p3 != 'n' || *(p3 + 1) != 'o'; + if (!p3) + goto checkmap; + if (p1) + { + *p2 = 0; + n = streq(p1, pp.pass); + *p2 = ':'; + if (!n) + goto checkmap; + } + else + n = 0; + i2 = *p4; + *p4 = 0; + if (((i1 = (int)hashref(pp.strtab, p3 + (i0 ? 0 : 2))) < 1 || i1 > X_last_option) && (i0 || (i1 = (int)hashref(pp.strtab, p3)) > X_last_option)) + i1 = 0; + if ((pp.state & (COMPATIBILITY|STRICT)) == STRICT && !(pp.mode & (HOSTED|RELAX))) + { + if (pp.optflags[i1] & OPT_GLOBAL) + goto donedirective; + if (n || (pp.mode & WARN)) + { + n = 0; + error(1, "#%s: non-standard directive ignored", dirname(PRAGMA)); + } + i1 = 0; + } + if (!n) + { + if (!(pp.optflags[i1] & OPT_GLOBAL)) + { + *p4 = i2; + goto checkmap; + } + if (!(pp.optflags[i1] & OPT_PASS)) + n = 1; + } + else if (!i1) + error(2, "%s: unknown option", p1); + else if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX))) + error(1, "%s: non-standard option", p1); + p = p5; + switch (i1) + { + case X_ALLMULTIPLE: + ppop(PP_MULTIPLE, i0); + break; + case X_ALLPOSSIBLE: + setoption(ALLPOSSIBLE, i0); + break; + case X_BUILTIN: + setmode(BUILTIN, i0); + break; + case X_CATLITERAL: + setmode(CATLITERAL, i0); + if (pp.mode & CATLITERAL) + setoption(STRINGSPLIT, 0); + break; + case X_CDIR: + tokop(PP_CDIR, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP); + break; + case X_CHECKPOINT: +#if CHECKPOINT + ppload(p); +#else + error(3, "%s: preprocessor not compiled with checkpoint enabled", p3); +#endif + break; + case X_CHOP: + tokop(PP_CHOP, p3, p, i0, TOKOP_UNSET|TOKOP_STRING); + break; + case X_COMPATIBILITY: + ppop(PP_COMPATIBILITY, i0); + break; + case X_DEBUG: + error_info.trace = i0 ? (p ? -strtol(p, NiL, 0) : -1) : 0; + break; + case X_ELSEIF: + setoption(ELSEIF, i0); + break; + case X_EXTERNALIZE: + setmode(EXTERNALIZE, i0); + break; + case X_FINAL: + setoption(FINAL, i0); + break; + case X_HEADEREXPAND: + setoption(HEADEREXPAND, i0); + break; + case X_HEADEREXPANDALL: + setoption(HEADEREXPANDALL, i0); + break; + case X_HIDE: + case X_NOTE: + PUSH_LINE(p); + /* UNDENT...*/ + while (c = pplex()) + { + if (c != T_ID) error(1, "%s: %s: identifier expected", p3, pp.token); + else if (sym = ppsymset(pp.symtab, pp.token)) + { + if (i1 == X_NOTE) + { + sym->flags &= ~SYM_NOTICED; + ppfsm(FSM_MACRO, sym->name); + } + else if (i0) + { + if (!sym->hidden && !(sym->hidden = newof(0, struct pphide, 1, 0))) + error(3, "out of space"); + if (!sym->macro) + ppfsm(FSM_MACRO, sym->name); + if (!sym->hidden->level++) + { + pp.hiding++; + if (sym->macro && !(sym->flags & (SYM_ACTIVE|SYM_READONLY))) + { + sym->hidden->macro = sym->macro; + sym->macro = 0; + sym->hidden->flags = sym->flags; + sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC); + } + } + } + else if (sym->hidden) + { + if ((mac = sym->macro) && !(sym->flags & (SYM_ACTIVE|SYM_READONLY))) + { + if (mac->formals) free(mac->formals); + free(mac->value); + free(mac); + sym->macro = 0; + sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC); + } + if (!--sym->hidden->level) + { + pp.hiding--; + if (sym->hidden->macro) + { + sym->macro = sym->hidden->macro; + sym->flags = sym->hidden->flags; + } + free(sym->hidden); + sym->hidden = 0; + } + } + } + } + /*...INDENT*/ + POP_LINE(); + break; + case X_HOSTDIR: + tokop(PP_HOSTDIR, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP); + break; + case X_HOSTED: + setmode(HOSTED, i0); + break; + case X_HOSTEDTRANSITION: + setmode(HOSTEDTRANSITION, i0); + break; + case X_ID: + tokop(PP_ID, p3, p, i0, TOKOP_UNSET|TOKOP_STRING); + break; + case X_IGNORE: + tokop(PP_IGNORE, p3, p, i0, TOKOP_UNSET|TOKOP_STRING); + break; + case X_INCLUDE: + tokop(PP_INCLUDE, p3, p, i0, TOKOP_STRING|TOKOP_DUP); + break; + case X_INITIAL: + setoption(INITIAL, i0); + break; + case X_KEYARGS: + ppop(PP_KEYARGS, i0); + break; + case X_LINE: + if (pp.linesync) pp.olinesync = pp.linesync; + pp.linesync = i0 ? pp.olinesync : (PPLINESYNC)0; + break; + case X_LINEBASE: + ppop(PP_LINEBASE, i0); + break; + case X_LINEFILE: + ppop(PP_LINEFILE, i0); + break; + case X_LINEID: + ppop(PP_LINEID, i0 ? p : (char*)0); + break; + case X_LINETYPE: + ppop(PP_LINETYPE, i0 ? (p ? strtol(p, NiL, 0) : 1) : 0); + break; + case X_MACREF: + if (!p) + { + if (i0 && !pp.macref) + { + ppop(PP_LINETYPE, 1); + ppop(PP_MACREF, ppmacref); + } + else error(2, "%s: option cannot be unset", p3); + } + else if (s = strchr(p, ' ')) + { + if (pp.macref && (s = strchr(p, ' '))) + { + *s++ = 0; + c = strtol(s, NiL, 0); + var.type = pp.truncate; + pp.truncate = PPTOKSIZ; + (*pp.macref)(pprefmac(p, REF_CREATE), error_info.file, error_info.line - (c == REF_NORMAL ? 2 : 1), c, (s = strchr(s, ' ')) ? strtol(s, NiL, 0) : 0L); + pp.truncate = var.type; + } + error_info.line -= 2; + } + break; + case X_MAP: + /*UNDENT*/ + /* + * #pragma pp:map [id ...] "/from/[,/to/]" [ "/old/new/[glnu]" ... ] + */ + + if (!i0) + { + error(2, "%s: option cannot be unset", p3); + goto donedirective; + } + if (!p5) + { + error(2, "%s: address argument expected", p3); + goto donedirective; + } + PUSH_LINE(p5); + while ((c = pplex()) == T_ID) + { + sfsprintf(pp.tmpbuf, MAXTOKEN, "__%s__", s = pp.token); + if (c = (int)hashget(pp.dirtab, s)) + { + hashput(pp.dirtab, 0, 0); + hashput(pp.dirtab, pp.tmpbuf, c); + } + if (c = (int)hashget(pp.strtab, s)) + { + hashput(pp.strtab, 0, 0); + hashput(pp.strtab, pp.tmpbuf, c); + } + } + if (c != T_STRING || !*(s = pp.token)) + { + if (c) + error(2, "%s: %s: address argument expected", p3, pptokstr(pp.token, 0)); + goto eatmap; + } + map = newof(0, struct map, 1, 0); + + /* + * /from/ + */ + + if (i0 = regcomp(&map->re, s, REG_AUGMENTED|REG_DELIMITED|REG_LENIENT|REG_NULL)) + regfatal(&map->re, 3, i0); + if (*(s += map->re.re_npat)) + { + error(2, "%s: invalid characters after pattern: %s ", p3, s); + goto eatmap; + } + + /* + * /old/new/[flags] + */ + + edit = 0; + while ((c = pplex()) == T_STRING) + { + if (!*(s = pp.token)) + { + error(2, "%s: substitution argument expected", p3); + goto eatmap; + } + if (edit) + edit = edit->next = newof(0, struct edit, 1, 0); + else + edit = map->edit = newof(0, struct edit, 1, 0); + if (!(i0 = regcomp(&edit->re, s, REG_AUGMENTED|REG_DELIMITED|REG_LENIENT|REG_NULL)) && !(i0 = regsubcomp(&edit->re, s += edit->re.re_npat, NiL, 0, 0))) + s += edit->re.re_npat; + if (i0) + regfatal(&edit->re, 3, i0); + if (*s) + { + error(2, "%s: invalid characters after substitution: %s ", p3, s); + goto eatmap; + } + } + if (c) + { + error(2, "%s: %s: substitution argument expected", p3, pptokstr(pp.token, 0)); + goto eatmap; + } + map->next = (struct map*)pp.maps; + pp.maps = (char*)map; + eatmap: + POP_LINE(); + /*INDENT*/ + break; + case X_MAPINCLUDE: + ppmapinclude(NiL, p5); + break; + case X_MODERN: + setoption(MODERN, i0); + break; + case X_MULTIPLE: + n = 1; + if (pp.in->type == IN_FILE) + ppmultiple(ppsetfile(error_info.file), i0 ? INC_CLEAR : INC_TEST); + break; + case X_NATIVE: + setoption(NATIVE, i0); + break; + case X_OPSPACE: + ppfsm(FSM_OPSPACE, i0 ? p4 : (char*)0); + break; + case X_PASSTHROUGH: + ppop(PP_PASSTHROUGH, i0); + break; + case X_PEDANTIC: + ppop(PP_PEDANTIC, i0); + break; + case X_PLUSCOMMENT: + ppop(PP_PLUSCOMMENT, i0); + break; + case X_PLUSPLUS: + ppop(PP_PLUSPLUS, i0); + break; + case X_PLUSSPLICE: + setoption(PLUSSPLICE, i0); + break; + case X_PRAGMAEXPAND: + setoption(PRAGMAEXPAND, i0); + break; + case X_PRAGMAFLAGS: + tokop(PP_PRAGMAFLAGS, p3, p, i0, 0); + break; + case X_PREDEFINED: + setoption(PREDEFINED, i0); + break; + case X_PREFIX: + setoption(PREFIX, i0); + break; + case X_PRESERVE: + setoption(PRESERVE, i0); + if (pp.option & PRESERVE) + { + setmode(CATLITERAL, 0); + ppop(PP_COMPATIBILITY, 1); + ppop(PP_TRANSITION, 0); + ppop(PP_PLUSCOMMENT, 1); + ppop(PP_SPACEOUT, 1); + setoption(STRINGSPAN, 1); + setoption(STRINGSPLIT, 0); + ppop(PP_HOSTDIR, "-", 1); + } + break; + case X_PROTOTYPED: + /* + * this option doesn't bump the token count + */ + + n = 1; + directive = ENDIF; +#if PROTOTYPE + setoption(PROTOTYPED, i0); +#else + error(1, "preprocessor not compiled with prototype conversion enabled"); +#endif + break; + case X_PROTO: + setoption(NOPROTO, !i0); + break; + case X_QUOTE: + tokop(PP_QUOTE, p3, p, i0, TOKOP_UNSET|TOKOP_STRING); + break; + case X_READONLY: + setmode(READONLY, i0); + break; + case X_REGUARD: + setoption(REGUARD, i0); + break; + case X_RESERVED: + tokop(PP_RESERVED, p3, p, i0, 0); + break; + case X_SPACEOUT: + if (!(pp.state & (COMPATIBILITY|COMPILE))) + ppop(PP_SPACEOUT, i0); + break; + case X_SPLICECAT: + setoption(SPLICECAT, i0); + break; + case X_SPLICESPACE: + setoption(SPLICESPACE, i0); + break; + case X_STANDARD: + tokop(PP_STANDARD, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP); + break; + case X_STRICT: + ppop(PP_STRICT, i0); + break; + case X_STRINGSPAN: + setoption(STRINGSPAN, i0); + break; + case X_STRINGSPLIT: + setoption(STRINGSPLIT, i0); + if (pp.option & STRINGSPLIT) + setmode(CATLITERAL, 0); + break; + case X_SYSTEM_HEADER: + if (i0) + { + pp.mode |= HOSTED; + pp.flags |= PP_hosted; + pp.in->flags |= IN_hosted; + } + else + { + pp.mode &= ~HOSTED; + pp.flags &= ~PP_hosted; + pp.in->flags &= ~PP_hosted; + } + break; + case X_TEST: + ppop(PP_TEST, p); + break; + case X_TEXT: + if (!(pp.option & KEEPNOTEXT)) + setstate(NOTEXT, !i0); + break; + case X_TRANSITION: + ppop(PP_TRANSITION, i0); + if (pp.state & TRANSITION) ppop(PP_COMPATIBILITY, i0); + break; + case X_TRUNCATE: + ppop(PP_TRUNCATE, i0 ? (p ? strtol(p, NiL, 0) : TRUNCLENGTH) : 0); + break; + case X_VENDOR: + tokop(PP_VENDOR, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP); + break; + case X_VERSION: + if (!(*pp.control & SKIP) && pp.pragma && !(pp.state & NOTEXT)) + { + sfsprintf(pp.tmpbuf, MAXTOKEN, "\"%s\"", pp.version); + (*pp.pragma)(dirname(PRAGMA), pp.pass, p3, pp.tmpbuf, !n); + if (pp.linesync && !n) + (*pp.linesync)(error_info.line, error_info.file); + emitted = 1; + } + break; + case X_WARN: + ppop(PP_WARN, i0); + break; + case X_ZEOF: + setoption(ZEOF, i0); + break; +#if DEBUG + case 0: + case X_INCLUDED: + case X_NOTICED: + case X_OPTION: + case X_STATEMENT: + break; + default: + error(PANIC, "%s: option recognized but not implemented", pp.valbuf); + break; +#endif + } + *p4 = i2; + if (!n) + goto checkmap; + goto donedirective; + case RENAME: + if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX))) + error(1, "#%s: non-standard directive", pp.token); + if ((c = pplex()) != T_ID) + { + error(1, "%s: invalid macro name", pptokstr(pp.token, 0)); + goto eatdirective; + } + if (!(sym = pprefmac(pp.token, REF_DELETE)) || !sym->macro) + goto eatdirective; + if (sym->flags & (SYM_ACTIVE|SYM_READONLY)) + { + if (!(pp.option & ALLPOSSIBLE)) + error(2, "%s: macro is %s", sym->name, (sym->flags & SYM_READONLY) ? "readonly" : "active"); + goto eatdirective; + } + if ((c = pplex()) != T_ID) + { + error(1, "%s: invalid macro name", pptokstr(pp.token, 0)); + goto eatdirective; + } + var.symbol = pprefmac(pp.token, REF_CREATE); + if (mac = var.symbol->macro) + { + if (var.symbol->flags & (SYM_ACTIVE|SYM_READONLY)) + { + if (!(pp.option & ALLPOSSIBLE)) + error(2, "%s: macro is %s", var.symbol->name, (var.symbol->flags & SYM_READONLY) ? "readonly" : "active"); + goto eatdirective; + } + if (!(pp.mode & HOSTED) || !(var.symbol->flags & SYM_INITIAL)) + error(1, "%s redefined", var.symbol->name); + if (mac->formals) free(mac->formals); + free(mac->value); + free(mac); + } + ppfsm(FSM_MACRO, var.symbol->name); + var.symbol->flags = sym->flags; + sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC); + var.symbol->macro = sym->macro; + sym->macro = 0; + break; + case UNDEF: + if ((c = pplex()) != T_ID) + { + error(1, "%s: invalid macro name", pptokstr(pp.token, 0)); + goto eatdirective; + } + if (sym = pprefmac(pp.token, REF_DELETE)) + { + if (mac = sym->macro) + { + if (sym->flags & (SYM_ACTIVE|SYM_READONLY)) + { + if (!(pp.option & ALLPOSSIBLE)) + error(2, "%s: macro is %s", sym->name, (sym->flags & SYM_READONLY) ? "readonly" : "active"); + goto eatdirective; + } + if (mac->formals) free(mac->formals); + free(mac->value); + free(mac); + mac = sym->macro = 0; + } + if ((pp.option & (DEFINITIONS|PREDEFINITIONS|REGUARD)) && !sym->hidden && !(sym->flags & SYM_MULTILINE) && ((pp.option & PREDEFINITIONS) || !(pp.mode & INIT)) && ((pp.option & (DEFINITIONS|PREDEFINITIONS)) || !(pp.state & NOTEXT))) + { + ppsync(); + ppprintf("#%s %s", dirname(UNDEF), sym->name); + emitted = 1; + } + sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC); + n2 = error_info.line; + goto benign; + } + else pprefmac(pp.token, REF_UNDEF); + break; +#if DEBUG + default: + error(PANIC, "#%s: directive recognized but not implemented", pp.token); + goto eatdirective; +#endif + } + break; + case '\n': + break; + default: + error(1, "%s: invalid directive name", pptokstr(pp.token, 0)); + goto eatdirective; + } + enddirective: +#if COMPATIBLE + if (c != '\n' && !(pp.state & COMPATIBILITY)) +#else + if (c != '\n') +#endif + { + pp.state |= DISABLE|NOSPACE; + if ((c = pplex()) != '\n' && (pp.mode & (HOSTED|PEDANTIC)) == PEDANTIC) + error(1, "%s: invalid characters after directive", pptokstr(pp.token, 0)); + } + eatdirective: + if (c != '\n') + { + pp.state |= DISABLE; + while (pplex() != '\n'); + } + donedirective: +#if _HUH_2002_05_09 + if (!(pp.state & EOF2NL)) + error(2, "%s in directive", pptokchr(0)); +#endif + pp.state &= ~RESTORE; + pp.mode &= ~RELAX; + if (!(*pp.control & SKIP)) + { + pp.state |= restore; + switch (directive) + { + case LINE: + return 0; + case INCLUDE: + if (pp.include) + { + error_info.line++; + PUSH_FILE(pp.include, n); + if (!pp.vendor && (pp.found->type & TYPE_VENDOR)) + pp.vendor = 1; + pp.include = 0; + return 0; + } + if (pp.incref) + (*pp.incref)(error_info.file, ppgetfile(pp.path)->name, error_info.line, PP_SYNC_IGNORE); + else if (pp.linesync && pp.macref) + { + pp.flags |= PP_lineignore; + (*pp.linesync)(error_info.line, ppgetfile(pp.path)->name); + } + /*FALLTHROUGH*/ + default: + pp.in->flags |= IN_tokens; + /*FALLTHROUGH*/ + case ENDIF: + error_info.line++; + if (emitted) + { + ppputchar('\n'); + ppcheckout(); + } + else + { + pp.state |= HIDDEN; + pp.hidden++; + } + return 0; + } + } + pp.state |= restore|HIDDEN|SKIPCONTROL; + pp.hidden++; + pp.level++; + error_info.line++; + return 0; +} + +/* + * grow the pp nesting control stack + */ + +void +ppnest(void) +{ + register struct ppinstk* ip; + int oz; + int nz; + long adjust; + long* op; + long* np; + + oz = pp.constack; + op = pp.maxcon - oz + 1; + nz = oz * 2; + np = newof(op, long, nz, 0); + if (adjust = (np - op)) + { + ip = pp.in; + do + { + if (ip->control) + ip->control += adjust; + } while (ip = ip->prev); + } + pp.control = np + oz; + pp.constack = nz; + pp.maxcon = np + nz - 1; +} diff --git a/usr/src/lib/libpp/common/ppcpp.c b/usr/src/lib/libpp/common/ppcpp.c new file mode 100644 index 0000000000..23e3fe7541 --- /dev/null +++ b/usr/src/lib/libpp/common/ppcpp.c @@ -0,0 +1,30 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * standalone preprocessor lexical analyzer + */ + +#define CPP 1 + +#include "pplex.c" diff --git a/usr/src/lib/libpp/common/ppdata.c b/usr/src/lib/libpp/common/ppdata.c new file mode 100644 index 0000000000..4c15eaf940 --- /dev/null +++ b/usr/src/lib/libpp/common/ppdata.c @@ -0,0 +1,179 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor data + * + * intended to be a conforming implementation of the translation phases + * (2.1.1.2) 1,2,3,4 and 6 of the "American National Standard for + * Information Systems -- Programming Language -- C", ANSI X3.159-1989. + * + * STANDARD INTERPRETATION: + * + * include files are forced to preserve #if nesting levels + * support for this is found in the recursive description for + * include file processing in the translation phases + * + * ID"..." produces two tokens: {ID}{"..."} + * ID'...' produces two tokens: {ID}{'...'} + * + * COMPATIBILITY: + * + * only sane Reiser compatibility is implemented + * + * strange handling of `\newline', especially in directives, + * is not implemented + * + * dissappearing comments used as concatenation operators work + * only within macro bodies + */ + +static const char id[] = "\n@(#)$Id: libpp (AT&T Research) 2006-11-23 $\0\n"; + +#include "pplib.h" + +#ifndef IDNAME +#define IDNAME "pp" +#endif + +static char addbuf[MAXTOKEN+1]; /* ADD buffer */ +static char argsbuf[MAXTOKEN+1]; /* predicate args */ +static char catbuf[MAXTOKEN+1]; /* catenation buffer */ +static char hidebuf[MAXTOKEN+1]; /* pp:hide buffer */ +static char outbuf[2*(PPBUFSIZ+MAXTOKEN)];/* output buffer */ +static char pathbuf[MAXTOKEN+1]; /* full path of last #include */ +static char tmpbuf[MAXTOKEN+1]; /* very temporary buffer */ +static char tokbuf[2*MAXTOKEN+1]; /* token buffer */ +static char valbuf[MAXTOKEN+1]; /* builtin macro value buffer */ + +static char optflags[X_last_option+1];/* OPT_* flags indexed by X_* */ + +static char null[1]; + +static struct ppinstk instack = /* input stream stack */ +{ + &null[0] /* nextchr */ +}; + +static struct ppdirs stddir = /* standard include directory */ +{ + PPSTANDARD, 0, 1, INC_STANDARD, TYPE_INCLUDE|TYPE_DIRECTORY|TYPE_HOSTED +}; + +static struct ppdirs firstdir = /* first include directory */ +{ + "", &stddir, 0, INC_PREFIX, TYPE_INCLUDE|TYPE_DIRECTORY +}; + +struct ppglobals pp = +{ + /* public globals */ + + &id[10], /* version */ + "", /* lineid */ + "/dev/stdout", /* outfile */ + IDNAME, /* pass */ + &tokbuf[0], /* token */ + 0, /* symbol */ + + /* exposed for the output macros */ + + &outbuf[0], /* outb */ + &outbuf[0], /* outbuf */ + &outbuf[0], /* outp */ + &outbuf[PPBUFSIZ], /* oute */ + 0, /* offset */ + + /* public context */ + + &firstdir, /* lcldirs */ + &firstdir, /* stddirs */ + 0, /* flags */ + 0, /* symtab */ + + /* private context */ + + 0, /* context */ + 0, /* state */ + ALLMULTIPLE|CATLITERAL, /* mode */ + PREFIX, /* option */ + 0, /* test */ + 0, /* filedeps.sp */ + 0, /* filedeps.flags */ + &firstdir, /* firstdir */ + &firstdir, /* lastdir */ + 0, /* hide */ + 0, /* column */ + -1, /* pending */ + 0, /* firstfile */ + 0, /* lastfile */ + 0, /* ignore */ + 0, /* probe */ + 0, /* filtab */ + 0, /* prdtab */ + 0, /* date */ + 0, /* time */ + 0, /* maps */ + 0, /* ro_state */ + 0, /* ro_mode */ + 0, /* ro_option */ + {0}, /* cdir */ + {0}, /* hostdir */ + 0, /* ppdefault */ + 0, /* firstindex */ + 0, /* lastindex */ + 0, /* firstop */ + 0, /* lastop */ + 0, /* firsttx */ + 0, /* lasttx */ + 0, /* arg_file */ + 0, /* arg_mode */ + 0, /* arg_style */ + 0, /* c */ + 0, /* hosted */ + 0, /* ignoresrc */ + 0, /* initialized */ + 0, /* standalone */ + 0, /* spare_1 */ + + /* library private globals */ + + "\"08/11/94\"", /* checkpoint (with quotes!) */ + 128, /* constack */ + &instack, /* in */ + &addbuf[0], /* addp */ + &argsbuf[0], /* args */ + &addbuf[0], /* addbuf */ + &catbuf[0], /* catbuf */ + 0, /* hdrbuf */ + &hidebuf[0], /* hidebuf */ + &pathbuf[0], /* path */ + &tmpbuf[0], /* tmpbuf */ + &valbuf[0], /* valbuf */ + &optflags[0], /* optflags */ + '\n', /* lastout */ + + /* the rest are implicitly initialized */ +}; + +char ppctype[UCHAR_MAX]; diff --git a/usr/src/lib/libpp/common/pperror.c b/usr/src/lib/libpp/common/pperror.c new file mode 100644 index 0000000000..46f7442ec7 --- /dev/null +++ b/usr/src/lib/libpp/common/pperror.c @@ -0,0 +1,38 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor error handler + */ + +#include "pplib.h" + +void +pperror(int level, ...) +{ + va_list ap; + + va_start(ap, level); + errorv(pp.pass, level, ap); + va_end(ap); +} diff --git a/usr/src/lib/libpp/common/ppexpr.c b/usr/src/lib/libpp/common/ppexpr.c new file mode 100644 index 0000000000..5fd93afde5 --- /dev/null +++ b/usr/src/lib/libpp/common/ppexpr.c @@ -0,0 +1,697 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor expression evaluation support + */ + +#include "pplib.h" + +#include <regex.h> + +#define lex(c) ((((c)=peektoken)>=0?(peektoken=(-1)):((c)=pplex())),(c)) +#define unlex(c) (peektoken=(c)) + +static int peektoken; /* expression lookahead token */ +static char* errmsg; /* subexpr() error message */ + +/* + * exists predicate evaluation + */ + +static int +exists(int op, char* pred, register char* args) +{ + register int c; + register int type; + char* pptoken; + long state; + char file[MAXTOKEN + 1]; + + state = (pp.state & ~DISABLE); + PUSH_STRING(args); + pptoken = pp.token; + pp.token = file; + pp.state |= HEADER|PASSEOF; + type = pplex(); + pp.state &= ~HEADER; + pp.token = pptoken; + switch (type) + { + case T_STRING: + case T_HEADER: + break; + default: + error(1, "%s: \"...\" or <...> argument expected", pred); + c = 0; + goto done; + } + if (op == X_EXISTS) + { + if ((c = pplex()) == ',') + { + while ((c = pplex()) == T_STRING) + { + if (pathaccess(pp.path, pp.token, file, NiL, 0)) + { + pathcanon(pp.path, 0); + message((-2, "%s: %s found", pred, pp.path)); + c = 1; + goto done; + } + if ((c = pplex()) != ',') break; + } + if (c) error(1, "%s: \"...\" arguments expected", pred); + strcpy(pp.path, file); + message((-2, "%s: %s not found", pred, file)); + c = 0; + } + else c = ppsearch(file, type, SEARCH_EXISTS) >= 0; + } + else + { + register struct ppfile* fp; + + fp = ppsetfile(file); + c = fp->flags || fp->guard == INC_IGNORE; + } + done: + while (pplex()); + pp.state = state; + return c; +} + +/* + * strcmp/match predicate evaluation + */ + +static int +compare(char* pred, char* args, int match) +{ + register int c; + char* pptoken; + long state; + regex_t re; + char tmp[MAXTOKEN + 1]; + + state = (pp.state & ~DISABLE); + PUSH_STRING(args); + pp.state |= PASSEOF; + pptoken = pp.token; + pp.token = tmp; + if (!pplex()) + goto bad; + pp.token = pptoken; + if (pplex() != ',' || !pplex()) + goto bad; + if (!match) + c = strcmp(tmp, pp.token); + else if ((c = regcomp(&re, pp.token, REG_AUGMENTED|REG_LENIENT|REG_NULL)) || (c = regexec(&re, tmp, NiL, 0, 0)) && c != REG_NOMATCH) + regfatal(&re, 3, c); + else + { + c = !c; + regfree(&re); + } + if ((pp.state & PASSEOF) && pplex()) + goto bad; + pp.state = state; + return c; + bad: + pp.token = pptoken; + error(2, "%s: 2 arguments expected", pred); + while (pplex()); + pp.state = state; + return 0; +} + +/* + * #if predicate parse and evaluation + */ + +static int +predicate(int warn) +{ + register char* args; + register struct pplist* p; + register struct ppsymbol* sym; + register int type; + int index; + + static char pred[MAXID + 1]; + + /* + * first gather the args + */ + + index = (int)hashref(pp.strtab, pp.token); + if (warn && peekchr() != '(') switch (index) + { + case X_DEFINED: + case X_EXISTS: + case X_INCLUDED: + case X_MATCH: + case X_NOTICED: + case X_OPTION: + case X_SIZEOF: + case X_STRCMP: + break; + default: + if (pp.macref) pprefmac(pp.token, REF_IF); + return 0; + } + strcpy(pred, pp.token); + pp.state |= DISABLE; + type = pppredargs(); + pp.state &= ~DISABLE; + switch (type) + { + case T_ID: + case T_STRING: + break; + default: + unlex(type); + /*FALLTHROUGH*/ + case 0: + if (index && !(pp.state & STRICT)) + error(1, "%s: predicate argument expected", pred); + if (pp.macref) pprefmac(pred, REF_IF); + return 0; + } + args = pp.args; + + /* + * now evaluate + */ + + debug((-6, "pred=%s args=%s", pred, args)); + if ((pp.state & STRICT) && !(pp.mode & HOSTED)) switch (index) + { + case X_DEFINED: + case X_SIZEOF: + break; + default: + error(1, "%s(%s): non-standard predicate test", pred, args); + return 0; + } + switch (index) + { + case X_DEFINED: + if (type != T_ID) error(1, "%s: identifier argument expected", pred); + else if ((sym = pprefmac(args, REF_IF)) && sym->macro) return 1; + else if (args[0] == '_' && args[1] == '_' && !strncmp(args, "__STDPP__", 9)) + { + if (pp.hosted == 1 && pp.in->prev->type == IN_FILE) + { + pp.mode |= HOSTED; + pp.flags |= PP_hosted; + } + return *(args + 9) ? (int)hashref(pp.strtab, args + 9) : 1; + } + break; + case X_EXISTS: + case X_INCLUDED: + return exists(index, pred, args); + case X_MATCH: + case X_STRCMP: + return compare(pred, args, index == X_MATCH); + case X_NOTICED: + if (type != T_ID) error(1, "%s: identifier argument expected", pred); + else if (((sym = pprefmac(args, REF_IF)) || (sym = ppsymref(pp.symtab, args))) && (sym->flags & SYM_NOTICED)) return 1; + break; + case X_OPTION: + return ppoption(args); + case X_SIZEOF: + error(2, "%s invalid in #%s expressions", pred, dirname(IF)); + break; + default: + if (warn && !(pp.mode & HOSTED) && (sym = ppsymref(pp.symtab, pred)) && (sym->flags & SYM_PREDICATE)) + error(1, "use #%s(%s) to disambiguate", pred, args); + if (p = (struct pplist*)hashget(pp.prdtab, pred)) + { + if (!*args) return 1; + while (p) + { + if (streq(p->value, args)) return 1; + p = p->next; + } + } + break; + } + return 0; +} + +/* + * evaluate a long integer subexpression with precedence + * taken from the library routine streval() + * may be called recursively + * + * NOTE: all operands are evaluated as both the parse + * and evaluation are done on the fly + */ + +static long +subexpr(register int precedence, int* pun) +{ + register int c; + register long n; + register long x; + register int operand = 1; + int un = 0; + int xn; + + switch (lex(c)) + { + case 0: + case '\n': + unlex(c); + if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "more tokens expected"; + return 0; + case '-': + n = -subexpr(13, &un); + break; + case '+': + n = subexpr(13, &un); + break; + case '!': + n = !subexpr(13, &un); + break; + case '~': + n = ~subexpr(13, &un); + break; + default: + unlex(c); + n = 0; + operand = 0; + break; + } + un <<= 1; + for (;;) + { + switch (lex(c)) + { + case 0: + case '\n': + goto done; + case ')': + if (!precedence) + { + if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "too many )'s"; + return 0; + } + goto done; + case '(': + n = subexpr(1, &un); + if (lex(c) != ')') + { + unlex(c); + if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "closing ) expected"; + return 0; + } + gotoperand: + if (operand) + { + if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "operator expected"; + return 0; + } + operand = 1; + un <<= 1; + continue; + case '?': + if (precedence > 1) goto done; + un = 0; + if (lex(c) == ':') + { + if (!n) n = subexpr(2, &un); + else + { + x = pp.mode; + pp.mode |= INACTIVE; + subexpr(2, &xn); + pp.mode = x; + } + } + else + { + unlex(c); + x = subexpr(2, &xn); + if (lex(c) != ':') + { + unlex(c); + if (!errmsg && !(pp.mode & INACTIVE)) errmsg = ": expected for ? operator"; + return 0; + } + if (n) + { + n = x; + un = xn; + subexpr(2, &xn); + } + else n = subexpr(2, &un); + } + break; + case ':': + goto done; + case T_ANDAND: + case T_OROR: + xn = (c == T_ANDAND) ? 4 : 3; + if (precedence >= xn) goto done; + if ((n != 0) == (c == T_ANDAND)) n = subexpr(xn, &un) != 0; + else + { + x = pp.mode; + pp.mode |= INACTIVE; + subexpr(xn, &un); + pp.mode = x; + } + un = 0; + break; + case '|': + if (precedence > 4) goto done; + n |= subexpr(5, &un); + break; + case '^': + if (precedence > 5) goto done; + n ^= subexpr(6, &un); + break; + case '&': + if (precedence > 6) goto done; + n &= subexpr(7, &un); + break; + case T_EQ: + case T_NE: + if (precedence > 7) goto done; + n = (n == subexpr(8, &un)) == (c == T_EQ); + un = 0; + break; + case '<': + case T_LE: + case T_GE: + case '>': + if (precedence > 8) goto done; + x = subexpr(9, &un); + switch (c) + { + case '<': + switch (un) + { + case 01: + n = n < (unsigned long)x; + break; + case 02: + n = (unsigned long)n < x; + break; + case 03: + n = (unsigned long)n < (unsigned long)x; + break; + default: + n = n < x; + break; + } + break; + case T_LE: + switch (un) + { + case 01: + n = n <= (unsigned long)x; + break; + case 02: + n = (unsigned long)n <= x; + break; + case 03: + n = (unsigned long)n <= (unsigned long)x; + break; + default: + n = n <= x; + break; + } + break; + case T_GE: + switch (un) + { + case 01: + n = n >= (unsigned long)x; + break; + case 02: + n = (unsigned long)n >= x; + break; + case 03: + n = (unsigned long)n >= (unsigned long)x; + break; + default: + n = n >= x; + break; + } + break; + case '>': + switch (un) + { + case 01: + n = n > (unsigned long)x; + break; + case 02: + n = (unsigned long)n > x; + break; + case 03: + n = (unsigned long)n > (unsigned long)x; + break; + default: + n = n > x; + break; + } + break; + } + un = 0; + break; + case T_LSHIFT: + case T_RSHIFT: + if (precedence > 9) goto done; + x = subexpr(10, &un); + if (c == T_LSHIFT) n <<= x; + else n >>= x; + un >>= 1; + break; + case '+': + case '-': + if (precedence > 10) goto done; + x = subexpr(11, &un); + if (c == '+') n += x; + else n -= x; + break; + case '*': + case '/': + case '%': + if (precedence > 11) goto done; + x = subexpr(12, &un); + if (c == '*') n *= x; + else if (x == 0) + { + if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "divide by zero"; + return 0; + } + else if (c == '/') n /= x; + else n %= x; + break; + case '#': + pp.state |= DISABLE; + c = pplex(); + pp.state &= ~DISABLE; + if (c != T_ID) + { + if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "# must precede a predicate identifier"; + return 0; + } + n = predicate(0); + goto gotoperand; + case T_ID: + n = predicate(1); + goto gotoperand; + case T_CHARCONST: + c = *(pp.toknxt - 1); + *(pp.toknxt - 1) = 0; + n = chrtoi(pp.token + 1); + *(pp.toknxt - 1) = c; + if (n & ~((1<<CHAR_BIT)-1)) + { + if (!(pp.mode & HOSTED)) + error(1, "'%s': multi-character character constants are not portable", pp.token); + } +#if CHAR_MIN < 0 + else n = (char)n; +#endif + goto gotoperand; + case T_DECIMAL_U: + case T_DECIMAL_UL: + case T_OCTAL_U: + case T_OCTAL_UL: + case T_HEXADECIMAL_U: + case T_HEXADECIMAL_UL: + un |= 01; + /*FALLTHROUGH*/ + case T_DECIMAL: + case T_DECIMAL_L: + case T_OCTAL: + case T_OCTAL_L: + case T_HEXADECIMAL: + case T_HEXADECIMAL_L: + n = strtoul(pp.token, NiL, 0); + if ((unsigned long)n > LONG_MAX) un |= 01; + goto gotoperand; + case T_WCHARCONST: + n = chrtoi(pp.token); + goto gotoperand; + default: + if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "invalid token"; + return 0; + } + if (errmsg) return 0; + if (!operand) goto nooperand; + } + done: + unlex(c); + if (!operand) + { + nooperand: + if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "operand expected"; + return 0; + } + if (un) *pun |= 01; + return n; +} + +/* + * preprocessor expression evaluator using modified streval(3) + * *pun!=0 if result is unsigned + */ + +long +ppexpr(int* pun) +{ + long n; + int opeektoken; + long ppstate; + + ppstate = (pp.state & (CONDITIONAL|DISABLE|NOSPACE|STRIP)); + pp.state &= ~(DISABLE|STRIP); + pp.state |= CONDITIONAL|NOSPACE; + opeektoken = peektoken; + peektoken = -1; + *pun = 0; + n = subexpr(0, pun); + if (peektoken == ':' && !errmsg && !(pp.mode & INACTIVE)) errmsg = "invalid use of :"; + if (errmsg) + { + error(2, "%s in expression", errmsg); + errmsg = 0; + n = 0; + } + peektoken = opeektoken; + pp.state &= ~(CONDITIONAL|NOSPACE); + pp.state |= ppstate; + if (*pun) debug((-4, "ppexpr() = %luU", n)); + else debug((-4, "ppexpr() = %ld", n)); + return n; +} + +/* + * return non-zero if option s is set + */ + +int +ppoption(char* s) +{ + switch ((int)hashget(pp.strtab, s)) + { + case X_ALLMULTIPLE: + return pp.mode & ALLMULTIPLE; + case X_BUILTIN: + return pp.mode & BUILTIN; + case X_CATLITERAL: + return pp.mode & CATLITERAL; + case X_COMPATIBILITY: + return pp.state & COMPATIBILITY; + case X_DEBUG: + return -error_info.trace; + case X_ELSEIF: + return pp.option & ELSEIF; + case X_FINAL: + return pp.option & FINAL; + case X_HOSTDIR: + return pp.mode & HOSTED; + case X_HOSTED: + return pp.flags & PP_hosted; + case X_INITIAL: + return pp.option & INITIAL; + case X_KEYARGS: + return pp.option & KEYARGS; + case X_LINEBASE: + return pp.flags & PP_linebase; + case X_LINEFILE: + return pp.flags & PP_linefile; + case X_LINETYPE: + return pp.flags & PP_linetype; + case X_PLUSCOMMENT: + return pp.option & PLUSCOMMENT; + case X_PLUSPLUS: + return pp.option & PLUSPLUS; + case X_PLUSSPLICE: + return pp.option & PLUSSPLICE; + case X_PRAGMAEXPAND: + return pp.option & PRAGMAEXPAND; + case X_PREDEFINED: + return pp.option & PREDEFINED; + case X_PREFIX: + return pp.option & PREFIX; + case X_PROTOTYPED: + return pp.option & PROTOTYPED; + case X_READONLY: + return pp.mode & READONLY; + case X_REGUARD: + return pp.option & REGUARD; + case X_SPACEOUT: + return pp.state & SPACEOUT; + case X_SPLICECAT: + return pp.option & SPLICECAT; + case X_SPLICESPACE: + return pp.option & SPLICESPACE; + case X_STRICT: + return pp.state & STRICT; + case X_STRINGSPAN: + return pp.option & STRINGSPAN; + case X_STRINGSPLIT: + return pp.option & STRINGSPLIT; + case X_TEST: + return pp.test; + case X_TEXT: + return !(pp.state & NOTEXT); + case X_TRANSITION: + return pp.state & TRANSITION; + case X_TRUNCATE: + return pp.truncate; + case X_WARN: + return pp.state & WARN; + default: + if (pp.state & WARN) error(1, "%s: unknown option name", s); + return 0; + } +} diff --git a/usr/src/lib/libpp/common/ppfsm.c b/usr/src/lib/libpp/common/ppfsm.c new file mode 100644 index 0000000000..5cef65db2a --- /dev/null +++ b/usr/src/lib/libpp/common/ppfsm.c @@ -0,0 +1,946 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor and proto lexical analyzer fsm + * define PROTOMAIN for standalone proto + */ + +#include "pplib.h" +#include "ppfsm.h" + +/* + * lexical FSM encoding + * derived from a standalone ansi cpp by Dennis Ritchie + * modified for libpp by Glenn Fowler + * + * fsm[] is initialized from fsminit[]. The encoding is blown out into + * fsm[] for time efficiency. When in state state, and one of the + * characters in ch arrives, enter nextstate. States >= TERMINAL are + * either final, or at least require special action. In fsminit[] there + * is a line for each <state,charset,nextstate>. Early entries are + * overwritten by later ones. C_XXX is the universal set and should + * always be first. Some of the fsminit[] entries are templates for + * groups of states. The OP entries trigger the state copies. States + * above TERMINAL are represented in fsm[] as negative values. S_TOK and + * S_TOKB encode the resulting token type in the upper bits. These actions + * differ in that S_TOKB has a lookahead char. + * + * fsm[] has three start states: + * + * PROTO proto (ANSI -> K&R,C++,ANSI) + * QUICK standalone ppcpp() + * TOKEN tokenizing pplex() + * + * If the next state remains the same then the fsm[] transition value is 0. + * MAX+1 is a power of 2 so that fsm[state][EOF==MAX+1] actually accesses + * fsm[state+1][0] which is ~S_EOB for all states. This preserves the + * power of 2 fsm[] row size for efficient array indexing. Thanks to + * D. G. Korn for the last two observations. The pseudo non-terminal state + * fsm[TERMINAL][state+1] is used to differentiate EOB from EOF. + * + * The bit layout is: + * + * TERM arg SPLICE next + * 15 14-8 7 6-0 + */ + +/* + * NOTE: these must be `control' characters for all native codesets + * currently ok for {ascii,ebcdic1,ebcdic2,ebcdic3} + */ + +#define C_DEC 001 +#define C_EOF 002 +#define C_HEX 003 +#define C_LET 021 +#define C_OCT 022 +#define C_XXX 023 + +#define OP (-1) +#define END 0 +#define COPY 1 + +#define copy(t,f) (memcpy(&fsm[t][1],&fsm[f][1],(MAX+1)*sizeof(short)),fsm[TERMINAL][(t)+1]=fsm[TERMINAL][(f)+1]) + +struct fsminit /* fsm initialization row */ +{ + int state; /* if in this state */ + unsigned char ch[4]; /* and see one of these */ + int nextstate; /* enter this state if <TERMINAL*/ +}; + +static struct fsminit fsminit[] = +{ + /* proto start state */ + { PROTO, { C_XXX }, S_CHR, }, + { PROTO, { C_EOF }, S_EOF, }, + { PROTO, { C_DEC }, BAD1, }, + { PROTO, { '.' }, DOT, }, + { PROTO, { C_LET }, NID, }, + { PROTO, { 'L' }, LIT, }, + { PROTO, { 'd', 'e', 'f', 'i' }, RES1, }, + { PROTO, { 'r', 's', 't', 'v' }, RES1, }, + { PROTO, { 'w', 'N' }, RES1, }, + { PROTO, { '"', '\'' }, S_LITBEG, }, + { PROTO, { '/' }, COM1, }, + { PROTO, { '\n' }, S_NL, }, + { PROTO, { ' ','\t','\f','\v' }, WS1, }, + +/* proto {do,else,extern,for,if,inline,return,static,typedef,va_start,void,while,NoN} */ + { RES1, { C_XXX }, S_MACRO, }, + { RES1, { C_LET, C_DEC }, NID, }, + { RES1, { 'a' }, RES1a, }, + { RES1, { 'e' }, RES1e, }, + { RES1, { 'f' }, RES1f, }, + { RES1, { 'h' }, RES1h, }, + { RES1, { 'l' }, RES1l, }, + { RES1, { 'n' }, RES1n, }, + { RES1, { 'o' }, RES1o, }, + { RES1, { 't' }, RES1t, }, + { RES1, { 'x' }, RES1x, }, + { RES1, { 'y' }, RES1y, }, + + /* proto reserved {va_start} */ + { RES1a, { C_XXX }, S_RESERVED, }, + { RES1a, { C_LET, C_DEC }, NID, }, + { RES1a, { '_','s','t','a' }, RES1a, }, + { RES1a, { 'r' }, RES1a, }, + + /* proto reserved {return} */ + { RES1e, { C_XXX }, S_RESERVED, }, + { RES1e, { C_LET, C_DEC }, NID, }, + { RES1e, { 't','u','r','n' }, RES1e, }, + + /* proto reserved {if} */ + { RES1f, { C_XXX }, S_RESERVED, }, + { RES1f, { C_LET, C_DEC }, NID, }, + + /* proto reserved {while} */ + { RES1h, { C_XXX }, S_RESERVED, }, + { RES1h, { C_LET, C_DEC }, NID, }, + { RES1h, { 'i','l','e' }, RES1h, }, + + /* proto reserved {else} */ + { RES1l, { C_XXX }, S_RESERVED, }, + { RES1l, { C_LET, C_DEC }, NID, }, + { RES1l, { 's','e' }, RES1l, }, + + /* proto reserved {inline} */ + { RES1n, { C_XXX }, S_RESERVED, }, + { RES1n, { C_LET, C_DEC }, NID, }, + { RES1n, { 'l','i','n','e' }, RES1n, }, + + /* proto reserved {do,for,void} */ + { RES1o, { C_XXX }, S_RESERVED, }, + { RES1o, { C_LET, C_DEC }, NID, }, + { RES1o, { 'r','i','d','N' }, RES1o, }, + + /* proto reserved {static} */ + { RES1t, { C_XXX }, S_RESERVED, }, + { RES1t, { C_LET, C_DEC }, NID, }, + { RES1t, { 'a','t','i','c' }, RES1t, }, + + /* proto reserved {extern} */ + { RES1x, { C_XXX }, S_RESERVED, }, + { RES1x, { C_LET, C_DEC }, NID, }, + { RES1x, { 't','e','r','n' }, RES1x, }, + + /* proto reserved {typedef} */ + { RES1y, { C_XXX }, S_RESERVED, }, + { RES1y, { C_LET, C_DEC }, NID, }, + { RES1y, { 'p','e','d','f' }, RES1y, }, + + /* saw /, perhaps start of comment */ + { COM1, { C_XXX }, S_CHRB, }, + { COM1, { '*' }, COM2, }, +#if PROTOMAIN + { COM1, { '/' }, COM5, }, +#endif + + /* saw / *, start of comment */ + { COM2, { C_XXX }, COM2, }, + { COM2, { '\n', C_EOF }, S_COMMENT, }, + { COM2, { '/' }, COM4, }, + { COM2, { '*' }, COM3, }, + { COM2, { '#', ';', ')' }, QUAL(COM2), }, + + /* saw the * possibly ending a comment */ + { COM3, { C_XXX }, COM2, }, + { COM3, { '\n', C_EOF }, S_COMMENT, }, + { COM3, { '#', ';', ')' }, QUAL(COM2), }, + { COM3, { '*' }, COM3, }, + { COM3, { '/' }, S_COMMENT, }, + + /* saw / in / * comment, possible malformed nest */ + { COM4, { C_XXX }, COM2, }, + { COM4, { '*', '\n', C_EOF }, S_COMMENT, }, + { COM4, { '/' }, COM4, }, + + /* saw / /, start of comment */ + { COM5, { C_XXX }, COM5, }, + { COM5, { '\n', C_EOF }, S_COMMENT, }, + { COM5, { '/' }, COM6, }, + { COM5, { '*' }, COM7, }, + + /* saw / in / / comment, possible malformed nest */ + { COM6, { C_XXX }, COM5, }, + { COM6, { '*', '\n', C_EOF }, S_COMMENT, }, + { COM6, { '/' }, COM6, }, + + /* saw * in / /, possible malformed nest */ + { COM7, { C_XXX }, COM5, }, + { COM7, { '\n', C_EOF }, S_COMMENT, }, + { COM7, { '*' }, COM7, }, + { COM7, { '/' }, S_COMMENT, }, + + /* normal identifier -- always a macro candidate */ + { NID, { C_XXX }, S_MACRO, }, + { NID, { C_LET, C_DEC }, NID, }, + + /* saw ., operator or dbl constant */ + { DOT, { C_XXX }, S_CHRB, }, + { DOT, { '.' }, DOT2, }, + { DOT, { C_DEC }, BAD1, }, + + /* saw .., possible ... */ + { DOT2, { C_XXX }, BACK(T_INVALID), }, + { DOT2, { '.' }, KEEP(T_VARIADIC), }, + + /* saw L (possible start of normal wide literal) */ + { LIT, { C_XXX }, S_MACRO, }, + { LIT, { C_LET, C_DEC }, NID, }, + { LIT, { '"', '\'' }, QUAL(LIT1), }, + + /* saw " or ' beginning literal */ + { LIT1, { C_XXX }, LIT1, }, + { LIT1, { '"', '\'' }, S_LITEND, }, + { LIT1, { '\n', C_EOF }, S_LITEND, }, + { LIT1, { '\\' }, LIT2, }, + + /* saw \ in literal */ + { LIT2, { C_XXX }, S_LITESC, }, + { LIT2, { '\n', C_EOF }, S_LITEND, }, + + /* eat malformed numeric constant */ + { BAD1, { C_XXX }, BACK(T_INVALID), }, + { BAD1, { C_LET, C_DEC, '.' }, BAD1, }, + { BAD1, { 'e', 'E' }, BAD2, }, + + /* eat malformed numeric fraction|exponent */ + { BAD2, { C_XXX }, BACK(T_INVALID), }, + { BAD2, { C_LET, C_DEC, '.' }, BAD1, }, + { BAD2, { '+', '-' }, BAD1, }, + + /* saw white space, eat it up */ + { WS1, { C_XXX }, S_WS, }, + { WS1, { ' ', '\t' }, WS1, }, + { WS1, { '\f', '\v' }, S_VS, }, + +#if !PROTOMAIN + + /* quick template */ + { QUICK, { C_XXX }, QTOK, }, + { QUICK, { C_EOF, MARK }, S_CHRB, }, + { QUICK, { C_LET, C_DEC }, QID, }, + { QUICK, { 'L' }, LIT0, }, + { QUICK, { '"', '\'' }, S_LITBEG, }, + { QUICK, { '/' }, S_CHRB, }, + { QUICK, { '*' }, QCOM, }, + { QUICK, { '#' }, SHARP1, }, + { QUICK, { '\n' }, S_NL, }, + { QUICK, { '\f', '\v' }, S_VS, }, + + /* copy QUICK to QUICK+1 through MAC0+1 */ + { OP, {QUICK,QUICK+1,MAC0+1}, COPY, }, + + /* quick start state */ + { QUICK, { C_EOF }, S_EOF, }, + { QUICK, { C_DEC }, QNUM, }, + { QUICK, { MARK }, QTOK, }, + { QUICK, { '/' }, COM1, }, + { QUICK, { ' ', '\t' }, QUICK, }, + + /* grab non-macro tokens */ + { QTOK, { C_DEC }, QNUM, }, + + /* grab numeric and invalid tokens */ + { QNUM, { C_LET, C_DEC, '.' }, QNUM, }, + { QNUM, { 'e', 'E' }, QEXP, }, + + /* grab exponent token */ + { QEXP, { C_LET, C_DEC, '.' }, QNUM, }, + { QEXP, { '+', '-' }, QNUM, }, + + /* saw *, grab possible bad comment terminator */ + { QCOM, { C_DEC }, QNUM, }, + { QCOM, { '/' }, S_COMMENT, }, + + /* saw L (possible start of wide string or first macro char) */ + { MAC0, { 'L' }, QID, }, + { MAC0, { '"', '\'' }, QUAL(LIT1), }, + + /* macro candidate template */ + { MAC0+1, { 'L' }, QID, }, + + /* copy MAC0+1 to MAC0+2 through MACN */ + { OP, {MAC0+1,MAC0+2,MACN}, COPY }, + + /* saw L (possible start of wide string or macro L) */ + { HIT0, { C_XXX }, S_MACRO, }, + { HIT0, { C_LET, C_DEC }, QID, }, + { HIT0, { '"', '\'' }, QUAL(LIT1), }, + + /* macro hit template */ + { HIT0+1, { C_XXX }, S_MACRO, }, + { HIT0+1, { C_LET, C_DEC }, QID, }, + + /* copy HIT0+1 to HIT0+2 through HITN */ + { OP, {HIT0+1,HIT0+2,HITN}, COPY }, + + /* saw L (possible start of wide literal) */ + { LIT0, { C_XXX }, S_MACRO, }, + { LIT0, { C_LET, C_DEC }, QID, }, + { LIT0, { '"', '\'' }, QUAL(LIT1), }, + + /* (!PROTOMAIN COM1) saw /, perhaps start of comment or /= */ + { COM1, { '=' }, KEEP(T_DIVEQ), }, + + /* normal start state */ + { TOKEN, { C_XXX }, S_HUH, }, + { TOKEN, { C_EOF }, S_EOF, }, + { TOKEN, { C_DEC }, DEC1, }, + { TOKEN, { '0' }, OCT1, }, + { TOKEN, { '.' }, DOT1, }, + { TOKEN, { C_LET }, NID, }, + { TOKEN, { 'L' }, LIT, }, + { TOKEN, { '"', '\'', '<' }, S_LITBEG, }, + { TOKEN, { '/' }, COM1, }, + { TOKEN, { '\n' }, S_NL, }, + { TOKEN, { ' ', '\t' }, WS1, }, + { TOKEN, { '\f', '\v' }, S_VS, }, + { TOKEN, { '#' }, SHARP1, }, + { TOKEN, { ':' }, COLON1, }, + { TOKEN, { '%' }, PCT1, }, + { TOKEN, { '&' }, AND1, }, + { TOKEN, { '*' }, STAR1, }, + { TOKEN, { '+' }, PLUS1, }, + { TOKEN, { '-' }, MINUS1, }, + { TOKEN, { '=' }, EQ1, }, + { TOKEN, { '!' }, NOT1, }, + { TOKEN, { '>' }, GT1, }, + { TOKEN, { '^' }, CIRC1, }, + { TOKEN, { '|' }, OR1, }, + { TOKEN, { '(', ')', '[', ']' }, S_CHR, }, + { TOKEN, { '{', '}', ',', ';' }, S_CHR, }, + { TOKEN, { '~', '?' }, S_CHR, }, + + /* saw 0, possible oct|hex|dec|dbl constant */ + { OCT1, { C_XXX }, BACK(T_DECIMAL), }, + { OCT1, { C_LET, C_DEC }, BAD1, }, + { OCT1, { C_OCT }, OCT2, }, + { OCT1, { 'e', 'E' }, DBL2, }, + { OCT1, { 'l', 'L', 'u', 'U' }, QUAL(DEC2), }, + { OCT1, { 'x', 'X' }, HEX1, }, + { OCT1, { '.' }, DBL1, }, + + /* saw 0<oct>, oct constant */ + { OCT2, { C_XXX }, BACK(T_OCTAL), }, + { OCT2, { C_LET, C_DEC }, BAD1, }, + { OCT2, { C_OCT }, OCT2, }, + { OCT2, { 'e', 'E' }, DBL2, }, + { OCT2, { 'l', 'L', 'u', 'U' }, QUAL(OCT3), }, + { OCT2, { '.' }, DBL1, }, + + /* oct constant qualifier */ + { OCT3, { C_XXX }, BACK(T_OCTAL), }, + { OCT3, { C_LET, C_DEC, '.' }, BAD1, }, + { OCT3, { 'l', 'L', 'u', 'U' }, QUAL(OCT3), }, + + /* saw 0 [xX], hex constant */ + { HEX1, { C_XXX }, BACK(T_HEXADECIMAL), }, + { HEX1, { C_LET }, BAD1, }, + { HEX1, { C_HEX }, HEX1, }, + { HEX1, { 'e', 'E' }, HEX3, }, + { HEX1, { 'l', 'L', 'u', 'U' }, QUAL(HEX2), }, + { HEX1, { '.' }, HEX4, }, + { HEX1, { 'p', 'P' }, HEX5, }, + + /* hex constant qualifier */ + { HEX2, { C_XXX }, BACK(T_HEXADECIMAL), }, + { HEX2, { C_LET, C_DEC, '.' }, BAD1, }, + { HEX2, { 'l', 'L', 'u', 'U' }, QUAL(HEX2), }, + + /* hex [eE][-+] botch */ + { HEX3, { C_XXX }, BACK(T_HEXADECIMAL), }, + { HEX3, { C_LET, '.', '-', '+'},BAD1, }, + { HEX3, { C_HEX }, HEX1, }, + { HEX3, { 'e', 'E' }, HEX3, }, + { HEX3, { 'l', 'L', 'u', 'U' }, QUAL(HEX2), }, + + /* hex dbl fraction */ + { HEX4, { C_XXX }, BACK(T_HEXDOUBLE), }, + { HEX4, { C_LET, '.' }, BAD1, }, + { HEX4, { C_HEX }, HEX4, }, + { HEX4, { 'p', 'P' }, HEX5, }, + { HEX4, { 'f', 'F', 'l', 'L' }, QUAL(HEX8), }, + + /* optional hex dbl exponent sign */ + { HEX5, { C_XXX }, BACK(T_INVALID), }, + { HEX5, { C_LET, '.' }, BAD1, }, + { HEX5, { '+', '-' }, HEX6, }, + { HEX5, { C_DEC }, HEX7, }, + + /* mandatory hex dbl exponent first digit */ + { HEX6, { C_XXX }, BACK(T_INVALID), }, + { HEX6, { C_LET, '.' }, BAD1, }, + { HEX6, { C_DEC }, HEX7, }, + + /* hex dbl exponent digits */ + { HEX7, { C_XXX }, BACK(T_HEXDOUBLE), }, + { HEX7, { C_LET, '.' }, BAD1, }, + { HEX7, { C_DEC }, HEX7, }, + { HEX7, { 'f', 'F', 'l', 'L' }, QUAL(HEX8), }, + + /* hex dbl constant qualifier */ + { HEX8, { C_XXX }, BACK(T_HEXDOUBLE), }, + { HEX8, { C_LET, '.' }, BAD1, }, + { HEX8, { 'f', 'F', 'l', 'L' }, QUAL(HEX8), }, + + /* saw <dec>, dec constant */ + { DEC1, { C_XXX }, BACK(T_DECIMAL), }, + { DEC1, { C_LET }, BAD1, }, + { DEC1, { C_DEC }, DEC1, }, + { DEC1, { 'e', 'E' }, DBL2, }, + { DEC1, { 'l', 'L', 'u', 'U' }, QUAL(DEC2), }, + { DEC1, { '.' }, DBL1, }, + + /* dec constant qualifier */ + { DEC2, { C_XXX }, BACK(T_DECIMAL), }, + { DEC2, { C_LET, C_DEC }, BAD1, }, + { DEC2, { 'l', 'L', 'u', 'U' }, QUAL(DEC2), }, + + /* saw ., operator or dbl constant */ + { DOT1, { C_XXX }, S_CHRB, }, + { DOT1, { '.' }, DOT2, }, + { DOT1, { C_DEC }, DBL1, }, + + /* dbl fraction */ + { DBL1, { C_XXX }, BACK(T_DOUBLE), }, + { DBL1, { C_LET, '.' }, BAD1, }, + { DBL1, { C_DEC }, DBL1, }, + { DBL1, { 'e', 'E' }, DBL2, }, + { DBL1, { 'f', 'F', 'l', 'L' }, QUAL(DBL5), }, + + /* optional dbl exponent sign */ + { DBL2, { C_XXX }, BACK(T_INVALID), }, + { DBL2, { C_LET, '.' }, BAD1, }, + { DBL2, { '+', '-' }, DBL3, }, + { DBL2, { C_DEC }, DBL4, }, + + /* mandatory dbl exponent first digit */ + { DBL3, { C_XXX }, BACK(T_INVALID), }, + { DBL3, { C_LET, '.' }, BAD1, }, + { DBL3, { C_DEC }, DBL4, }, + + /* dbl exponent digits */ + { DBL4, { C_XXX }, BACK(T_DOUBLE), }, + { DBL4, { C_LET, '.' }, BAD1, }, + { DBL4, { C_DEC }, DBL4, }, + { DBL4, { 'f', 'F', 'l', 'L' }, QUAL(DBL5), }, + + /* dbl constant qualifier */ + { DBL5, { C_XXX }, BACK(T_DOUBLE), }, + { DBL5, { C_LET, '.' }, BAD1, }, + { DBL5, { 'f', 'F', 'l', 'L' }, QUAL(DBL5), }, + + /* saw < starting include header */ + { HDR1, { C_XXX }, HDR1, }, + { HDR1, { '>', '\n', C_EOF }, S_LITEND, }, + + /* saw <binop><space> expecting = */ + { BIN1, { C_XXX }, S_HUH, }, + { BIN1, { ' ', '\t' }, BIN1, }, + + /* 2-char ops */ + + { SHARP1, { C_XXX }, S_SHARP, }, + + { PCT1, { C_XXX }, S_CHRB, }, + { PCT1, { '=' }, KEEP(T_MODEQ), }, + + { AND1, { C_XXX }, S_CHRB, }, + { AND1, { '=' }, KEEP(T_ANDEQ), }, + { AND1, { '&' }, KEEP(T_ANDAND), }, + + { STAR1, { C_XXX }, S_CHRB, }, + { STAR1, { '=' }, KEEP(T_MPYEQ), }, + { STAR1, { '/' }, S_COMMENT, }, + + { PLUS1, { C_XXX }, S_CHRB, }, + { PLUS1, { '=' }, KEEP(T_ADDEQ), }, + { PLUS1, { '+' }, KEEP(T_ADDADD), }, + + { MINUS1, { C_XXX }, S_CHRB, }, + { MINUS1, { '=' }, KEEP(T_SUBEQ), }, + { MINUS1, { '-' }, KEEP(T_SUBSUB), }, + { MINUS1, { '>' }, KEEP(T_PTRMEM), }, + + { COLON1, { C_XXX }, S_CHRB, }, + { COLON1, { '=', '>' }, S_HUH, }, + + { LT1, { C_XXX }, S_CHRB, }, + { LT1, { '=' }, KEEP(T_LE), }, + { LT1, { '<' }, LSH1, }, + + { EQ1, { C_XXX }, S_CHRB, }, + { EQ1, { '=' }, KEEP(T_EQ), }, + + { NOT1, { C_XXX }, S_CHRB, }, + { NOT1, { '=' }, KEEP(T_NE), }, + + { GT1, { C_XXX }, S_CHRB, }, + { GT1, { '=' }, KEEP(T_GE), }, + { GT1, { '>' }, RSH1, }, + + { CIRC1, { C_XXX }, S_CHRB, }, + { CIRC1, { '=' }, KEEP(T_XOREQ), }, + + { OR1, { C_XXX }, S_CHRB, }, + { OR1, { '=' }, KEEP(T_OREQ), }, + { OR1, { '|' }, KEEP(T_OROR), }, + + /* 3-char ops */ + + { ARROW1, { C_XXX }, BACK(T_PTRMEM), }, + { ARROW1, { '*' }, KEEP(T_PTRMEMREF), }, + + { LSH1, { C_XXX }, BACK(T_LSHIFT), }, + { LSH1, { '=' }, KEEP(T_LSHIFTEQ), }, + + { RSH1, { C_XXX }, BACK(T_RSHIFT), }, + { RSH1, { '=' }, KEEP(T_RSHIFTEQ), }, + +#endif + + /* end */ + { OP, { 0 }, END, } +}; + +short fsm[TERMINAL+1][MAX+1]; + +char trigraph[MAX+1]; + +#if PROTOMAIN +static char spl[] = { '\\', '\r', 0 }; +static char aln[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$@"; +#else +static char spl[] = { MARK, '?', '\\', '\r', CC_sub, 0 }; +static char aln[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"; +#endif +static char* let = &aln[10]; +static char hex[] = "fedcbaFEDCBA9876543210"; +static char* dec = &hex[12]; +static char* oct = &hex[14]; + +/* + * runtime FSM modifications + * ppfsm(FSM_INIT,0) must be called first + */ + +void +ppfsm(int op, register char* s) +{ + register int c; + register int n; + register int i; + register short* rp; + register struct fsminit* fp; +#if !PROTOMAIN + char* t; + int x; +#endif + + switch (op) + { + +#if !PROTOMAIN + + case FSM_IDADD: + while (c = *s++) + if (!ppisid(c)) + { + if (fsm[TOKEN][c] == ~S_HUH) + { + setid(c); + for (i = 0; i < TERMINAL; i++) + fsm[i][c] = IDSTATE(fsm[i]['_']); + } + else error(2, "%c: cannot add to identifier set", c); + } + break; + + case FSM_IDDEL: + while (c = *s++) + if (ppisid(c)) + { + clrid(c); + for (i = 0; i < TERMINAL; i++) + fsm[i][c] = ~S_HUH; + } + break; + +#endif + + case FSM_INIT: + for (fp = fsminit;; fp++) + { + if ((n = fp->nextstate) >= TERMINAL) n = ~n; + if (fp->state == OP) + { +#if !PROTOMAIN + switch (n) + { + case COPY: + c = fp->ch[0]; + n = fp->ch[2]; + for (i = fp->ch[1]; i <= n; i++) + copy(i, c); + continue; + default: + break; + } +#endif + break; + } + rp = fsm[fp->state]; + for (i = 0; i < sizeof(fp->ch) && (c = fp->ch[i]); i++) + { + switch (c) + { + case C_XXX: + for (c = 0; c <= MAX; c++) + rp[c] = n; + /*FALLTHROUGH*/ + + case C_EOF: + fsm[TERMINAL][fp->state+1] = n < 0 ? ~n : n; + continue; + + case C_LET: + s = let; + break; + + case C_HEX: + s = hex; + break; + + case C_DEC: + s = dec; + break; + + case C_OCT: + s = oct; + break; + + default: + rp[c] = n; + continue; + } + while (c = *s++) + rp[c] = n; + } + } + + /* + * install splice special cases + * and same non-terminal transitions + */ + + for (i = 0; i < TERMINAL; i++) + { + rp = fsm[i]; + s = spl; + while (c = *s++) + if (c != MARK || !INCOMMENT(rp)) + { + if (rp[c] >= 0) rp[c] = ~rp[c]; + rp[c] &= ~SPLICE; + } + rp[EOB] = ~S_EOB; + for (c = 0; c <= MAX; c++) + if (rp[c] == i) + rp[c] = 0; + } + fsm[TERMINAL][0] = ~S_EOB; + +#if !PROTOMAIN + + /* + * default character types + */ + + s = let; + while (c = *s++) + setid(c); + s = dec; + while (c = *s++) + setdig(c); + s = spl; + do setsplice(c = *s++); while (c); + + /* + * trigraph map + */ + + trigraph['='] = '#'; + trigraph['('] = '['; + trigraph['/'] = '\\'; + trigraph[')'] = ']'; + trigraph['\''] = '^'; + trigraph['<'] = '{'; + trigraph['!'] = '|'; + trigraph['>'] = '}'; + trigraph['-'] = '~'; +#endif + break; + +#if !PROTOMAIN + + case FSM_PLUSPLUS: + if (pp.option & PLUSPLUS) + { + fsm[COLON1][':'] = ~KEEP(T_SCOPE); + fsm[DOT1]['*'] = ~KEEP(T_DOTREF); + fsm[MINUS1]['>'] = ARROW1; + fsm[COM1]['/'] = COM5; + t = "%<:"; + for (i = 0; i < TERMINAL; i++) + { + rp = fsm[i]; + if (!INCOMMENT(rp) && !INQUOTE(rp)) + { + s = t; + while (c = *s++) + { + if (rp[c] > 0) rp[c] = ~rp[c]; + else if (!rp[c]) rp[c] = ~i; + rp[c] &= ~SPLICE; + } + } + } + s = t; + while (c = *s++) setsplice(c); + } + else + { + fsm[COLON1][':'] = ~S_CHRB; + fsm[DOT1]['*'] = ~S_CHRB; + fsm[MINUS1]['>'] = ~KEEP(T_PTRMEM); + fsm[COM1]['/'] = (pp.option & PLUSCOMMENT) ? COM5 : ~S_CHRB; + } + break; + +#if COMPATIBLE + + case FSM_COMPATIBILITY: + if (pp.state & COMPATIBILITY) + { + fsm[HEX1]['e'] = HEX1; + fsm[HEX1]['E'] = HEX1; + fsm[QNUM]['e'] = QNUM; + fsm[QNUM]['E'] = QNUM; + fsm[QNUM]['u'] = ~QUAL(QNUM); + fsm[QNUM]['U'] = ~QUAL(QNUM); + } + else + { + fsm[HEX1]['e'] = HEX3; + fsm[HEX1]['E'] = HEX3; + fsm[QNUM]['e'] = QEXP; + fsm[QNUM]['E'] = QEXP; + fsm[QNUM]['u'] = QNUM; + fsm[QNUM]['U'] = QNUM; + } + break; + +#endif + + case FSM_QUOTADD: + while (c = *s++) + if (fsm[TOKEN][c] == ~S_HUH) + for (i = 0; i < TERMINAL; i++) + fsm[i][c] = fsm[i]['"']; + else error(2, "%c: cannot add to quote set", c); + break; + + case FSM_QUOTDEL: + while (c = *s++) + if (c != '"' && fsm[TOKEN][c] == fsm[TOKEN]['"']) + for (i = 0; i < TERMINAL; i++) + fsm[i][c] = fsm[i]['_']; + break; + + case FSM_OPSPACE: + n = s ? BIN1 : ~S_CHRB; + fsm[COM1][' '] = fsm[COM1]['\t'] = n; + fsm[AND1][' '] = fsm[AND1]['\t'] = n; + fsm[STAR1][' '] = fsm[STAR1]['\t'] = n; + fsm[PCT1][' '] = fsm[PCT1]['\t'] = n; + fsm[PLUS1][' '] = fsm[PLUS1]['\t'] = n; + fsm[MINUS1][' '] = fsm[MINUS1]['\t'] = n; + fsm[CIRC1][' '] = fsm[CIRC1]['\t'] = n; + fsm[OR1][' '] = fsm[OR1]['\t'] = n; + fsm[LSH1][' '] = fsm[LSH1]['\t'] = s ? BIN1 : ~BACK(T_LSHIFT); + fsm[RSH1][' '] = fsm[RSH1]['\t'] = s ? BIN1 : ~BACK(T_RSHIFT); + break; + + case FSM_MACRO: + if (pp.truncate && strlen(s) >= pp.truncate) + { + x = s[pp.truncate]; + s[pp.truncate] = 0; + } + else x = -1; + i = MAC0 + ((c = *s++) != 'L'); + if ((n = fsm[QUICK][c]) != (i + NMAC)) + { + n = i; + if (!*s) n += NMAC; + } + if (fsm[QUICK][c] != n) + fsm[QUICK][c] = fsm[QCOM][c] = fsm[QTOK][c] = n; + if (c = *s++) + { + for (;;) + { + if ((i = n) < HIT0) + { + if (n < MACN) n++; + if (!*s) + { + n += NMAC; + break; + } + if (fsm[i][c] < HIT0) + fsm[i][c] = n; + if (fsm[i + NMAC][c] < HIT0) + fsm[i + NMAC][c] = n; + } + else + { + if (n < HITN) n++; + if (!*s) break; + if (fsm[i][c] < HIT0) + { + n -= NMAC; + fsm[i][c] = n; + } + } + c = *s++; + } + if (x >= 0) + { + *s = x; + for (n = CHAR_MIN; n <= CHAR_MAX; n++) + if (ppisidig(n)) + fsm[HITN][n] = HITN; + n = HITN; + } + if (fsm[i][c] < n) + fsm[i][c] = n; + if (i < HIT0 && fsm[i + NMAC][c] < n) + fsm[i + NMAC][c] = n; + } + break; + +#endif + + } +} + +#if !PROTOMAIN + +/* + * file buffer refill + * c is current input char + */ + +void +refill(register int c) +{ + if (pp.in->flags & IN_eof) + { + pp.in->nextchr--; + c = 0; + } + else + { + *((pp.in->nextchr = pp.in->buffer + PPBAKSIZ) - 1) = c; + c = +#if PROTOTYPE + (pp.in->flags & IN_prototype) ? pppread(pp.in->nextchr) : +#endif + read(pp.in->fd, pp.in->nextchr, PPBUFSIZ); + } + if (c > 0) + { + if (pp.in->nextchr[c - 1] == '\n') pp.in->flags |= IN_newline; + else pp.in->flags &= ~IN_newline; +#if PROTOTYPE + if (!(pp.in->flags & IN_prototype)) +#endif + if (c < PPBUFSIZ && (pp.in->flags & IN_regular)) + { + pp.in->flags |= IN_eof; + close(pp.in->fd); + pp.in->fd = -1; + } + } + else + { + if (c < 0) + { + error(ERROR_SYSTEM|3, "read error"); + c = 0; + } + else if ((pp.in->flags ^ pp.in->prev->flags) & IN_c) + { + static char ket[] = { 0, '}', '\n', 0 }; + + pp.in->flags ^= IN_c; + pp.in->nextchr = ket + 1; + c = 2; + } + pp.in->flags |= IN_eof; + } +#if CHECKPOINT + pp.in->buflen = c; +#endif + pp.in->nextchr[c] = 0; + debug((-7, "refill(\"%s\") = %d = \"%-.*s%s\"", error_info.file, c, (c > 32 ? 32 : c), pp.in->nextchr, c > 32 ? "..." : "")); + if (pp.test & 0x0080) + sfprintf(sfstderr, "===== refill(\"%s\") = %d =====\n%s\n===== eob(\"%s\") =====\n", error_info.file, c, pp.in->nextchr, error_info.file); +} + +#endif diff --git a/usr/src/lib/libpp/common/ppfsm.h b/usr/src/lib/libpp/common/ppfsm.h new file mode 100644 index 0000000000..1aff931d2b --- /dev/null +++ b/usr/src/lib/libpp/common/ppfsm.h @@ -0,0 +1,278 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor lexical analyzer definitions + */ + +#ifndef _PPFSM_H +#define _PPFSM_H + +#define BITSTATE 16 /* bitsof(state) */ +#define BITNONTERM 7 /* bitsof(non-terminal-state) */ +#define BITTERM 7 /* bitsof(terminal-state) */ +#define NMAC 19 /* number of MAC states */ + +#define SPLICE (1<<BITTERM) + +#define CODE(tok,act) ((((tok)-N_PP)<<(BITTERM+1))|(act)) +#define TERM(st) ((st)&((1<<(BITTERM+1))-1)) +#define NEXT(st) (((st)>>(BITTERM+1))&((1<<BITNONTERM)-1)) +#define QUAL(st) (((st)<<(BITTERM+1))|(S_QUAL)) +#define TYPE(st) (NEXT(st)+N_PP) + +#define BACK(tok) CODE(tok,S_TOKB) +#define KEEP(tok) CODE(tok,S_TOK) + +#undef MAX +#define MAX 255 + +#undef EOB +#define EOB 0 +#undef EOF +#define EOF (MAX+1) + +/* + * FSM states + * + * NOTE: preserve the ranges + */ + +#define INDEX(p) (((p)-fsm[0])/(MAX+1)) + +#define IDSTATE(x) (((x)>=0&&INQMACRO(fsm[x]))?QID:(x)) + +#define INCOMMENT(p) ((p)>=fsm[COM2]&&(p)<=fsm[COM7]) +#define INCOMMENTXX(p) ((p)>=fsm[COM5]&&(p)<=fsm[COM7]) +#define INQMACRO(p) ((p)>=fsm[MAC0]&&(p)<=fsm[LIT0]) +#define INTMACRO(p) ((p)>=fsm[NID]&&(p)<=fsm[LIT]) +#define INQUOTE(p) ((p)>=fsm[LIT1]&&(p)<=fsm[LIT2]) +#define INOPSPACE(p) ((p)==fsm[BIN1]) +#define INSPACE(p) ((p)==fsm[WS1]) + +/* + * proto non-terminal states + */ + +#define PROTO 0 +#define RES1 (PROTO+1) +#define RES1a (PROTO+2) +#define RES1e (PROTO+3) +#define RES1f (PROTO+4) +#define RES1h (PROTO+5) +#define RES1l (PROTO+6) +#define RES1n (PROTO+7) +#define RES1o (PROTO+8) +#define RES1t (PROTO+9) +#define RES1x (PROTO+10) +#define RES1y (PROTO+11) +#define COM1 (PROTO+12) +#define COM2 (PROTO+13) +#define COM3 (PROTO+14) +#define COM4 (PROTO+15) +#define COM5 (PROTO+16) +#define COM6 (PROTO+17) +#define COM7 (PROTO+18) +#define NID (PROTO+19) +#define LIT (PROTO+20) +#define LIT1 (PROTO+21) +#define LIT2 (PROTO+22) +#define BAD1 (PROTO+23) +#define BAD2 (PROTO+24) +#define DOT (PROTO+25) +#define DOT2 (PROTO+26) +#define WS1 (PROTO+27) + +#if PROTOMAIN + +#define TERMINAL (PROTO+28) /* PROTOMAIN */ + +#else + +/* + * quick non-terminal states + */ + +#define QUICK (PROTO+28) +#define QTOK (QUICK+1) +#define QNUM (QUICK+2) +#define QEXP (QUICK+3) +#define QCOM (QUICK+4) +#define QID (QUICK+5) +#define MAC0 (QUICK+6) +#define MACN (MAC0+NMAC-1) +#define HIT0 (MACN+1) +#define HITN (HIT0+NMAC-1) +#define LIT0 (HITN+1) +#define SHARP1 (HITN+2) + +/* + * tokenize non-terminal states + */ + +#define TOKEN (HITN+3) +#define OCT1 (TOKEN+1) +#define OCT2 (TOKEN+2) +#define OCT3 (TOKEN+3) +#define NOT1 (TOKEN+4) +#define PCT1 (TOKEN+5) +#define AND1 (TOKEN+6) +#define STAR1 (TOKEN+7) +#define PLUS1 (TOKEN+8) +#define MINUS1 (TOKEN+9) +#define ARROW1 (TOKEN+10) +#define COLON1 (TOKEN+11) +#define LT1 (TOKEN+12) +#define LSH1 (TOKEN+13) +#define EQ1 (TOKEN+14) +#define RSH1 (TOKEN+15) +#define GT1 (TOKEN+16) +#define CIRC1 (TOKEN+17) +#define OR1 (TOKEN+18) +#define DEC1 (TOKEN+19) +#define DEC2 (TOKEN+20) +#define HEX1 (TOKEN+21) +#define HEX2 (TOKEN+22) +#define HEX3 (TOKEN+23) +#define HEX4 (TOKEN+24) +#define HEX5 (TOKEN+25) +#define HEX6 (TOKEN+26) +#define HEX7 (TOKEN+27) +#define HEX8 (TOKEN+28) +#define DBL1 (TOKEN+29) +#define DBL2 (TOKEN+30) +#define DBL3 (TOKEN+31) +#define DBL4 (TOKEN+32) +#define DBL5 (TOKEN+33) +#define DOT1 (TOKEN+34) +#define HDR1 (TOKEN+35) +#define BIN1 (TOKEN+36) + +#define TERMINAL (TOKEN+37) + +#endif + +/* + * quick terminal states grouped together + */ + +#define S_CHRB (TERMINAL+0) +#define S_COMMENT (TERMINAL+1) +#define S_EOB (TERMINAL+2) +#define S_LITBEG (TERMINAL+3) +#define S_LITEND (TERMINAL+4) +#define S_LITESC (TERMINAL+5) +#define S_MACRO (TERMINAL+6) +#define S_NL (TERMINAL+7) +#define S_QUAL (TERMINAL+8) +#define S_SHARP (TERMINAL+9) +#define S_VS (TERMINAL+10) + +/* + * and the remaining terminal states + */ + +#define S_CHR (TERMINAL+11) +#define S_HUH (TERMINAL+12) +#define S_TOK (TERMINAL+13) +#define S_TOKB (TERMINAL+14) +#define S_WS (TERMINAL+15) + +#define S_RESERVED (S_HUH) + +/* + * the last terminal state (for tracing) + */ + +#define LAST (S_WS) + +/* + * pseudo terminal states + */ + +#define S_EOF (0) + +/* + * common lex macros + * + * NOTE: common local variable names assumed + */ + +#define GET(p,c,tp,xp) \ + do \ + { \ + if ((c = GETCHR()) == EOB && pp.in->type == IN_FILE) \ + FGET(p, c, tp, xp); \ + } while (0) + +#define FGET(p,c,tp,xp) \ + do \ + { \ + if (op > xp + PPTOKSIZ) \ + { \ + if (!INCOMMENT(rp) && !(pp.state & (NOTEXT|SKIPCONTROL))) \ + error(2, "long token truncated"); \ + op = xp + PPTOKSIZ; \ + } \ + if ((pp.in->flags & IN_flush) && pp.level == 1 && !INMACRO(rp) && (!pp.comment || !INCOMMENT(rp)) && (c = op - pp.outbuf) > 0 && *(op - 1) == '\n') \ + { \ + PPWRITE(c); \ + op = tp = pp.outp = pp.outbuf; \ + } \ + SYNCIN(); \ + refill(p); \ + CACHEIN(); \ + if ((c = GETCHR()) == EOB) BACKIN(); \ + } while (0) + +#define POP() \ + do \ + { \ + debug((-7, "POP in=%s next=%s state=%s", ppinstr(cur), pptokchr(*prv->nextchr), pplexstr(INDEX(rp)))); \ + ip = (pp.in = prv)->nextchr; \ + } while (0) + +/* + * fsm implementaion globals + */ + +#define fsm _pp_fsmtab +#define refill _pp_refill +#define trigraph _pp_trigraph + +/* + * first index is state, second is char, value is next state + * except for fsm[TERMINAL] where second is state+1 for EOF transition + */ + +extern short fsm[TERMINAL+1][MAX+1]; + +/* + * the index is char, value is trigraph value for <?><?><char>, 0 if invalid + */ + +extern char trigraph[MAX+1]; + +extern void refill(int); + +#endif diff --git a/usr/src/lib/libpp/common/ppincref.c b/usr/src/lib/libpp/common/ppincref.c new file mode 100644 index 0000000000..336940bb12 --- /dev/null +++ b/usr/src/lib/libpp/common/ppincref.c @@ -0,0 +1,49 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * common include reference handler + * the type arg is inclusive or of PP_SYNC_* + */ + +#include "pplib.h" + +void +ppincref(char* parent, char* file, int line, int type) +{ + register struct ppinstk* sp; + int level; + + NoP(parent); + NoP(line); + if (type & PP_SYNC_PUSH) + { + level = 0; + for (sp = pp.in; sp; sp = sp->prev) + if (sp->type == IN_FILE) + level++; + if (level > 0) + level--; + error(0, "%-*s%s", level * 4, "", file); + } +} diff --git a/usr/src/lib/libpp/common/ppinput.c b/usr/src/lib/libpp/common/ppinput.c new file mode 100644 index 0000000000..170e5f5dca --- /dev/null +++ b/usr/src/lib/libpp/common/ppinput.c @@ -0,0 +1,721 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor stacked input stream support + */ + +#include "pplib.h" + + +/* + * convert path to native representation + */ + +#if 0 +#include "../../lib/libast/path/pathnative.c" /* drop in 2002 */ +#else +/* Modified by gisburn 2006-08-18 for OpenSolaris ksh93-integration */ +#include "../../libast/common/path/pathnative.c" +#endif + +static char* +native(register const char* s) +{ + register int c; + register struct ppfile* xp; + int m; + int n; + + static Sfio_t* np; + static Sfio_t* qp; + + if (!s) + return 0; + if (!np && !(np = sfstropen()) || !qp && !(qp = sfstropen())) + return (char*)s; + n = PATH_MAX; + do + { + m = n; + n = pathnative(s, sfstrrsrv(np, m), m); + } while (n > m); + sfstrseek(np, n, SEEK_CUR); + s = (const char*)sfstruse(np); + for (;;) + { + switch (c = *s++) + { + case 0: + break; + case '\\': + case '"': + sfputc(qp, '\\'); + /*FALLTHROUGH*/ + default: + sfputc(qp, c); + continue; + } + break; + } + if (!(xp = ppsetfile(sfstruse(qp)))) + return (char*)s; + return xp->name; +} + +/* + * push stream onto input stack + * used by the PUSH_type macros + */ + +void +pppush(register int t, register char* s, register char* p, int n) +{ + register struct ppinstk* cur; + + PUSH(t, cur); + cur->line = error_info.line; + cur->file = error_info.file; + switch (t) + { + case IN_FILE: + if (pp.option & NATIVE) + s = native(s); + cur->flags |= IN_newline; + cur->fd = n; + cur->hide = ++pp.hide; + cur->symbol = 0; +#if CHECKPOINT + if ((pp.mode & (DUMP|INIT)) == DUMP) + { + cur->index = newof(0, struct ppindex, 1, 0); + if (pp.lastindex) pp.lastindex->next = cur->index; + else pp.firstindex = cur->index; + pp.lastindex = cur->index; + cur->index->file = pp.original; + cur->index->begin = ppoffset(); + } +#endif + n = 1; +#if CHECKPOINT + if (!(pp.mode & DUMP)) +#endif + if (!cur->prev->prev && !(pp.state & COMPILE) && isatty(0)) + cur->flags |= IN_flush; +#if ARCHIVE + if (pp.member) + { + switch (pp.member->archive->type & (TYPE_BUFFER|TYPE_CHECKPOINT)) + { + case 0: +#if CHECKPOINT + cur->buflen = pp.member->size; +#endif + p = (cur->buffer = oldof(0, char, 0, pp.member->size + PPBAKSIZ + 1)) + PPBAKSIZ; + if (sfseek(pp.member->archive->info.sp, pp.member->offset, SEEK_SET) != pp.member->offset) + error(3, "%s: archive seek error", pp.member->archive->name); + if (sfread(pp.member->archive->info.sp, p, pp.member->size) != pp.member->size) + error(3, "%s: archive read error", pp.member->archive->name); + pp.member = 0; + break; + case TYPE_BUFFER: +#if CHECKPOINT + case TYPE_CHECKPOINT|TYPE_BUFFER: + cur->buflen = pp.member->size; +#endif + p = cur->buffer = pp.member->archive->info.buffer + pp.member->offset; + cur->flags |= IN_static; + pp.member = 0; + break; +#if CHECKPOINT + case TYPE_CHECKPOINT: + p = cur->buffer = ""; + cur->flags |= IN_static; + break; +#endif + } + cur->flags |= IN_eof|IN_newline; + cur->fd = -1; + } + else +#endif + { + if (lseek(cur->fd, 0L, SEEK_END) > 0 && !lseek(cur->fd, 0L, SEEK_SET)) + cur->flags |= IN_regular; + errno = 0; +#if PROTOTYPE + if (!(pp.option & NOPROTO) && !(pp.test & TEST_noproto) && ((pp.state & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY || (pp.option & PLUSPLUS) || (pp.mode & EXTERNALIZE)) && (cur->buffer = pppopen(NiL, cur->fd, NiL, NiL, NiL, NiL, (PROTO_HEADER|PROTO_RETAIN)|(((pp.mode & EXTERNALIZE) || (pp.option & PROTOTYPED)) ? PROTO_FORCE : PROTO_PASS)|((pp.mode & EXTERNALIZE) ? PROTO_EXTERNALIZE : 0)|((pp.mode & MARKC) ? PROTO_PLUSPLUS : 0)))) + { + *(p = cur->buffer - 1) = 0; + cur->buffer -= PPBAKSIZ; + cur->flags |= IN_prototype; + cur->fd = -1; + } + else +#endif + *(p = (cur->buffer = oldof(0, char, 0, PPBUFSIZ + PPBAKSIZ + 1)) + PPBAKSIZ) = 0; + } + if (pp.incref && !(pp.mode & INIT)) + (*pp.incref)(error_info.file, s, error_info.line - 1, PP_SYNC_PUSH); + if (pp.macref || (pp.option & IGNORELINE)) + cur->flags |= IN_ignoreline; + cur->prefix = pp.prefix; + /*FALLTHROUGH*/ + case IN_BUFFER: + case IN_INIT: + case IN_RESCAN: + pushcontrol(); + cur->control = pp.control; + *pp.control = 0; + cur->vendor = pp.vendor; + if (cur->type != IN_RESCAN) + { + if (cur->type == IN_INIT) + pp.mode |= MARKHOSTED; + error_info.file = s; + error_info.line = n; + } + if (pp.state & HIDDEN) + { + pp.state &= ~HIDDEN; + pp.hidden = 0; + if (!(pp.state & NOTEXT) && pplastout() != '\n') + ppputchar('\n'); + } + pp.state |= NEWLINE; + if (pp.mode & HOSTED) cur->flags |= IN_hosted; + else cur->flags &= ~IN_hosted; + if (pp.mode & (INIT|MARKHOSTED)) + { + pp.mode |= HOSTED; + pp.flags |= PP_hosted; + } + switch (cur->type) + { + case IN_FILE: + if (!(pp.mode & (INIT|MARKHOSTED))) + { + pp.mode &= ~HOSTED; + pp.flags &= ~PP_hosted; + } +#if CATSTRINGS + if (pp.state & JOINING) pp.state |= HIDDEN|SYNCLINE; + else +#endif + if (pp.linesync) + (*pp.linesync)(error_info.line, error_info.file); +#if ARCHIVE && CHECKPOINT + if (pp.member) + ppload(NiL); +#endif + if (pp.mode & MARKC) + { + cur->flags |= IN_c; + pp.mode &= ~MARKC; + if (!(cur->prev->flags & IN_c)) + { + debug((-7, "PUSH in=%s next=%s [%s]", ppinstr(pp.in), pptokchr(*pp.in->nextchr), pp.in->nextchr)); + PUSH_BUFFER("C", "extern \"C\" {\n", 1); + return; + } + } + else if (cur->prev->flags & IN_c) + { + debug((-7, "PUSH in=%s next=%s [%s]", ppinstr(pp.in), pptokchr(*pp.in->nextchr), pp.in->nextchr)); + PUSH_BUFFER("C", "extern \"C++\" {\n", 1); + return; + } + break; + case IN_BUFFER: + cur->buffer = p = strdup(p); + break; + default: + cur->buffer = p; + break; + } + cur->nextchr = p; + break; +#if DEBUG + default: + error(PANIC, "use PUSH_<%d>(...) instead of pppush(IN_<%d>, ...)", cur->type, cur->type); + break; +#endif + } + debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); +} + +/* + * external buffer push + */ + +void +ppinput(char* b, char* f, int n) +{ + PUSH_BUFFER(f, b, n); +} + +/* + * return expanded value of buffer p + */ + +char* +ppexpand(register char* p) +{ + register char* m; + register int n; + register int c; + long restore; + char* pptoken; + char* ppmactop; + struct ppmacstk* nextmacp; + struct ppinstk* cur; + + debug((-7, "before expand: %s", p)); + if (ppmactop = pp.mactop) + { + nextmacp = pp.macp->next; + nextframe(pp.macp, pp.mactop); + } + restore = pp.state & (COLLECTING|DISABLE|STRIP); + pp.state &= ~restore; + pp.mode &= ~MARKMACRO; + PUSH_STRING(p); + cur = pp.in; + pp.in->flags |= IN_expand; + pptoken = pp.token; + n = 2 * MAXTOKEN; + pp.token = p = oldof(0, char, 0, n); + m = p + MAXTOKEN; + for (;;) + { + if (pplex()) + { + if ((pp.token = pp.toknxt) > m) + { + c = pp.token - p; + p = newof(p, char, n += MAXTOKEN, 0); + m = p + n - MAXTOKEN; + pp.token = p + c; + } + if (pp.mode & MARKMACRO) + { + pp.mode &= ~MARKMACRO; + *pp.token++ = MARK; + *pp.token++ = 'X'; + } + } + else if (pp.in == cur) + break; + } + *pp.token = 0; + if (ppmactop) + pp.macp->next = nextmacp; + debug((-7, "after expand: %s", p)); + pp.token = pptoken; + pp.state |= restore; + pp.in = pp.in->prev; + return p; +} + +#if CHECKPOINT + +#define LOAD_FUNCTION (1<<0) +#define LOAD_MULTILINE (1<<1) +#define LOAD_NOEXPAND (1<<2) +#define LOAD_PREDICATE (1<<3) +#define LOAD_READONLY (1<<4) +#define LOAD_VARIADIC (1<<5) + +/* + * macro definition dump + */ + +static int +dump(const char* name, char* v, void* handle) +{ + register struct ppmacro* mac; + register struct ppsymbol* sym = (struct ppsymbol*)v; + register int flags; + + NoP(name); + NoP(handle); + if ((mac = sym->macro) && !(sym->flags & (SYM_BUILTIN|SYM_PREDEFINED))) + { + ppprintf("%s", sym->name); + ppputchar(0); + flags = 0; + if (sym->flags & SYM_FUNCTION) flags |= LOAD_FUNCTION; + if (sym->flags & SYM_MULTILINE) flags |= LOAD_MULTILINE; + if (sym->flags & SYM_NOEXPAND) flags |= LOAD_NOEXPAND; + if (sym->flags & SYM_PREDICATE) flags |= LOAD_PREDICATE; + if (sym->flags & SYM_READONLY) flags |= LOAD_READONLY; + if (sym->flags & SYM_VARIADIC) flags |= LOAD_VARIADIC; + ppputchar(flags); + if (sym->flags & SYM_FUNCTION) + { + ppprintf("%d", mac->arity); + ppputchar(0); + if (mac->arity) + { + ppprintf("%s", mac->formals); + ppputchar(0); + } + } + ppprintf("%s", mac->value); + ppputchar(0); + } + return(0); +} + +/* + * dump macro definitions for quick loading via ppload() + */ + +void +ppdump(void) +{ + register struct ppindex* ip; + unsigned long macro_offset; + unsigned long index_offset; + + /* + * NOTE: we assume '\0' does not occur in valid preprocessed output + */ + + ppputchar(0); + + /* + * output global flags + */ + + macro_offset = ppoffset(); + ppputchar(0); + + /* + * output macro definitions + */ + + hashwalk(pp.symtab, 0, dump, NiL); + ppputchar(0); + + /* + * output include file index + */ + + index_offset = ppoffset(); + ip = pp.firstindex; + while (ip) + { + ppprintf("%s", ip->file->name); + ppputchar(0); + if (ip->file->guard != INC_CLEAR && ip->file->guard != INC_IGNORE && ip->file->guard != INC_TEST) + ppprintf("%s", ip->file->guard->name); + ppputchar(0); + ppprintf("%lu", ip->begin); + ppputchar(0); + ppprintf("%lu", ip->end); + ppputchar(0); + ip = ip->next; + } + ppputchar(0); + + /* + * output offset directory + */ + + ppprintf("%010lu", macro_offset); + ppputchar(0); + ppprintf("%010lu", index_offset); + ppputchar(0); + ppflushout(); +} + +/* + * load text and macro definitions from a previous ppdump() + * s is the string argument from the pragma (including quotes) + */ + +void +ppload(register char* s) +{ + register char* b; + register Sfio_t* sp; + int m; + char* g; + char* t; + unsigned long n; + unsigned long p; + unsigned long macro_offset; + unsigned long index_offset; + unsigned long file_offset; + unsigned long file_size; + unsigned long keep_begin; + unsigned long keep_end; + unsigned long skip_end; + unsigned long next_begin; + unsigned long next_end; + struct ppfile* fp; + struct ppsymbol* sym; + struct ppmacro* mac; + + char* ip = 0; + + pp.mode |= LOADING; + if (!(pp.state & STANDALONE)) + error(3, "checkpoint load in standalone mode only"); +#if ARCHIVE + if (pp.member) + { + sp = pp.member->archive->info.sp; + file_offset = pp.member->offset; + file_size = pp.member->size; + if (sfseek(sp, file_offset + 22, SEEK_SET) != file_offset + 22 || !(s = sfgetr(sp, '\n', 1))) + error(3, "checkpoint magic error"); + } + else +#endif + { + if (pp.in->type != IN_FILE) + error(3, "checkpoint load from files only"); + if (pp.in->flags & IN_prototype) + pp.in->fd = pppdrop(pp.in->buffer + PPBAKSIZ); + file_offset = 0; + if (pp.in->fd >= 0) + { + if (!(sp = sfnew(NiL, NiL, SF_UNBOUND, pp.in->fd, SF_READ))) + error(3, "checkpoint read error"); + file_size = sfseek(sp, 0L, SEEK_END); + } + else + { + file_size = pp.in->buflen; + if (!(sp = sfnew(NiL, pp.in->buffer + ((pp.in->flags & IN_static) ? 0 : PPBAKSIZ), file_size, -1, SF_READ|SF_STRING))) + error(3, "checkpoint read error"); + } + } + if (!streq(s, pp.checkpoint)) + error(3, "checkpoint version %s does not match %s", s, pp.checkpoint); + + /* + * get the macro and index offsets + */ + + p = file_offset + file_size - 22; + if ((n = sfseek(sp, p, SEEK_SET)) != p) + error(3, "checkpoint directory seek error"); + if (!(t = sfreserve(sp, 22, 0))) + error(3, "checkpoint directory read error"); + macro_offset = file_offset + strtol(t, &t, 10); + index_offset = file_offset + strtol(t + 1, NiL, 10); + + /* + * read the include index + */ + + if (sfseek(sp, index_offset, SEEK_SET) != index_offset) + error(3, "checkpoint index seek error"); + if (!(s = sfreserve(sp, n - index_offset, 0))) + error(3, "checkpoint index read error"); + if (sfset(sp, 0, 0) & SF_STRING) + b = s; + else if (!(b = ip = memdup(s, n - index_offset))) + error(3, "checkpoint index alloc error"); + + /* + * loop on the index and copy the non-ignored chunks to the output + */ + + ppcheckout(); + p = PPBUFSIZ - (pp.outp - pp.outbuf); + keep_begin = 0; + keep_end = 0; + skip_end = 0; + while (*b) + { + fp = ppsetfile(b); + while (*b++); + g = b; + while (*b++); + next_begin = strtol(b, &t, 10); + next_end = strtol(t + 1, &t, 10); +if (pp.test & 0x0200) error(2, "%s: %s p=%lu next=<%lu,%lu> keep=<%lu,%lu> skip=<-,%lu> guard=%s", keyname(X_CHECKPOINT), fp->name, p, next_begin, next_end, keep_begin, keep_end, skip_end, fp->guard == INC_CLEAR ? "[CLEAR]" : fp->guard == INC_TEST ? "[TEST]" : fp->guard == INC_IGNORE ? "[IGNORE]" : fp->guard->name); + b = t + 1; + if (next_begin >= skip_end) + { + if (!ppmultiple(fp, INC_TEST)) + { +if (pp.test & 0x0100) error(2, "%s: %s IGNORE", keyname(X_CHECKPOINT), fp->name); + if (!keep_begin && skip_end < next_begin) + keep_begin = skip_end; + if (keep_begin) + { + flush: + if (sfseek(sp, file_offset + keep_begin, SEEK_SET) != file_offset + keep_begin) + error(3, "checkpoint data seek error"); + n = next_begin - keep_begin; +if (pp.test & 0x0100) error(2, "%s: copy <%lu,%lu> n=%lu p=%lu", keyname(X_CHECKPOINT), keep_begin, next_begin - 1, n, p); + while (n > p) + { + if (sfread(sp, pp.outp, p) != p) + error(3, "checkpoint data read error"); + PPWRITE(PPBUFSIZ); + pp.outp = pp.outbuf; + n -= p; + p = PPBUFSIZ; + } + if (n) + { + if (sfread(sp, pp.outp, n) != n) + error(3, "checkpoint data read error"); + pp.outp += n; + p -= n; + } + keep_begin = 0; + if (keep_end <= next_end) + keep_end = 0; + } + skip_end = next_end; + } + else if (!keep_begin) + { + if (skip_end) + { + keep_begin = skip_end; + skip_end = 0; + } + else keep_begin = next_begin; + if (keep_end < next_end) + keep_end = next_end; + } + } + if (*g && fp->guard != INC_IGNORE) + fp->guard = ppsymset(pp.symtab, g); + } + if (keep_end) + { + if (!keep_begin) + keep_begin = skip_end > next_end ? skip_end : next_end; + next_begin = next_end = keep_end; + g = b; + goto flush; + } +if (pp.test & 0x0100) error(2, "%s: loop", keyname(X_CHECKPOINT)); + + /* + * read the compacted definitions + */ + + if (sfseek(sp, macro_offset, SEEK_SET) != macro_offset) + error(3, "checkpoint macro seek error"); + if (!(s = sfreserve(sp, index_offset - macro_offset, 0))) + error(3, "checkpoint macro read error"); + + /* + * read the flags + */ + + while (*s) + { +#if _options_dumped_ + if (streq(s, "OPTION")) /* ... */; + else +#endif + error(3, "%-.48s: unknown flags in checkpoint file", s); + } + s++; + + /* + * unpack and enter the definitions + */ + + while (*s) + { + b = s; + while (*s++); + m = *s++; + sym = ppsymset(pp.symtab, b); + if (sym->macro) + { + if (m & LOAD_FUNCTION) + { + if (*s++ != '0') + while (*s++); + while (*s++); + } +if (pp.test & 0x1000) error(2, "checkpoint SKIP %s=%s [%s]", sym->name, s, sym->macro->value); + while (*s++); + } + else + { + ppfsm(FSM_MACRO, b); + sym->flags = 0; + if (m & LOAD_FUNCTION) sym->flags |= SYM_FUNCTION; + if (m & LOAD_MULTILINE) sym->flags |= SYM_MULTILINE; + if (m & LOAD_NOEXPAND) sym->flags |= SYM_NOEXPAND; + if (m & LOAD_PREDICATE) sym->flags |= SYM_PREDICATE; + if (m & LOAD_READONLY) sym->flags |= SYM_READONLY; + if (m & LOAD_VARIADIC) sym->flags |= SYM_VARIADIC; + mac = sym->macro = newof(0, struct ppmacro, 1, 0); + if (sym->flags & SYM_FUNCTION) + { + for (n = 0; *s >= '0' && *s <= '9'; n = n * 10 + *s++ - '0'); + if (*s++) error(3, "%-.48: checkpoint macro arity botched", sym->name); + if (mac->arity = n) + { + b = s; + while (*s++); + mac->formals = (char*)memcpy(oldof(0, char, 0, s - b), b, s - b); + } + } + b = s; + while (*s++); + mac->size = s - b - 1; + mac->value = (char*)memcpy(oldof(0, char, 0, mac->size + 1), b, mac->size + 1); +if (pp.test & 0x1000) error(2, "checkpoint LOAD %s=%s", sym->name, mac->value); + } + } + + /* + * we are now at EOF + */ + + if (ip) + { + pp.in->fd = -1; + free(ip); + } +#if ARCHIVE + if (pp.member) pp.member = 0; + else +#endif + { + sfclose(sp); + pp.in->flags |= IN_eof|IN_newline; + pp.in->nextchr = pp.in->buffer + PPBAKSIZ; + *pp.in->nextchr++ = 0; + *pp.in->nextchr = 0; + } + pp.mode &= ~LOADING; +} + +#endif diff --git a/usr/src/lib/libpp/common/ppkey.c b/usr/src/lib/libpp/common/ppkey.c new file mode 100644 index 0000000000..6dfe481cc4 --- /dev/null +++ b/usr/src/lib/libpp/common/ppkey.c @@ -0,0 +1,118 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor C language reserved keyword token table + * for use by PP_COMPILE + * + * "-" keywords entered without SYM_KEYWORD + * "+" keywords entered without SYM_KEYWORD unless PP_PLUSPLUS was set + * upper case are pseudo keywords for PP_RESERVED token classes + */ + +#include "pplib.h" +#include "ppkey.h" + +struct ppkeyword ppkey[] = +{ + "auto", T_AUTO, + "break", T_BREAK, + "case", T_CASE, + "char", T_CHAR, + "continue", T_CONTINUE, + "default", T_DEFAULT, + "do", T_DO, + "double", T_DOUBLE_T, + "else", T_ELSE, + "extern", T_EXTERN, + "float", T_FLOAT_T, + "for", T_FOR, + "goto", T_GOTO, + "if", T_IF, + "int", T_INT, + "long", T_LONG, + "register", T_REGISTER, + "return", T_RETURN, + "short", T_SHORT, + "sizeof", T_SIZEOF, + "static", T_STATIC, + "struct", T_STRUCT, + "switch", T_SWITCH, + "typedef", T_TYPEDEF, + "union", T_UNION, + "unsigned", T_UNSIGNED, + "while", T_WHILE, + "-const", T_CONST, + "-enum", T_ENUM, + "-signed", T_SIGNED, + "-void", T_VOID, + "-volatile", T_VOLATILE, + "+asm", T_ASM, + "+class", T_CLASS, + "+delete", T_DELETE, + "+friend", T_FRIEND, + "+inline", T_INLINE, + "+new", T_NEW, + "+operator", T_OPERATOR, + "+overload", T_OVERLOAD, + "+private", T_PRIVATE, + "+public", T_PUBLIC, + "+this", T_THIS, + "+virtual", T_VIRTUAL, + "-and", T_ANDAND, + "-and_eq", T_ANDEQ, + "-bitand", '&', + "-bitor", '|', + "-bool", T_BOOL, + "-catch", T_CATCH, + "-compl", '~', + "-const_cast", T_CONST_CAST, + "-dynamic_cast",T_DYNAMIC_CAST, + "-explicit", T_EXPLICIT, + "-false", T_FALSE, + "-mutable", T_MUTABLE, + "-namespace", T_NAMESPACE, + "-not", '!', + "-not_eq", T_NE, + "-or", T_OROR, + "-or_eq", T_OREQ, + "-protected", T_PROTECTED, + "-reinterpret_cast", T_REINTERPRET_CAST, + "-static_cast", T_STATIC_CAST, + "-template", T_TEMPLATE, + "-throw", T_THROW, + "-true", T_TRUE, + "-try", T_TRY, + "-typeid", T_TYPEID, + "-using", T_USING, + "-wchar_t", T_WCHAR_T, + "-xor", '^', + "-xor_eq", T_XOREQ, + "-int64", T_INT64, + "-NOISES", T_NOISES, + "-NOISE", T_NOISE, + "-GROUP", T_X_GROUP, + "-LINE", T_X_LINE, + "-STATEMENT", T_X_STATEMENT, + 0, 0, 0 +}; diff --git a/usr/src/lib/libpp/common/ppkey.h b/usr/src/lib/libpp/common/ppkey.h new file mode 100644 index 0000000000..95f89e52c1 --- /dev/null +++ b/usr/src/lib/libpp/common/ppkey.h @@ -0,0 +1,146 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor C language keyword token values + * handles classic, ANSI and C++ + * additional non-standard keyword tokens are + * crammed into T_NOISE and T_X_* + */ + +#ifndef _PPKEY_H +#define _PPKEY_H + +/* + * NOTE: preserve the ranges for is*() + */ + +#define ppisnoise(x) ((x)>=T_NOISE&&(x)<T_KEYWORD) + +/* + * classic + */ + +#define T_AUTO (T_TOKEN+0) +#define T_BREAK (T_TOKEN+1) +#define T_CASE (T_TOKEN+2) +#define T_CHAR (T_TOKEN+3) +#define T_CONTINUE (T_TOKEN+4) +#define T_DEFAULT (T_TOKEN+5) +#define T_DO (T_TOKEN+6) +#define T_DOUBLE_T (T_TOKEN+7) +#define T_ELSE (T_TOKEN+8) +#define T_EXTERN (T_TOKEN+9) +#define T_FLOAT_T (T_TOKEN+10) +#define T_FOR (T_TOKEN+11) +#define T_GOTO (T_TOKEN+12) +#define T_IF (T_TOKEN+13) +#define T_INT (T_TOKEN+14) +#define T_LONG (T_TOKEN+15) +#define T_REGISTER (T_TOKEN+16) +#define T_RETURN (T_TOKEN+17) +#define T_SHORT (T_TOKEN+18) +#define T_SIZEOF (T_TOKEN+19) +#define T_STATIC (T_TOKEN+20) +#define T_STRUCT (T_TOKEN+21) +#define T_SWITCH (T_TOKEN+22) +#define T_TYPEDEF (T_TOKEN+23) +#define T_UNION (T_TOKEN+24) +#define T_UNSIGNED (T_TOKEN+25) +#define T_WHILE (T_TOKEN+26) + +/* + * ANSI + */ + +#define T_CONST (T_TOKEN+27) +#define T_ENUM (T_TOKEN+28) +#define T_SIGNED (T_TOKEN+29) +#define T_VOID (T_TOKEN+30) +#define T_VOLATILE (T_TOKEN+31) + +/* + * C++ + */ + +#define T_ASM (T_TOKEN+32) +#define T_BOOL (T_TOKEN+33) +#define T_CATCH (T_TOKEN+34) +#define T_CLASS (T_TOKEN+35) +#define T_CONST_CAST (T_TOKEN+36) +#define T_DELETE (T_TOKEN+37) +#define T_DYNAMIC_CAST (T_TOKEN+38) +#define T_EXPLICIT (T_TOKEN+39) +#define T_FALSE (T_TOKEN+40) +#define T_FRIEND (T_TOKEN+41) +#define T_INLINE (T_TOKEN+42) +#define T_MUTABLE (T_TOKEN+43) +#define T_NAMESPACE (T_TOKEN+44) +#define T_NEW (T_TOKEN+45) +#define T_OPERATOR (T_TOKEN+46) +#define T_OVERLOAD (T_TOKEN+47) +#define T_PRIVATE (T_TOKEN+48) +#define T_PROTECTED (T_TOKEN+49) +#define T_PUBLIC (T_TOKEN+50) +#define T_REINTERPRET_CAST (T_TOKEN+51) +#define T_STATIC_CAST (T_TOKEN+52) +#define T_TEMPLATE (T_TOKEN+53) +#define T_THIS (T_TOKEN+54) +#define T_THROW (T_TOKEN+55) +#define T_TRUE (T_TOKEN+56) +#define T_TRY (T_TOKEN+57) +#define T_TYPEID (T_TOKEN+58) +#define T_USING (T_TOKEN+59) +#define T_VIRTUAL (T_TOKEN+60) +#define T_WCHAR_T (T_TOKEN+61) + +/* + * future + */ + +#define T_INT64 (T_TOKEN+62) + +/* + * non-standard + */ + +#define T_BUILTIN (T_TOKEN+63) +#define T_NOISES (T_TOKEN+64) +#define T_NOISE (T_TOKEN+65) +#define T_X_GROUP (T_TOKEN+66) +#define T_X_LINE (T_TOKEN+67) +#define T_X_STATEMENT (T_TOKEN+68) + +/* + * first available keyword token value + */ + +#define T_KEYWORD (T_TOKEN+69) + +/* + * implementation globals + */ + +extern struct ppkeyword ppkey[]; + +#endif diff --git a/usr/src/lib/libpp/common/pplex.c b/usr/src/lib/libpp/common/pplex.c new file mode 100644 index 0000000000..364854d8ae --- /dev/null +++ b/usr/src/lib/libpp/common/pplex.c @@ -0,0 +1,2441 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor lexical analyzer + * standalone and tokenizing lexer combined in one source + * define CPP=1 for standalone + */ + +#include "pplib.h" +#include "ppfsm.h" + +#if CPP + +/* + * standalone entry point + */ + +#define PPCPP_T void + +#define START QUICK +#define INMACRO(x) INQMACRO(x) +#define DOSTRIP() (st&STRIP) + +#if DEBUG & TRACE_debug +static int hit[LAST-TERMINAL+2]; +#endif + +#define BACKIN() (ip--) +#define BACKOUT() (op=tp) +#define CACHE() do{CACHEINX();CACHEOUTX();st=pp.state;if(!pp.hidden)spliced=0;}while(0) +#define CACHEIN() do{CACHEINX();st=pp.state;if(!pp.hidden)spliced=0;}while(0) +#define CACHEINX() do{ip=pp.in->nextchr;}while(0) +#define CACHEOUT() do{CACHEOUTX();st=pp.state;if(!pp.hidden)spliced=0;}while(0) +#define CACHEOUTX() do{tp=op=pp.outp;xp=pp.oute;if(sp)sp=op;}while(0) +#define GETCHR() (*(unsigned char*)ip++) +#define LASTCHR() (*(ip-1)) +#define LASTOUT() ((op>pp.outbuf)?*(op-1):pp.lastout) +#define SKIPIN() (ip++) +#define PUTCHR(c) (*op++=(c)) +#define SETCHR(c) (*op=(c)) +#define SYNC() do{SYNCINX();SYNCOUTX();pp.state=st;}while(0) +#define SYNCIN() do{SYNCINX();pp.state=st;}while(0) +#define SYNCINX() do{pp.in->nextchr=ip;}while(0) +#define SYNCOUT() do{SYNCOUTX();pp.state=st;}while(0) +#define SYNCOUTX() do{if(sp)op=tp=sp;pp.outp=op;}while(0) +#define UNGETCHR(c) (*--ip=(c)) + +#define PPCHECKOUT() do{if(op>xp){{PPWRITE(PPBUFSIZ);if(pp.outbuf==pp.outb){pp.outbuf+=PPBUFSIZ;xp=pp.oute+=PPBUFSIZ;}else{pp.outbuf-=PPBUFSIZ;memcpy(pp.outbuf,xp,op-xp);xp=pp.oute-=PPBUFSIZ;op-=2*PPBUFSIZ;}}}}while(0) +#define PPCHECKOUTSP() do{if(op>xp){if(sp)op=sp;else{PPWRITE(PPBUFSIZ);if(pp.outbuf==pp.outb){pp.outbuf+=PPBUFSIZ;xp=pp.oute+=PPBUFSIZ;}else{pp.outbuf-=PPBUFSIZ;memcpy(pp.outbuf,xp,op-xp);xp=pp.oute-=PPBUFSIZ;op-=2*PPBUFSIZ;}}}}while(0) +#define PPCHECKOUTTP() do{if(op>xp){{PPWRITE(PPBUFSIZ);if(pp.outbuf==pp.outb){pp.outbuf+=PPBUFSIZ;xp=pp.oute+=PPBUFSIZ;}else{pp.outbuf-=PPBUFSIZ;memcpy(pp.outbuf,xp,op-xp);xp=pp.oute-=PPBUFSIZ;op-=2*PPBUFSIZ;}}tp=op;}}while(0) + +#define PPSYNCLINE() do { \ + if ((st & (ADD|HIDDEN)) && !(*pp.control & SKIP)) \ + { \ + if (spliced) \ + { \ + error_info.line += spliced; \ + spliced = 0; \ + } \ + else \ + { \ + if (st & ADD) \ + { \ + st &= ~ADD; \ + m = pp.addp - pp.addbuf; \ + pp.addp = pp.addbuf; \ + memcpy(op, pp.addbuf, m); \ + op += m; \ + PPCHECKOUT(); \ + } \ + if (pp.linesync) \ + { \ + if ((st & SYNCLINE) || pp.hidden >= MAXHIDDEN) \ + { \ + pp.hidden = 0; \ + st &= ~(HIDDEN|SYNCLINE); \ + if (error_info.line) \ + { \ + if (LASTOUT() != '\n') \ + PUTCHR('\n'); \ + SYNCOUT(); \ + (*pp.linesync)(error_info.line, error_info.file); \ + CACHEOUT(); \ + } \ + } \ + else \ + { \ + m = pp.hidden; \ + pp.hidden = 0; \ + st &= ~HIDDEN; \ + while (m-- > 0) \ + PUTCHR('\n'); \ + } \ + } \ + else \ + { \ + pp.hidden = 0; \ + st &= ~HIDDEN; \ + PUTCHR('\n'); \ + } \ + } \ + } \ + } while (0) + +#if POOL + +/* + * <wait.h> is poison here so pool moved to the end + */ + +static void poolstatus(void); +static void pool(void); + +#endif + +#else + +/* + * return next pp token + * + * NOTE: pp.token points to at least MAXTOKEN*2 chars and is + * truncated back to MAXTOKEN on EOB + */ + +#define PPCPP_T int +#define ppcpp pplex + +#define START TOKEN +#define INMACRO(x) INTMACRO(x) +#define DOSTRIP() ((st&STRIP)||pp.level==1&&(st&(COMPILE|JOINING))==COMPILE&&!(pp.option&PRESERVE)) + +#define st pp.state +#define tp pp.token +#define xp &pp.token[MAXTOKEN] + +#define BACKIN() (ip--) +#define BACKOUT() (op=pp.token) +#define CACHE() do{CACHEIN();CACHEOUT();}while(0) +#define CACHEIN() (ip=pp.in->nextchr) +#define CACHEOUT() (op=pp.token) +#define GETCHR() (*(unsigned char*)ip++) +#define LASTCHR() (*(ip-1)) +#define PUTCHR(c) (*op++=(c)) +#define SETCHR(c) (*op=(c)) +#define SKIPIN() (ip++) +#define SYNC() do{SYNCIN();SYNCOUT();}while(0) +#define SYNCIN() (pp.in->nextchr=ip) +#define SYNCOUT() (pp.toknxt=op) +#define UNGETCHR(c) (*--ip=(c)) + +#endif + +PPCPP_T +ppcpp(void) +{ + register short* rp; + register char* ip; + register int state; + register int c; + register char* op; + char* bp; + int n; + int m; + int quot; + int quotquot; + int comdelim = 0; + int comstart = 0; + int comwarn = 0; + char* s; + struct ppsymbol* sym; +#if CPP + register long st; + char* tp; + char* xp; + char* sp = 0; + int qual = 0; + int spliced = 0; +#else + int qual; +#endif + +#if CPP +#if POOL + fsm_pool: +#endif +#else + count(pplex); +#endif + error_info.indent++; + pp.level++; + CACHE(); +#if !CPP + fsm_top: + qual = 0; +#endif + fsm_start: +#if CPP + PPCHECKOUTSP(); + tp = op; +#endif + state = START; + fsm_begin: + bp = ip; + do + { + rp = fsm[state]; + fsm_get: + while (!(state = rp[c = GETCHR()])); + fsm_next: + ; + } while (state > 0); + if (((state = ~state) != S_COMMENT || pp.comment || c == '/' && !INCOMMENT(rp)) && (n = ip - bp - 1) > 0) + { + ip = bp; +#if CPP + if (op == tp && (st & (ADD|HIDDEN)) && !(st & PASSTHROUGH)) + switch (TERM(state)) + { + case S_SHARP: + break; + case S_CHRB: + case S_NL: + if (*ip == '\n') + break; + /*FALLTHROUGH*/ + default: + PPSYNCLINE(); + tp = op; + break; + } +#endif + MEMCPY(op, ip, n); + ip++; + } + count(terminal); +#if CPP && (DEBUG & TRACE_debug) + hit[(state & SPLICE) ? (elementsof(hit) - 1) : (TERM(state) - TERMINAL)]++; +#endif + fsm_terminal: + debug((-9, "TERM %s > %s%s%s |%-*.*s|%s|", pplexstr(INDEX(rp)), pplexstr(state), (st & NEWLINE) ? "|NEWLINE" : "", (st & SKIPCONTROL) ? "|SKIP" : "", op - tp, op - tp, tp, pptokchr(c))); + switch (TERM(state)) + { + +#if !CPP + case S_CHR: + PUTCHR(c); + break; +#endif + + case S_CHRB: + BACKIN(); +#if CPP + st &= ~NEWLINE; + pp.in->flags |= IN_tokens; + count(token); + goto fsm_start; +#else + c = *tp; + break; +#endif + + case S_COMMENT: + switch (c) + { + case '\n': + if (!INCOMMENTXX(rp)) + { + qual = 0; + if (!comstart) comstart = comdelim = error_info.line; + error_info.line++; + if (pp.comment) PUTCHR(c); + else BACKOUT(); +#if CPP + rp = fsm[COM2]; + bp = ip; + goto fsm_get; +#else + state = COM2; + goto fsm_begin; +#endif + } + else if (comwarn < 0 && !(pp.mode & HOSTED)) + error(1, "/* appears in // comment"); + break; + case '*': + if (!comwarn && !(pp.mode & HOSTED)) + { + if (INCOMMENTXX(rp)) comwarn = -1; + else if (comstart && comstart != error_info.line) + { + if (qual || comdelim < error_info.line - 1) + { + error(1, "/* appears in /* ... */ comment starting at line %d", comstart); + comwarn = 1; + } + else comdelim = error_info.line; + } + } + fsm_comment: + PUTCHR(c); +#if CPP + rp = fsm[INCOMMENTXX(rp) ? COM5 : COM3]; + bp = ip; + goto fsm_get; +#else + state = INCOMMENTXX(rp) ? COM5 : COM3; + goto fsm_begin; +#endif + case '/': + if (!INCOMMENT(rp)) + { + if (!(pp.mode & HOSTED)) + error(1, "*/ appears outside of comment"); + BACKIN(); +#if CPP + st &= ~NEWLINE; + pp.in->flags |= IN_tokens; + count(token); + goto fsm_start; +#else + c = '*'; + if (!pp.comment) PUTCHR(c); + goto fsm_token; +#endif + } + else if (INCOMMENTXX(rp)) + { + if (!(pp.mode & HOSTED)) + { + if (comwarn < 0) comwarn = 0; + else if (!comwarn) + { + comwarn = 1; + error(1, "*/ appears in // comment"); + } + } + goto fsm_comment; + } + break; + case EOF: + BACKIN(); + if (!(pp.mode & HOSTED)) + { + if (comstart) error(2, "unterminated /* ... */ comment starting at line %d", comstart); + else if (INCOMMENTXX(rp)) error(2, "unterminated // ... comment"); + else error(2, "unterminated /* ... */ comment"); + } + break; + } +#if CPP + if (!pp.comment || sp) + { +#if COMPATIBLE + if (!(pp.state & COMPATIBILITY) || *bp == ' ' || *bp == '\t') +#endif + { + BACKOUT(); + PUTCHR(' '); + tp = op; + } + } + else if (pp.in->type & IN_TOP) +#else + if (pp.comment && !(st & (COLLECTING|DIRECTIVE|JOINING)) && !(*pp.control & SKIP) && (pp.in->type & IN_TOP)) +#endif + { + st &= ~HIDDEN; + pp.hidden = 0; + *(op - (c != '\n')) = 0; + m = (op - (c != '\n') - tp > MAXTOKEN - 6) ? (error_info.line - MAXHIDDEN) : 0; + BACKOUT(); + SYNC(); + while (*tp != '/') tp++; + (*pp.comment)(c == '\n' ? "//" : "/*", tp + 2, c == '\n' ? "" : (st & HEADER) ? "*/\n" : "*/", comstart ? comstart : error_info.line); + CACHE(); + comstart = m; + } + if (comstart) + { + st |= HIDDEN; + pp.hidden += error_info.line - comstart; + comstart = 0; + } + qual = comwarn = comdelim = 0; + BACKOUT(); + if (c == '\n') goto fsm_newline; + if ((st & PASSTHROUGH) && ((st & (HIDDEN|NEWLINE)) || *ip == '\n')) + { + if (*ip == '\n') + ip++; + goto fsm_newline; + } +#if COMPATIBLE + if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY) st &= ~NEWLINE; +#endif +#if !CPP + if (pp.level > 1 && !(st & (NOSPACE|SKIPCONTROL))) + { +#if COMPATIBLE + c = ((st & (COMPATIBILITY|DEFINITION)) == ((COMPATIBILITY|DEFINITION))) ? '\t' : ' '; +#else + c = ' '; +#endif + goto fsm_return; + } +#endif + goto fsm_start; + + case S_EOB: + if (c) + { + if (state = fsm[TERMINAL][INDEX(rp)+1]) + goto fsm_terminal; +#if CPP +#if POOL + if (pp.pool.input) + { + BACKIN(); + SYNC(); + pool(); + CACHE(); + goto fsm_pool; + } +#endif + SYNCOUT(); + return; +#else + BACKIN(); + c = 0; + goto fsm_return; +#endif + } + { + register struct ppinstk* cur = pp.in; + register struct ppinstk* prv = pp.in->prev; + +#if CPP + if (sp) op = sp; +#endif + switch (cur->type) + { + case IN_BUFFER: + case IN_INIT: + case IN_RESCAN: +#if CPP + if (prv) +#else + if (!(st & PASSEOF) && prv) +#endif + { + if (cur->type == IN_RESCAN || cur->type == IN_BUFFER) + { + fsm_pop: +#if PROTOTYPE + if (cur->flags & IN_prototype) + pppclose(cur->buffer + PPBAKSIZ); + else +#endif + if (!(cur->flags & IN_static)) + free(cur->buffer); + } + while (pp.control-- != cur->control) + error(2, "#%s on line %d has no #%s", dirname(IF), GETIFLINE(pp.control+1), dirname(ENDIF)); + st |= NEWLINE; + error_info.file = cur->file; + error_info.line = cur->line; + pp.hidden = 0; +#if CPP + spliced = 0; +#endif + if (cur->flags & IN_hosted) + { + pp.mode |= HOSTED; + pp.flags |= PP_hosted; + } + else + { + pp.mode &= ~HOSTED; + pp.flags &= ~PP_hosted; + } +#if !CPP && CATSTRINGS + if (st & JOINING) st |= HIDDEN|SYNCLINE; + else +#endif + { + st &= ~(HIDDEN|SYNCLINE); + switch (cur->type) + { + case IN_BUFFER: + case IN_INIT: + if (!prv->prev) break; + /*FALLTHROUGH*/ + case IN_FILE: + case IN_RESCAN: + if (prv->type == IN_FILE || cur->type == IN_FILE && (prv->type == IN_RESCAN || prv->type == IN_MULTILINE)) + { + if (pp.linesync && (cur->type != IN_RESCAN || (cur->flags & IN_sync))) + { + POP(); + SYNCOUT(); + (*pp.linesync)(error_info.line, error_info.file); + CACHEOUT(); + prv = pp.in; + } + } +#if DEBUG + else if (!prv->prev) + { + /*UNDENT*/ + c = 0; +#if DEBUG & TRACE_count + if (pp.test & TEST_count) + { + c = 1; + sfprintf(sfstderr, "\n"); + sfprintf(sfstderr, "%7d: pplex calls\n", pp.counter.pplex); + sfprintf(sfstderr, "%7d: terminal states\n", pp.counter.terminal); + sfprintf(sfstderr, "%7d: emitted tokens\n", pp.counter.token); + sfprintf(sfstderr, "%7d: input stream pushes\n", pp.counter.push); + sfprintf(sfstderr, "%7d: macro candidates\n", pp.counter.candidate); + sfprintf(sfstderr, "%7d: macro expansions\n", pp.counter.macro); + sfprintf(sfstderr, "%7d: function macros\n", pp.counter.function); + } +#endif +#if CPP && (DEBUG & TRACE_debug) + if (pp.test & TEST_hit) + { + c = 1; + sfprintf(sfstderr, "\n"); + if (hit[elementsof(hit) - 1]) + sfprintf(sfstderr, "%7d: SPLICE\n", hit[elementsof(hit) - 1]); + for (n = 0; n < elementsof(hit) - 1; n++) + if (hit[n]) + sfprintf(sfstderr, "%7d: %s\n", hit[n], pplexstr(TERMINAL + n)); + } +#endif + if (pp.test & (TEST_hashcount|TEST_hashdump)) + { + c = 1; + sfprintf(sfstderr, "\n"); + hashdump(NiL, (pp.test & TEST_hashdump) ? HASH_BUCKET : 0); + } + if (c) sfprintf(sfstderr, "\n"); + /*INDENT*/ + } +#endif + break; + } + } +#if CHECKPOINT + if (cur->index) + { + SYNCOUT(); + cur->index->end = ppoffset(); + cur->index = 0; + CACHEOUT(); + } +#endif + POP(); + bp = ip; + tp = op; + goto fsm_get; + } + c = EOF; + break; + case IN_COPY: + if (prv) + { + error_info.line = cur->line; + if (!(prv->symbol->flags & SYM_MULTILINE)) + prv->symbol->flags |= SYM_DISABLED; + POP(); + bp = ip; + goto fsm_get; + } + c = EOF; + break; + case IN_EXPAND: + if (prv) + { + error_info.line = cur->line; + free(cur->buffer); + POP(); + bp = ip; + goto fsm_get; + } + c = EOF; + break; + case IN_FILE: + FGET(c, c, tp, xp); + if (c == EOB) + { +#if CPP + if ((st & (NOTEXT|HIDDEN)) == HIDDEN && LASTOUT() != '\n') + PUTCHR('\n'); + if (prv) +#else + if (st & EOF2NL) + { + st &= ~EOF2NL; + *(ip - 1) = c = '\n'; + } + else if (!(st & (FILEPOP|PASSEOF)) && prv) +#endif + { + if (!(cur->flags & IN_newline)) + { + cur->flags |= IN_newline; + if ((pp.mode & (HOSTED|PEDANTIC)) == PEDANTIC && LASTCHR() != '\f' && LASTCHR() != CC_sub) + error(1, "file does not end with %s", pptokchr('\n')); + *(ip - 1) = c = '\n'; + } + else + { + if (!(cur->flags & (IN_noguard|IN_tokens)) && cur->symbol) + ppmultiple(ppsetfile(error_info.file), cur->symbol); + if (cur->fd >= 0) + close(cur->fd); + if (pp.incref && !(pp.mode & INIT)) + { + SYNCOUT(); + (*pp.incref)(error_info.file, cur->file, error_info.line - 1, PP_SYNC_POP); + CACHEOUT(); + } + goto fsm_pop; + } + } + else + c = EOF; + } + break; + case IN_MACRO: + case IN_MULTILINE: +#if !CPP + if (!(st & PASSEOF)) +#endif +#if COMPATIBLE + if (prv && (!INMACRO(rp) || (st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY && ppismac(*prv->nextchr))) +#else + if (prv && !INMACRO(rp)) +#endif + { + if (cur->type == IN_MULTILINE) + { + while (pp.control-- != cur->control) + error(2, "#%s on line %d has no #%s", dirname(IF), GETIFLINE(pp.control+1), dirname(ENDIF)); + free(cur->buffer); + error_info.file = cur->file; + error_info.line = cur->line; + if (pp.linesync) + { + SYNCOUT(); + (*pp.linesync)(error_info.line, error_info.file); + CACHEOUT(); + } + } + cur->symbol->flags &= ~SYM_DISABLED; + if (cur->symbol->flags & SYM_FUNCTION) + popframe(pp.macp); + POP(); +#if CPP + if (!(st & COMPATIBILITY) && ppisidig(*(op - 1)) && ppisidig(*ip)) UNGETCHR(' '); +#endif + bp = ip; + goto fsm_get; + } + c = EOF; + break; + case IN_QUOTE: + if (prv) + { + error_info.line = cur->line; + st &= ~(ESCAPE|QUOTE); + POP(); + c = '"'; + } + else c = EOF; + break; + case IN_SQUOTE: + if (prv) + { + error_info.line = cur->line; + st &= ~(ESCAPE|SQUOTE); + POP(); + c = '\''; + } + else c = EOF; + break; + case IN_STRING: +#if CPP + if (prv) +#else + if (!(st & PASSEOF) && !(cur->flags & IN_expand) && prv) +#endif + { + if (cur->flags & IN_disable) st |= DISABLE; + else st &= ~DISABLE; + POP(); + bp = ip; + goto fsm_get; + } + c = EOF; + break; + default: + c = EOF; + break; + } + } + bp = ip - 1; + if (state = rp[c]) goto fsm_next; + goto fsm_get; + +#if !CPP + case S_HUH: + if (INOPSPACE(rp)) + { + if (c == '=') + { +#if PROTOTYPE + if (pp.in->flags & IN_prototype) PUTCHR(c); + else + { +#endif + while (*(op - 1) == ' ' || *(op - 1) == '\t') op--; + PUTCHR(c); + if (st & (STRICT|WARN)) error(1, "%-*.*s: space ignored in operator", op - tp, op - tp, tp); +#if PROTOTYPE + } +#endif + switch (*tp) + { + case '/': + c = T_DIVEQ; + break; + case '%': + c = T_MODEQ; + break; + case '&': + c = T_ANDEQ; + break; + case '*': + c = T_MPYEQ; + break; + case '+': + c = T_ADDEQ; + break; + case '-': + c = T_SUBEQ; + break; + case '^': + c = T_XOREQ; + break; + case '|': + c = T_OREQ; + break; + case '<': + c = T_LSHIFTEQ; + break; + case '>': + c = T_RSHIFTEQ; + break; + } + } + else + { + BACKIN(); + switch (c = *tp) + { + case '<': + c = T_LSHIFT; + break; + case '>': + c = T_RSHIFT; + break; + } + } + } + else if (pp.level > 1 || (pp.option & PRESERVE)) PUTCHR(c); + else if (tp == op) + { + if (pp.in->type != IN_BUFFER) + { + if (!(pp.option & ALLPOSSIBLE)) + error(1, "%s: invalid character ignored", pptokchr(c)); + goto fsm_top; + } + PUTCHR(c); + } + else if (*tp == ':') + { + PUTCHR(c); + if (c == '=') error(2, "real programmers use ="); + else c = '+'; + } + else + { + BACKIN(); + c = *tp; + } + break; +#endif + + case S_QUAL: + if ((state = NEXT(state)) != LIT1) + { + rp = fsm[state]; + bp = ip; +#if CPP + qual = 1; +#if COMPATIBLE + if (!(st & COMPATIBILITY) || c != 'u' && c != 'U') +#endif + PUTCHR(c); +#else + switch (c) + { + case 'f': + case 'F': + qual |= N_FLOAT; +#if COMPATIBLE + if (!(st & COMPATIBILITY)) +#endif + PUTCHR(c); + break; + case 'l': + case 'L': + qual |= N_LONG; + PUTCHR(c); + break; + case 'u': + case 'U': + qual |= N_UNSIGNED; +#if COMPATIBLE + if (!(st & COMPATIBILITY)) +#endif + PUTCHR(c); + break; + default: + PUTCHR(c); + break; + } +#endif + goto fsm_get; + } +#if !CPP + qual |= N_WIDE; + if (DOSTRIP()) BACKOUT(); +#endif + /*FALLTHROUGH*/ + + case S_LITBEG: +#if CPP + quot = c; + rp = fsm[LIT1]; + if (op == tp) + { + PPSYNCLINE(); + tp = op; + } +#else + if ((quot = c) == '<') + { + if (!(st & HEADER) || (pp.option & (HEADEREXPAND|HEADEREXPANDALL)) && pp.in->type != IN_FILE && pp.in->type != IN_BUFFER && pp.in->type != IN_INIT && pp.in->type != IN_RESCAN) + { + PUTCHR(c); + bp = ip; + rp = fsm[LT1]; + goto fsm_get; + } + quot = '>'; + rp = fsm[HDR1]; + } + else rp = fsm[LIT1]; + if (!DOSTRIP()) +#endif + PUTCHR(c); + bp = ip; + goto fsm_get; + + case S_LITEND: + n = 1; + if (c != quot) + { + if (c != '\n' && c != EOF) + { + if (st & (QUOTE|SQUOTE)) + { + if (!(st & ESCAPE)) + { + st |= ESCAPE; + quotquot = c; + } + else if (c == quotquot) st &= ~ESCAPE; + } + PUTCHR(c); + bp = ip; + goto fsm_get; + } +#if CPP + if (st & PASSTHROUGH) + { + if (c == '\n') goto fsm_newline; + bp = ip; + goto fsm_start; + } +#endif + m = (st & SKIPCONTROL) && (pp.mode & HOSTED) ? -1 : 1; + if (c == '\n' && quot == '\'' && (pp.option & STRINGSPAN)) n = 0; + else +#if COMPATIBLE && !CPP + if ((st & (COMPATIBILITY|DEFINITION)) != (COMPATIBILITY|DEFINITION)) +#endif + { + switch (quot) + { + case '"': + if (c == '\n') + { + if (!(pp.option & STRINGSPAN) || (st & (COMPATIBILITY|STRICT)) == STRICT) + error(m, "%s in string", pptokchr(c)); + error_info.line++; + if (!(pp.option & STRINGSPAN)) + { + PUTCHR('\\'); + c = 'n'; + } + else if (pp.option & STRINGSPLIT) + { + PUTCHR('\\'); + PUTCHR('n'); + PUTCHR('"'); + PUTCHR('\n'); + c = '"'; + } + PUTCHR(c); + bp = ip; + goto fsm_get; + } + error(m, "%s in string", pptokchr(c)); + c = '\n'; + break; + case '\'': + if (!(st & DIRECTIVE) || !(pp.mode & (HOSTED|RELAX))) + error(m, "%s in character constant", pptokchr(c)); + break; + case '>': + error(m, "%s in header constant", pptokchr(c)); + break; + default: + error(m, "%s in %c quote", pptokchr(c), quot); + break; + } +#if !CPP + if (!DOSTRIP()) +#endif + PUTCHR(quot); + } + if (c == '\n') + { + UNGETCHR(c); + c = quot; + } + } + else if (st & (SQUOTE|QUOTE)) + { + if (!(st & ESCAPE)) + { + st |= ESCAPE; + quotquot = c; + } + else if (c == quotquot) st &= ~ESCAPE; + PUTCHR('\\'); + PUTCHR(c); + bp = ip; + goto fsm_get; + } +#if CPP + else PUTCHR(c); +#else + else if (!DOSTRIP()) PUTCHR(c); +#endif +#if CATSTRINGS +#if CPP + if (c == '"' && !(st & (COLLECTING|NOTEXT|PASSTHROUGH|SKIPCONTROL)) && (pp.mode & CATLITERAL)) +#else + if (c == '"' && pp.level == 1 && !(st & (COLLECTING|JOINING|NOTEXT|SKIPCONTROL)) && (pp.mode & CATLITERAL)) +#endif + { + char* pptoken; + long ppstate; + + pptoken = pp.token; + pp.token = pp.catbuf; + *pp.token++ = 0; + ppstate = (st & STRIP); + if (DOSTRIP()) + ppstate |= ADD|QUOTE; + st |= JOINING; + st &= ~(NEWLINE|STRIP); + + /* + * revert to the top level since string + * concatenation crosses file boundaries + * (allowing intervening directives) + */ + + pp.level = 0; + SYNCIN(); + m = n = 0; + for (;;) + { + switch (c = pplex()) + { + case '\n': + m++; + continue; + case ' ': + *pp.catbuf = ' '; + continue; + case T_WSTRING: +#if !CPP + qual = N_WIDE; +#endif + if (ppstate & ADD) + ppstate &= ~ADD; + else if (m == n || !(st & SPACEOUT)) + op--; + else + { + n = m; + *(op - 1) = '\\'; + *op++ = '\n'; + } + STRCOPY(op, pp.token + 2 + (*pp.token == ' '), s); + continue; + case T_STRING: + if (ppstate & ADD) + ppstate &= ~ADD; + else if (m == n || !(st & SPACEOUT)) + op--; + else + { + n = m; + *(op - 1) = '\\'; + *op++ = '\n'; + } + STRCOPY(op, pp.token + 1 + (*pp.token == ' '), s); + continue; + case 0: + m = error_info.line ? (error_info.line - 1) : 0; + *pp.token = 0; + /*FALLTHROUGH*/ + default: + if (m) + { + if (--m) + { + pp.state |= HIDDEN|SYNCLINE; + pp.hidden += m; + } +#if COMPATIBLE + if ((st & COMPATIBILITY) && c == '#' && *(pp.token - 1)) + { + *(pp.token + 3) = *(pp.token + 2); + *(pp.token + 2) = *(pp.token + 1); + *(pp.token + 1) = *pp.token; + *pp.token = *(pp.token - 1); + } + error_info.line--; + *--pp.token = '\n'; +#endif + } + else if (*(pp.token - 1)) + pp.token--; + if (ppisidig(*pp.token)) + *op++ = ' '; + if (pp.in->type == IN_MACRO && (s = strchr(pp.token, MARK)) && !*(s + 1)) + { + *(s + 1) = MARK; + *(s + 2) = 0; + } + PUSH_STRING(pp.token); + pp.state &= ~(JOINING|NEWLINE); + pp.state |= ppstate & ~(ADD|QUOTE); + if ((ppstate & (ADD|QUOTE)) == QUOTE) + op--; + break; + } + break; + } + pp.token = pptoken; + CACHEIN(); + pp.level = 1; +#if !CPP + c = T_STRING | qual; + break; +#endif + } +#endif +#if CPP + if (n && !(st & (PASSTHROUGH|SKIPCONTROL|NOTEXT)) && c == '\'' && (op - tp) <= 2 && !(pp.mode & (HOSTED|RELAX))) + error(1, "empty character constant"); + st &= ~(ESCAPE|NEWLINE); + pp.in->flags |= IN_tokens; + count(token); + goto fsm_start; +#else + st &= ~ESCAPE; + switch (quot) + { + case '\'': + if (n && !(st & NOTEXT) && (op - tp) <= (DOSTRIP() ? 0 : 2) && !(pp.mode & (HOSTED|RELAX))) + error(1, "empty character constant"); + c = T_CHARCONST | qual; + break; + case '>': + c = T_HEADER; + break; + default: + if (c == quot) + c = T_STRING | qual; + break; + } + break; +#endif + + case S_LITESC: + if (st & (COLLECTING|DIRECTIVE|QUOTE|SQUOTE)) + { + if (st & ESCAPE) + { + PUTCHR('\\'); + if (c == quot) PUTCHR('\\'); + } + PUTCHR(c); + } +#if CPP + else if (st & PASSTHROUGH) PUTCHR(c); +#endif + else if (pp.option & PRESERVE) PUTCHR(c); + else switch (c) + { + case 'b': + case 'f': + case 'n': + case 'r': + case 't': + case '\\': + case '\'': + case '"': + case '?': + PUTCHR(c); + break; +#if COMPATIBLE + case '8': + case '9': + if (!(st & COMPATIBILITY)) goto unknown; + if (st & STRICT) error(1, "%c: invalid character in octal character escape", c); + /*FALLTHROUGH*/ +#endif + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + n = c - '0'; + for (m = 0; m < 2; m++) + { + GET(c, c, tp, xp); + switch (c) + { +#if COMPATIBLE + case '8': + case '9': + if (!(st & COMPATIBILITY)) + { + UNGETCHR(c); + break; + } + if (st & STRICT) error(1, "%c: invalid character in octal character escape", c); + /*FALLTHROUGH*/ +#endif + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + n = (n << 3) + c - '0'; + continue; + default: + UNGETCHR(c); + break; + } + break; + } + if (n & ~0777) error(1, "octal character constant too large"); + goto octal; + case 'a': + if (pp.option & MODERN) + { + PUTCHR(c); + break; + } +#if COMPATIBLE + if (st & COMPATIBILITY) goto unknown; +#endif + n = CC_bel; + goto octal; + case 'v': + if (pp.option & MODERN) + { + PUTCHR(c); + break; + } + n = CC_vt; + goto octal; + case 'E': + if (st & (COMPATIBILITY|STRICT)) goto unknown; + n = CC_esc; + goto octal; + case 'x': +#if COMPATIBLE + if (st & COMPATIBILITY) goto unknown; +#endif + n = 0; + for (m = 0; m < 3; m++) + { + GET(c, c, tp, xp); + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + n = (n << 4) + c - '0'; + continue; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + n = (n << 4) + c - 'a' + 10; + continue; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + n = (n << 4) + c - 'A' + 10; + continue; + default: + if (!m) error(1, "\\x%c: invalid character in hexadecimal character constant", c); + UNGETCHR(c); + break; + } + break; + } + if (n & ~0777) error(1, "hexadecimal character constant too large"); + octal: + PUTCHR(((n >> 6) & 07) + '0'); + PUTCHR(((n >> 3) & 07) + '0'); + PUTCHR((n & 07) + '0'); + break; + default: + unknown: + if (st & (STRICT|WARN)) error(1, "\\%c: non-standard character constant", c); + PUTCHR(c); + break; + } + state = LIT1; + goto fsm_begin; + + case S_MACRO: + BACKIN(); +#if CPP + if (st & (DISABLE|SKIPCONTROL|SKIPMACRO)) + { + if (st & SKIPMACRO) + pp.mode |= MARKMACRO; + st &= ~(NEWLINE|SKIPMACRO); + pp.in->flags |= IN_tokens; + count(token); + goto fsm_start; + } + count(candidate); + SETCHR(0); + switch (state = INDEX(rp)) + { + case HIT0: + tp = op - 1; + break; + case HITN: + bp = tp; + tp = op - ((pp.truncate && pp.truncate < (HITN - HIT0)) ? (pp.truncate - 1) : (HITN - HIT0)); + while (tp > bp && ppisidig(*(tp - 1))) tp--; + break; + default: + bp = tp; + if ((tp = op - (state - HIT0)) > bp && *(tp - 1) == 'L') tp--; + break; + } + if (sym = ppsymref(pp.symtab, tp)) + { + SYNCIN(); + n = ppcall(sym, 0); + CACHEIN(); + if (n >= 0) + { + BACKOUT(); + if (!n) + { + if (sp) op = sp; + else + { + s = ip; + ip = sym->macro->value; + c = sym->macro->size; + while (c > 0) + { + if (op + c < xp + PPBUFSIZ) n = c; + else n = xp + PPBUFSIZ - op; + MEMCPY(op, ip, n); + c -= n; + PPCHECKOUT(); + } + ip = s; + } + } + else if ((sym->flags & SYM_MULTILINE) && pp.linesync) + { + SYNCOUT(); + if (!(state & NEWLINE)) + ppputchar('\n'); + (*pp.linesync)(error_info.line, error_info.file); + CACHEOUT(); + } + } + } + pp.in->flags |= IN_tokens; + goto fsm_start; +#else + if (st & (COLLECTING|DEFINITION|DISABLE|SKIPCONTROL|SKIPMACRO)) + { + if (st & SKIPMACRO) + pp.mode |= MARKMACRO; + st &= ~(NEWLINE|NOEXPAND|SKIPMACRO); + c = T_ID; + if (pp.level == 1) + { + pp.in->flags |= IN_tokens; + if (st & NOTEXT) + { + BACKOUT(); + goto fsm_top; + } + if (st & COMPILE) + { + SETCHR(0); + if (pp.truncate && (op - tp) > pp.truncate) tp[pp.truncate] = 0; + sym = (pp.option & NOHASH) ? ppsymref(pp.symtab, tp) : ppsymset(pp.symtab, tp); + fsm_noise: + if (pp.symbol = sym) + { + if ((sym->flags & SYM_KEYWORD) && (!pp.truncate || (op - tp) <= pp.truncate || (tp[pp.truncate] = '_', tp[pp.truncate + 1] = 0, pp.symbol = sym = (pp.option & NOHASH) ? ppsymref(pp.symtab, tp) : ppsymset(pp.symtab, tp), 0))) + { + c = ((struct ppsymkey*)sym)->lex; + /*UNDENT*/ + +#define ADVANCE() do{if(pp.toknxt<op)pp.token=pp.toknxt;}while(0) + +#define NOISE_BRACE 01 +#define NOISE_NOSPACEOUT 02 +#define NOISE_PAREN 04 + + if ((pp.option & NOISE) && ppisnoise(c)) + { + if (c != T_NOISE) + { + int p; + int f; + char* pptoken; + PPCOMMENT ppcomment; + + SYNCIN(); + pp.toknxt = op; + f = 0; + if (!(pp.state & SPACEOUT)) + { + pp.state |= SPACEOUT; + f |= NOISE_NOSPACEOUT; + } + ppcomment = pp.comment; + pp.comment = 0; + op = (pptoken = tp) + MAXTOKEN; + switch (c) + { + case T_X_GROUP: + m = p = 0; + quot = 1; + for (;;) + { + ADVANCE(); + switch (c = pplex()) + { + case '(': + case '{': + if (!p) + { + if (c == '(') + { + if (f & NOISE_PAREN) + { + ungetchr(c); + *--pp.toknxt = 0; + break; + } + f |= NOISE_PAREN; + p = ')'; + } + else + { + f |= NOISE_BRACE|NOISE_PAREN; + p = '}'; + } + n = 1; + m = c; + } + else if (c == m) n++; + quot = 0; + continue; + case ')': + case '}': + if (c == p && --n <= 0) + { + if (c == '}') break; + m = '\n'; + p = 0; + } + quot = 0; + continue; + case ' ': + continue; + case '\n': + error_info.line++; + if (!m) m = '\n'; + continue; + case 0: + break; + case T_ID: + if (quot) continue; + /*FALLTHROUGH*/ + default: + if (m == '\n') + { + /* + * NOTE: token expanded again + */ + + s = pp.toknxt; + while (s > pp.token) ungetchr(*--s); + *(pp.toknxt = s) = 0; + break; + } + continue; + } + break; + } + break; + case T_X_LINE: + for (;;) + { + ADVANCE(); + switch (pplex()) + { + case 0: + break; + case '\n': + error_info.line++; + break; + default: + continue; + } + break; + } + break; + case T_X_STATEMENT: + for (;;) + { + ADVANCE(); + switch (pplex()) + { + case 0: + break; + case ';': + ungetchr(';'); + *(pp.toknxt = pp.token) = 0; + break; + default: + continue; + } + break; + } + break; + } + pp.comment = ppcomment; + if (f & NOISE_NOSPACEOUT) + pp.state &= ~SPACEOUT; + CACHEIN(); + tp = pptoken; + op = pp.toknxt; + c = T_NOISES; + } + if (pp.option & NOISEFILTER) + { + BACKOUT(); + goto fsm_top; + } + } + + /*INDENT*/ + } + else if ((pp.option & NOISE) && c == T_ID && strneq(tp, "__builtin_", 10)) + { + hashlook(pp.symtab, tp, HASH_DELETE, NiL); + pp.symbol = sym = (struct ppsymbol*)ppkeyset(pp.symtab, tp); + sym->flags |= SYM_KEYWORD; + c = ((struct ppsymkey*)sym)->lex = T_BUILTIN; + } + } + } + goto fsm_symbol; + } + goto fsm_check; + } + if (pp.level == 1) + { + st &= ~(NEWLINE|PASSEOF); + pp.in->flags |= IN_tokens; + } + else st &= ~PASSEOF; + count(candidate); + SETCHR(0); + if (sym = ppsymref(pp.symtab, tp)) + { + SYNCIN(); + c = ppcall(sym, 1); + CACHEIN(); + if (c >= 0) + { + BACKOUT(); + if ((sym->flags & SYM_MULTILINE) && pp.linesync) + { + SYNCOUT(); + (*pp.linesync)(error_info.line, error_info.file); + CACHEOUT(); + } + goto fsm_top; + } + } + c = T_ID; + if (pp.level == 1) + { + if (st & NOTEXT) + { + BACKOUT(); + goto fsm_top; + } + if (st & COMPILE) + { + if (pp.truncate && (op - tp) > pp.truncate) + { + tp[pp.truncate] = 0; + sym = 0; + } + if (!sym) + { + if (!(pp.option & NOHASH)) sym = ppsymset(pp.symtab, tp); + else if (!(sym = ppsymref(pp.symtab, tp))) goto fsm_symbol; + } + goto fsm_noise; + } + goto fsm_symbol; + } + goto fsm_check; +#endif + + case S_SHARP: + if (c == '(') + { + pp.in->flags |= IN_tokens; + if ((st & STRICT) && pp.in->type != IN_MACRO && pp.in->type != IN_MULTILINE) + { + if (!(pp.mode & HOSTED)) error(1, "non-standard reference to #(...)"); + if (st & STRICT) + { + PUTCHR(c); +#if CPP + st &= ~NEWLINE; + count(token); + goto fsm_start; +#else + break; +#endif + } + } + if (st & (COLLECTING|DEFINITION|DISABLE|SKIPCONTROL)) + { + PUTCHR(c); +#if CPP + st &= ~NEWLINE; + count(token); + goto fsm_start; +#else + st &= ~NOEXPAND; + break; +#endif + } + op--; + SYNC(); + ppbuiltin(); + CACHE(); +#if CPP + count(token); + goto fsm_start; +#else + goto fsm_top; +#endif + } + BACKIN(); +#if CPP + if (!(st & NEWLINE) || !(pp.in->type & IN_TOP)) + { + fsm_nondirective: + st &= ~NEWLINE; + pp.in->flags |= IN_tokens; + count(token); + goto fsm_start; + } + if (*(s = tp) != '#') + { +#if COMPATIBLE + if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY) goto fsm_nondirective; +#endif + while (*s == ' ' || *s == '\t') s++; + if (*s != '#') goto fsm_nondirective; + } + BACKOUT(); +#else + if (!(st & NEWLINE) || (st & DEFINITION) || !(pp.in->type & IN_TOP)) + { + if (c == '#') + { + SKIPIN(); + if (!(st & DEFINITION)) + PUTCHR(c); + c = T_TOKCAT; + } + else if (pp.level == 1 && !(st & (JOINING|SPACEOUT)) && !(pp.option & PRESERVE)) + { + char* pptoken; + char* oop; + PPCOMMENT ppcomment; + + SYNCIN(); + pp.toknxt = oop = op; + pp.state |= SPACEOUT; + ppcomment = pp.comment; + pp.comment = 0; + op = (pptoken = tp) + MAXTOKEN; + for (;;) + { + ADVANCE(); + switch (pplex()) + { + case 0: + break; + case '\n': + error_info.line++; + break; + default: + continue; + } + break; + } + pp.comment = ppcomment; + pp.state &= ~SPACEOUT; + CACHEIN(); + tp = pptoken; + *--op = 0; + op = oop; + if (pp.pragma && !(st & NOTEXT)) + { + *s = 0; + SYNC(); + (*pp.pragma)(NiL, NiL, NiL, tp, 1); + CACHE(); + } + if (!c) BACKIN(); + goto fsm_top; + } + else c = '#'; + break; + } + if ((st & (COLLECTING|STRICT)) == (COLLECTING|STRICT)) + error(1, "directives in macro call arguments are not portable"); +#endif + if (c == '#' && pp.in->type == IN_RESCAN) + { + /* + * pass line to pp.pragma VERBATIM + */ + + SKIPIN(); + s = pp.valbuf; + while ((c = GETCHR()) && c != '\n') + if ((*s++ = c) == MARK) SKIPIN(); + if (pp.pragma && !(st & NOTEXT)) + { + *s = 0; + SYNC(); + (*pp.pragma)(NiL, NiL, NiL, pp.valbuf, 1); + CACHE(); + } + if (!c) BACKIN(); +#if CPP + goto fsm_start; +#else + goto fsm_top; +#endif + } + SYNC(); + ppcontrol(); + CACHE(); +#if CPP + if (st & (NOTEXT|SKIPCONTROL)) + { + if (!sp) + { + PPCHECKOUTTP(); + sp = tp; + } + } + else if (sp) + { + tp = op = sp; + sp = 0; + } + goto fsm_start; +#else + goto fsm_top; +#endif + + case S_NL: +#if CPP + if (op == tp && !(st & JOINING) && pp.in->type == IN_FILE) + { + st |= NEWLINE|HIDDEN; + pp.hidden++; + error_info.line++; + goto fsm_start; + } +#endif + fsm_newline: +#if CPP + if (sp) + op = sp; + else if (!(pp.in->flags & IN_noguard)) + { + while (tp < op) + if ((c = *tp++) != ' ' && c != '\t') + { + pp.in->flags |= IN_tokens; + break; + } + c = '\n'; + } + st |= NEWLINE; + error_info.line++; + if (*ip == '\n' && *(ip + 1) != '\n' && !pp.macref && !(st & (ADD|HIDDEN))) + { + ip++; + PUTCHR('\n'); + error_info.line++; + } + if ((st & NOTEXT) && ((pp.mode & FILEDEPS) || (pp.option & (DEFINITIONS|PREDEFINITIONS)))) + BACKOUT(); + else + { + debug((-5, "token[%d] %03o = %s [line=%d]", pp.level, c, pptokchr(c), error_info.line)); + PUTCHR('\n'); + PPSYNCLINE(); + if (sp) + { + PPCHECKOUT(); + sp = op; + } + } + goto fsm_start; +#else + st |= NEWLINE; + if (pp.level == 1) + { + error_info.line++; + if (!(st & (JOINING|SPACEOUT))) + { + debug((-5, "token[%d] %03o = %s [line=%d]", pp.level, c, pptokchr(c), error_info.line)); + BACKOUT(); + goto fsm_top; + } + } + BACKOUT(); + if (st & SKIPCONTROL) + { + error_info.line++; + st |= HIDDEN; + pp.hidden++; + goto fsm_start; + } + PUTCHR(c = '\n'); + goto fsm_return; +#endif + +#if !CPP + case S_TOK: + PUTCHR(c); + c = TYPE(state) | qual; + break; + + case S_TOKB: + BACKIN(); + c = TYPE(state) | qual; + break; +#endif + + case S_VS: + PUTCHR(c); +#if !CPP + if (st & NOVERTICAL) + { + error(1, "%s invalid in directives", pptokchr(c)); + st &= ~NOVERTICAL; + } +#endif +#if COMPATIBLE + if (st & COMPATIBILITY) st |= NEWLINE; +#endif +#if CPP + if (!(pp.in->flags & IN_noguard)) + while (tp < op) + if ((c = *tp++) != ' ' && c != '\t') + { + pp.in->flags |= IN_tokens; + break; + } + goto fsm_start; +#else + bp = ip; + rp = fsm[WS1]; + goto fsm_get; +#endif + +#if !CPP + case S_WS: +#if COMPATIBLE + if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY) st &= ~NEWLINE; +#endif + if (pp.level == 1) + { + if ((st & (COMPATIBILITY|SPACEOUT)) && !(st & TRANSITION)) + { + if (st & (COMPILE|NOTEXT)) + { +#if CATSTRINGS + if ((st & (JOINING|NOTEXT|SPACEOUT)) != SPACEOUT) +#else + if ((st & (NOTEXT|SPACEOUT)) != SPACEOUT) +#endif + { + BACKOUT(); + bp = ip - 1; + rp = fsm[START]; + if (state = rp[c]) goto fsm_next; + goto fsm_get; + } + } + else +#if CATSTRINGS + if (!(st & JOINING)) +#endif + { + tp = op; + bp = ip - 1; + rp = fsm[START]; + if (state = rp[c]) goto fsm_next; + goto fsm_get; + } + BACKIN(); + c = ' '; + goto fsm_return; + } + BACKOUT(); + bp = ip - 1; + rp = fsm[START]; + if (state = rp[c]) goto fsm_next; + goto fsm_get; + } + if (st & (NOSPACE|SKIPCONTROL)) + { + BACKOUT(); + bp = ip - 1; + rp = fsm[START]; + if (state = rp[c]) goto fsm_next; + goto fsm_get; + } + if (c != '\n') + { + BACKIN(); + c = ' '; + } + if (!(pp.option & PRESERVE)) + { + BACKOUT(); + PUTCHR(c); + } + goto fsm_return; +#endif + + default: + if (state & SPLICE) + { + switch (c) + { + case MARK: + /* + * internal mark + */ + + switch (pp.in->type) + { + case IN_BUFFER: + case IN_FILE: +#if !CPP + case IN_INIT: +#if CATSTRINGS + if ((st & JOINING) && (!INQUOTE(rp) || quot != '"') || pp.level > 1 && (rp == fsm[START] || INQUOTE(rp))) +#else + if (pp.level > 1 && (rp == fsm[START] || INQUOTE(rp))) +#endif + PUTCHR(c); +#endif + break; + default: + switch (GETCHR()) + { + case 'A': + if (!(st & (DEFINITION|DISABLE))) + { + c = GETCHR(); + SYNCIN(); + if (pp.macp->arg[c - ARGOFFSET][-1]) + PUSH_EXPAND(pp.macp->arg[c - ARGOFFSET], pp.macp->line); + else + PUSH_COPY(pp.macp->arg[c - ARGOFFSET], pp.macp->line); + CACHEIN(); + bp = ip; + goto fsm_get; + } + /*FALLTHROUGH*/ + case 'C': + c = GETCHR() - ARGOFFSET; + if (!*(s = pp.macp->arg[c]) && (pp.in->symbol->flags & SYM_VARIADIC) && pp.in->symbol->macro->arity == (c + 1)) + { + s = ip - 3; + while (--op > tp && --s > bp && ppisidig(*s)); + } + else + { + SYNCIN(); + PUSH_COPY(s, pp.macp->line); + CACHEIN(); + } + bp = ip; + goto fsm_get; + case 'F': + error_info.file = (char*)strtoul(ip, &s, 16); + debug((-6, "actual sync: file = \"%s\"", error_info.file)); + bp = ip = s + 1; + goto fsm_get; + case 'L': + error_info.line = strtoul(ip, &s, 16); + debug((-6, "actual sync: line = %d", error_info.line)); + bp = ip = s + 1; + goto fsm_get; + case 'Q': + c = GETCHR(); + SYNCIN(); + PUSH_QUOTE(pp.macp->arg[c - ARGOFFSET], pp.macp->line); + CACHEIN(); + bp = ip - 1; + if (st & (COLLECTING|EOF2NL|JOINING)) rp = fsm[START]; + if (state = rp[c = '"']) goto fsm_next; + goto fsm_get; + case 'S': + c = GETCHR(); + SYNCIN(); + PUSH_SQUOTE(pp.macp->arg[c - ARGOFFSET], pp.macp->line); + CACHEIN(); + bp = ip - 1; + if (st & COLLECTING) rp = fsm[START]; + if (state = rp[c = '\'']) goto fsm_next; + goto fsm_get; + case 'X': + if (pp.in->type != IN_COPY) + st |= SKIPMACRO; + if (pp.level <= 1) + { + bp = ip; + goto fsm_get; + } + if (pp.in->type == IN_EXPAND) + { + st &= ~SKIPMACRO; + PUTCHR(c); + PUTCHR('X'); + } + c = GETCHR(); + break; + case 0: + if ((state &= ~SPLICE) >= TERMINAL) goto fsm_terminal; + goto fsm_begin; + default: +#if DEBUG + error(PANIC, "invalid mark op `%c'", LASTCHR()); + /*FALLTHROUGH*/ + case MARK: +#endif +#if CATSTRINGS + if ((st & (JOINING|QUOTE)) == JOINING) + { + if (!INQUOTE(rp)) + PUTCHR(c); + } + else +#endif +#if CPP + if (rp != fsm[START] && !INQUOTE(rp)) + UNGETCHR(c); +#else + if (rp != fsm[START] && !INQUOTE(rp)) + UNGETCHR(c); + else if (pp.level > 1) + PUTCHR(c); +#endif + break; + } + break; + } + break; + case '?': + /* + * trigraph + */ + + if (pp.in->type == IN_FILE) + { + GET(c, n, tp, xp); + if (n == '?') + { + GET(c, n, tp, xp); + if (c = trigraph[n]) + { + if ((st & WARN) && (st & (COMPATIBILITY|TRANSITION)) && !(pp.mode & HOSTED) && !INCOMMENT(rp)) + error(1, "trigraph conversion %c%c%c -> %c%s", '?', '?', n, c, (st & TRANSITION) ? "" : " inhibited"); +#if COMPATIBLE + if ((st & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY) + { +#endif + *(bp = ip - 1) = c; + if (state = rp[c]) goto fsm_next; + goto fsm_get; +#if COMPATIBLE + } +#endif + } + if (n != EOB) BACKIN(); + UNGETCHR(c = '?'); + } + else if (n != EOB) BACKIN(); + } + break; + case '%': + case '<': + case ':': + /* + * digraph = --trigraph + */ + + if (pp.in->type == IN_FILE && (pp.option & PLUSPLUS)) + { + m = 0; + GET(c, n, tp, xp); + switch (n) + { + case '%': + if (c == '<') m = '{'; + break; + case '>': + if (c == '%') m = '}'; + else if (c == ':') m = ']'; + break; + case ':': + if (c == '%') m = '#'; + else if (c == '<') m = '['; + break; + } + if (m) + { + if ((st & WARN) && (st & (COMPATIBILITY|TRANSITION)) && !(pp.mode & HOSTED) && !INCOMMENT(rp)) + error(1, "digraph conversion %c%c -> %c%s", c, n, m, (st & TRANSITION) ? "" : " inhibited"); +#if COMPATIBLE + if ((st & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY) + { +#endif + *(bp = ip - 1) = c = m; + if (state = rp[c]) goto fsm_next; + goto fsm_get; +#if COMPATIBLE + } +#endif + } + if (n != EOB) BACKIN(); + } + break; + case '\\': + /* + * line splice + */ + + if (pp.in->type == IN_FILE && (!(pp.option & PLUSSPLICE) || !INCOMMENTXX(rp))) + { + m = 0; + GET(c, n, tp, xp); + if ((pp.option & SPLICESPACE) && !INQUOTE(rp)) + while (n == ' ') + { + GET(c, n, tp, xp); + m = 1; + } + if (n == '\r') + { + GET(c, n, tp, xp); + if (n != '\n' && n != EOB) + BACKIN(); + } + if (n == '\n') + { +#if CPP + if (INQUOTE(rp)) + { + if ((pp.option & STRINGSPLIT) && quot == '"') + { + PUTCHR(quot); + PUTCHR(n); + PUTCHR(quot); + } + else if (*pp.lineid) + { + PUTCHR(c); + PUTCHR(n); + } + else + { + st |= HIDDEN; + pp.hidden++; + } + } + else +#else +#if COMPATIBLE + if (!INQUOTE(rp) && (st & (COMPATIBILITY|DEFINITION|TRANSITION)) == (COMPATIBILITY|DEFINITION)) + { + if (op == tp) + { + st |= HIDDEN; + pp.hidden++; + error_info.line++; + if (st & SPACEOUT) + goto fsm_start; + c = (pp.option & SPLICECAT) ? '\t' : ' '; + PUTCHR(c); + goto fsm_check; + } + UNGETCHR(n); + state &= ~SPLICE; + goto fsm_terminal; + } +#endif +#endif + { + st |= HIDDEN; + pp.hidden++; + } +#if CPP + spliced++; +#else + error_info.line++; +#endif + bp = ip; + goto fsm_get; + } + else if ((n == 'u' || n == 'U') && !INQUOTE(rp)) + { + PUTCHR(c); + PUTCHR(n); + bp = ip; + goto fsm_get; + } +#if COMPATIBLE + else if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY && (n == '"' || n == '\'') && !INQUOTE(rp)) + { + PUTCHR(c); + PUTCHR(n); + bp = ip; + goto fsm_get; + } +#endif + else if (n != EOB) + BACKIN(); + if (m && INSPACE(rp)) + UNGETCHR(c); + } +#if COMPATIBLE + else if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY && !INQUOTE(rp)) + { + GET(c, n, tp, xp); + if (n == '"' || n == '\'') + { + PUTCHR(c); + PUTCHR(n); + bp = ip; + goto fsm_get; + } + if (n != EOB) + BACKIN(); + } +#endif + break; + case '\r': + /* + * barf + */ + + if (pp.in->type == IN_FILE) + { + GET(c, n, tp, xp); + if (n == '\n') + { + *(bp = ip - 1) = c = n; + if (state = rp[c]) goto fsm_next; + goto fsm_get; + } + if (n != EOB) BACKIN(); + } + break; + case CC_sub: + /* + * barf & puke + */ + + if ((pp.option & ZEOF) && pp.in->type == IN_FILE) + { + pp.in->flags |= IN_eof; + c = 0; + state = S_EOB; + goto fsm_terminal; + } + break; + } + if ((state &= ~SPLICE) >= TERMINAL) + goto fsm_terminal; + PUTCHR(c); + goto fsm_begin; + } +#if CPP + if (INOPSPACE(rp)) + { + BACKIN(); + goto fsm_start; + } +#endif + PUTCHR(c); + bp = ip; + goto fsm_get; + } +#if !CPP + fsm_token: + st &= ~NEWLINE; + if (pp.level == 1) + { + pp.in->flags |= IN_tokens; + if (st & NOTEXT) + { + BACKOUT(); + goto fsm_top; + } + fsm_symbol: + count(token); + } + fsm_check: + if (st & SKIPCONTROL) + { + BACKOUT(); + goto fsm_start; + } + fsm_return: +#if CPP + error_info.line += spliced; +#endif + SETCHR(0); + debug((-5, "token[%d] %03o = %s", pp.level, c, pptokstr(tp, 0))); + SYNC(); + pp.level--; + error_info.indent--; + return c; +#endif +} + +#if CPP && POOL + +#include <ls.h> +#include <wait.h> + +/* + * output pool status on exit + */ + +static void +poolstatus(void) +{ + error(ERROR_OUTPUT|0, pp.pool.output, "%d", error_info.errors != 0); +} + +/* + * loop on < input output > + */ + +static void +pool(void) +{ + char* ifile; + char* ofile; + + ppflushout(); + if (!sfnew(sfstdin, NiL, SF_UNBOUND, pp.pool.input, SF_READ)) + error(ERROR_SYSTEM|3, "cannot dup pool input"); + + /* + * kick the -I cache + */ + + ppsearch(".", T_STRING, SEARCH_EXISTS); + + /* + * loop on < input output > + */ + + pp.pool.input = 0; + while (ifile = sfgetr(sfstdin, '\n', 1)) + { + if (!(ofile = strchr(ifile, ' '))) + error(3, "%s: pool output file expected", ifile); + *ofile++ = 0; + waitpid(0, NiL, WNOHANG); + switch (fork()) + { + case -1: + error(ERROR_SYSTEM|3, "cannot fork pool"); + case 0: + atexit(poolstatus); + error_info.errors = 0; + error_info.warnings = 0; + close(0); + if (open(ifile, O_RDONLY)) + error(ERROR_SYSTEM|3, "%s: cannot read", ifile); + close(1); + if (open(ofile, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) != 1) + error(ERROR_SYSTEM|3, "%s: cannot create", ofile); + pp.outfile = ofile; + pathcanon(ifile, 0); + ifile = ppsetfile(ifile)->name; +#if CHECKPOINT + if (pp.mode & DUMP) + { + if (!pp.pragma) + error(3, "#%s must be enabled for checkpoints", dirname(PRAGMA)); + (*pp.pragma)(dirname(PRAGMA), pp.pass, keyname(X_CHECKPOINT), pp.checkpoint, 1); + } +#endif + PUSH_FILE(ifile, 0); + return; + } + } + while (wait(NiL) != -1); +} + +#endif diff --git a/usr/src/lib/libpp/common/pplib.h b/usr/src/lib/libpp/common/pplib.h new file mode 100644 index 0000000000..3428b4d55f --- /dev/null +++ b/usr/src/lib/libpp/common/pplib.h @@ -0,0 +1,863 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor library private definitions + */ + +#ifndef _PPLIB_H +#define _PPLIB_H + +/* + * the first definitions control optional code -- 0 disables + */ + +#ifndef ARCHIVE +#define ARCHIVE 1 /* -I can specify header archives */ +#endif +#ifndef CATSTRINGS +#define CATSTRINGS 1 /* concatenate adjacent strings */ +#endif +#ifndef CHECKPOINT +#define CHECKPOINT 1 /* checkpoint preprocessed files */ +#endif +#ifndef COMPATIBLE +#define COMPATIBLE 1 /* enable COMPATIBILITY related code */ +#endif +#ifndef MACKEYARGS +#define MACKEYARGS _BLD_DEBUG /* name=value macro formals and actuals */ +#endif +#ifndef POOL +#define POOL 1 /* enable loop on input,output,error */ +#endif +#ifndef PROTOTYPE +#define PROTOTYPE 1 /* enable ppproto code */ +#endif + +#define TRUNCLENGTH 8 /* default TRUNCATE length */ + +#if _BLD_DEBUG +#undef DEBUG +#define DEBUG (TRACE_message|TRACE_count|TRACE_debug) +#else +#ifndef DEBUG +#define DEBUG (TRACE_message) +#endif +#endif + +/* + * the lower tests are transient + */ + +#define TEST_count (1L<<24) +#define TEST_hashcount (1L<<25) +#define TEST_hashdump (1L<<26) +#define TEST_hit (1L<<27) +#define TEST_noinit (1L<<28) +#define TEST_nonoise (1L<<29) +#define TEST_noproto (1L<<30) + +#define TEST_INVERT (1L<<31) + +#define PROTO_CLASSIC (1<<0) /* classic to prototyped */ +#define PROTO_DISABLE (1<<1) /* disable conversion */ +#define PROTO_EXTERNALIZE (1<<2) /* static fun() => extern fun() */ +#define PROTO_FORCE (1<<3) /* force even if no magic */ +#define PROTO_HEADER (1<<4) /* header defines too */ +#define PROTO_INCLUDE (1<<5) /* <prototyped.h> instead */ +#define PROTO_INITIALIZED (1<<6) /* internal initialization */ +#define PROTO_LINESYNC (1<<7) /* force standalone line syncs */ +#define PROTO_NOPRAGMA (1<<8) /* delete pragma prototyped */ +#define PROTO_PASS (1<<9) /* pass blocks if no magic */ +#define PROTO_PLUSPLUS (1<<10) /* extern () -> extern (...) */ +#define PROTO_RETAIN (1<<11) /* defines retained after close */ +#define PROTO_TEST (1<<12) /* enable test code */ + +#define PROTO_USER (1<<13) /* first user flag */ + +#define SEARCH_EXISTS 0 /* ppsearch for existence */ +#define SEARCH_HOSTED (1<<0) /* search hosted dirs only */ +#define SEARCH_IGNORE (1<<1) /* ignore if not found */ +#define SEARCH_INCLUDE (1<<2) /* ppsearch for include */ +#define SEARCH_VENDOR (1<<3) /* search vendor dirs only */ +#define SEARCH_USER (1<<4) /* first user flag */ + +#define STYLE_gnu (1<<0) /* gnu style args */ + +#define IN_c (1<<0) /* C language file */ +#define IN_defguard (1<<1) /* did multiple include check */ +#define IN_disable (1<<2) /* saved state&DISABLE */ +#define IN_endguard (1<<3) /* did multiple include check */ +#define IN_eof (1<<4) /* reached EOF */ +#define IN_expand (1<<5) /* ppexpand buffer */ +#define IN_flush (1<<6) /* flush stdout on file_refill()*/ +#define IN_hosted (1<<7) /* saved mode&HOSTED */ +#define IN_ignoreline (1<<8) /* ignore #line until file */ +#define IN_newline (1<<9) /* newline at end of last fill */ +#define IN_noguard (1<<10) /* no multiple include guard */ +#define IN_prototype (1<<11) /* ppproto() input */ +#define IN_regular (1<<12) /* regular input file */ +#define IN_static (1<<13) /* static buffer - don't free */ +#define IN_sync (1<<14) /* line sync required on pop */ +#define IN_tokens (1L<<15)/* non-space tokens encountered */ + +#define OPT_GLOBAL (1<<0) /* pp: pass optional */ +#define OPT_PASS (1<<1) /* pass on */ + +struct ppsymbol; +struct ppindex; + +typedef char* (*PPBUILTIN)(char*, const char*, const char*); +typedef void (*PPCOMMENT)(const char*, const char*, const char*, int); +typedef void (*PPINCREF)(const char*, const char*, int, int); +typedef void (*PPLINESYNC)(int, const char*); +typedef void (*PPMACREF)(struct ppsymbol*, const char*, int, int, unsigned long); +typedef int (*PPOPTARG)(int, int, const char*); +typedef void (*PPPRAGMA)(const char*, const char*, const char*, const char*, int); + +struct ppinstk /* input stream stack frame */ +{ + char* nextchr; /* next input char (first elt) */ + struct ppinstk* next; /* next frame (for allocation) */ + struct ppinstk* prev; /* previous frame */ + long* control; /* control block level */ + char* buffer; /* buffer base pointer */ + char* file; /* saved file name */ + char* prefix; /* directory prefix */ + struct ppsymbol* symbol; /* macro info */ +#if CHECKPOINT + struct ppindex* index; /* checkpoint include index */ + int buflen; /* buffer count */ +#endif + int line; /* saved line number */ + int vendor; /* saved pp.vendor */ + short fd; /* file descriptor */ + short hide; /* hide index (from pp.hide) */ + short flags; /* IN_[a-z]* flags */ + char type; /* input type */ +}; + +#if MACKEYARGS +struct ppkeyarg /* pp macro keyword arg info */ +{ + char* name; /* keyword arg name */ + char* value; /* keyword arg value */ +}; +#endif + +struct pplist /* string list */ +{ + char* value; /* string value */ + struct pplist* next; /* next in list */ +}; + +struct oplist /* queue op until PP_INIT */ +{ + int op; /* PP_* op */ + char* value; /* op value */ + struct oplist* next; /* next op */ +}; + +struct pphide /* hidden symbol info */ +{ + struct ppmacro* macro; /* saved macro info */ + unsigned long flags; /* saved symbol flags if macro */ + int level; /* nesting level */ +}; + +struct ppmacstk /* macro invocation stack frame */ +{ + struct ppmacstk* next; /* next frame (for allocation) */ + struct ppmacstk* prev; /* previous frame */ + int line; /* line number of first arg */ + char* arg[1]; /* arg text pointers */ +}; + +struct ppmember /* archive member pun on ppfile */ +{ + struct ppdirs* archive; /* archive holding file */ + unsigned long offset; /* data offset */ + unsigned long size; /* data size */ +}; + +struct counter /* monitoring counters */ +{ + int candidate; /* macro candidates */ + int function; /* function macros */ + int macro; /* macro hits */ + int pplex; /* pplex() calls */ + int push; /* input stream pushes */ + int terminal; /* terminal states */ + int token; /* emitted tokens */ +}; + +struct pptuple /* tuple macro */ +{ + struct pptuple* nomatch; /* nomatch tuple */ + struct pptuple* match; /* match tuple */ + char token[1]; /* matching token */ +}; + +struct ppfileid /* physical file id */ +{ + unsigned long st_dev; /* dev */ + unsigned long st_ino; /* ino */ +}; + +struct pathid /* physical file name and id */ +{ + char* path; /* file path */ + struct ppfileid id; /* file id */ +}; + +#define SAMEID(a,b) ((a)->st_ino==(unsigned long)(b)->st_ino&&(a)->st_dev==(unsigned long)(b)->st_dev) +#define SAVEID(a,b) ((a)->st_ino=(unsigned long)(b)->st_ino,(a)->st_dev=(unsigned long)(b)->st_dev) + +#define _PP_CONTEXT_PRIVATE_ /* ppglobals private context */ \ + struct ppcontext* context; /* current context */ \ + long state; /* pp state flags */ \ + long mode; /* uncoupled pp state flags */ \ + long option; /* option flags */ \ + long test; /* implementation tests */ \ + struct \ + { \ + Sfio_t* sp; /* FILEDEPS output stream */ \ + long flags; /* PP_FILEDEPS flags */ \ + } filedeps; /* FILEDEPS info */ \ + struct ppdirs* firstdir; /* first include dir */ \ + struct ppdirs* lastdir; /* last include dir */ \ + int hide; /* current include hide index */ \ + int column; /* FILEDEPS column */ \ + int pending; /* ppline() pending output */ \ + char* firstfile; /* ppline() first file */ \ + char* lastfile; /* ppline() most recent file */ \ + char* ignore; /* include ignore list file */ \ + char* probe; /* ppdefault probe key */ \ + Hash_table_t* filtab; /* file name hash table */ \ + Hash_table_t* prdtab; /* predicate hash table */ \ + char* date; /* start date string */ \ + char* time; /* start time string */ \ + char* maps; /* directive maps */ \ + long ro_state; /* readonly state */ \ + long ro_mode; /* readonly mode */ \ + long ro_option; /* readonly option */ \ + struct pathid cdir; /* arg C dir */ \ + struct pathid hostdir; /* arg host dir */ \ + char* ppdefault; /* arg default info file */ \ + struct ppindex* firstindex; /* first include index entry */ \ + struct ppindex* lastindex; /* last include index entry */ \ + struct oplist* firstop; /* first arg op */ \ + struct oplist* lastop; /* last arg op */ \ + struct oplist* firsttx; /* first text file */ \ + struct oplist* lasttx; /* last text file */ \ + unsigned char arg_file; /* arg file index */ \ + unsigned char arg_mode; /* arg mode */ \ + unsigned char arg_style; /* arg style */ \ + unsigned char c; /* arg C state */ \ + unsigned char hosted; /* arg hosted state */ \ + unsigned char ignoresrc; /* arg ignore source state */ \ + unsigned char initialized; /* arg initialized state */ \ + unsigned char standalone; /* arg standalone state */ \ + unsigned char spare_1; /* padding spare */ + +#define _PP_GLOBALS_PRIVATE_ /* ppglobals private additions */ \ + char* checkpoint; /* checkpoint version */ \ + int constack; /* pp.control size */ \ + struct ppinstk* in; /* input stream stack pointer */ \ + char* addp; /* addbuf pointer */ \ + char* args; /* predicate args */ \ + char* addbuf; /* ADD buffer */ \ + char* catbuf; /* catenation buffer */ \ + char* hdrbuf; /* HEADEREXPAND buffer */ \ + char* hidebuf; /* pp:hide buffer */ \ + char* path; /* full path of last #include */ \ + char* tmpbuf; /* very temporary buffer */ \ + char* valbuf; /* builtin macro value buffer */ \ + char* optflags; /* OPT_* flags indexed by X_* */ \ + int lastout; /* last output char */ \ + /* the rest are implicitly initialized */ \ + char* include; /* saved path of last #include */ \ + char* prefix; /* current directory prefix */ \ + struct ppmember* member; /* include archive member data */ \ + int hidden; /* hidden newline count */ \ + int hiding; /* number of symbols in hiding */ \ + int level; /* pplex() recursion level */ \ + struct \ + { \ + int input; /* pool input */ \ + int output; /* pool output */ \ + } pool; /* loop on input,output,error */ \ + struct \ + { \ + long ro_state; /* original pp.ro_state */ \ + long ro_mode; /* original pp.ro_mode */ \ + long ro_option; /* original pp.ro_option */ \ + int on; /* PP_RESET enabled */ \ + Hash_table_t* symtab; /* original pp.symtab scope */ \ + } reset; /* PP_RESET state */ \ + int truncate; /* identifier truncation length */ \ + struct ppmacstk* macp; /* top of macro actual stack */ \ + char* maxmac; /* maximum size of macro stack */ \ + char* mactop; /* top of current macro frame */ \ + char* toknxt; /* '\0' of pp.token */ \ + long* control; /* control block flags pointer */ \ + long* maxcon; /* max control block frame */ \ + struct oplist* chop; /* include prefix chop list */ \ + struct ppfile* insert; /* inserted line sync file */ \ + struct ppfile* original; /* original include name */ \ + struct ppdirs* found; /* last successful ppsearch dir */ \ + int vendor; /* vendor includes only */ \ + Hash_table_t* dirtab; /* directive hash table */ \ + Hash_table_t* strtab; /* string hash table */ \ + PPBUILTIN builtin; /* builtin macro handler */ \ + PPCOMMENT comment; /* pass along comments */ \ + PPINCREF incref; /* include file push/return */ \ + PPLINESYNC linesync; /* pass along line sync info */ \ + PPLINESYNC olinesync; /* original linesync value */ \ + PPMACREF macref; /* called on macro def/ref */ \ + PPOPTARG optarg; /* unknown option arg handler */ \ + PPPRAGMA pragma; /* pass along unknown pragmas */ \ + struct counter counter; /* monitoring counters */ \ + char funbuf[256]; /* last __FUNCTION__ */ + +#define _PP_SYMBOL_PRIVATE_ /* ppsymbol private additions */ \ + struct pphide* hidden; /* hidden symbol info */ + +#if MACKEYARGS +#define _PP_MACRO_PRIVATE_ /* ppmacro private additions */ \ + struct pptuple* tuple; /* tuple macro */ \ + union \ + { \ + char* formal; /* normal formals list */ \ + struct ppkeyarg* key; /* keyword formals table */ \ + } args; /* macro args info */ \ + int size; /* body size */ +#define formals args.formal /* formal argument list */ +#define formkeys args.key /* formal keyword argument list */ +#else +#define _PP_MACRO_PRIVATE_ /* ppmacro private additions */ \ + struct pptuple* tuple; /* tuple macro */ \ + char* formals; /* formal argument list */ \ + int size; /* body size */ +#endif + +#define _PP_DIRS_PRIVATE_ /* ppdirs private additions */ \ + unsigned char c; /* files here are C language */ \ + unsigned char index; /* prefix,local,standard index */ \ + unsigned char type; /* dir type */ \ + union \ + { \ + char* buffer; /* TYPE_BUFFER buffer */ \ + Sfio_t* sp; /* archive stream */ \ + struct ppdirs* subdir; /* subdir list */ \ + } info; /* type info */ \ + struct ppfileid id; /* directory id */ \ + +#if !PROTOMAIN +#include <ast.h> +#include <error.h> +#endif + +#undef newof +#define newof(p,t,n,x) ((p)?(t*)realloc((char*)(p),sizeof(t)*(n)+(x)):(t*)calloc(1,sizeof(t)*(n)+(x))) + +#include "pp.h" +#include "ppdef.h" +#include "ppkey.h" + +#undef setstate /* random clash! */ + +/* + * DEBUG is encoded with the following bits + */ + +#define TRACE_message 01 +#define TRACE_count 02 +#define TRACE_debug 04 + +#if DEBUG && !lint +#define PANIC (ERROR_PANIC|ERROR_SOURCE|ERROR_SYSTEM),__FILE__,__LINE__ +#else +#define PANIC ERROR_PANIC +#endif + +#if DEBUG & TRACE_count +#define count(x) pp.counter.x++ +#else +#define count(x) +#endif + +#if DEBUG & TRACE_message +#define message(x) do { if (tracing) error x; } while (0) +#else +#define message(x) +#endif + +#if DEBUG & TRACE_debug +#define debug(x) do { if (tracing) error x; } while (0) +#else +#define debug(x) +#endif + +/* + * note that MEMCPY advances the associated pointers + */ + +#define MEMCPY(to,fr,n) \ + do switch(n) \ + { default : memcpy(to,fr,n); to += n; fr += n; break; \ + case 7 : *to++ = *fr++; \ + case 6 : *to++ = *fr++; \ + case 5 : *to++ = *fr++; \ + case 4 : *to++ = *fr++; \ + case 3 : *to++ = *fr++; \ + case 2 : *to++ = *fr++; \ + case 1 : *to++ = *fr++; \ + case 0 : break; \ + } while (0) + +#define NEWDIRECTIVE (-1) + +#undef dirname +#undef error + +#define dirname(x) ppkeyname(x,1) +#define error pperror +#define keyname(x) ppkeyname(x,0) +#define nextframe(m,p) (m->next=m+(p-(char*)m+sizeof(struct ppmacstk)-1)/sizeof(struct ppmacstk)+1) +#define popframe(m) (m=m->prev) +#define pptokchr(c) pptokstr(NiL,(c)) +#define pushcontrol() do { if (pp.control++ >= pp.maxcon) ppnest(); } while (0) +#define pushframe(m) (m->next->prev=m,m=m->next) +#define setmode(m,v) ((v)?(pp.mode|=(m)):(pp.mode&=~(m))) +#define setoption(m,v) ((v)?(pp.option|=(m)):(pp.option&=~(m))) +#define setstate(s,v) ((v)?(pp.state|=(s)):(pp.state&=~(s))) +#define tracing (error_info.trace<0) + +#define ppgetfile(x) ((struct ppfile*)hashlook(pp.filtab,x,HASH_LOOKUP,NiL)) +#define ppsetfile(x) ((struct ppfile*)hashlook(pp.filtab,x,HASH_CREATE|HASH_SIZE(sizeof(struct ppfile)),NiL)) + +#define ppkeyget(t,n) (struct ppsymkey*)hashlook(t,n,HASH_LOOKUP,NiL) +#define ppkeyref(t,n) (struct ppsymkey*)hashlook(t,n,HASH_LOOKUP|HASH_INTERNAL,NiL) +#define ppkeyset(t,n) (struct ppsymkey*)hashlook(t,n,HASH_CREATE|HASH_SIZE(sizeof(struct ppsymkey)),NiL) + +#define MARK '@' /* internal mark */ +#define ARGOFFSET '1' /* macro arg mark offset */ + +#define STRAPP(p,v,r) do{r=(v);while((*p++)=(*r++));}while(0) +#define STRCOPY(p,v,r) do{r=(v);while((*p++)=(*r++));p--;}while(0) +#define STRCOPY2(p,r) do{while((*p++)=(*r++));p--;}while(0) + +#define SETFILE(p,v) (p+=sfsprintf(p,16,"%c%c%lx%c",MARK,'F',(long)v,MARK)) +#define SETLINE(p,v) (p+=sfsprintf(p,16,"%c%c%lx%c",MARK,'L',(long)v,MARK)) + +#define peekchr() (*pp.in->nextchr) +#define ungetchr(c) (*--pp.in->nextchr=(c)) + +#define MAXID 255 /* maximum identifier size */ +#define MAXTOKEN PPTOKSIZ /* maximum token size */ +#define MAXFORMALS 64 /* maximum number macro formals */ +#define MAXHIDDEN 8 /* ppline if hidden>=MAXHIDDEN */ +#define DEFMACSTACK (MAXFORMALS*32*32)/* default macstack size */ + +#define FSM_COMPATIBILITY 1 /* compatibility mode */ +#define FSM_IDADD 2 /* add to identifer set */ +#define FSM_IDDEL 3 /* delete from identifer set */ +#define FSM_INIT 4 /* initilize */ +#define FSM_MACRO 5 /* add new macro */ +#define FSM_OPSPACE 6 /* handle <binop><space>= */ +#define FSM_PLUSPLUS 7 /* C++ lexical analysis */ +#define FSM_QUOTADD 8 /* add to quote set */ +#define FSM_QUOTDEL 9 /* delete from quote set */ + +#define IN_TOP 01 /* top level -- directives ok */ + +#define IN_BUFFER (2|IN_TOP) /* buffer of lines */ +#define IN_COPY 2 /* macro arg (copied) */ +#define IN_EXPAND 4 /* macro arg (expanded) */ +#define IN_FILE (4|IN_TOP) /* file */ +#define IN_INIT (6|IN_TOP) /* initialization IN_BUFFER */ +#define IN_MACRO 8 /* macro text */ +#define IN_MULTILINE (8|IN_TOP) /* multi-line macro text */ +#define IN_QUOTE 10 /* "..." macro arg (copied) */ +#define IN_RESCAN (10|IN_TOP) /* directive rescan buffer */ +#define IN_SQUOTE 12 /* '...' macro arg (copied) */ +#define IN_STRING 14 /* string */ + +#define INC_CLEAR ((struct ppsymbol*)0) +#define INC_IGNORE ((struct ppsymbol*)pp.addbuf) +#define INC_TEST ((struct ppsymbol*)pp.catbuf) + +#define INC_BOUND(n) (1<<(n)) +#define INC_MEMBER(n) (1<<((n)+INC_MAX)) +#define INC_PREFIX 0 +#define INC_LOCAL 1 +#define INC_STANDARD 2 +#define INC_VENDOR 3 +#define INC_MAX 4 +#define INC_SELF (1<<(2*INC_MAX+0)) +#define INC_EXISTS (1<<(2*INC_MAX+1)) +#define INC_LISTED (1<<(2*INC_MAX+2)) +#define INC_MAPALL (1<<(2*INC_MAX+3)) +#define INC_MAPHOSTED (1<<(2*INC_MAX+4)) +#define INC_MAPNOHOSTED (1<<(2*INC_MAX+5)) +#define INC_MAPNOLOCAL (1<<(2*INC_MAX+6)) +#define INC_HOSTED (1<<(2*INC_MAX+7)) + +#define TYPE_ARCHIVE (1<<0) +#define TYPE_BUFFER (1<<1) +#define TYPE_CHECKPOINT (1<<2) +#define TYPE_DIRECTORY (1<<3) +#define TYPE_HOSTED (1<<4) +#define TYPE_INCLUDE (1<<5) +#define TYPE_VENDOR (1<<6) + +#define TOK_BUILTIN (1<<0) /* last token was #( */ +#define TOK_FORMAL (1<<1) /* last token was arg formal id */ +#define TOK_ID (1<<2) /* last token was identifier */ +#define TOK_TOKCAT (1<<3) /* last token was ## */ + +#define HADELSE (1<<0) /* already had else part */ +#define KEPT (1<<1) /* already kept part of block */ +#define SKIP (1<<2) /* skip this block */ +#define BLOCKBITS 3 /* block flag bits */ + +#define SETIFBLOCK(p) (*(p)=(*((p)-1)&SKIP)|((long)error_info.line<<BLOCKBITS)) +#define GETIFLINE(p) ((*(p)>>BLOCKBITS)&((1L<<(sizeof(long)*CHAR_BIT-BLOCKBITS))-1)) + +#define PUSH(t,p) \ + do \ + { \ + count(push); \ + if (!pp.in->next) \ + { \ + pp.in->next = newof(0, struct ppinstk, 1, 0); \ + pp.in->next->prev = pp.in; \ + } \ + p = pp.in = pp.in->next; \ + p->type = t; \ + p->flags = 0; \ + } while (0) + +#define PUSH_BUFFER(f,p,n) \ + pppush(IN_BUFFER,f,p,n) + +#define PUSH_COPY(p,n) \ + do \ + { \ + register struct ppinstk* cur; \ + PUSH(IN_COPY, cur); \ + cur->line = error_info.line; \ + error_info.line = n; \ + cur->nextchr = p; \ + cur->prev->symbol->flags &= ~SYM_DISABLED; \ + debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); \ + } while (0) + +#define PUSH_EXPAND(p,n) \ + do \ + { \ + register struct ppinstk* cur; \ + PUSH(IN_EXPAND, cur); \ + cur->line = error_info.line; \ + error_info.line = n; \ + cur->prev->symbol->flags &= ~SYM_DISABLED; \ + cur->buffer = cur->nextchr = ppexpand(p); \ + if (!(cur->prev->symbol->flags & SYM_MULTILINE)) \ + cur->prev->symbol->flags |= SYM_DISABLED; \ + debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); \ + } while (0) + +#define PUSH_FILE(f,d) \ + pppush(IN_FILE,f,NiL,d) + +#define PUSH_INIT(f,p) \ + pppush(IN_INIT,f,p,1) + +#define PUSH_MACRO(p) \ + do \ + { \ + register struct ppinstk* cur; \ + PUSH(IN_MACRO, cur); \ + cur->symbol = p; \ + cur->nextchr = p->macro->value; \ + p->flags |= SYM_DISABLED; \ + if (p->flags & SYM_FUNCTION) pushframe(pp.macp); \ + pp.state &= ~NEWLINE; \ + debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); \ + } while (0) + +#define PUSH_TUPLE(p,v) \ + do \ + { \ + register struct ppinstk* cur; \ + PUSH(IN_MACRO, cur); \ + cur->symbol = p; \ + cur->nextchr = v; \ + p->flags |= SYM_DISABLED; \ + pp.state &= ~NEWLINE; \ + debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); \ + } while (0) + +#define PUSH_MULTILINE(p) \ + do \ + { \ + register struct ppinstk* cur; \ + register int n; \ + PUSH(IN_MULTILINE, cur); \ + cur->symbol = p; \ + cur->flags |= IN_defguard|IN_endguard|IN_noguard; \ + pushcontrol(); \ + cur->control = pp.control; \ + *pp.control = 0; \ + cur->file = error_info.file; \ + n = strlen(error_info.file) + strlen(((struct ppsymbol*)p)->name) + 24; \ + error_info.file = cur->buffer = newof(0, char, n, 0); \ + sfsprintf(error_info.file, n, "%s:%s,%d", cur->file, p->name, error_info.line); \ + cur->line = error_info.line; \ + error_info.line = 1; \ + cur->nextchr = p->macro->value; \ + if (p->flags & SYM_FUNCTION) pushframe(pp.macp); \ + pp.state &= ~NEWLINE; \ + debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); \ + } while (0) + +#define PUSH_QUOTE(p,n) \ + do \ + { \ + register struct ppinstk* cur; \ + PUSH(IN_QUOTE, cur); \ + cur->nextchr = p; \ + pp.state |= QUOTE; \ + cur->line = error_info.line; \ + error_info.line = n; \ + debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); \ + } while (0) + +#define PUSH_RESCAN(p) \ + pppush(IN_RESCAN,NiL,p,0) + +#define PUSH_SQUOTE(p,n) \ + do \ + { \ + register struct ppinstk* cur; \ + PUSH(IN_SQUOTE, cur); \ + cur->nextchr = p; \ + pp.state |= SQUOTE; \ + cur->line = error_info.line; \ + error_info.line = n; \ + debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); \ + } while (0) + +#define PUSH_STRING(p) \ + do \ + { \ + register struct ppinstk* cur; \ + PUSH(IN_STRING, cur); \ + cur->nextchr = p; \ + if (pp.state & DISABLE) cur->flags |= IN_disable; \ + debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); \ + } while (0) + +#define PUSH_LINE(p) \ + do \ + { \ + register struct ppinstk* cur; \ + PUSH(IN_STRING, cur); \ + cur->nextchr = p; \ + pp.state |= DISABLE|NOSPACE|PASSEOF|STRIP; \ + debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr))); \ + } while (0) + +#define POP_LINE() \ + do \ + { \ + debug((-7, "POP in=%s", ppinstr(pp.in))); \ + pp.in = pp.in->prev; \ + pp.state &= ~(DISABLE|NOSPACE|PASSEOF|STRIP); \ + } while (0) + +struct ppcontext /* pp context */ +{ + _PP_CONTEXT_PUBLIC_ + _PP_CONTEXT_PRIVATE_ +}; + +struct ppfile /* include file info */ +{ + HASH_HEADER; /* this is a hash bucket too */ + struct ppsymbol* guard; /* guard symbol */ + struct ppfile* bound[INC_MAX]; /* include bindings */ + int flags; /* INC_* flags */ +}; + +#if CHECKPOINT + +struct ppindex /* checkpoint include index */ +{ + struct ppindex* next; /* next in list */ + struct ppfile* file; /* include file */ + unsigned long begin; /* beginning output offset */ + unsigned long end; /* ending output offset */ +}; + +#endif + +struct ppsymkey /* pun for SYM_KEYWORD lex val */ +{ + struct ppsymbol sym; /* symbol as usual */ + int lex; /* lex value for SYM_KEYWORD */ +}; + +#if PROTOMAIN && PROTO_STANDALONE + +#if defined(__STDC__) || defined(__cplusplus) || defined(c_plusplus) +#define NiL 0 +#define NoP(x) (&x,1) +#else +#define NiL ((char*)0) +#define NoP(x) +#endif + +#define newof(p,t,n,x) ((p)?(t*)realloc((char*)(p),sizeof(t)*(n)+(x)):(t*)calloc(1,sizeof(t)*(n)+(x))) + +#define _PP_DELAY_ # + +_PP_DELAY_ ifdef __STDC__ + +_PP_DELAY_ include <stdlib.h> +_PP_DELAY_ include <unistd.h> +_PP_DELAY_ include <time.h> +_PP_DELAY_ include <string.h> + +_PP_DELAY_ else + +_PP_DELAY_ define size_t int + +extern void* realloc(void*, size_t); +extern void* calloc(size_t, size_t); +extern char* ctime(time_t*); +extern void free(void*); + +_PP_DELAY_ ifndef O_RDONLY + +extern int access(const char*, int); +extern int close(int); +extern int creat(const char*, int); +extern void exit(int); +extern int link(const char*, const char*); +extern int open(const char*, int, ...); +extern int read(int, void*, int); +extern time_t time(time_t*); +extern int unlink(const char*); +extern int write(int, const void*, int); + +_PP_DELAY_ endif + +_PP_DELAY_ endif + +#else + +/* + * library implementation globals + */ + +#define ppassert _pp_assert +#define ppbuiltin _pp_builtin +#define ppcall _pp_call +#define ppcontrol _pp_control +#define ppdump _pp_dump +#define ppexpand _pp_expand +#define ppexpr _pp_expr +#define ppfsm _pp_fsm +#define ppinmap _pp_inmap +#define ppinstr _pp_instr +#define ppkeyname _pp_keyname +#define pplexmap _pp_lexmap +#define pplexstr _pp_lexstr +#define ppload _pp_load +#define ppmodestr _pp_modestr +#define ppmultiple _pp_multiple +#define ppnest _pp_nest +#define ppoption _pp_option +#define ppoptionstr _pp_optionstr +#define pppclose _pp_pclose +#define pppdrop _pp_pdrop +#define pppopen _pp_popen +#define pppread _pp_pread +#define pppredargs _pp_predargs +#define pppush _pp_push +#define pprefmac _pp_refmac +#define ppsearch _pp_search +#define ppstatestr _pp_statestr +#define pptokstr _pp_tokstr +#define pptrace _pp_trace + +#endif + +extern void ppassert(int, char*, char*); +extern void ppbuiltin(void); +extern int ppcall(struct ppsymbol*, int); +extern int ppcontrol(void); +extern void ppdump(void); +extern char* ppexpand(char*); +extern long ppexpr(int*); +extern void ppfsm(int, char*); +extern char* ppinstr(struct ppinstk*); +extern char* ppkeyname(int, int); +extern char* pplexstr(int); +extern void ppload(char*); +extern void ppmapinclude(char*, char*); +extern char* ppmodestr(long); +extern int ppmultiple(struct ppfile*, struct ppsymbol*); +extern void ppnest(void); +extern int ppoption(char*); +extern char* ppoptionstr(long); +extern void pppclose(char*); +extern int pppdrop(char*); +extern char* pppopen(char*, int, char*, char*, char*, char*, int); +extern int pppread(char*); +extern int pppredargs(void); +extern void pppush(int, char*, char*, int); +extern struct ppsymbol* pprefmac(char*, int); +extern int ppsearch(char*, int, int); +extern char* ppstatestr(long); +extern char* pptokstr(char*, int); +extern void pptrace(int); + +#if _std_malloc + +#include <vmalloc.h> + +#undef free +#define free(p) vmfree(Vmregion,(void*)p) +#undef newof +#define newof(p,t,n,x) vmnewof(Vmregion,p,t,n,x) +#undef oldof +#define oldof(p,t,n,x) vmoldof(Vmregion,p,t,n,x) +#undef strdup +#define strdup(s) vmstrdup(Vmregion,s) + +#endif + +#endif diff --git a/usr/src/lib/libpp/common/ppline.c b/usr/src/lib/libpp/common/ppline.c new file mode 100644 index 0000000000..8ff7c23339 --- /dev/null +++ b/usr/src/lib/libpp/common/ppline.c @@ -0,0 +1,86 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * common preprocessor line sync handler + */ + +#include "pplib.h" + +void +ppline(int line, char* file) +{ + char* s; + static char type[5]; + + if (pp.flags & PP_lineignore) + { + pp.flags &= ~PP_lineignore; + if (!(pp.flags & PP_linetype) || *pp.lineid) + { + ppline(1, file); + file = error_info.file; + } + else + type[1] = PP_sync_ignore; + } + else if (file != pp.lastfile) + { + if (!pp.firstfile) + pp.firstfile = file; + type[1] = ((pp.flags & PP_linetype) && !*pp.lineid && pp.lastfile) ? (line <= 1 ? (file == pp.firstfile ? PP_sync : PP_sync_push) : PP_sync_pop) : PP_sync; + pp.lastfile = file; + } + else + { + if (!(pp.flags & PP_linefile)) + file = 0; + type[1] = PP_sync; + } + if (!(pp.flags & PP_linetype) || *pp.lineid || type[1] == PP_sync) + type[0] = 0; + else + { + type[0] = ' '; + if ((pp.flags & (PP_hosted|PP_linehosted)) == (PP_hosted|PP_linehosted)) + { + type[2] = ' '; + type[3] = PP_sync_hosted; + } + else + type[2] = 0; + } + + /* + * some front ends can't handle two line syncs in a row + */ + + if (pp.pending == pppendout() || pplastout() != '\n') + ppputchar('\n'); + if (file) + ppprintf("#%s %d \"%s\"%s\n", pp.lineid, line, (pp.flags & PP_linebase) && (s = strrchr(file, '/')) ? s + 1 : file, type); + else + ppprintf("#%s %d\n", pp.lineid, line); + if (!pp.macref) + pp.pending = pppendout(); +} diff --git a/usr/src/lib/libpp/common/ppmacref.c b/usr/src/lib/libpp/common/ppmacref.c new file mode 100644 index 0000000000..d744f99803 --- /dev/null +++ b/usr/src/lib/libpp/common/ppmacref.c @@ -0,0 +1,58 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * common preprocessor macro reference handler + */ + +#include "pplib.h" + +void +ppmacref(struct ppsymbol* sym, char* file, int line, int type, unsigned long sum) +{ + register char* p; + + NoP(file); + NoP(line); + p = (pp.state & (DIRECTIVE|JOINING)) == DIRECTIVE ? pp.outp : pp.addp; + p += sfsprintf(p, MAXTOKEN, "\n#%s %d", pp.lineid, error_info.line); + p += sfsprintf(p, MAXTOKEN, "\n#%s %s:%s %s %d", dirname(PRAGMA), pp.pass, keyname(X_MACREF), sym->name, type); + if (type > 0) + { + if (sym->macro && sym->macro->value) + sum = strsum(sym->macro->value, (long)sym->macro->arity); + p += sfsprintf(p, MAXTOKEN, " %lu", sum); + } + if ((pp.state & (DIRECTIVE|JOINING)) == DIRECTIVE) + { + pp.outp = p; + ppcheckout(); + } + else + { + *p++ = '\n'; + pp.addp = p; + pp.state |= ADD; + } + pp.pending = pppendout(); +} diff --git a/usr/src/lib/libpp/common/ppmisc.c b/usr/src/lib/libpp/common/ppmisc.c new file mode 100644 index 0000000000..d7b5d3730e --- /dev/null +++ b/usr/src/lib/libpp/common/ppmisc.c @@ -0,0 +1,242 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * miscellaneous preprocessor support + */ + +#include "pplib.h" + +/* + * macro symbol def|ref + */ + +struct ppsymbol* +pprefmac(char* name, int ref) +{ + register struct ppsymbol* sym; + + if (!(sym = ppsymget(pp.symtab, name)) && (ref <= REF_NORMAL && pp.macref || ref == REF_CREATE || ref == REF_DELETE && (pp.mode & (INIT|READONLY)))) + { + if ((pp.state & COMPILE) && pp.truncate && strlen(name) > pp.truncate) + name[pp.truncate] = 0; + sym = ppsymset(pp.symtab, NiL); + } + if (sym && ref <= REF_NORMAL) + { + if (pp.macref) (*pp.macref)(sym, error_info.file, error_info.line, ref == REF_NORMAL && (pp.state & CONDITIONAL) ? REF_IF : ref, 0L); + if (!sym->macro) sym = 0; + } +#if COMPATIBLE + if (!(pp.state & COMPATIBILITY)) +#endif + if (ref == REF_IF && sym && (sym->flags & SYM_PREDEFINED) && *name != '_' && !(pp.mode & (HOSTED|INACTIVE))) + { + if (pp.state & STRICT) + { + error(1, "%s: obsolete predefined symbol reference disabled", name); + return(0); + } + error(1, "%s: obsolete predefined symbol referenced", name); + } + return(sym); +} + +/* + * common predicate assertion operations + * op is DEFINE or UNDEF + */ + +void +ppassert(int op, char* pred, char* args) +{ + register struct pplist* a; + register struct ppsymbol* sym; + register struct pplist* p; + register struct pplist* q; + + if (!args) switch (op) + { + case DEFINE: + goto mark; + case UNDEF: + a = 0; + goto unmark; + } + if (a = (struct pplist*)hashget(pp.prdtab, pred)) + { + p = 0; + q = a; + while (q) + { + if (streq(q->value, args)) + { + if (op == DEFINE) return; + q = q->next; + if (p) p->next = q; + else a = q; + } + else + { + p = q; + q = q->next; + } + } + if (op == UNDEF) + { + unmark: + hashput(pp.prdtab, pred, a); + if (sym = ppsymref(pp.symtab, pred)) + sym->flags &= ~SYM_PREDICATE; + return; + } + } + if (op == DEFINE) + { + p = newof(0, struct pplist, 1, 0); + p->next = a; + p->value = strdup(args); + hashput(pp.prdtab, NiL, p); + mark: + if ((pp.state & COMPILE) && pp.truncate) return; + if (sym = ppsymset(pp.symtab, pred)) + sym->flags |= SYM_PREDICATE; + } +} + +/* + * parse a predicate argument list + * the args are placed in pp.args + * the first non-space/paren argument token type is returned + * forms: + * + * predicate <identifier> type=T_ID + * predicate ( <identifier> ) type=T_ID + * predicate ( ) type=0 + * predicate ( <balanced-paren-list> ) type=T_STRING + * otherwise type=<other> + */ + +int +pppredargs(void) +{ + register int c; + register int n; + register int type; + char* pptoken; + + pptoken = pp.token; + pp.token = pp.args; + switch (type = pplex()) + { + case '(': + type = 0; + n = 1; + pp.state |= HEADER; + pp.state &= ~STRIP; + c = pplex(); + pp.state &= ~NOSPACE; + for (;;) + { + switch (c) + { + case '(': + n++; + break; + case '\n': + ungetchr(c); + error(2, "missing %d )%s in predicate argument list", n, n == 1 ? "" : "'s"); + type = 0; + goto done; + case ')': + if (!--n) goto done; + break; + } + pp.token = pp.toknxt; + if (c != ' ') + { + if (type) type = T_STRING; + else type = (c == T_ID) ? T_ID : T_STRING; + } + c = pplex(); + } + done: + pp.state &= ~HEADER; + pp.state |= NOSPACE|STRIP; + if (pp.token > pp.args && *(pp.token - 1) == ' ') pp.token--; + *pp.token = 0; + break; + case '\n': + ungetchr('\n'); + type = 0; + break; + } + pp.token = pptoken; + return(type); +} + +/* + * sync output line number + */ + +int +ppsync(void) +{ + long m; + + if ((pp.state & (ADD|HIDDEN))) + { + if (pp.state & ADD) + { + pp.state &= ~ADD; + m = pp.addp - pp.addbuf; + pp.addp = pp.addbuf; + ppprintf("%-.*s", m, pp.addbuf); + } + if (pp.linesync) + { + if ((pp.state & SYNCLINE) || pp.hidden >= MAXHIDDEN) + { + pp.hidden = 0; + pp.state &= ~(HIDDEN|SYNCLINE); + if (error_info.line) + (*pp.linesync)(error_info.line, error_info.file); + } + else + { + m = pp.hidden; + pp.hidden = 0; + pp.state &= ~HIDDEN; + while (m-- > 0) + ppputchar('\n'); + } + } + else + { + pp.hidden = 0; + pp.state &= ~HIDDEN; + ppputchar('\n'); + } + } + return 0; +} diff --git a/usr/src/lib/libpp/common/ppop.c b/usr/src/lib/libpp/common/ppop.c new file mode 100644 index 0000000000..86e3651864 --- /dev/null +++ b/usr/src/lib/libpp/common/ppop.c @@ -0,0 +1,1553 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor library control interface + */ + +#include "pplib.h" +#include "pptab.h" + +#include <ls.h> + +#define REFONE (pp.truncate?(Hash_table_t*)0:pp.symtab) +#define REFALL (pp.truncate?pp.dirtab:pp.symtab) + +#define ppiskey(t,v,p) (p=t,v>=p->value&&value<=(p+elementsof(t)-2)->value) + +/* + * set option value + * initialization files have lowest precedence + */ + +static void +set(register long* p, register long op, int val) +{ + long* r; + + r = p == &pp.state ? &pp.ro_state : p == &pp.mode ? &pp.ro_mode : &pp.ro_option; + if (!(pp.mode & INIT) || !(pp.in->type == IN_FILE) || !(*r & op)) + { + if (!pp.initialized && !(pp.mode & INIT)) + *r |= op; + if (val) + *p |= op; + else + *p &= ~op; + } + debug((-7, "set(%s)=%s", p == &pp.state ? "state" : p == &pp.mode ? "mode" : "option", p == &pp.state ? ppstatestr(*p) : p == &pp.mode ? ppmodestr(*p) : ppoptionstr(*p))); +} + +/* + * initialize hash table with keywords from key + */ + +static void +inithash(register Hash_table_t* tab, register struct ppkeyword* key) +{ + register char* s; + + for (; s = key->name; key++) + { + if (!ppisid(*s)) + s++; + hashput(tab, s, key->value); + } +} + +/* + * return ppkeyword table name given value + */ + +char* +ppkeyname(register int value, int dir) +{ + register char* s; + register struct ppkeyword* p; + + if (dir && ppiskey(directives, value, p) || !dir && (ppiskey(options, value, p) || ppiskey(predicates, value, p) || ppiskey(variables, value, p))) + { + s = (p + (value - p->value))->name; + return s + !ppisid(*s); + } +#if DEBUG + error(PANIC, "no keyword table name for value=%d", value); +#endif + return "UNKNOWN"; +} + +/* + * add to the include maps + */ + +void +ppmapinclude(char* file, register char* s) +{ + register int c; + register struct ppdirs* dp; + int fd; + int flags; + int index; + int token; + char* t; + char* old_file; + long old_state; + struct ppfile* fp; + struct ppfile* mp; + + old_file = error_info.file; + old_state = pp.state; + if (s) + PUSH_BUFFER("mapinclude", s, 1); + else if (file) + { + if (*file == '-') + { + if (!error_info.file) + { + error(1, "%s: input file name required for %s ignore", file, dirname(INCLUDE)); + return; + } + s = t = strcopy(pp.tmpbuf, error_info.file); + c = *++file; + for (;;) + { + if (s <= pp.tmpbuf || *s == '/') + { + s = t; + break; + } + else if (*s == c) + break; + s--; + } + strcpy(s, file); + file = pp.tmpbuf; + } + if ((fd = ppsearch(file, INC_LOCAL, SEARCH_INCLUDE)) < 0) + return; + PUSH_FILE(file, fd); + } + else + return; +#if CATSTRINGS + pp.state |= (COMPILE|FILEPOP|HEADER|JOINING|STRIP|NOSPACE|PASSEOF); +#else + pp.state |= (COMPILE|FILEPOP|HEADER|STRIP|NOSPACE|PASSEOF); +#endif + pp.level++; + flags = INC_MAPALL; + fp = mp = 0; + for (;;) + { + switch (token = pplex()) + { + case 0: + case T_STRING: + case T_HEADER: + if (fp) + { + fp->guard = INC_IGNORE; + for (dp = pp.firstdir->next; dp; dp = dp->next) + if (dp->name && (c = strlen(dp->name)) && !strncmp(dp->name, fp->name, c) && fp->name[c] == '/') + { + ppsetfile(fp->name + c + 1)->guard = INC_IGNORE; + break; + } + } + if (!token) + break; + pathcanon(pp.token, 0); + fp = ppsetfile(pp.token); + if (mp) + { + mp->flags |= flags; + if (streq(fp->name, ".")) + mp->flags |= INC_MAPNOLOCAL; + else + mp->bound[index] = fp; + + fp = mp = 0; + } + else + index = token == T_HEADER ? INC_STANDARD : INC_LOCAL; + continue; + case '=': + if (!(mp = fp)) + error(3, "%s: \"name\" = \"binding\" expected"); + fp = 0; + continue; + case '\n': + continue; + case T_ID: + if (streq(pp.token, "all")) + { + flags = INC_MAPALL; + continue; + } + else if (streq(pp.token, "hosted")) + { + flags = INC_MAPHOSTED; + continue; + } + else if (streq(pp.token, "nohosted")) + { + flags = INC_MAPNOHOSTED; + continue; + } + /*FALLTHROUGH*/ + default: + error(3, "%s unexpected in %s map list", pptokstr(pp.token, 0), dirname(INCLUDE)); + break; + } + break; + } + pp.level--; + error_info.file = old_file; + pp.state = old_state; +} + +/* + * return non-0 if file is identical to fd + */ + +static int +identical(char* file, int fd) +{ + struct stat a; + struct stat b; + + return !stat(file, &a) && !fstat(fd, &b) && a.st_dev == b.st_dev && a.st_ino == b.st_ino; +} + +/* + * compare up to pp.truncate chars + * + * NOTE: __STD* and symbols containing ' ' are not truncated + */ + +static int +trunccomp(register char* a, register char* b) +{ + return !strchr(b, ' ') && !strneq(b, "__STD", 5) ? strncmp(a, b, pp.truncate) : strcmp(a, b); +} + +/* + * hash up to pp.truncate chars + * + * NOTE: __STD* and symbols containing ' ' are not truncated + */ + +static unsigned int +trunchash(char* a) +{ + int n; + + return memhash(a, (n = strlen(a)) > pp.truncate && !strchr(a, ' ') && !strneq(a, "__STD", 5) ? pp.truncate : n); +} + +#if DEBUG & TRACE_debug +/* + * append context to debug trace + */ + +static int +context(Sfio_t* sp, int level, int flags) +{ + static int state; + + NoP(level); + NoP(flags); + if (error_info.trace <= -10 && pp.state != state) + { + state = pp.state; + sfprintf(sp, " %s", ppstatestr(pp.state)); + } + return 1; +} +#endif + +/* + * reset include guard + */ + +static int +unguard(const char* name, char* v, void* handle) +{ + register struct ppfile* fp = (struct ppfile*)v; + + fp->guard = 0; + return 0; +} + +/* + * reset macro definition + */ + +static void +undefine(void* p) +{ + struct ppmacro* mac = ((struct ppsymbol*)p)->macro; + + if (mac) + { + if (mac->formals) + free(mac->formals); + free(mac->value); + free(mac); + } +} + +/* + * pp operations + * + * NOTE: PP_INIT must be done before the first pplex() call + * PP_DONE must be done after the last pplex() call + * PP_INIT-PP_DONE must be done for each new PP_INPUT + */ + +void +ppop(int op, ...) +{ + va_list ap; + register char* p; + register struct ppkeyword* kp; + register char* s; + int c; + long n; + char* t; + struct ppdirs* dp; + struct ppdirs* hp; + struct ppsymkey* key; + struct oplist* xp; + Sfio_t* sp; + struct stat st; + PPCOMMENT ppcomment; + PPLINESYNC pplinesync; + + static int initialized; + + va_start(ap, op); + switch (op) + { + case PP_ASSERT: + case PP_DEFINE: + case PP_DIRECTIVE: + case PP_OPTION: + case PP_READ: + case PP_UNDEF: + if (pp.initialized) + goto before; + if ((p = va_arg(ap, char*)) && *p) + { + if (pp.lastop) + pp.lastop = (pp.lastop->next = newof(0, struct oplist, 1, 0)); + else + pp.firstop = pp.lastop = newof(0, struct oplist, 1, 0); + pp.lastop->op = op; + pp.lastop->value = p; + } + break; + case PP_BUILTIN: + pp.builtin = va_arg(ap, PPBUILTIN); + break; + case PP_CDIR: + p = va_arg(ap, char*); + c = va_arg(ap, int); + pp.cdir.path = 0; + if (!p) + pp.c = c; + else if (streq(p, "-")) + { + pp.c = c; + for (dp = pp.firstdir; dp; dp = dp->next) + dp->c = c; + } + else if (!pp.c) + { + if (!*p || stat((pathcanon(p, 0), p), &st)) + pp.c = c; + else + { + for (dp = pp.firstdir; dp; dp = dp->next) + { + if (!pp.c && (dp->c || dp->name && SAMEID(&dp->id, &st))) + pp.c = 1; + dp->c = pp.c == 1; + } + if (!pp.c) + { + pp.cdir.path = p; + SAVEID(&pp.cdir.id, &st); + } + } + } + break; + case PP_CHOP: + if (p = va_arg(ap, char*)) + { + c = strlen(p); + xp = newof(0, struct oplist, 1, c + 1); + xp->value = ((char*)xp) + sizeof(struct oplist); + s = xp->value; + c = *p++; + while (*p && *p != c) + *s++ = *p++; + *s++ = '/'; + xp->op = s - xp->value; + *s++ = 0; + if (*p && *++p && *p != c) + { + while (*p && *p != c) + *s++ = *p++; + *s++ = '/'; + } + *s = 0; + xp->next = pp.chop; + pp.chop = xp; + } + break; + case PP_COMMENT: + if (pp.comment = va_arg(ap, PPCOMMENT)) + pp.flags |= PP_comment; + else + pp.flags &= ~PP_comment; + break; + case PP_COMPATIBILITY: + set(&pp.state, COMPATIBILITY, va_arg(ap, int)); +#if COMPATIBLE + if (pp.initialized) + ppfsm(FSM_COMPATIBILITY, NiL); +#else + if (pp.state & COMPATIBILITY) + error(3, "preprocessor not compiled with compatibility dialect enabled [COMPATIBLE]"); +#endif + if (pp.state & COMPATIBILITY) + pp.flags |= PP_compatibility; + else + pp.flags &= ~PP_compatibility; + break; + case PP_COMPILE: + if (pp.initialized) + goto before; + pp.state |= COMPILE; + if (!pp.symtab) + pp.symtab = hashalloc(NiL, HASH_name, "symbols", 0); + if (kp = va_arg(ap, struct ppkeyword*)) + for (; s = kp->name; kp++) + { + n = SYM_LEX; + switch (*s) + { + case '-': + s++; + break; + case '+': + s++; + if (!(pp.option & PLUSPLUS)) + break; + /*FALLTHROUGH*/ + default: + n |= SYM_KEYWORD; + break; + } + if (key = ppkeyset(pp.symtab, s)) + { + key->sym.flags = n; + key->lex = kp->value; + } + } + break; + case PP_DEBUG: + error_info.trace = va_arg(ap, int); + break; + case PP_DEFAULT: + if (p = va_arg(ap, char*)) + p = strdup(p); + if (pp.ppdefault) + free(pp.ppdefault); + pp.ppdefault = p; + break; + case PP_DONE: +#if CHECKPOINT + if (pp.mode & DUMP) + ppdump(); +#endif + if (pp.mode & FILEDEPS) + { + sfputc(pp.filedeps.sp, '\n'); + if (pp.filedeps.sp == sfstdout) + sfsync(pp.filedeps.sp); + else + sfclose(pp.filedeps.sp); + } + if (pp.state & STANDALONE) + { + if ((pp.state & (NOTEXT|HIDDEN)) == HIDDEN && pplastout() != '\n') + ppputchar('\n'); + ppflushout(); + } + error_info.file = 0; + break; + case PP_DUMP: + set(&pp.mode, DUMP, va_arg(ap, int)); +#if !CHECKPOINT + if (pp.mode & DUMP) + error(3, "preprocessor not compiled with checkpoint enabled [CHECKPOINT]"); +#endif + break; + case PP_FILEDEPS: + if (n = va_arg(ap, int)) + pp.filedeps.flags |= n; + else + pp.filedeps.flags = 0; + break; + case PP_FILENAME: + error_info.file = va_arg(ap, char*); + break; + case PP_HOSTDIR: + if (!(pp.mode & INIT)) + pp.ro_mode |= HOSTED; + else if (pp.ro_mode & HOSTED) + break; + pp.ro_mode |= INIT; + p = va_arg(ap, char*); + c = va_arg(ap, int); + pp.hostdir.path = 0; + if (!p) + pp.hosted = c; + else if (streq(p, "-")) + { + if (pp.initialized) + set(&pp.mode, HOSTED, c); + else + { + pp.hosted = c ? 1 : 2; + for (dp = pp.firstdir; dp; dp = dp->next) + if (pp.hosted == 1) + dp->type |= TYPE_HOSTED; + else + dp->type &= ~TYPE_HOSTED; + } + } + else if (!pp.hosted) + { + if (!*p || stat((pathcanon(p, 0), p), &st)) + pp.hosted = 1; + else + { + for (dp = pp.firstdir; dp; dp = dp->next) + { + if (!pp.hosted && ((dp->type & TYPE_HOSTED) || dp->name && SAMEID(&dp->id, &st))) + pp.hosted = 1; + if (pp.hosted == 1) + dp->type |= TYPE_HOSTED; + else + dp->type &= ~TYPE_HOSTED; + } + if (!pp.hosted) + { + pp.hostdir.path = p; + SAVEID(&pp.hostdir.id, &st); + } + } + } + break; + case PP_ID: + p = va_arg(ap, char*); + c = va_arg(ap, int); + if (p) + ppfsm(c ? FSM_IDADD : FSM_IDDEL, p); + break; + case PP_IGNORE: + if (p = va_arg(ap, char*)) + { + pathcanon(p, 0); + ppsetfile(p)->guard = INC_IGNORE; + message((-3, "%s: ignore", p)); + } + break; + case PP_IGNORELIST: + if (pp.initialized) + goto before; + pp.ignore = va_arg(ap, char*); + break; + case PP_INCLUDE: + if ((p = va_arg(ap, char*)) && *p) + { + pathcanon(p, 0); + if (stat(p, &st)) + break; + for (dp = pp.stddirs; dp = dp->next;) + if (dp->name && SAMEID(&dp->id, &st)) + break; + if (pp.cdir.path && SAMEID(&pp.cdir.id, &st)) + { + pp.cdir.path = 0; + pp.c = 1; + } + if (pp.hostdir.path && SAMEID(&pp.hostdir.id, &st)) + { + pp.hostdir.path = 0; + pp.hosted = 1; + } + if ((pp.mode & INIT) && !(pp.ro_mode & INIT)) + pp.hosted = 1; + c = dp && dp->c || pp.c == 1; + n = dp && (dp->type & TYPE_HOSTED) || pp.hosted == 1; + if (!dp || dp == pp.lastdir->next) + { + if (dp) + { + c = dp->c; + n = dp->type & TYPE_HOSTED; + } + dp = newof(0, struct ppdirs, 1, 0); + dp->name = p; + SAVEID(&dp->id, &st); + dp->type |= TYPE_INCLUDE; + dp->index = INC_LOCAL + pp.ignoresrc != 0; + dp->next = pp.lastdir->next; + pp.lastdir = pp.lastdir->next = dp; + } + dp->c = c; + if (n) + dp->type |= TYPE_HOSTED; + else + dp->type &= ~TYPE_HOSTED; + } + break; + case PP_INCREF: + pp.incref = va_arg(ap, PPINCREF); + break; + case PP_RESET: + pp.reset.on = 1; + break; + case PP_INIT: + if (pp.initialized) + { + error_info.errors = 0; + error_info.warnings = 0; + } + else + { + /* + * context initialization + */ + + if (!initialized) + { + /* + * out of malloc is fatal + */ + + memfatal(); + + /* + * initialize the error message interface + */ + + error_info.version = (char*)pp.version; +#if DEBUG & TRACE_debug + error_info.auxilliary = context; + pptrace(0); +#endif + + /* + * initialize pplex tables + */ + + ppfsm(FSM_INIT, NiL); + + /* + * fixed macro stack size -- room for improvement + */ + + pp.macp = newof(0, struct ppmacstk, DEFMACSTACK, 0); + pp.macp->next = pp.macp + 1; + pp.maxmac = (char*)pp.macp + DEFMACSTACK; + initialized = 1; + + /* + * initial include/if control stack + */ + + pp.control = newof(0, long, pp.constack, 0); + pp.maxcon = pp.control + pp.constack - 1; + } + + /* + * validate modes + */ + + switch (pp.arg_mode) + { + case 'a': + case 'C': + ppop(PP_COMPATIBILITY, 0); + ppop(PP_TRANSITION, 1); + break; + case 'A': + case 'c': + ppop(PP_COMPATIBILITY, 0); + ppop(PP_STRICT, 1); + break; + case 'f': + ppop(PP_COMPATIBILITY, 1); + ppop(PP_PLUSPLUS, 1); + ppop(PP_TRANSITION, 1); + break; + case 'F': + ppop(PP_COMPATIBILITY, 0); + ppop(PP_PLUSPLUS, 1); + break; + case 'k': + case 's': + ppop(PP_COMPATIBILITY, 1); + ppop(PP_STRICT, 1); + break; + case 'o': + case 'O': + ppop(PP_COMPATIBILITY, 1); + ppop(PP_TRANSITION, 0); + break; + case 't': + ppop(PP_COMPATIBILITY, 1); + ppop(PP_TRANSITION, 1); + break; + } + if (!(pp.arg_style & STYLE_gnu)) + ppop(PP_PEDANTIC, 1); + if (pp.state & PASSTHROUGH) + { + if (pp.state & COMPILE) + { + pp.state &= ~PASSTHROUGH; + error(1, "passthrough ignored for compile"); + } + else + { + ppop(PP_COMPATIBILITY, 1); + ppop(PP_HOSTDIR, "-", 1); + ppop(PP_SPACEOUT, 1); + set(&pp.state, DISABLE, va_arg(ap, int)); + } + } + + /* + * create the hash tables + */ + + if (!pp.symtab) + pp.symtab = hashalloc(NiL, HASH_name, "symbols", 0); + if (!pp.dirtab) + { + pp.dirtab = hashalloc(REFONE, HASH_name, "directives", 0); + inithash(pp.dirtab, directives); + } + if (!pp.filtab) + pp.filtab = hashalloc(REFALL, HASH_name, "files", 0); + if (!pp.prdtab) + pp.prdtab = hashalloc(REFALL, HASH_name, "predicates", 0); + if (!pp.strtab) + { + pp.strtab = hashalloc(REFALL, HASH_name, "strings", 0); + inithash(pp.strtab, options); + inithash(pp.strtab, predicates); + inithash(pp.strtab, variables); + } + pp.optflags[X_PROTOTYPED] = OPT_GLOBAL; + pp.optflags[X_SYSTEM_HEADER] = OPT_GLOBAL|OPT_PASS; + + /* + * mark macros that are builtin predicates + */ + + for (kp = predicates; s = kp->name; kp++) + { + if (!ppisid(*s)) + s++; + ppassert(DEFINE, s, 0); + } + + /* + * the remaining entry names must be allocated + */ + + hashset(pp.dirtab, HASH_ALLOCATE); + hashset(pp.filtab, HASH_ALLOCATE); + hashset(pp.prdtab, HASH_ALLOCATE); + hashset(pp.strtab, HASH_ALLOCATE); + hashset(pp.symtab, HASH_ALLOCATE); + if (pp.test & TEST_nonoise) + { + c = error_info.trace; + error_info.trace = 0; + } +#if DEBUG + if (!(pp.test & TEST_noinit)) + { +#endif + + /* + * compose, push and read the builtin initialization script + */ + + if (!(sp = sfstropen())) + error(3, "temporary buffer allocation error"); + sfprintf(sp, +"\ +#%s %s:%s \"/#<assert> /\" \"/assert /%s #/\"\n\ +#%s %s:%s \"/#<unassert> /\" \"/unassert /%s #/\"\n\ +", + dirname(PRAGMA), + pp.pass, + keyname(X_MAP), + dirname(DEFINE), + dirname(PRAGMA), + pp.pass, + keyname(X_MAP), + dirname(UNDEF)); + if (pp.ppdefault && *pp.ppdefault) + { + if (pp.probe) + { + c = pp.lastdir->next->type; + pp.lastdir->next->type = 0; + } + if (ppsearch(pp.ppdefault, T_STRING, SEARCH_EXISTS) < 0) + { + free(pp.ppdefault); + if (!(pp.ppdefault = pathprobe(pp.path, NiL, "C", pp.pass, pp.probe ? pp.probe : PPPROBE, 0))) + error(1, "cannot determine default definitions for %s", pp.probe ? pp.probe : PPPROBE); + } + if (pp.ppdefault) + sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), pp.ppdefault); + if (pp.probe) + pp.lastdir->next->type = c; + } + while (pp.firstop) + { + switch (pp.firstop->op) + { + case PP_ASSERT: + sfprintf(sp, "#%s #%s\n", dirname(DEFINE), pp.firstop->value); + break; + case PP_DEFINE: + if (*pp.firstop->value == '#') + sfprintf(sp, "#%s %s\n", dirname(DEFINE), pp.firstop->value); + else + { + if (s = strchr(pp.firstop->value, '=')) + sfprintf(sp, "#%s %-.*s %s\n", dirname(DEFINE), s - pp.firstop->value, pp.firstop->value, s + 1); + else + sfprintf(sp, "#%s %s 1\n", dirname(DEFINE), pp.firstop->value); + } + break; + case PP_DIRECTIVE: + sfprintf(sp, "#%s\n", pp.firstop->value); + break; + case PP_OPTION: + if (s = strchr(pp.firstop->value, '=')) + sfprintf(sp, "#%s %s:%-.*s %s\n", dirname(PRAGMA), pp.pass, s - pp.firstop->value, pp.firstop->value, s + 1); + else + sfprintf(sp, "#%s %s:%s\n", dirname(PRAGMA), pp.pass, pp.firstop->value); + break; + case PP_READ: + sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), pp.firstop->value); + break; + case PP_UNDEF: + sfprintf(sp, "#%s %s\n", dirname(UNDEF), pp.firstop->value); + break; + } + pp.lastop = pp.firstop; + pp.firstop = pp.firstop->next; + free(pp.lastop); + } + sfprintf(sp, +"\ +#%s %s:%s\n\ +#%s %s:%s\n\ +#%s !#%s(%s)\n\ +#%s !#%s(%s) || #%s(%s)\n\ +" + , dirname(PRAGMA) + , pp.pass + , keyname(X_BUILTIN) + , dirname(PRAGMA) + , pp.pass + , keyname(X_PREDEFINED) + , dirname(IF) + , keyname(X_OPTION) + , keyname(X_PLUSPLUS) + , dirname(IF) + , keyname(X_OPTION) + , keyname(X_COMPATIBILITY) + , keyname(X_OPTION) + , keyname(X_TRANSITION) + ); + sfprintf(sp, +"\ +#%s __STDC__\n\ +#%s __STDC__ #(STDC)\n\ +#%s\n\ +#%s #%s(%s)\n\ +#%s %s:%s\n\ +#%s %s:%s\n\ +#%s __STRICT__ 1\n\ +#%s\n\ +#%s\n\ +" + , dirname(IFNDEF) + , dirname(DEFINE) + , dirname(ENDIF) + , dirname(IF) + , keyname(X_OPTION) + , keyname(X_STRICT) + , dirname(PRAGMA) + , pp.pass + , keyname(X_ALLMULTIPLE) + , dirname(PRAGMA) + , pp.pass + , keyname(X_READONLY) + , dirname(DEFINE) + , dirname(ENDIF) + , dirname(ENDIF) + ); + for (kp = readonlys; s = kp->name; kp++) + { + if (!ppisid(*s)) + s++; + sfprintf(sp, "#%s %s\n", dirname(UNDEF), s); + } + sfprintf(sp, +"\ +#%s\n\ +#%s __STDPP__ 1\n\ +#%s %s:no%s\n\ +" + , dirname(ENDIF) + , dirname(DEFINE) + , dirname(PRAGMA) + , pp.pass + , keyname(X_PREDEFINED) + ); + if (!pp.truncate) + sfprintf(sp, +"\ +#%s __STDPP__directive #(%s)\n\ +" + , dirname(DEFINE) + , keyname(V_DIRECTIVE) + ); + for (kp = variables; s = kp->name; kp++) + if (ppisid(*s) || *s++ == '+') + { + t = *s == '_' ? "" : "__"; + sfprintf(sp, "#%s %s%s%s #(%s)\n" , dirname(DEFINE), t, s, t, s); + } + sfprintf(sp, +"\ +#%s %s:no%s\n\ +#%s %s:no%s\n\ +" + , dirname(PRAGMA) + , pp.pass + , keyname(X_READONLY) + , dirname(PRAGMA) + , pp.pass + , keyname(X_BUILTIN) + ); + t = sfstruse(sp); + debug((-9, "\n/* begin initialization */\n%s/* end initialization */", t)); + ppcomment = pp.comment; + pp.comment = 0; + pplinesync = pp.linesync; + pp.linesync = 0; + PUSH_INIT(pp.pass, t); + pp.mode |= INIT; + while (pplex()); + pp.mode &= ~INIT; + pp.comment = ppcomment; + pp.linesync = pplinesync; + pp.prefix = 0; + sfstrclose(sp); + if (error_info.trace) + for (dp = pp.firstdir; dp; dp = dp->next) + message((-1, "include directory %s%s%s%s", dp->name, (dp->type & TYPE_VENDOR) ? " [VENDOR]" : "", (dp->type & TYPE_HOSTED) ? " [HOSTED]" : "", dp->c ? " [C]" : "")); +#if DEBUG + } + if (pp.test & TEST_nonoise) + error_info.trace = c; +#endif + { + /* + * this is sleazy but at least it's + * hidden in the library + */ +#include <preroot.h> +#if FS_PREROOT + struct pplist* preroot; + + if ((preroot = (struct pplist*)hashget(pp.prdtab, "preroot"))) + setpreroot(NiL, preroot->value); +#endif + } + if (pp.ignoresrc) + { + if (pp.ignoresrc > 1 && pp.stddirs != pp.firstdir) + error(1, "directories up to and including %s are for \"...\" include files only", pp.stddirs->name); + pp.lcldirs = pp.lcldirs->next; + } + if (pp.ignore) + { + if (*pp.ignore) + ppmapinclude(pp.ignore, NiL); + else + pp.ignore = 0; + } + if (pp.standalone) + pp.state |= STANDALONE; +#if COMPATIBLE + ppfsm(FSM_COMPATIBILITY, NiL); +#endif + ppfsm(FSM_PLUSPLUS, NiL); + pp.initialized = 1; + if (pp.reset.on) + { + pp.reset.symtab = pp.symtab; + pp.symtab = 0; + pp.reset.ro_state = pp.ro_state; + pp.reset.ro_mode = pp.ro_mode; + pp.reset.ro_option = pp.ro_option; + } + } + if (pp.reset.on) + { + if (pp.symtab) + { + hashwalk(pp.filtab, 0, unguard, NiL); + hashfree(pp.symtab); + } + pp.symtab = hashalloc(NiL, HASH_name, "symbols", HASH_free, undefine, HASH_set, HASH_ALLOCATE|HASH_BUCKET, 0); + hashview(pp.symtab, pp.reset.symtab); + pp.ro_state = pp.reset.ro_state; + pp.ro_mode = pp.reset.ro_mode; + pp.ro_option = pp.reset.ro_option; + } +#if CHECKPOINT + if (pp.mode & DUMP) + { + if (!pp.pragma) + error(3, "#%s must be enabled for checkpoints", dirname(PRAGMA)); + (*pp.pragma)(dirname(PRAGMA), pp.pass, keyname(X_CHECKPOINT), pp.checkpoint, 1); + } +#endif + if (n = pp.filedeps.flags) + { + if (!(n & PP_deps_file)) + { + pp.state |= NOTEXT; + pp.option |= KEEPNOTEXT; + pp.linesync = 0; + } + if (n & PP_deps_generated) + pp.mode |= GENDEPS; + if (n & PP_deps_local) + pp.mode &= ~HEADERDEPS; + else if (!(pp.mode & FILEDEPS)) + pp.mode |= HEADERDEPS; + pp.mode |= FILEDEPS; + } + + /* + * push the main input file -- special case for hosted mark + */ + + if (pp.firstdir->type & TYPE_HOSTED) + pp.mode |= MARKHOSTED; + else + pp.mode &= ~MARKHOSTED; +#if CHECKPOINT + if (!(pp.mode & DUMP)) +#endif + { + if (!(p = error_info.file)) + p = ""; + else + { + error_info.file = 0; + if (*p) + { + pathcanon(p, 0); + p = ppsetfile(p)->name; + } + } + PUSH_FILE(p, 0); + } + if (pp.mode & FILEDEPS) + { + if (s = strrchr(error_info.file, '/')) + s++; + else + s = error_info.file; + if (!*s) + s = "-"; + s = strcpy(pp.tmpbuf, s); + if ((t = p = strrchr(s, '.')) && (*++p == 'c' || *p == 'C')) + { + if (c = *++p) + while (*++p == c); + if (*p) + t = 0; + else + t++; + } + if (!t) + { + t = s + strlen(s); + *t++ = '.'; + } + *(t + 1) = 0; + if (pp.state & NOTEXT) + pp.filedeps.sp = sfstdout; + else + { + *t = 'd'; + if (!(pp.filedeps.sp = sfopen(NiL, s, "w"))) + error(ERROR_SYSTEM|3, "%s: cannot create", s); + } + *t = 'o'; + pp.column = sfprintf(pp.filedeps.sp, "%s :", s); + if (*error_info.file) + pp.column += sfprintf(pp.filedeps.sp, " %s", error_info.file); + } + if (xp = pp.firsttx) + { + if (!(sp = sfstropen())) + error(3, "temporary buffer allocation error"); + while (xp) + { + sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), xp->value); + xp = xp->next; + } + t = sfstruse(sp); + PUSH_BUFFER("options", t, 1); + sfstrclose(sp); + } + break; + case PP_INPUT: +#if CHECKPOINT && POOL + if (!(pp.mode & DUMP) || pp.pool.input) +#else +#if CHECKPOINT + if (!(pp.mode & DUMP)) +#else +#if POOL + if (pp.pool.input) +#endif +#endif +#endif + { + p = va_arg(ap, char*); + if (!error_info.file) + error_info.file = p; + close(0); + if (open(p, O_RDONLY) != 0) + error(ERROR_SYSTEM|3, "%s: cannot read", p); + if (strmatch(p, "*.(s|S|as|AS|asm|ASM)")) + { + set(&pp.mode, CATLITERAL, 0); + ppop(PP_SPACEOUT, 1); + } + break; + } + /*FALLTHROUGH*/ + case PP_TEXT: + if (pp.initialized) + goto before; + if ((p = va_arg(ap, char*)) && *p) + { + if (pp.lasttx) + pp.lasttx = pp.lasttx->next = newof(0, struct oplist, 1, 0); + else + pp.firsttx = pp.lasttx = newof(0, struct oplist, 1, 0); + pp.lasttx->op = op; + pp.lasttx->value = p; + } + break; + case PP_KEYARGS: + if (pp.initialized) + goto before; + set(&pp.option, KEYARGS, va_arg(ap, int)); + if (pp.option & KEYARGS) +#if MACKEYARGS + set(&pp.mode, CATLITERAL, 1); +#else + error(3, "preprocessor not compiled with macro keyword arguments enabled [MACKEYARGS]"); +#endif + break; + case PP_LINE: + pp.linesync = va_arg(ap, PPLINESYNC); + break; + case PP_LINEBASE: + if (va_arg(ap, int)) + pp.flags |= PP_linebase; + else + pp.flags &= ~PP_linebase; + break; + case PP_LINEFILE: + if (va_arg(ap, int)) + pp.flags |= PP_linefile; + else + pp.flags &= ~PP_linefile; + break; + case PP_LINEID: + if (!(p = va_arg(ap, char*))) + pp.lineid = ""; + else if (*p != '-') + pp.lineid = strdup(p); + else + pp.option |= IGNORELINE; + break; + case PP_LINETYPE: + if ((n = va_arg(ap, int)) >= 1) + pp.flags |= PP_linetype; + else + pp.flags &= ~PP_linetype; + if (n >= 2) + pp.flags |= PP_linehosted; + else + pp.flags &= ~PP_linehosted; + break; + case PP_LOCAL: + if (pp.initialized) + goto before; + pp.ignoresrc++; + pp.stddirs = pp.lastdir; + if (!(pp.ro_option & PREFIX)) + pp.option &= ~PREFIX; + break; + case PP_MACREF: + pp.macref = va_arg(ap, PPMACREF); + break; + case PP_MULTIPLE: + set(&pp.mode, ALLMULTIPLE, va_arg(ap, int)); + break; + case PP_NOHASH: + set(&pp.option, NOHASH, va_arg(ap, int)); + break; + case PP_NOISE: + op = va_arg(ap, int); + set(&pp.option, NOISE, op); + set(&pp.option, NOISEFILTER, op < 0); + break; + case PP_OPTARG: + pp.optarg = va_arg(ap, PPOPTARG); + break; + case PP_OUTPUT: + pp.outfile = va_arg(ap, char*); + if (identical(pp.outfile, 0)) + error(3, "%s: identical to input", pp.outfile); + close(1); + if (open(pp.outfile, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) != 1) + error(ERROR_SYSTEM|3, "%s: cannot create", pp.outfile); + break; + case PP_PASSTHROUGH: + if (!(pp.state & COMPILE)) + set(&pp.state, PASSTHROUGH, va_arg(ap, int)); + break; + case PP_PEDANTIC: + set(&pp.mode, PEDANTIC, va_arg(ap, int)); + break; + case PP_PLUSCOMMENT: + set(&pp.option, PLUSCOMMENT, va_arg(ap, int)); + if (pp.initialized) + ppfsm(FSM_PLUSPLUS, NiL); + break; + case PP_PLUSPLUS: + set(&pp.option, PLUSPLUS, va_arg(ap, int)); + set(&pp.option, PLUSCOMMENT, va_arg(ap, int)); + if (pp.initialized) + ppfsm(FSM_PLUSPLUS, NiL); + break; + case PP_POOL: + if (pp.initialized) + goto before; + if (va_arg(ap, int)) + { +#if POOL + pp.pool.input = dup(0); + pp.pool.output = dup(1); + p = "/dev/null"; + if (!identical(p, 0)) + { + if (!identical(p, 1)) + ppop(PP_OUTPUT, p); + ppop(PP_INPUT, p); + } +#else + error(3, "preprocessor not compiled with input pool enabled [POOL]"); +#endif + } + break; + case PP_PRAGMA: + pp.pragma = va_arg(ap, PPPRAGMA); + break; + case PP_PRAGMAFLAGS: + if (p = va_arg(ap, char*)) + { + n = OPT_GLOBAL; + if (*p == '-') + p++; + else + n |= OPT_PASS; + if ((c = (int)hashref(pp.strtab, p)) > 0 && c <= X_last_option) + pp.optflags[c] = n; + } + break; + case PP_PROBE: + pp.probe = va_arg(ap, char*); + break; + case PP_QUOTE: + p = va_arg(ap, char*); + c = va_arg(ap, int); + if (p) + ppfsm(c ? FSM_QUOTADD : FSM_QUOTDEL, p); + break; + case PP_REGUARD: + set(&pp.option, REGUARD, va_arg(ap, int)); + break; + case PP_RESERVED: + if ((pp.state & COMPILE) && (p = va_arg(ap, char*))) + { + if (!(sp = sfstropen())) + error(3, "temporary buffer allocation error"); + sfputr(sp, p, -1); + p = sfstruse(sp); + if (s = strchr(p, '=')) + *s++ = 0; + else + s = p; + while (*s == '_') + s++; + for (t = s + strlen(s); t > s && *(t - 1) == '_'; t--); + if (*t == '_') + *t = 0; + else + t = 0; + op = ((key = ppkeyref(pp.symtab, s)) && (key->sym.flags & SYM_LEX)) ? key->lex : T_NOISE; + if (pp.test & 0x0400) + error(1, "reserved#1 `%s' %d", s, op); + if (t) + *t = '_'; + if (!(key = ppkeyget(pp.symtab, p))) + key = ppkeyset(pp.symtab, NiL); + else if (!(key->sym.flags & SYM_LEX)) + { + struct ppsymbol tmp; + + tmp = key->sym; + hashlook(pp.symtab, p, HASH_DELETE, NiL); + key = ppkeyset(pp.symtab, NiL); + key->sym.flags = tmp.flags; + key->sym.macro = tmp.macro; + key->sym.value = tmp.value; + key->sym.hidden = tmp.hidden; + } + if (!(key->sym.flags & SYM_KEYWORD)) + { + key->sym.flags |= SYM_KEYWORD|SYM_LEX; + key->lex = op; + if (pp.test & 0x0400) + error(1, "reserved#2 `%s' %d", p, op); + } + sfstrclose(sp); + } + break; + case PP_SPACEOUT: + set(&pp.state, SPACEOUT, va_arg(ap, int)); + break; + case PP_STANDALONE: + if (pp.initialized) + goto before; + pp.standalone = 1; + break; + case PP_STANDARD: + if ((pp.lastdir->next->name = ((p = va_arg(ap, char*)) && *p) ? p : NiL) && !stat(p, &st)) + SAVEID(&pp.lastdir->next->id, &st); + for (dp = pp.firstdir; dp; dp = dp->next) + if (dp->name) + for (hp = pp.firstdir; hp != dp; hp = hp->next) + if (hp->name && SAMEID(&hp->id, &dp->id)) + { + hp->c = dp->c; + if (dp->type & TYPE_HOSTED) + hp->type |= TYPE_HOSTED; + else + hp->type &= ~TYPE_HOSTED; + } + break; + case PP_STRICT: + set(&pp.state, TRANSITION, 0); + pp.flags &= ~PP_transition; + set(&pp.state, STRICT, va_arg(ap, int)); + if (pp.state & STRICT) + pp.flags |= PP_strict; + else + pp.flags &= ~PP_strict; + break; + case PP_TEST: + if (p = va_arg(ap, char*)) + for (;;) + { + while (*p == ' ' || *p == '\t') p++; + for (s = p; n = *s; s++) + if (n == ',' || n == ' ' || n == '\t') + { + *s++ = 0; + break; + } + if (!*p) + break; + n = 0; + if (*p == 'n' && *(p + 1) == 'o') + { + p += 2; + op = 0; + } + else + op = 1; + if (streq(p, "count")) + n = TEST_count; + else if (streq(p, "hashcount")) + n = TEST_hashcount; + else if (streq(p, "hashdump")) + n = TEST_hashdump; + else if (streq(p, "hit")) + n = TEST_hit; + else if (streq(p, "init")) + n = TEST_noinit|TEST_INVERT; + else if (streq(p, "noise")) + n = TEST_nonoise|TEST_INVERT; + else if (streq(p, "proto")) + n = TEST_noproto|TEST_INVERT; + else if (*p >= '0' && *p <= '9') + n = strtoul(p, NiL, 0); + else + { + error(1, "%s: unknown test", p); + break; + } + if (n & TEST_INVERT) + { + n &= ~TEST_INVERT; + op = !op; + } + if (op) + pp.test |= n; + else + pp.test &= ~n; + p = s; + debug((-4, "test = 0%o", pp.test)); + } + break; + case PP_TRANSITION: + set(&pp.state, STRICT, 0); + pp.flags &= ~PP_strict; + set(&pp.state, TRANSITION, va_arg(ap, int)); + if (pp.state & TRANSITION) + pp.flags |= PP_transition; + else + pp.flags &= ~PP_transition; + break; + case PP_TRUNCATE: + if (pp.initialized) + goto before; + if ((op = va_arg(ap, int)) < 0) + op = 0; + set(&pp.option, TRUNCATE, op); + if (pp.option & TRUNCATE) + { + Hash_bucket_t* b; + Hash_bucket_t* p; + Hash_position_t* pos; + Hash_table_t* tab; + + pp.truncate = op; + tab = pp.symtab; + pp.symtab = hashalloc(NiL, HASH_set, tab ? HASH_ALLOCATE : 0, HASH_compare, trunccomp, HASH_hash, trunchash, HASH_name, "truncate", 0); + if (tab && (pos = hashscan(tab, 0))) + { + if (p = hashnext(pos)) + do + { + b = hashnext(pos); + hashlook(pp.symtab, (char*)p, HASH_BUCKET|HASH_INSTALL, NiL); + } while (p = b); + hashdone(pos); + } + } + else + pp.truncate = 0; + break; + case PP_VENDOR: + p = va_arg(ap, char*); + c = va_arg(ap, int) != 0; + if (!p || !*p) + for (dp = pp.firstdir; dp; dp = dp->next) + dp->type &= ~TYPE_VENDOR; + else if (streq(p, "-")) + { + for (dp = pp.firstdir; dp; dp = dp->next) + if (c) + dp->type |= TYPE_VENDOR; + else + dp->type &= ~TYPE_VENDOR; + } + else if (!stat((pathcanon(p, 0), p), &st)) + { + c = 0; + for (dp = pp.firstdir; dp; dp = dp->next) + { + if (!c && ((dp->type & TYPE_VENDOR) || dp->name && SAMEID(&dp->id, &st))) + c = 1; + if (c) + dp->type |= TYPE_VENDOR; + else + dp->type &= ~TYPE_VENDOR; + } + } + break; + case PP_WARN: + set(&pp.state, WARN, va_arg(ap, int)); + break; + before: + error(3, "ppop(%d): preprocessor operation must be done before PP_INIT", op); + break; + default: + error(3, "ppop(%d): invalid preprocessor operation", op); + break; + } + va_end(ap); +} diff --git a/usr/src/lib/libpp/common/pppragma.c b/usr/src/lib/libpp/common/pppragma.c new file mode 100644 index 0000000000..875a17e5eb --- /dev/null +++ b/usr/src/lib/libpp/common/pppragma.c @@ -0,0 +1,66 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * common preprocessor pragma handler + */ + +#include "pplib.h" + +void +pppragma(char* directive, char* pass, char* name, char* value, int newline) +{ + register int sep = 0; + + ppsync(); + if (directive) + { + ppprintf("#%s", directive); + sep = 1; + } + if (pass) + { + if (sep) + { + sep = 0; + ppprintf(" "); + } + ppprintf("%s:", pass); + } + if (name) + { + if (sep) + ppprintf(" "); + else + sep = 1; + ppprintf("%s", name); + } + if (value) + { + if (sep || pass) + ppprintf(" "); + ppprintf("%s", value); + } + if (newline) + ppprintf("\n"); +} diff --git a/usr/src/lib/libpp/common/ppprintf.c b/usr/src/lib/libpp/common/ppprintf.c new file mode 100644 index 0000000000..b8c6c77a07 --- /dev/null +++ b/usr/src/lib/libpp/common/ppprintf.c @@ -0,0 +1,45 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor printf using ppputchar() buffering + */ + +#include "pplib.h" + +int +ppprintf(char* format, ...) +{ + va_list ap; + Sfio_t* sp; + + if (!(sp = sfnew(NiL, pp.outp, MAXTOKEN, -1, SF_WRITE|SF_STRING))) + error(3, "temporary buffer allocation error"); + va_start(ap, format); + sfvprintf(sp, format, ap); + va_end(ap); + pp.outp += sfseek(sp, 0L, SEEK_CUR); + ppcheckout(); + sfclose(sp); + return 0; +} diff --git a/usr/src/lib/libpp/common/ppproto.c b/usr/src/lib/libpp/common/ppproto.c new file mode 100644 index 0000000000..f03b2535bc --- /dev/null +++ b/usr/src/lib/libpp/common/ppproto.c @@ -0,0 +1,2549 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * convert C prototypes to ANSI, K&R and C++ styles or K&R to ANSI + * slips into the pp block read + * + * define PROTOMAIN for standalone proto + * PROTOMAIN is coded for minimal library support + */ + +static const char id[] = "\n@(#)$Id: proto (AT&T Research) 2006-06-28 $\0\n"; + +#if PROTOMAIN + +#include "ppfsm.c" + +#include <hashkey.h> + +#if PROTO_STANDALONE +#undef O_RDONLY +#endif + +#else + +#include "pplib.h" +#include "ppfsm.h" + +#endif + +#define MAGICGEN "/* : : generated by proto : : */\n" + +#define MAGICDIR "pragma" /* proto magic directive */ +#define MAGICARG "prototyped" /* proto magic directive arg */ +#define MAGICOFF "noticed" /* no notice if found in pragma */ +#define MAGICTOP 64 /* must be in these top lines */ +#define NOTICED "Copyright" /* no notice if found in magic */ + +struct proto /* proto buffer state */ +{ + int brace; /* {..} level */ + int call; /* call level */ + int fd; /* input file descriptor */ + char* file; /* input file name */ + long flags; /* coupled flags */ + long options; /* uncoupled flags */ + char* package; /* header package */ + int line; /* input line count */ + int test; /* testing */ + + char* tp; /* input token base */ + + int iz; /* input buffer size */ + char* ib; /* input buffer base */ + char* ip; /* input buffer pointer */ + + int oz; /* output buffer size */ + char* ob; /* output buffer base */ + char* op; /* output buffer pointer */ + char* ox; /* output buffer externalize */ + + char cc[3]; /* beg mid end comment char */ + char pushback[4]; /* pushback area for caller */ + + char variadic[256]; /* variadic args buffer */ + + /* output buffer */ + /* slide buffer */ + /* input buffer */ +}; + +/* + * proto is separate from pp so these undef's are ok + */ + +#undef CLASSIC +#define CLASSIC (1L<<0) +#undef DECLARE +#define DECLARE (1L<<1) +#undef DEFINE +#define DEFINE (1L<<2) +#undef DIRECTIVE +#define DIRECTIVE (1L<<3) +#undef ERROR +#define ERROR (1L<<4) +#undef EXTERN +#define EXTERN (1L<<5) +#undef EXTERNALIZE +#define EXTERNALIZE (1L<<6) +#undef IDID +#define IDID (1L<<7) +#undef INDIRECT +#define INDIRECT (1L<<8) +#undef INIT +#define INIT (1L<<9) +#undef INIT_DEFINE +#define INIT_DEFINE (1L<<10) +#undef INIT_INCLUDE +#define INIT_INCLUDE (1L<<11) +#undef JUNK +#define JUNK (1L<<12) +#undef LINESYNC +#define LINESYNC (1L<<13) +#undef MANGLE +#define MANGLE (1L<<14) +#undef MATCH +#define MATCH (1L<<15) +#undef MORE +#define MORE (1L<<16) +#undef OTHER +#define OTHER (1L<<17) +#undef PASS +#define PASS (1L<<18) +#undef PLUSONLY +#define PLUSONLY (1L<<19) +#undef PLUSPLUS +#define PLUSPLUS (1L<<20) +#undef RECURSIVE +#define RECURSIVE (1L<<21) +#undef SHARP +#define SHARP (1L<<22) +#undef SKIP +#define SKIP (1L<<23) +#undef SLIDE +#define SLIDE (1L<<24) +#undef TOKENS +#define TOKENS (1L<<25) +#undef TYPEDEF +#define TYPEDEF (1L<<26) +#undef VARIADIC +#define VARIADIC (1L<<27) +#undef VARIADIC2 +#define VARIADIC2 (1L<<28) +#undef YACC +#define YACC (1L<<29) +#undef YACCSPLIT +#define YACCSPLIT (1L<<30) +#undef YACC2 +#define YACC2 (1L<<31) + +#undef GLOBAL +#define GLOBAL (MORE) + +#undef REGULAR +#define REGULAR (1L<<0) + +#ifndef CHUNK +#define CHUNK 1024 +#endif +#define BLOCK (8*CHUNK) + +#define T_VA_START (N_TOKEN+1) + +#define RESERVED(b,e,n) ((((long)(b))<<16)|(((long)(e))<<8)|((long)(n))) + +/* + * generate integer + * pointer to end returned + */ + +static char* +number(register char* p, register long n) +{ + register long d; + + for (d = 1000000; d > 1; d /= 10) + if (n >= d) *p++ = '0' + (n / d) % 10; + *p++ = '0' + n % 10; + return p; +} + +#if PROTOMAIN + +static int errors; + +#if PROTO_STANDALONE + +/* + * namespace pollution forces us to claim parts of libc + */ + +#undef memcpy +#define memcpy(t,f,n) memcopy(t,f,n) +#undef strcpy +#define strcpy(t,f) strcopy(t,f) +#undef strlen +#define strlen(s) sstrlen(s) +#undef strncmp +#define strncmp(s,t,n) sstrncmp(s,t,n) + +/* + * environmentally safe strlen() + */ + +static int +sstrlen(register const char* s) +{ + register const char* b; + + for (b = s; *s; s++); + return s - b; +} + +/* + * environmentally safe strncmp() + */ + +static int +sstrncmp(register const char* s, register char* t, register int n) +{ + register const char* e = s + n; + + while (s < e) + { + if (*s != *t || !*s) + return *s - *t; + s++; + t++; + } + return 0; +} + +/* + * strcpy() except pointer to end returned + */ + +static char* +strcopy(register char* s, register const char* t) +{ + while (*s++ = *t++); + return s - 1; +} + +#endif + +static void +proto_error(char* iob, int level, char* msg, char* arg) +{ + register char* p; + char buf[1024]; + + p = strcopy(buf, "proto: "); + if (iob) + { + register struct proto* proto = (struct proto*)(iob - sizeof(struct proto)); + + if (proto->line) + { + if (proto->file) + { + *p++ = '"'; + p = strcopy(p, proto->file); + *p++ = '"'; + *p++ = ','; + *p++ = ' '; + } + p = strcopy(p, "line "); + p = number(p, proto->line); + } + else if (proto->file) + p = strcopy(p, proto->file); + } + else + { + p = strcopy(p, msg); + msg = arg; + arg = 0; + } + if (*(p - 1) != ' ') + { + *p++ = ':'; + *p++ = ' '; + } + if (level == 1) + p = strcopy(p, "warning: "); + p = strcopy(p, msg); + if (arg) + { + *p++ = ' '; + p = strcopy(p, arg); + } + *p++ = '\n'; + write(2, buf, p - buf); + if (level >= 3) + exit(level - 2); + if (level >= 2) + errors++; +} + +/* + * memcpy() but pointer to end returned + */ + +static char* +memcopy(register char* s, register char* t, int n) +{ + register char* e = t + n; + + while (t < e) *s++ = *t++; + return s; +} + +#include "../libast/port/astlicense.c" + +#else + +#define memcopy(s,t,n) (((char*)memcpy(s,t,n))+(n)) + +#endif + +/* + * generate line sync + * pointer to end returned + */ + +static char* +linesync(register struct proto* proto, register char* p, register long n) +{ +#if PROTOMAIN + if (proto->flags & LINESYNC) +#endif + { +#if PROTOMAIN + p = strcopy(p, "\n#line "); +#else + p = strcopy(p, "\n# "); +#endif + p = number(p, n); + *p++ = '\n'; + } + return p; +} + +/* + * output init header + * pointer to end returned + */ + +static char* +init(struct proto* proto, char* op, int flags) +{ + register char* s; + + if (flags & INIT_DEFINE) + { + op = strcopy(op, "\ +\n\ +#if !defined(__PROTO__)\n\ +# if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)\n\ +# if defined(__cplusplus)\n\ +# define __LINKAGE__ \"C\"\n\ +# else\n\ +# define __LINKAGE__\n\ +# endif\n\ +# define __STDARG__\n\ +# define __PROTO__(x) x\n\ +# define __OTORP__(x)\n\ +# define __PARAM__(n,o) n\n\ +# if !defined(__STDC__) && !defined(__cplusplus)\n\ +# if !defined(c_plusplus)\n\ +# define const\n\ +# endif\n\ +# define signed\n\ +# define void int\n\ +# define volatile\n\ +# define __V_ char\n\ +# else\n\ +# define __V_ void\n\ +# endif\n\ +# else\n\ +# define __PROTO__(x) ()\n\ +# define __OTORP__(x) x\n\ +# define __PARAM__(n,o) o\n\ +# define __LINKAGE__\n\ +# define __V_ char\n\ +# define const\n\ +# define signed\n\ +# define void int\n\ +# define volatile\n\ +# endif\n\ +# define __MANGLE__ __LINKAGE__\n\ +# if defined(__cplusplus) || defined(c_plusplus)\n\ +# define __VARARG__ ...\n\ +# else\n\ +# define __VARARG__\n\ +# endif\n\ +# if defined(__STDARG__)\n\ +# define __VA_START__(p,a) va_start(p,a)\n\ +# else\n\ +# define __VA_START__(p,a) va_start(p)\n\ +# endif\n\ +# if !defined(__INLINE__)\n\ +# if defined(__cplusplus)\n\ +# define __INLINE__ extern __MANGLE__ inline\n\ +# else\n\ +# if defined(_WIN32) && !defined(__GNUC__)\n\ +# define __INLINE__ __inline\n\ +# endif\n\ +# endif\n\ +# endif\n\ +#endif\n\ +#if !defined(__LINKAGE__)\n\ +#define __LINKAGE__ /* 2004-08-11 transition */\n\ +#endif\n\ +"); + } + else + op = strcopy(op, "\ +\n\ +#if !defined(__PROTO__)\n\ +#include <prototyped.h>\n\ +#endif\n\ +#if !defined(__LINKAGE__)\n\ +#define __LINKAGE__ /* 2004-08-11 transition */\n\ +#endif\n\ +"); + if (proto->package) + { + s = "\ +#ifndef __MANGLE_%_DATA__\n\ +# ifdef _BLD_%\n\ +# ifdef __EXPORT__\n\ +# define __MANGLE_%_DATA__ __MANGLE__ __EXPORT__\n\ +# else\n\ +# define __MANGLE_%_DATA__ __MANGLE__\n\ +# endif\n\ +# define __MANGLE_%_FUNC__ __MANGLE__\n\ +# else\n\ +# ifdef __IMPORT__\n\ +# define __MANGLE_%_DATA__ __MANGLE__ __IMPORT__\n\ +# else\n\ +# define __MANGLE_%_DATA__ __MANGLE__\n\ +# endif\n\ +# define __MANGLE_%_FUNC__ __MANGLE__\n\ +# endif\n\ +#endif\n\ +"; + for (;;) + { + switch (*op++ = *s++) + { + case 0: + op--; + break; + case '%': + op = strcopy(op - 1, proto->package); + continue; + default: + continue; + } + break; + } + } + return op; +} + +#define BACKOUT() (op=ko) +#define CACHE() do{CACHEIN();CACHEOUT();call=proto->call;}while(0) +#define CACHEIN() (ip=proto->ip) +#define CACHEOUT() (op=proto->op) +#define GETCHR() (*(unsigned char*)ip++) +#define KEEPOUT() (ko=op) +#define LASTOUT() (*(op-1)) +#define PUTCHR(c) (*op++=(c)) +#define SYNC() do{SYNCIN();SYNCOUT();proto->flags&=~(EXTERN|INIT|OTHER|VARIADIC|VARIADIC2);proto->flags|=flags&(EXTERN|INIT|OTHER|VARIADIC|VARIADIC2);proto->call=call;}while(0) +#define SYNCIN() (proto->ip=ip) +#define SYNCOUT() (proto->op=op) +#define UNGETCHR() (ip--) +#define UNPUTCHR() (op--) + +/* + * advance to the next non-space character + */ + +static char* +nns(register char* s) +{ + while (*s == ' ' || *s == '\t' || *s == '\n') + s++; + return s; +} + +#define DIR_if 01 +#define DIR_el 02 +#define DIR_en 03 +#define DIR 03 + +/* + * update directive mask + */ + +static int +directive(register char* s, int dir) +{ + switch (*(s = nns(s))) + { + case 'e': + case 'i': + dir <<= 2; + switch (*++s) + { + case 'f': + dir |= DIR_if; + break; + case 'l': + dir |= DIR_el; + break; + case 'n': + dir |= DIR_en; + break; + } + break; + } + return dir; +} + +/* + * the tokenizer + * top level calls loop until EOB + * recursive calls just return the next token + */ + +static int +lex(register struct proto* proto, register long flags) +{ + register char* ip; + register char* op; + register int c; + register int state; + register short* rp; + char* m; + char* e; + char* t; + char* bp; + char* v; + char* im; + char* ko; + char* aom; + int n; + int line; + int quot; + int brack; + int sub; + int x; + int vc; + + char* ie = 0; + char* om = 0; + char* aim = 0; + char* aie = 0; + char* func = 0; + int call = 0; + int dir = 0; + int group = 0; + int last = 0; + int paren = 0; +#if PROTOMAIN + char* qe = 0; + int qn = 0; + int args = 0; +#endif + + CACHE(); +#if PROTOMAIN + if (flags & EXTERN) KEEPOUT(); +#endif + fsm_start: + proto->tp = ip; + state = PROTO; + bp = ip; + do + { + rp = fsm[state]; + fsm_get: + while (!(state = rp[c = GETCHR()])); + fsm_next: + ; + } while (state > 0); + if ((n = ip - bp - 1) > 0) + { + ip = bp; + MEMCPY(op, ip, n); + ip++; + } + state = ~state; + fsm_terminal: + switch (TERM(state)) + { + case S_CHR: + if (op > proto->ob && *(op - 1) == '=' && (op == proto->ob + 1 || *(op - 2) != '=')) switch (c) + { + case '+': + case '-': + case '*': + case '&': + PUTCHR(' '); + break; + } + PUTCHR(c); + break; + + case S_CHRB: + UNGETCHR(); + c = LASTOUT(); + break; + + case S_COMMENT: + switch (c) + { + case '\n': + if (INCOMMENTXX(rp)) goto fsm_newline; + PUTCHR(c); + proto->line++; + rp = fsm[COM2]; + break; + case '/': +#if PROTOMAIN + if ((flags & (EXTERN|MATCH)) == EXTERN) BACKOUT(); + else +#endif + PUTCHR(c); + if (INCOMMENTXX(rp)) + { + rp = fsm[COM5]; + break; + } + goto fsm_start; + case EOF: + break; + default: +#if PROTOMAIN + if ((flags & (EXTERN|MATCH)) == EXTERN) BACKOUT(); + else +#endif + PUTCHR(c); + rp = fsm[INCOMMENTXX(rp) ? COM5 : COM3]; + break; + } + bp = ip; + goto fsm_get; + + case S_EOB: + if (c) + { + if (state = fsm[TERMINAL][INDEX(rp)+1]) + goto fsm_terminal; + SYNC(); + return 0; + } + UNGETCHR(); + fsm_eob: + if ((flags & (DECLARE|GLOBAL|RECURSIVE)) == GLOBAL && (proto->flags & MORE)) + { +#if PROTOMAIN + if (!(flags & EXTERN)) /* XXX */ +#endif + flags |= SLIDE; + c = ip - proto->ib; + if (!(flags & MATCH)) + im = proto->tp; + if (ip > proto->ib) + { + n = ip - im; + if (ip - n < proto->ib) + proto->flags |= ERROR; + memcopy(proto->ib - n, ip - n, n); + ip = proto->ib; + } + proto->tp -= c; + if (flags & MATCH) + { + im -= c; + ie -= c; + } + if (aim) + aim -= c; + if (aie) + aie -= c; + if ((n = read(proto->fd, ip, proto->iz)) > 0) + { + if ((proto->options & REGULAR) && n < proto->iz) + { + proto->flags &= ~MORE; + close(proto->fd); + } + *(ip + n) = 0; + if (state & SPLICE) + goto fsm_splice; + bp = ip; + goto fsm_get; + } + *ip = 0; + proto->flags &= ~MORE; + close(proto->fd); + } + if (state & SPLICE) + goto fsm_splice; + /* NOTE: RECURSIVE lex() should really SLIDE too */ + if (!(flags & RECURSIVE) && (state = rp[c = EOF])) + { + bp = ip; + goto fsm_next; + } + SYNC(); + return 0; + + case S_LITBEG: + quot = c; +#if PROTOMAIN + if (c == '"' && qe) + { + for (n = 0, t = qe + 1; t < op && (*t == ' ' || *t == '\t' || *t == '\n' && ++n || *t >= 'A' && *t <= 'Z' || *t == '_'); t++); + if (t == op) + { + op = qe; + qe = 0; + qn = n; + } + else PUTCHR(c); + } + else +#endif + PUTCHR(c); + rp = fsm[LIT1]; + bp = ip; + goto fsm_get; + + case S_LITEND: + if (c == quot) + { +#if PROTOMAIN + if (!(flags & DIRECTIVE)) + qe = (c == '"') ? op : (char*)0; +#endif + PUTCHR(c); +#if PROTOMAIN + while (qn > 0) + { + qn--; + PUTCHR('\n'); + } +#endif + } + else if (c != '\n' && c != EOF) + { + PUTCHR(c); + bp = ip; + goto fsm_get; + } + else + { +#if PROTOMAIN + while (qn > 0) + { + qn--; + PUTCHR('\n'); + } +#endif + UNGETCHR(); + } + c = T_INVALID; + break; + + case S_LITESC: +#if PROTOMAIN + if (flags & CLASSIC) PUTCHR(c); + else +#endif + switch (c) + { + case 'a': + n = CC_bel; + goto fsm_oct; + case 'E': + n = CC_esc; + goto fsm_oct; + case 'v': + n = CC_vt; + goto fsm_oct; + case 'x': + SYNC(); + lex(proto, (flags & GLOBAL) | RECURSIVE); + for (n = x = 0; (c = GETCHR()), x < 3; x++) switch (c) + { + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': + n = (n << 4) + c - '0'; + break; + case 'a': case 'b': case 'c': case 'd': + case 'e': case 'f': + n = (n << 4) + c - 'a' + 10; + break; + case 'A': case 'B': case 'C': case 'D': + case 'E': case 'F': + n = (n << 4) + c - 'A' + 10; + break; + default: + goto fsm_hex; + } + fsm_hex: + UNGETCHR(); + fsm_oct: + PUTCHR(((n >> 6) & 07) + '0'); + PUTCHR(((n >> 3) & 07) + '0'); + PUTCHR((n & 07) + '0'); + break; + default: + PUTCHR(c); + break; + } + rp = fsm[LIT1]; + bp = ip; + goto fsm_get; + + case S_MACRO: + UNGETCHR(); +#if PROTOMAIN + if ((flags & EXTERN) && *proto->tp == 's' && !strncmp(proto->tp, "static", 6)) + { + c = T_EXTERN; + break; + } +#endif + if (*proto->tp == '_' && !strncmp(proto->tp, "__STDPP__directive", 6)) c = '#'; + else c = T_ID; + + break; + + case S_NL: + fsm_newline: + proto->line++; +#if PROTOMAIN + if (flags & EXTERN) + { + if (op != proto->ob && LASTOUT() != ' ' && LASTOUT() != '\n') + PUTCHR(' '); + } + else +#endif + PUTCHR(c); + if (flags & DIRECTIVE) + { +#if PROTOMAIN + if (flags & CLASSIC) + { + if (flags & EXTERN) BACKOUT(); + if (flags & JUNK) + { + *(ip - 1) = 0; + op = strcopy(om, "/* "); + op = strcopy(op, im); + op = strcopy(op, " */\n"); + } + flags &= ~(DEFINE|DIRECTIVE|IDID|INDIRECT|JUNK|MATCH|SHARP|TYPEDEF); + } + else +#endif + { + if ((flags & (DEFINE|SHARP)) == (DEFINE|SHARP)) + { + *(ip - 1) = 0; + op = strcopy(om, "#if defined(__STDC__) || defined(__STDPP__)\n"); + op = strcopy(op, im); + op = strcopy(op, "\n#else\n"); + bp = ip; + ip = im; + *op++ = *ip++; + while (*op = *ip++) + if (*op++ == '#' && *ip != '(') + { + op--; + while (*--op == ' ' || *op == '\t'); + if (*ip == '#') + { + op = strcopy(op + 1, "/**/"); + while (*++ip == ' ' || *ip == '\t'); + } + else + { + if (*op != '"') *++op = '"'; + op++; + while (*ip == ' ' || *ip == '\t') ip++; + while ((c = *ip) >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c >= '0' && c <= '9' || c == '_') *op++ = *ip++; + while (*ip == ' ' || *ip == '\t') ip++; + if (*ip == '"') ip++; + else *op++ = '"'; + } + } + ip = bp; + op = strcopy(op, "\n#endif\n"); + op = linesync(proto, op, proto->line); + } + flags &= ~(DEFINE|DIRECTIVE|IDID|INDIRECT|MATCH|OTHER|SHARP|SKIP|TOKENS|TYPEDEF); + } + call = 0; + group = 0; + paren = 0; + last = '\n'; + } + if (paren == 0 && (flags & (MATCH|RECURSIVE|SKIP|SLIDE)) == SLIDE) + { +#if PROTOMAIN + if (flags & EXTERN) BACKOUT(); +#endif + SYNC(); + return 0; + } + goto fsm_start; + + case S_QUAL: + PUTCHR(c); + rp = fsm[NEXT(state)]; + bp = ip; + goto fsm_get; + + case S_TOK: + PUTCHR(c); + c = TYPE(state); + break; + + case S_TOKB: + UNGETCHR(); + c = TYPE(state); + break; + + case S_RESERVED: + UNGETCHR(); + c = T_ID; + if (!(flags & DECLARE)) switch (RESERVED(*proto->tp, *(ip - 1), ip - proto->tp)) + { + case RESERVED('N', 'N', 3): + if (proto->tp[1] == 'o') + c = T_DO; + break; + case RESERVED('d', 'o', 2): + c = T_DO; + break; + case RESERVED('e', 'e', 4): + if (!(flags & RECURSIVE) && (flags & (DIRECTIVE|TOKENS)) != DIRECTIVE && !strncmp(proto->tp, "else", 4)) + { + c = T_ELSE; + goto fsm_id; + } + break; + case RESERVED('e', 'n', 6): + if (!strncmp(proto->tp, "extern", 6)) + c = T_EXTERN; + break; + case RESERVED('f', 'r', 3): + if (!(flags & RECURSIVE) && !strncmp(proto->tp, "for", 3)) + { + c = T_FOR; + goto fsm_id; + } + break; + case RESERVED('i', 'f', 2): + c = T_IF; + break; + case RESERVED('i', 'e', 6): + if (!strncmp(proto->tp, "inline", 6) && !(flags & (MATCH|SKIP|TOKENS|TYPEDEF)) && proto->brace == 0 && paren == 0 && group == 0 && (last == ';' || last == '}' || last == '\n' || last == 0)) + { + flags |= SKIP; + SYNC(); + line = proto->line; + op = strcopy(op - 6, "__INLINE__"); + SYNC(); + } + break; + case RESERVED('r', 'n', 6): + if (!(flags & RECURSIVE) && !strncmp(proto->tp, "return", 6)) + { + c = T_RETURN; + goto fsm_id; + } + break; + case RESERVED('s', 'c', 6): + if ((proto->options & EXTERNALIZE) && !strncmp(proto->tp, "static", 6)) + { + proto->ox = op - 6; + flags |= EXTERNALIZE; + } + break; + case RESERVED('t', 'f', 7): + if (!(flags & RECURSIVE) && !strncmp(proto->tp, "typedef", 7)) + { + flags |= TYPEDEF; + c = T_EXTERN; + } + break; + case RESERVED('v', 't', 8): + if (*ip == '(' && !strncmp(proto->tp, "va_start", 8)) c = T_VA_START; + break; + case RESERVED('v', 'd', 4): + if (!strncmp(proto->tp, "void", 4)) + { + if (flags & (CLASSIC|PLUSONLY|INIT_DEFINE|INIT_INCLUDE)) c = T_VOID; + else + { + SYNC(); + line = proto->line; + if (lex(proto, (flags & GLOBAL) | RECURSIVE) == '*') + { + memcopy(op - 4, "__V_", 4); + memcopy(ip - 4, "__V_", 4); + } + else c = T_VOID; + proto->line = line; + SYNC(); + bp = ip; + } + } + break; + case RESERVED('w', 'e', 5): + if (!(flags & RECURSIVE) && !strncmp(proto->tp, "while", 5)) + { + c = T_WHILE; + goto fsm_id; + } + break; + } +#if PROTOMAIN + if ((flags & CLASSIC) && c != T_EXTERN) + c = T_ID; +#endif + break; + + case S_VS: + goto fsm_start; + + case S_WS: + UNGETCHR(); +#if PROTOMAIN + if ((flags & (EXTERN|MATCH)) == EXTERN) + { + while (op > proto->ob && (*(op - 1) == ' ' || *(op - 1) == '\t')) + op--; + if (op > proto->ob && *(op - 1) != '\n') *op++ = ' '; + } +#endif + goto fsm_start; + + default: + if (state & SPLICE) + { + if (c == '\\') + { + if (!(n = GETCHR())) + { + goto fsm_eob; + fsm_splice: + c = '\\'; + n = GETCHR(); + } + if (n == '\n') + { + proto->line++; + PUTCHR('\\'); + PUTCHR('\n'); + bp = ip; + goto fsm_get; + } + UNGETCHR(); + } + state &= ~SPLICE; + if (state >= TERMINAL) + goto fsm_terminal; + rp = fsm[state]; + } + PUTCHR(c); + bp = ip; + goto fsm_get; + } + if (!(flags & (INIT_DEFINE|INIT_INCLUDE|RECURSIVE))) + { + if (!(flags & DIRECTIVE)) switch (c) + { + case '(': +#if PROTOMAIN + if (!(flags & CLASSIC) || proto->brace == 0) +#endif + { + if (paren++ == 0) + { +#if PROTOMAIN + if (!(flags & CLASSIC) || group <= 1) +#endif + { +#if PROTOMAIN + args = 0; +#endif + if (group++ == 0) group++; + else if (flags & INDIRECT) call++; + flags |= MATCH; + im = ip - 1; + om = op - 1; + } + sub = 0; + } + else if (paren == 2 && !aim) + { + sub++; + if (last == '(') + { + flags &= ~MATCH; + om = 0; + } + else if (flags & INDIRECT) + { + aim = ip - 1; + aom = op - 1; + } + else if ((flags & (MATCH|TOKENS)) == MATCH) + { + for (m = ip - 2; m > im && (*m == ' ' || *m == '\t'); m--); + if (m != im && sub == 1) + { + m = im + (*nns(ip) == '*'); + } + if (m == im) + { + flags &= ~MATCH; + om = 0; + } + } + else if ((flags & MATCH) && sub == 1 && *nns(ip) != '*') + { + flags &= ~MATCH; + om = 0; + } + } + flags &= ~TOKENS; + } + break; + case ')': +#if PROTOMAIN + if (!(flags & CLASSIC) || proto->brace == 0) +#endif + if (--paren == 0) + { +#if PROTOMAIN + if (flags & CLASSIC) + { + if (group != 2) + { + c = T_ID; + break; + } + group++; + } +#endif + ie = ip; + } + else if (paren == 1 && (flags & INDIRECT) && !aie) + aie = ip; + break; + case '*': + if (last == '(' && group == 2) + { + group--; + if (paren == 1) + { + flags |= INDIRECT; + aim = aie = 0; + } + } + break; + case '#': + dir = directive(ip, dir); + if (proto->brace == 0 && paren == 0 && last != '=' && (flags & (CLASSIC|DECLARE|DIRECTIVE|MATCH|PLUSONLY|SKIP|TOKENS)) == (MATCH|TOKENS) && ((dir & DIR) != DIR_en || ((dir>>2) & DIR) != DIR_if)) + flags |= DIRECTIVE; + else if (!(flags & (DECLARE|DIRECTIVE))) + { + flags |= DIRECTIVE; + if (!(flags & PLUSONLY)) + { + bp = ip; + while (*ip == ' ' || *ip == '\t') ip++; + if (*ip == 'l' && *++ip == 'i' && *++ip == 'n' && *++ip == 'e') + { + if (*++ip == ' ' || *ip == '\t') + { + proto->line = 0; + while (*++ip >= '0' && *ip <= '9') + proto->line = proto->line * 10 + *ip - '0'; + proto->line--; + } + } +#if PROTOMAIN + else if ((flags & (CLASSIC|EXTERN)) == CLASSIC) + { + n = 0; + t = ip + 6; + while (ip < t && *ip >= 'a' && *ip <= 'z') + n = HASHKEYPART(n, *ip++); + switch (n) + { + case HASHKEY4('e','l','s','e'): + case HASHKEY5('e','n','d','i','f'): + while (*ip == ' ' || *ip == '\t') ip++; + if (*ip != '\n' && *ip != '/' && *(ip + 1) != '*') + { + flags |= JUNK|MATCH; + im = ip; + om = op + (ip - bp); + } + break; + case HASHKEY4('e','l','i','f'): + case HASHKEY5('e','r','r','o','r'): + case HASHKEY2('i','f'): + case HASHKEY5('i','f','d','e','f'): + case HASHKEY6('i','f','n','d','e','f'): + case HASHKEY5('u','n','d','e','f'): + break; + case HASHKEY6('i','n','c','l','u','d'): + if (*ip == 'e') ip++; + /*FALLTHROUGH*/ + case HASHKEY6('d','e','f','i','n','e'): + case HASHKEY6('p','r','a','g','m','a'): + if (*ip < 'a' || *ip > 'z') break; + /*FALLTHROUGH*/ + default: + flags |= JUNK|MATCH; + im = bp - 1; + om = op - 1; + break; + } + } + else +#endif + { + if (*ip == 'i' && *++ip == 'n' && *++ip == 'c' && *++ip == 'l' && *++ip == 'u' && *++ip == 'd' && *++ip == 'e') + { + while (*++ip == ' ' || *ip == '\t'); + if (*ip++ == '<' && *ip++ == 's' && *ip++ == 't' && *ip++ == 'd' && *ip++ == 'a' && *ip++ == 'r' && *ip++ == 'g' && *ip++ == '.' && *ip++ == 'h' && *ip++ == '>') + { + op = strcopy(op, "\ +if !defined(va_start)\n\ +#if defined(__STDARG__)\n\ +#include <stdarg.h>\n\ +#else\n\ +#include <varargs.h>\n\ +#endif\n\ +#endif\n\ +"); + op = linesync(proto, op, proto->line); + break; + } + } + else if (*ip == 'd' && *++ip == 'e' && *++ ip == 'f' && *++ip == 'i' && *++ip == 'n' && *++ip == 'e' && (*++ip == ' ' || *ip == '\t')) + { + while (*++ip == ' ' || *ip == '\t'); + if (*ip == 'e' && *++ip == 'x' && *++ ip == 't' && *++ip == 'e' && *++ip == 'r' && *++ip == 'n' && (*++ip == ' ' || *ip == '\t')) + { + t = ip; + while (*++t == ' ' || *t == '\t'); + if (*t == 'e' && *++t == 'x' && *++ t == 't' && *++t == 'e' && *++t == 'r' && *++t == 'n' && (*++t == ' ' || *t == '\t' || *t == '\n' || *t == '\r')) + ip = t; + t = ip; + while (*++t == ' ' || *t == '\t'); + if (*t == '_' && *(t + 1) == '_') + { + op = strcopy(op, "undef __MANGLE__\n"); + op = linesync(proto, op, proto->line); + op = strcopy(op, "#define __MANGLE__ __LINKAGE__"); + break; + } + } + flags |= DEFINE|MATCH; + im = bp - 1; + om = op - 1; + } + else if (*ip == 'u' && *++ip == 'n' && *++ ip == 'd' && *++ip == 'e' && *++ip == 'f' && (*++ip == ' ' || *ip == '\t')) + { + while (*++ip == ' ' || *ip == '\t'); + if (*ip == 'e' && *++ip == 'x' && *++ ip == 't' && *++ip == 'e' && *++ip == 'r' && *++ip == 'n' && (*++ip == ' ' || *ip == '\t' || *ip == '\n' || *ip == '\r')) + { + op = strcopy(op, "undef __MANGLE__\n"); + op = linesync(proto, op, proto->line); + op = strcopy(op, "#define __MANGLE__ __LINKAGE__"); + break; + } + flags |= DEFINE|MATCH; + im = bp - 1; + om = op - 1; + } + } + ip = bp; + } + break; + } + else + break; + /*FALLTHROUGH*/ + case '{': + if (proto->brace++ == 0 && paren == 0) + { + if (last == '=') flags |= INIT; +#if PROTOMAIN + else if (flags & CLASSIC) + { + if ((flags & (MATCH|OTHER|SKIP)) == MATCH) + { + if (args) + { + v = number(op, args < 0 ? -args : args); + v = strcopy(v, " argument actual/formal mismatch"); + *v++ = ' '; + v = memcopy(v, im, ie - im); + *v = 0; + proto_error((char*)proto + sizeof(struct proto), 2, op, NiL); + } + ip--; + /*UNDENT...*/ + v = ie; + while (ie < ip) + if (*ie++ == '/' && *ie == '*') + { + e = ie - 1; + while (++ie < ip) + { + if (*ie == '*') + { + while (ie < ip && *ie == '*') ie++; + if (ie < ip && *ie == '/') + { + while (++ie < ip && (*ie == ' ' || *ie == '\t')); + while (e > v && (*(e - 1) == ' ' || *(e - 1) == '\t')) e--; + if (e > v && *e != '\n') *e++ = ' '; + t = ie; + while (--e >= v) + *--t = *e; + v = t; + break; + } + } + } + } + ie = v; + /*...INDENT*/ + op = om++; + if (flags & EXTERN) + { + v = op; + while (v > ko && *--v != ' '); + if (*v != ' ') + { + om = (v = (op += 4)) + 1; + while (v >= ko + 4) + { + *v = *(v - 4); + v--; + } + memcopy(ko, "int ", 4); + } + if (*v == ' ') + { + while (*(v + 1) == '*') + *v++ = '*'; + *v = '\t'; + if ((v - ko) <= 8) + { + om = (e = ++op) + 1; + while (e > v) + { + *e = *(e - 1); + e--; + } + } + } + om = (v = (op += 7)) + 1; + while (v >= ko + 7) + { + *v = *(v - 7); + v--; + } + memcopy(ko, "extern ", 7); + } + PUTCHR('('); + t = op; + e = 0; + /*UNDENT...*/ + while (ie < ip) + { + if ((c = *ie) == ' ' || c == '\t' || c == '\n') + { + while ((c = *++ie) == ' ' || c == '\t' || c == '\n'); + if (ie >= ip) break; + if (c != '*' && op > om) PUTCHR(' '); + } + if ((n = ((c = *ie) == ',')) || c == ';') + { + if (flags & EXTERN) + { + m = op; + while (op > om && ((c = *(op - 1)) == '(' || c == ')' || c == '[' || c == ']')) + op--; + v = op; + while (op > om && (c = *(op - 1)) != ' ' && c != '*') + op--; + while (*(op - 1) == ' ') + op--; + if (!e) + { + e = op; + while (e > om && *(e - 1) == '*') + e--; + } +#if _s5r4_386_compiler_bug_fixed_ + if (op <= om || *(op - 1) == ',' && (*op++ = ' ')) + op = strcopy(op, "int"); +#else + if (op <= om) + op = strcopy(op, "int"); + else if (*(op - 1) == ',') + op = strcopy(op, " int"); +#endif + while (v < m) + PUTCHR(*v++); + } + PUTCHR(','); + if (n) + { + if (x = !e) e = op - 1; + PUTCHR(' '); + m = t; + while (m < e) + PUTCHR(*m++); + if (x) + { + m = e; + while (*--e != ' '); + while (*(e - 1) == '*') e--; + op -= m - e; + } + } + while ((c = *++ie) == ' ' || c == '\t' || c == '\n'); + if (ie >= ip) UNPUTCHR(); + else PUTCHR(' '); + if (!n) + { + t = op; + e = 0; + } + } + else if (*ie == '*') + { + if (op > om && (c = *(op - 1)) == ' ') op--; + while (*ie == '*') PUTCHR(*ie++); + while (*ie == ' ' || *ie == '\t' || *ie == '\n') ie++; + if (c != '(') PUTCHR(' '); + } + else if (*ie == '(') + { + if (op > om && *(op - 1) == ' ') op--; + PUTCHR(*ie++); + while (*ie == ' ' || *ie == '\t' || *ie == '\n') ie++; + } + else if (*ie == ')') + { + if (op > om && *(op - 1) == '(') + proto_error((char*)proto + sizeof(struct proto), 1, "function pointer argument prototype omitted", NiL); + PUTCHR(*ie++); + while (*ie == ' ' || *ie == '\t' || *ie == '\n') ie++; + } + else if ((flags & EXTERN) && (op == om || *(op - 1) == ' ') && *ie == 'r' && !strncmp(ie, "register", 8) && (*(ie + 8) == ' ' || *(ie + 8) == '\t' || *(ie + 8) == '\n')) + { + ie += 8; + if (op > om) UNPUTCHR(); + } + else PUTCHR(*ie++); + } + /*...INDENT*/ + if (op <= om) op = strcopy(op, "void"); + PUTCHR(')'); + if (flags & EXTERN) + { + PUTCHR(';'); + PUTCHR('\n'); + SYNCOUT(); + KEEPOUT(); + } + else + { + PUTCHR('\n'); + PUTCHR(*ip); + } + ip++; + flags &= ~(MATCH|SKIP); + } + } +#endif + else if ((flags & (MATCH|PLUSONLY|SKIP|TOKENS)) == (MATCH|TOKENS)) + { + line = proto->line; + op = strcopy(om, " __PARAM__("); + op = memcopy(op, im, ie - im); + PUTCHR(','); + PUTCHR(' '); + PUTCHR('('); + flags &= ~(MATCH|SKIP); + if (flags & VARIADIC) + { + if ((vc = ie - im + 1) > sizeof(proto->variadic)) vc = sizeof(proto->variadic); + memcopy(proto->variadic, im, vc); + op = strcopy(op, "va_alist)) __OTORP__(va_dcl)\n{"); + } + else + { + flags |= SKIP; + proto->ip = im; + proto->op = op; + group = 0; + brack = 0; + for (;;) + { + switch (lex(proto, (flags & GLOBAL) | RECURSIVE)) + { + case '[': + brack++; + continue; + case ']': + brack--; + continue; + case '(': + if (paren++) group++; + continue; + case ')': + if (--paren == 0) + { + group = 0; + if (flags & MATCH) + { + flags &= ~(MATCH|SKIP); + op = memcopy(op, m, e - m); + } + break; + } + continue; + case ',': + if (paren == 1) + { + group = 0; + if (flags & MATCH) + { + flags &= ~(MATCH|SKIP); + op = memcopy(op, m, e - m); + } + PUTCHR(','); + PUTCHR(' '); + proto->op = op; + } + continue; + case T_ID: + if (group <= 1 && !brack) + { + flags |= MATCH; + m = proto->tp; + e = proto->ip; + } + continue; + default: + continue; + } + break; + } + PUTCHR(')'); + PUTCHR(')'); + } + if (!(flags & SKIP)) + { + flags |= SKIP; + proto->op = strcopy(op, " __OTORP__("); + proto->ip = im + 1; + n = *(ie - 1); + *(ie - 1) = ';'; + c = *ie; + *ie = 0; + lex(proto, (flags & GLOBAL) | DECLARE); + *(ie - 1) = n; + *ie = c; + proto->ip = ie; + op = proto->op; + PUTCHR(')'); + } + if (flags & EXTERNALIZE) memcpy(proto->ox, "extern", 6); + op = linesync(proto, op, proto->line = line); + if (flags & DIRECTIVE) + { + proto->brace = 0; + PUTCHR('\n'); + PUTCHR('#'); + } + else if (!(flags & VARIADIC)) PUTCHR('{'); + } + } + flags &= ~(IDID|INDIRECT|MATCH|OTHER|SKIP); + call = 0; + group = 0; + break; + case '}': + flags &= ~(IDID|INDIRECT|MATCH|OTHER|SKIP|TOKENS); + if (--proto->brace == 0) + { + flags &= ~(INIT|VARIADIC|VARIADIC2); +#if PROTOMAIN + if (flags & EXTERN) BACKOUT(); +#endif + } + call = 0; + group = 0; + paren = 0; + break; + case '=': + if (last == '?') flags |= DIRECTIVE; + else if (paren == 0 && (flags & (INIT|MATCH|SKIP)) == MATCH) goto fsm_statement; + goto fsm_other; + case ',': +#if PROTOMAIN + if (flags & CLASSIC) + { + if (paren == 1) args++; + else + { + args--; + flags &= ~MATCH; + } + break; + } +#endif + if (paren == 0 && (flags & DECLARE)) *(op - 1) = c = ';'; + /*FALLTHROUGH*/ + case ';': + fsm_statement: + if (flags & INIT) /* ignore */; +#if PROTOMAIN + else if (flags & CLASSIC) + { + if (paren == 0) + { + if ((flags & MATCH) && last == ')') + flags &= ~MATCH; + if (!(flags & MATCH)) + { + call = 0; + group = 0; + flags &= ~SKIP; + if (flags & EXTERN) BACKOUT(); + if (flags & SLIDE) + { + SYNC(); + return 0; + } + } + else + { + args--; + if ((flags & (EXTERN|SKIP)) == (EXTERN|SKIP)) + BACKOUT(); + } + } + } +#endif + else if (paren == 0) + { + if ((flags & (MATCH|OTHER|SKIP)) == MATCH && call > 1) + { + if ((flags & MANGLE) && func) + { + func[0] = 'F'; + func[1] = 'U'; + func[2] = 'N'; + func[3] = 'C'; + func = 0; + } + if ((flags & (DECLARE|INDIRECT)) == INDIRECT && aim && aie < im) + { + while (aie < ip && (*aie == ' ' || *aie == '\t' || *aie == '\n')) aie++; + v = aim; + while (v < aie) + if (*v++ == ')') break; + while (v < aie && (*v == ' ' || *v == '\t' || *v == '\n')) v++; + if (v == aie || !(flags & PLUSPLUS)) + { + if (flags & PLUSPLUS) n = 3; + else if (v == aie && *v == '(') n = 10; + else n = 11; + ko = op; + om += n; + v = op += n; + while (v >= ko + n) + { + *v = *(v - n); + v--; + } + if (flags & PLUSPLUS) memcopy(aom, "(...))", 6); + else if (n == 10) memcopy(aom, "(__VARARG__))", 13); + else + { + ko = strcopy(aom, " __PROTO__("); + ko = memcopy(ko, aim, aie - aim); + *ko = ')'; + if (++ko >= om) + { + *ko++ = ')'; + om = ko; + } + } + } + } + else if (flags & TYPEDEF) + { + op = om; + while (*--op == ' ' || *op == '\t' || *op == '\n'); + if (*op != ')') + { + op = om += 14; + *--op = ')'; + while ((x = *(op - 14)) >= 'A' && x <= 'Z' || x >= 'a' && x <= 'z' || x >= '0' && x <= '9' || x == '_') + *--op = x; + memcopy(op - 13, "(__OTORP__(*)", 13); + } + } + if (flags & OTHER) + ; + else if (flags & PLUSPLUS) + { + op = om; + if (!(flags & TOKENS)) op = strcopy(op, "(...)"); + else op = memcopy(op, im, ie - im); + PUTCHR(c); + } + else + { + if (flags & DECLARE) op = strcopy(om, "()"); + else if (!(flags & TOKENS)) op = strcopy(om, "(__VARARG__)"); + else + { + op = strcopy(om, " __PROTO__("); + op = memcopy(op, im, ie - im); + PUTCHR(')'); + } + if (flags & EXTERNALIZE) memcpy(proto->ox, "extern", 6); + PUTCHR(c); + } + flags &= ~(MATCH|VARIADIC|VARIADIC2); + if (c == ',' && !(flags & INDIRECT)) + { + call = 1; + group = 0; + break; + } + } + else if (flags & (OTHER|SKIP)) call = 0; + if (c == ';') + { + flags &= ~(EXTERNALIZE|MANGLE|TOKENS|TYPEDEF); + call = 0; + if (flags & SLIDE) + { + SYNC(); + return 0; + } + } + else call = call > 1 && c == ','; + group = 0; + flags &= ~(IDID|INDIRECT|MATCH|OTHER|SKIP); + } + else if (paren == 1 && group == 1 && !(flags & (IDID|MANGLE))) flags |= TOKENS|OTHER; + break; + case T_DO: + case T_IF: + flags |= TOKENS|SKIP; + break; + case T_EXTERN: +#if PROTOMAIN + if (flags & CLASSIC) + { + if (proto->brace == 0) + flags |= SKIP; + } + else +#endif + if (paren == 0 && !(flags & TYPEDEF)) + { + flags |= MANGLE; + if (!(flags & PLUSONLY) || proto->package) + { + op = strcopy(op, " __MANGLE__"); + if (proto->package) + { + op = strcopy(op - 1, proto->package); + func = op + 1; + op = strcopy(op, "_DATA__"); + } + } + else + func = 0; + } + break; + case T_VARIADIC: + if (paren == 0 && (flags & (DECLARE|VARIADIC)) == DECLARE) + { + op -= 3; + SYNC(); + return c; + } + if (paren == 1 && !(flags & SKIP)) + flags |= VARIADIC; + flags |= TOKENS; + break; + case T_VOID: + goto fsm_id; + case T_VA_START: + if ((flags & (PLUSONLY|VARIADIC)) == VARIADIC) + { + flags &= ~MATCH; + line = proto->line; + op = strcopy(op - 8, "__VA_START__"); + SYNC(); + for (;;) + { + switch (lex(proto, (flags & GLOBAL) | RECURSIVE)) + { + case 0: + case ';': + break; + case T_ID: + if (!(flags & MATCH)) + { + flags |= MATCH; + m = proto->tp; + e = proto->ip; + } + continue; + default: + continue; + } + break; + } + CACHE(); + if (flags & MATCH) + { + v = m; + n = e - m; + } + else + { + v = "ap"; + n = 2; + } + op = strcopy(op, " __OTORP__("); + proto->ip = proto->variadic; + proto->op = op; + flags &= ~MATCH; + group = 0; + bp = proto->ip + 1; + if (*bp == 'r' && !strncmp(bp, "register", 8) && (*(bp + 8) == ' ' || *(bp + 8) == '\t')) bp += 9; + for (;;) + { + switch (lex(proto, (flags & GLOBAL) | RECURSIVE)) + { + case '(': + if (paren++) group++; + continue; + case ')': + if (--paren == 0) + { + if (flags & MATCH) + { + flags &= ~MATCH; + if (!(flags & VARIADIC2)) + { + op = memcopy(op, m, e - m); + op = strcopy(op, " = "); + } + op = strcopy(op, "va_arg("); + op = memcopy(op, v, n); + PUTCHR(','); + PUTCHR(' '); + if (m > bp) op = memcopy(op, bp, m - bp); + else op = strcopy(op, "int "); + if (group > 1) op = strcopy(op, ")()"); + else op = memcopy(op, e, proto->ip - e - 1); + PUTCHR(')'); + PUTCHR(';'); + } + group = 0; + break; + } + continue; + case ',': + if (paren == 1) + { + if (flags & MATCH) + { + flags &= ~MATCH; + if (!(flags & VARIADIC2)) + { + op = memcopy(op, m, e - m); + op = strcopy(op, " = "); + } + op = strcopy(op, "va_arg("); + op = memcopy(op, v, n); + PUTCHR(','); + PUTCHR(' '); + if (m > bp) op = memcopy(op, bp, m - bp); + else op = strcopy(op, "int "); + if (group > 1) op = strcopy(op, ")()"); + else op = memcopy(op, e, proto->ip - e - 1); + PUTCHR(')'); + PUTCHR(';'); + bp = proto->ip + 1; + if (*bp == 'r' && !strncmp(bp, "register", 8) && (*(bp + 8) == ' ' || *(bp + 8) == '\t')) bp += 9; + } + group = 0; + proto->op = op; + } + continue; + case T_ID: + if (group <= 1) + { + flags |= MATCH; + m = proto->tp; + e = proto->ip; + } + continue; + default: + continue; + } + break; + } + op = strcopy(op, ")"); + flags |= VARIADIC2; + proto->line = line; + call = 0; + break; + } + /*FALLTHROUGH*/ + case T_ID: + fsm_id: +#if PROTOMAIN + if (flags & CLASSIC) + { + if (!args && paren == 1) args++; + break; + } +#endif + if (paren == 0) + { + if (last == ')') + { + if (proto->brace == 0 && !(flags & DECLARE)) flags |= SKIP; + call = !call; + } + else if ((flags & SKIP) || c == T_ID || c == T_VOID) call++; + else flags |= SKIP; + if (last == T_ID) flags |= IDID; + } + c = T_ID; + flags |= TOKENS; + break; + case T_INVALID: + if (*proto->tp >= '0' && *proto->tp <= '9') + { + n = 0; + for (;; op--) + { + switch (*(op - 1)) + { + case 'f': + case 'F': + t = op; + while ((c = *--t) >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'); + if (*t == '.') + op--; + n = 0; + break; + case 'l': + case 'L': + if (!(n & 01)) + { + n |= 01; + t = op; + while ((c = *--t) >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'); + if (*t == '.') + { + n = 0; + op--; + break; + } + } + continue; + case 'u': + case 'U': + n |= 02; + continue; + } + break; + } + if (n & 01) + *op++ = 'L'; + if (n & 02) + { + m = op; + t = op = m + 10; + while ((c = *--m) >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z') + *--t = c; + c = *t; + strcopy(m + 1, "(unsigned)"); + *t = c; + break; + } + } + goto fsm_other; +#if PROTOMAIN + case '[': + if ((flags & CLASSIC) && paren == 0 && group <= 2) flags |= SKIP; + /*FALLTHROUGH*/ +#endif + default: + fsm_other: +#if PROTOMAIN + if (flags & CLASSIC) break; +#endif + flags |= TOKENS; + if (paren == 0) flags |= OTHER; + break; + } + else if (c == '#' && *ip != '(') flags |= SHARP; + last = c; +#if PROTOMAIN + if ((flags & (EXTERN|MATCH)) == (EXTERN|MATCH) && ((flags & (DIRECTIVE|SKIP)) || proto->brace || c != '(' && c != ')' && c != '*' && c != T_ID)) + CACHEOUT(); + else +#endif + SYNCOUT(); + goto fsm_start; + } + else if (flags & (INIT_DEFINE|INIT_INCLUDE)) + { +#if PROTOMAIN + if ((flags & YACC) && c == '%' && *ip == '{') t = 0; + else +#endif + { + if (c == '#') for (t = ip; *t == ' ' || *t == '\t'; t++); + else t = ""; + if (*t++ == 'i' && *t++ == 'f' && *t++ == 'n' && *t++ == 'd' && *t++ == 'e' && *t++ == 'f') + { +#if !PROTOMAIN + while (*t == ' ' || *t == '\t') t++; + if (*t != '_') +#endif + t = 0; + } + } + if (t) + { + ip = bp; + op = proto->op; + } + else while (*ip != '\n') *op++ = *ip++; + op = init(proto, op, flags); + op = linesync(proto, op, proto->line); + flags &= ~(INIT_DEFINE|INIT_INCLUDE); + proto->flags &= ~(INIT_DEFINE|INIT_INCLUDE); + goto fsm_start; + } + SYNC(); + return c; +} + +/* + * close a proto buffer stream + */ + +void +pppclose(char* iob) +{ + register struct proto* proto = (struct proto*)(iob - sizeof(struct proto)); + + if (proto->flags & MORE) close(proto->fd); + free((char*)proto); /* some ANSI cc's botch the free() prototype */ +} + +/* + * open a new proto buffer stream + * read buffer pointer returned + * 0 returned on error or if no magic + * + * file !=0 file path to open, otherwise use fd + * fd open file fd if file==0 + * notice !=0 copyright notice info commented at the top + * options !=0 additional notice name=value pairs, space or ; separated + * package !=0 generate header for this package + */ + +char* +pppopen(char* file, int fd, char* notice, char* options, char* package, char* comment, int flags) +{ + register struct proto* proto; + register char* iob; + register long n; + register char* s; + int pragma; + char* b; +#if PROTOMAIN + int comlen; + char com[80]; +#endif + int m = 0; + + static int retain; + + /* + * initialize proto + */ + +#if PROTOMAIN + if (flags & PROTO_CLASSIC) flags &= ~PROTO_INCLUDE; +#endif + if (flags & PROTO_RETAIN) flags &= ~retain; + else retain &= PROTO_INITIALIZED; + if (file && (fd = open(file, O_RDONLY)) < 0) return 0; +#if !PROTOMAIN + if ((n = lseek(fd, 0L, 2)) > 0) + { + if (lseek(fd, 0L, 0)) return 0; + if (n < CHUNK) n = CHUNK; + else if (n > 2 * BLOCK) n = 0; + m = 1; + } + if (n > 0) + { + /* + * file read in one chunk + */ + + if (!(proto = newof(0, struct proto, 1, 4 * n + 2))) + return 0; + proto->iz = n; + proto->oz = 3 * n; + n = 0; + } + else +#endif + { + /* + * file read in BLOCK chunks + */ + + n = BLOCK; + if (!(proto = newof(0, struct proto, 1, 5 * n + 2))) + return 0; + proto->iz = n; + proto->oz = 3 * n; + proto->flags |= MORE; + } + proto->fd = fd; + proto->package = package; + iob = (char*)proto + sizeof(struct proto); + proto->op = proto->ob = iob; + proto->ip = proto->ib = iob + proto->oz + n; + if (m) proto->options |= REGULAR; + if (!comment) + comment = "/*"; + if (!(proto->cc[0] = comment[0])) + notice = options = 0; + else if (comment[1]) + { + proto->cc[1] = comment[1]; + proto->cc[2] = comment[2] ? comment[2] : comment[0]; + } + else + proto->cc[1] = proto->cc[2] = comment[0]; + + /* + * read the first chunk + */ + + n = read(fd, proto->ip, proto->iz); + if (!(proto->flags & MORE)) + close(fd); + if (n < 0) + { + pppclose(iob); + return 0; + } + *(proto->ip + n) = 0; + + /* + * check for proto pragma in first block of lines + * pragma blanked out if found + * + * -1 no pragma + * 0 #pragma noprototyped + * 1 #pragma prototyped + * + * NOTE: matches may occur inside comments and quotes + */ + +#if PROTOMAIN + if (!notice && !options || (comlen = astlicense(com, sizeof(com), NiL, "type=check", proto->cc[0], proto->cc[1], proto->cc[2])) <= 0) + *com = 0; +#endif + pragma = -1; + s = proto->ip; + m = MAGICTOP; + while (m-- > 0 && *s) + { + while (*s == ' ' || *s == '\t') s++; + if (*s == '#') + { + b = s++; + while (*s == ' ' || *s == '\t') s++; + if (!strncmp(s, MAGICDIR, sizeof(MAGICDIR) - 1) && (*(s += sizeof(MAGICDIR) - 1) == ' ' || *s == '\t')) + { + while (*s == ' ' || *s == '\t') s++; + if (*s == 'n' && *(s + 1) == 'o') + { + s += 2; + pragma = -2; + } + if (!strncmp(s, MAGICARG, sizeof(MAGICARG) - 1) && (*(s += sizeof(MAGICARG) - 1) == ' ' || *s == '\t' || *s == '\n' || *s == '\r')) + while (*s) + { + if ((*(s - 1) == ' ' || *(s - 1) == '\t') && *s == *MAGICOFF && !strncmp(s, MAGICOFF, sizeof(MAGICOFF) - 1)) + notice = options = 0; + if (*s++ == '\n') + { + pragma += 2; +#if PROTOMAIN + if (!(flags & PROTO_DISABLE) || (flags & PROTO_NOPRAGMA)) +#endif + for (s--; b < s; *b++ = ' '); + goto magic; + } + } + pragma = -1; + } + } + else if (*s == '/' && !strncmp(s, MAGICGEN, sizeof(MAGICGEN) - 1)) + { + pragma = 0; + break; + } +#if PROTOMAIN + else if (*s == '%' && *(s + 1) == '{') + proto->flags |= YACC; + if (notice || options) + { + if (*s == *com && !strncmp(s, com, comlen)) + notice = options = 0; + else + while (*s) + { + if (*s == *NOTICED && !strncmp(s, NOTICED, sizeof(NOTICED) - 1)) + { + s += sizeof(NOTICED) - 1; + while (*s == ' ' || *s == '\t') + s++; + if (*s == '(' && (*(s + 1) == 'c' || *(s + 1) == 'C') && *(s + 2) == ')' || *s >= '0' && *s <= '9' && *(s + 1) >= '0' && *(s + 1) <= '9') + { + notice = options = 0; + break; + } + } + else if (*s++ == '\n') + { + s--; + break; + } + } + } +#endif + while (*s && *s++ != '\n'); + } + magic: + if (flags & PROTO_PLUSPLUS) proto->flags |= PLUSPLUS; + if (flags & PROTO_TEST) proto->test = 1; + if (flags & PROTO_EXTERNALIZE) proto->options |= EXTERNALIZE; +#if PROTOMAIN + if (flags & PROTO_CLASSIC) pragma = -pragma; + if (flags & PROTO_DISABLE) pragma = 0; + if (flags & PROTO_LINESYNC) proto->flags |= LINESYNC; + if (!(proto->flags & YACC) && file && (m = strlen(file)) > 2 && file[--m] == 'y' && file[--m] == '.') + proto->flags |= YACC; +#endif + if (pragma <= 0) + { + if (flags & PROTO_PLUSPLUS) + { + flags &= ~(PROTO_HEADER|PROTO_INCLUDE); + proto->flags |= PLUSONLY; + } + else if (!(flags & (PROTO_FORCE|PROTO_PASS))) + { + pppclose(iob); + return 0; + } + else if ((flags & (PROTO_FORCE|PROTO_PASS)) == PROTO_PASS || !pragma) + { + proto->flags |= PASS; + if (proto->flags & MORE) + proto->oz += proto->iz; + proto->iz = n; + if (notice || options) + { + if (proto->cc[0] == '#' && proto->ip[0] == '#' && proto->ip[1] == '!') + { + s = proto->ip; + while (*s && *s++ != '\n'); + m = s - proto->ip; + proto->op = memcopy(proto->op, proto->ip, m); + proto->ip = s; + proto->iz = n -= m; + } +#if PROTOMAIN + if (proto->cc[0]) + { + if ((comlen = astlicense(proto->op, proto->oz, notice, options, proto->cc[0], proto->cc[1], proto->cc[2])) < 0) + proto_error((char*)proto + sizeof(struct proto), 1, proto->op, NiL); + else + proto->op += comlen; + } + if (!(flags & PROTO_CLASSIC) && !(proto->flags & YACC)) +#endif + proto->op = linesync(proto, proto->op, 1); + proto->iz += proto->op - proto->ob; + } + memcopy(proto->op, proto->ip, n); + return iob; + } + } +#if PROTOMAIN + if (!(retain & PROTO_INITIALIZED)) + { + retain |= PROTO_INITIALIZED; + ppfsm(FSM_INIT, NiL); + } +#endif + proto->line = 1; +#if CHUNK >= 512 + if (notice || options || (flags & (PROTO_HEADER|PROTO_INCLUDE))) + { +#if PROTOMAIN + if (notice || options) + { + if ((comlen = astlicense(proto->op, proto->oz, notice, options, proto->cc[0], proto->cc[1], proto->cc[2])) < 0) + proto_error((char*)proto + sizeof(struct proto), 1, proto->op, NiL); + else + proto->op += comlen; + } +#endif + if (flags & PROTO_INCLUDE) + { + proto->flags |= INIT_INCLUDE; + if (flags & PROTO_RETAIN) + retain |= PROTO_INCLUDE; + } + else if (flags & PROTO_HEADER) + { + if (flags & PROTO_RETAIN) retain |= PROTO_HEADER; +#if PROTOMAIN + if (flags & PROTO_CLASSIC) + { + *proto->op++ = '#'; + proto->op = strcopy(proto->op, MAGICDIR); + *proto->op++ = ' '; + proto->op = strcopy(proto->op, MAGICARG); + *proto->op++ = '\n'; + } + else +#endif + proto->flags |= INIT_DEFINE; + } +#if PROTOMAIN + if (!(flags & PROTO_CLASSIC)) + { + if (proto->flags & YACC) + { + proto->op = strcopy(proto->op, "\n%{\n" + !notice); + proto->op = strcopy(proto->op, MAGICGEN); + proto->op = strcopy(proto->op, "%}\n"); + } + else + { + if (n || notice || options) + *proto->op++ = '\n'; + proto->op = strcopy(proto->op, MAGICGEN); + if (n) + proto->op = linesync(proto, proto->op, proto->line); + else if (proto->flags & (INIT_DEFINE|INIT_INCLUDE)) + proto->op = init(proto, proto->op, proto->flags); + } + } +#endif + } +#endif +#if PROTOMAIN + proto->file = file; + if (flags & PROTO_CLASSIC) + { + proto->flags |= CLASSIC; + if (!(flags & PROTO_HEADER)) proto->flags |= EXTERN; + } +#endif + return iob; +} + +/* + * read next proto'd chunk into iob + * the chunk is 0 terminated and its size is returned + */ + +int +pppread(char* iob) +{ + register struct proto* proto = (struct proto*)(iob - sizeof(struct proto)); + register int n; + + if (proto->flags & PASS) + { + if (proto->iz) + { + n = proto->iz; + proto->iz = 0; + } + else if (!(proto->flags & MORE)) n = 0; + else if ((n = read(proto->fd, proto->ob, proto->oz)) <= 0 || (proto->options & REGULAR) && n < proto->oz) + { + proto->flags &= ~MORE; + close(proto->fd); + } + } + else + { + if (proto->op == proto->ob) + { + if (proto->flags & ERROR) return -1; +#if PROTOMAIN + if (proto->flags & YACC) + { + register char* ip = proto->ip; + register char* op = proto->ob; + register char* ep = proto->ob + proto->oz - 2; + + if (!*ip) + { + ip = proto->ip = proto->ib; + if (!(proto->flags & MORE)) n = 0; + else if ((n = read(proto->fd, ip, proto->iz)) <= 0 || (proto->options & REGULAR) && n < proto->iz) + { + if (n < 0) n = 0; + proto->flags &= ~MORE; + close(proto->fd); + } + ip[n] = 0; + } + if (proto->flags & YACCSPLIT) + { + proto->flags &= ~YACCSPLIT; + if (*ip == '%') + { + *op++ = *ip++; + if (proto->flags & YACC2) proto->flags &= ~YACC; + else proto->flags |= YACC2; + } + } + if (proto->flags & YACC) + while (op < ep && (n = *op++ = *ip)) + { + ip++; + if (n == '%') + { + if (*ip == '%' && (ip == proto->ip + 1 || *(ip - 2) == '\n')) + { + *op++ = *ip++; + if (proto->flags & YACC2) proto->flags &= ~YACC; + else proto->flags |= YACC2; + break; + } + if (!*ip) + { + *op++ = '%'; + proto->flags |= YACCSPLIT; + break; + } + } + else if (n == '\n') proto->line++; + } + proto->op = memcopy(proto->ob, proto->ip, ip - proto->ip); + proto->ip = ip; + } + else +#endif + lex(proto, proto->flags); + if ((proto->flags & (ERROR|MORE)) == ERROR) + proto->op = strcopy(proto->op, "/* NOTE: some constructs may not have been converted */\n"); + } + n = proto->op - proto->ob; + proto->op = proto->ob; + } + return n; +} + +#if !PROTOMAIN + +/* + * drop control of iob after first pppread() + * return value is input fd + * if fd<0 then all data in iob + */ + +int +pppdrop(char* iob) +{ + register struct proto* proto = (struct proto*)(iob - sizeof(struct proto)); + + if (proto->flags & MORE) + { + proto->flags &= ~MORE; + return proto->fd; + } + return -1; +} + +#endif diff --git a/usr/src/lib/libpp/common/ppsearch.c b/usr/src/lib/libpp/common/ppsearch.c new file mode 100644 index 0000000000..f9bf29fe01 --- /dev/null +++ b/usr/src/lib/libpp/common/ppsearch.c @@ -0,0 +1,807 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * include file search support + */ + +#include "pplib.h" + +#define SEARCH_NEXT (SEARCH_USER<<1)/* search for next (uncover) */ +#define SEARCH_SKIP (SEARCH_USER<<2)/* current binding skipped */ +#define SEARCH_TEST (SEARCH_USER<<3)/* test for binding */ +#define SEARCH_FOUND (SEARCH_USER<<4)/* current binding found */ + +#define COLUMN_TAB 7 +#define COLUMN_MAX 72 + +#if ARCHIVE + +#include <vdb.h> +#include <ls.h> + +#endif + +/* + * multiple include test + * fp is a canonicalized ppfile pointer + * + * test + * + * INC_CLEAR can be included again + * INC_TEST test if include required + * <symbol> ifndef guard symbol + * + * test!=INC_CLEAR returns 1 if file can be included again + * + * NOTE: + * + * (1) different hard links to the same file are treated as + * different files + * + * (2) symbolic links in combination with .. may cause two + * different files to be treated as the same file: + * + * "../h/<file>" == "/usr/include/sys/../h/<file>" -> "/usr/include/h/<file>" + * "h/<file>" -> "/usr/include/h/<file>" + */ + +int +ppmultiple(register struct ppfile* fp, register struct ppsymbol* test) +{ + register struct ppsymbol* status; + + status = fp->guard; + message((-3, "search: %s: status=%s%s test=%s", fp->name, status == INC_CLEAR ? "[CLEAR]" : status == INC_TEST ? "[ONCE]" : status == INC_IGNORE ? "[IGNORE]" : status->name, (pp.mode & HOSTED) ? "[HOSTED]" : "", test == INC_CLEAR ? "[CLEAR]" : test == INC_TEST ? "[TEST]" : test->name)); + if (status == INC_IGNORE) + { + message((-2, "%s: ignored [%s]", fp->name, pp.ignore)); + return 0; + } + if (test == INC_TEST) + { + if (status != INC_CLEAR) + { + if (status != INC_TEST && status->macro || !(pp.mode & ALLMULTIPLE) && !(pp.state & STRICT)) + { + if ((pp.mode & (ALLMULTIPLE|LOADING)) == LOADING) + fp->guard = INC_IGNORE; + if (pp.state & WARN) + error(1, "%s: ignored -- already included", fp->name); + else + message((-3, "%s: ignored -- already included", fp->name)); + return 0; + } + return 1; + } + if ((pp.mode & (ALLMULTIPLE|LOADING)) == LOADING) + test = INC_IGNORE; + } + fp->guard = test; + return 1; +} + +/* + * search for file using directories in dp + */ + +static int +search(register struct ppfile* fp, register struct ppdirs* dp, int type, int flags) +{ + register char* prefix; + register struct ppdirs* up; + register struct ppfile* xp; + struct ppfile* mp; + int fd; + int index; + int need; + int markhosted; + char* t; + + if (!(pp.option & PREFIX)) + prefix = 0; + else if ((prefix = strrchr(fp->name, '/')) && prefix > fp->name) + { + *prefix = 0; + t = ppsetfile(fp->name)->name; + *prefix = '/'; + prefix = t; + } + message((-3, "search: %s %s%s%s%s%s%s type=%s prefix=%s flags=|%s%s%s%s%s%s start=%s=\"%s\" pre=%s lcl=%s vnd=%s std=%s cur=%s", + fp->name, + (flags & SEARCH_INCLUDE) ? "include" : "exists", + (flags & SEARCH_VENDOR) ? " vendor" : "", + (flags & SEARCH_HOSTED) ? " hosted" : "", + (flags & SEARCH_NEXT) ? " next" : "", + (flags & SEARCH_SKIP) ? " skip" : "", + (flags & SEARCH_TEST) ? " test" : "", + type == T_HEADER ? "<*>" : "\"*\"", prefix, + (fp->flags & INC_SELF) ? "SELF|" : "", + (fp->flags & INC_EXISTS) ? "EXISTS|" : "", + (fp->flags & INC_BOUND(INC_PREFIX)) ? "PREFIX|" : "", + (fp->flags & INC_BOUND(INC_LOCAL)) ? "LOCAL|" : "", + (fp->flags & INC_BOUND(INC_VENDOR)) ? "VENDOR|" : "", + (fp->flags & INC_BOUND(INC_STANDARD)) ? "STANDARD|" : "", + dp ? (dp->index == INC_PREFIX ? "pre" : dp->index == INC_LOCAL ? "lcl" : dp->index == INC_VENDOR ? "vnd" : "std") : NiL, + dp ? dp->name : NiL, + !(fp->flags & INC_MEMBER(INC_PREFIX)) && (xp = fp->bound[INC_PREFIX]) ? xp->name : NiL, + !(fp->flags & INC_MEMBER(INC_LOCAL)) && (xp = fp->bound[INC_LOCAL]) ? xp->name : NiL, + !(fp->flags & INC_MEMBER(INC_VENDOR)) && (xp = fp->bound[INC_VENDOR]) ? xp->name : NiL, + !(fp->flags & INC_MEMBER(INC_STANDARD)) && (xp = fp->bound[INC_STANDARD]) ? xp->name : NiL, + error_info.file + )); + if (flags & SEARCH_HOSTED) + need = TYPE_HOSTED; + else if (flags & SEARCH_VENDOR) + need = TYPE_VENDOR; + else + need = TYPE_INCLUDE; + for (index = -1; dp; dp = dp->next) + if (dp->type & need) + { + message((-3, "search: fp=%s need=%02x index=%d dp=%s type=%02x index=%d", fp->name, need, index, dp->name, dp->type, dp->index)); +#if ARCHIVE + if (!(dp->type & (TYPE_ARCHIVE|TYPE_DIRECTORY))) + { + struct stat st; + + if (stat(dp->name, &st)) + { + message((-3, "search: omit %s", dp->name)); + dp->type = 0; + continue; + } + if (S_ISREG(st.st_mode)) + { + register char* s; + char* e; + int delimiter; + int variant; + unsigned long siz; + unsigned long off; + struct ppmember* ap; + Sfio_t* sp; + + /* + * check for vdb header archive + */ + + if (!(sp = sfopen(NiL, dp->name, "r"))) + { + error(ERROR_SYSTEM|1, "%s: ignored -- cannot open", dp->name); + dp->type = 0; + continue; + } + variant = sfsprintf(pp.tmpbuf, MAXTOKEN, "%c%s%c%s:archive", VDB_DELIMITER, VDB_MAGIC, VDB_DELIMITER, pp.pass); + if (!(s = sfgetr(sp, '\n', 1)) || !strneq(s, pp.tmpbuf, variant)) + { + sfclose(sp); + error(1, "%s: ignored -- not a directory or archive", dp->name); + dp->type = 0; + continue; + } + + /* + * parse the options + */ + + dp->type |= TYPE_ARCHIVE; + for (s += variant;;) + { + while (*s == ' ') s++; + e = s; + for (t = 0; *s && *s != ' '; s++) + if (*s == '=') + { + *s = 0; + t = s + 1; + } + if (*s) + *s++ = 0; + if (!*e) + break; + switch ((int)hashref(pp.strtab, e)) + { + case X_CHECKPOINT: +#if CHECKPOINT + dp->type |= TYPE_CHECKPOINT; + break; +#else + error(1, "preprocessor not compiled with checkpoint enabled"); + goto notvdb; +#endif + case X_HIDE: + + if (t) + error(1, "%s: %s: archive option value ignored", e); + if (e = strrchr(dp->name, '/')) + *e = 0; + else + dp->name = "."; + break; + case X_MAP: + if (!t) + error(1, "%s: archive option value expected", e); + else + dp->name = strdup(t); + break; + default: + error(1, "%s: unknown archive option", e); + break; + } + } + if (sfseek(sp, -(VDB_LENGTH + 1), SEEK_END) <= 0 || !(s = sfgetr(sp, '\n', 1))) + { + notvdb: + sfclose(sp); + error(1, "%s: ignored -- cannot load archive", dp->name); + dp->type = 0; + continue; + } + if (variant = *s != 0) + s++; + else if (!(s = sfgetr(sp, '\n', 1))) + goto notvdb; + if (sfvalue(sp) != (VDB_LENGTH + variant)) + goto notvdb; + if (!strneq(s, VDB_DIRECTORY, sizeof(VDB_DIRECTORY) - 1)) + goto notvdb; + delimiter = s[VDB_OFFSET - 1]; + off = strtol(s + VDB_OFFSET, NiL, 10) - sizeof(VDB_DIRECTORY); + siz = strtol(s + VDB_SIZE, NiL, 10); + if (sfseek(sp, off, SEEK_SET) != off) + goto notvdb; + if (!(s = sfreserve(sp, siz + 1, 0))) + goto notvdb; + s[siz] = 0; + if (!strneq(s, VDB_DIRECTORY, sizeof(VDB_DIRECTORY)) - 1) + goto notvdb; + if (!(s = strchr(s, '\n'))) + goto notvdb; + s++; + while (e = strchr(s, '\n')) + { + delimiter = variant ? *s++ : delimiter; + if (!(t = strchr(s, delimiter))) + break; + *t = 0; + if (!streq(s, VDB_DIRECTORY)) + { + pathcanon(s, 0); + ap = newof(0, struct ppmember, 1, 0); + ap->archive = dp; + ap->offset = strtol(t + 1, &t, 10); + ap->size = strtol(t + 1, NiL, 10); + xp = ppsetfile(s); + xp->flags |= INC_MEMBER(dp->index); + xp->bound[dp->index] = (struct ppfile*)ap; +if (pp.test & 0x0020) error(1, "VDB#%d %s %s index=%d data=<%lu,%lu>", __LINE__, dp->name, xp->name, index, ap->offset, ap->size); + } + s = e + 1; + } + if (sfseek(sp, 0L, SEEK_SET)) + goto notvdb; + if (!(pp.test & 0x4000) && +#if POOL + (pp.pool.input || !(dp->type & TYPE_CHECKPOINT)) +#else + !(dp->type & TYPE_CHECKPOINT) +#endif + && (dp->info.buffer = sfreserve(sp, off, 0))) + dp->type |= TYPE_BUFFER; + else + { + dp->info.sp = sp; +#if POOL + if (pp.pool.input) + sfset(sp, SF_SHARE, 1); +#endif + } + } + else + dp->type |= TYPE_DIRECTORY; + } +#endif + if (streq(fp->name, ".")) + continue; + if (prefix && *fp->name != '/' && dp->index != INC_PREFIX) +#if ARCHIVE + if (dp->type & TYPE_DIRECTORY) +#endif + { + for (up = dp->info.subdir; up; up = up->next) + if (up->name == prefix) + break; + if (!up) + { + up = newof(0, struct ppdirs, 1, 0); + up->name = prefix; + up->type = dp->type; + up->next = dp->info.subdir; + dp->info.subdir = up; + if (!*dp->name) + t = prefix; + else + sfsprintf(t = pp.path, PATH_MAX - 1, "%s/%s", dp->name, prefix); + if (eaccess(t, X_OK)) + { + message((-3, "search: omit %s", t)); + continue; + } + up->type |= TYPE_HOSTED; + } + else if (!(up->type & TYPE_HOSTED)) + continue; + } + mp = xp = 0; + if (!(flags & SEARCH_NEXT) && index != dp->index && (!(need & TYPE_HOSTED) || dp->index == INC_STANDARD) && (!(need & TYPE_VENDOR) || dp->index == INC_VENDOR)) + { + if (index >= 0 && !(fp->flags & INC_MEMBER(index))) + fp->flags |= INC_BOUND(index); + index = dp->index; + if (fp->flags & INC_BOUND(index)) + { + xp = fp->bound[index]; + if (index == INC_PREFIX) + { + if (*fp->name == '/' || !*dp->name) + strcpy(pp.path, fp->name); + else + sfsprintf(pp.path, PATH_MAX - 1, "%s/%s", dp->name, fp->name); + pathcanon(pp.path, 0); + if (!xp || !streq(xp->name, pp.path)) + { + fp->bound[index] = xp = ppsetfile(pp.path); + if (dp->type & TYPE_HOSTED) + xp->flags |= INC_HOSTED; + if ((flags & SEARCH_INCLUDE) || (xp->flags & INC_EXISTS)) + { + if (!(flags & SEARCH_INCLUDE)) + return 0; + if (!ppmultiple(xp, INC_TEST)) + { + if (flags & SEARCH_TEST) + pp.include = xp->name; + return 0; + } + mp = xp; + } + } + } + else if (!xp) + { + while (dp->next && dp->next->index == index) + dp = dp->next; + message((-3, "search: omit %s/%s", dp->name, fp->name)); + continue; + } + else + { + strcpy(pp.path, xp->name); + if (!(flags & SEARCH_INCLUDE)) + return 0; + if (!ppmultiple(xp, INC_TEST)) + { + if (flags & SEARCH_TEST) + pp.include = xp->name; + return 0; + } + mp = xp; + } + } + } + if (!(fp->flags & INC_BOUND(index)) || (flags & SEARCH_NEXT)) + { + if (*fp->name == '/' || !*dp->name) + strcpy(pp.path, fp->name); + else + sfsprintf(pp.path, PATH_MAX - 1, "%s/%s", dp->name, fp->name); + pathcanon(pp.path, 0); + if (!(flags & SEARCH_SKIP)) + { + int found; + struct ppinstk* in; + + if (streq(error_info.file, pp.path)) + found = 1; + else + { + found = 0; + for (in = pp.in; in; in = in->prev) + if (in->type == IN_FILE && in->file && streq(in->file, pp.path)) + { + found = 1; + break; + } + } + if (found) + { + flags |= SEARCH_FOUND; + continue; + } + if (!(flags & SEARCH_FOUND)) + continue; + } + } + if ((xp || (xp = ppgetfile(pp.path))) && (xp->flags & INC_SELF)) + { + if (xp->flags & INC_EXISTS) + { + if (!(flags & SEARCH_INCLUDE)) + return 0; + if (!(flags & SEARCH_NEXT) && mp != xp && (mp = xp) && !ppmultiple(xp, INC_TEST)) + { + if (flags & SEARCH_TEST) + pp.include = xp->name; + return 0; + } + } + else if (*fp->name == '/') + break; + else + continue; + } + message((-3, "search: file=%s path=%s", fp->name, pp.path)); +#if ARCHIVE +if (pp.test & 0x0040) error(1, "SEARCH#%d dir=%s%s%s%s%s file=%s%s path=%s index=%d", __LINE__, dp->name, (dp->type & TYPE_ARCHIVE) ? " ARCHIVE" : "", (dp->type & TYPE_BUFFER) ? " BUFFER" : "", (dp->type & TYPE_CHECKPOINT) ? " CHECKPOINT" : "", (dp->type & TYPE_DIRECTORY) ? " DIRECTORY" : "", fp->name, (fp->flags & INC_MEMBER(index)) ? " MEMBER" : "", pp.path, index); + if ((fp->flags & INC_MEMBER(index)) && ((struct ppmember*)fp->bound[index])->archive == dp) + { + fd = 0; + pp.member = (struct ppmember*)fp->bound[index]; +if (pp.test & 0x0010) error(1, "SEARCH#%d file=%s path=%s index=%d data=<%lu,%lu>", __LINE__, fp->name, pp.path, index, pp.member->offset, pp.member->size); + } + else if (!(dp->type & TYPE_DIRECTORY)) + continue; + else +#endif + { + pp.member = 0; + fd = (flags & SEARCH_INCLUDE) ? open(pp.path, O_RDONLY) : eaccess(pp.path, R_OK); + } + if (fd >= 0) + { + pp.found = dp; + if ((pp.option & (PLUSPLUS|NOPROTO)) == PLUSPLUS && !(pp.test & TEST_noproto)) + { + if (dp->c) + pp.mode |= MARKC; + else + pp.mode &= ~MARKC; + } + if (xp) + markhosted = xp->flags & INC_HOSTED; + else if (!(markhosted = (dp->type & TYPE_HOSTED)) && dp->index == INC_PREFIX && (pp.mode & (FILEDEPS|HEADERDEPS|INIT)) == FILEDEPS) + { + up = dp; + while ((up = up->next) && !streq(up->name, dp->name)); + if (up && (up->type & TYPE_HOSTED)) + markhosted = 1; + } + if (markhosted) + pp.mode |= MARKHOSTED; + else + pp.mode &= ~MARKHOSTED; + xp = ppsetfile(pp.path); + if (markhosted) + xp->flags |= INC_HOSTED; + message((-2, "search: %s -> %s%s%s", fp->name, pp.path, (pp.mode & MARKC) ? " [C]" : "", (pp.mode & MARKHOSTED) ? " [hosted]" : "")); +#if ARCHIVE + if (!pp.member) + { +#endif + fp->flags |= INC_BOUND(index); + fp->bound[index] = xp; + if ((index == INC_STANDARD || index == INC_VENDOR) && type != T_HEADER && !(fp->flags & INC_BOUND(INC_LOCAL))) + { + fp->flags |= INC_BOUND(INC_LOCAL); + fp->bound[INC_LOCAL] = xp; + } +#if ARCHIVE + } +#endif + xp->flags |= INC_SELF|INC_EXISTS; + if (flags & SEARCH_INCLUDE) + { + if ((pp.prefix = prefix) || (pp.prefix = pp.in->prefix)) + message((-2, "search: %s: prefix=%s", xp->name, pp.prefix)); + if (!(pp.mode & ALLMULTIPLE)) + { + if (xp->guard == INC_CLEAR || xp == mp) + xp->guard = INC_TEST; + else + { + if (pp.state & WARN) + error(1, "%s: ignored -- already included", xp->name); + else + message((-3, "%s: ignored -- already included", xp->name)); + xp->guard = fp->guard = INC_IGNORE; +#if ARCHIVE + if (!pp.member) +#endif + if (fd > 0) + close(fd); + if (flags & SEARCH_TEST) + pp.include = xp->name; + return 0; + } + } + pp.include = xp->name; + if ((pp.mode & (FILEDEPS|INIT)) == FILEDEPS && ((pp.mode & HEADERDEPS) || !(pp.mode & MARKHOSTED)) && !(xp->flags & INC_LISTED)) + { + xp->flags |= INC_LISTED; + if ((pp.column + strlen(xp->name)) >= COLUMN_MAX) + { + sfprintf(pp.filedeps.sp, " \\\n"); + pp.column = COLUMN_TAB; + index = '\t'; + } + else + index = ' '; + pp.column += sfprintf(pp.filedeps.sp, "%c%s", index, xp->name); + } + } + return fd; + } + if (xp) + xp->flags |= INC_SELF; + if (errno == EMFILE) + error(3, "%s: too many open files", fp->name); + else if (errno != ENOENT && errno != ENOTDIR) + error(ERROR_SYSTEM|1, "%s: cannot open file for reading", pp.path); + if (*fp->name == '/') + break; + } + strcpy(pp.path, fp->name); + message((-2, "search: %s%s not found", (flags & SEARCH_NEXT) ? "next " : "", fp->name)); + return -1; +} + +/* + * search for an include file + * if (flags&SEARCH_INCLUDE) then + * if file found then open read file descriptor returned + * with pp.path set to the full path and + * pp.prefix set to the directory prefix + * otherwise 0 returned if file found but ignored + * otherwise -1 returned + * otherwise + * if file found then 0 returned + * otherwise -1 returned + */ + +int +ppsearch(char* file, int type, int flags) +{ + register struct ppfile* fp; + register char* s; + register struct ppdirs* dp; + struct oplist* cp; + struct ppfile* xp; + int dospath; + int fd; + int index; + char name[MAXTOKEN + 1]; + + pp.include = 0; + fd = -1; + dospath = 0; + again: + pathcanon(file, 0); + for (cp = pp.chop; cp; cp = cp->next) + if (strneq(file, cp->value, cp->op)) + { + if (cp->value[cp->op + 1]) + { + sfsprintf(name, sizeof(name) - 1, "%s%s", cp->value + cp->op + 1, file + cp->op); + message((-3, "chop: %s -> %s", file, name)); + file = name; + } + else if (strchr(file + cp->op, '/')) + { + message((-3, "chop: %s -> %s", file, file + cp->op)); + file += cp->op; + } + break; + } + fp = ppsetfile(file); + while ((fp->flags & INC_MAPALL) || (fp->flags & INC_MAPHOSTED) && (pp.mode & HOSTED) || (fp->flags & INC_MAPNOHOSTED) && !(pp.mode & HOSTED)) + { + if (!(xp = fp->bound[type == T_HEADER ? INC_STANDARD : INC_LOCAL]) || xp == fp) + break; + message((-1, "map: %s -> %s", fp->name, xp->name)); + fp = xp; + } + if ((fp->flags & INC_MAPNOLOCAL) && (pp.mode & HOSTED)) + flags |= SEARCH_HOSTED; + else if (pp.vendor) + flags |= SEARCH_VENDOR; + pp.original = fp; + if (type == T_HEADER && strneq(fp->name, "...", 3) && (!fp->name[3] || fp->name[3] == '/')) + { + if (fp->name[3] == '/') + { + int n; + int m; + + n = strlen(error_info.file); + m = strlen(fp->name + 4); + if (n < m || !streq(fp->name + 4, error_info.file + n - m)) + { + if ((fd = ppsearch(fp->name + 4, type, flags|SEARCH_TEST)) < 0) + return -1; + if (fd > 0) + close(fd); + s = error_info.file; + error_info.file = pp.include; + fd = ppsearch(fp->name + 4, type, flags|SEARCH_NEXT); + error_info.file = s; + return fd; + } + file = error_info.file + n - m; + } + else if (file = strrchr(error_info.file, '/')) + file++; + else + file = error_info.file; + flags |= SEARCH_NEXT; +#if _HUH_2002_05_28 + if (pp.in->prefix) + { + sfsprintf(name, sizeof(name) - 1, "%s/%s", pp.in->prefix, file); + fp = ppsetfile(name); + if ((fd = ppsearch(fp->name, type, flags)) >= 0) + return fd; + } +#endif + fp = ppsetfile(file); + return ppsearch(fp->name, type, flags); + } + else if ((flags & SEARCH_INCLUDE) && fp->guard == INC_IGNORE) + { + strcpy(pp.path, fp->name); + message((-2, "%s: ignored", fp->name)); + return 0; + } + else if (!(flags & SEARCH_NEXT)) + flags |= SEARCH_SKIP; + pp.prefix = 0; + if (type == T_HEADER) + dp = pp.stddirs->next; + else + { + dp = pp.lcldirs; + if (dp == pp.firstdir) + { + /* + * look in directory of including file first + */ + + if (error_info.file && (s = strrchr(error_info.file, '/'))) + { + *s = 0; + dp->name = ppsetfile(error_info.file)->name; + *s = '/'; + } + else + dp->name = ""; + } + else if (pp.in->prefix && pp.lcldirs != pp.firstdir) + { + /* + * look in prefix directory of including file first + */ + + if (*fp->name != '/') + { + if ((s = strchr(fp->name, '/')) && (fp->name[0] +!= '.' || fp->name[1] != '.' || fp->name[2] != '/')) + { + *s = 0; + if (!streq(fp->name, pp.in->prefix)) + fd = 0; + *s = '/'; + } + else + fd = 0; + } + if (fd >= 0) + { + sfsprintf(name, sizeof(name) - 1, "%s/%s", pp.in->prefix, fp->name); + pathcanon(name, 0); + xp = ppsetfile(name); + if ((fd = search(xp, dp, type, flags)) >= 0) + return fd; + } + } + } + if ((fd = search(fp, dp, type, flags)) < 0) + { + if ((pp.option & PLUSPLUS) && file != pp.tmpbuf) + { + s = file + strlen(file); + while (s > file && *--s != '/' && *s != '\\' && *s != '.'); + if (*s != '.') + { + sfsprintf(pp.tmpbuf, MAXTOKEN, "%s.h", file); + file = pp.tmpbuf; + goto again; + } + } + + /* + * hackery for msdos files viewed through unix + */ + + switch (dospath) + { + case 0: + if (s = strchr(file, '\\')) + { + do *s++ = '/'; while (s = strchr(s, '\\')); + pathcanon(file, 0); + dospath = 1; + goto again; + } + /*FALLTHROUGH*/ + case 1: + if (ppisid(file[0]) && file[1] == ':' && file[2] == '/') + { + file[1] = file[0]; + file[0] = '/'; + pathcanon(file, 0); + dospath = 2; + goto again; + } + break; + case 2: + file += 2; + goto again; + } + if ((flags & (SEARCH_INCLUDE|SEARCH_NEXT)) == SEARCH_INCLUDE) + { + if (!(pp.mode & GENDEPS)) + { + if (!(pp.option & ALLPOSSIBLE) || pp.in->prev->prev) + error(2, "%s: cannot find include file", file); + } + else if (!(pp.mode & INIT)) + { + xp = ppsetfile(file); + if (!(xp->flags & INC_LISTED)) + { + xp->flags |= INC_LISTED; + if ((pp.column + strlen(file)) >= COLUMN_MAX) + { + sfprintf(pp.filedeps.sp, " \\\n"); + pp.column = COLUMN_TAB; + index = '\t'; + } + else + index = ' '; + pp.column += sfprintf(pp.filedeps.sp, "%c%s", index, file); + } + } + } + } + return fd; +} diff --git a/usr/src/lib/libpp/common/ppsym.c b/usr/src/lib/libpp/common/ppsym.c new file mode 100644 index 0000000000..081f1bcd94 --- /dev/null +++ b/usr/src/lib/libpp/common/ppsym.c @@ -0,0 +1,94 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * cpp predefined symbol detection support + * + * with no args stdin is treated as an a.out for + * a Reiser derived cpp -- all strings that may + * be identifiers are listed on fd 3 (1 if no 3) + * + * with args the -D argument values are listed on fd 3 (1 if no 3) + */ + +#include <ast.h> +#include <ctype.h> + +int +main(int argc, char** argv) +{ + register int state; + register int c; + register char* s; + Sfio_t* out; + + NoP(argc); + if (dup(3) < 0 || !(out = sfnew(NiL, NiL, -1, 3, SF_WRITE))) + out = sfstdout; + if (*++argv) + { + while (s = *argv++) + if (*s++ == '-' && *s++ == 'D' && isalpha(*s)) + { + while (*s && *s != '=') sfputc(out, *s++); + sfputc(out, '\n'); + } + return 0; + } + state = 0; + for (;;) + { + switch (c = sfgetc(sfstdin)) + { + case EOF: + break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': + case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': + case 's': case 't': case 'u': case 'v': case 'w': case 'x': + case 'y': case 'z': case '_': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': + case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': + case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': + state++; + sfputc(out, c); + continue; + case '0': case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + if (state) + { + sfputc(out, c); + continue; + } + /*FALLTHROUGH*/ + default: + if (state) + { + sfputc(out, '\n'); + state = 0; + } + continue; + } + break; + } + return 0; +} diff --git a/usr/src/lib/libpp/common/pptrace.c b/usr/src/lib/libpp/common/pptrace.c new file mode 100644 index 0000000000..d1b1204817 --- /dev/null +++ b/usr/src/lib/libpp/common/pptrace.c @@ -0,0 +1,264 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1986-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * preprocessor library trace and debug support + */ + +#include "pplib.h" +#include "ppfsm.h" + +#include <ctype.h> + +/* + * convert token string to printable form + */ + +char* +pptokstr(register char* s, register int c) +{ + register char* t; + + static char buf[8]; + + if (t = s) + { + while (*t == ' ' || *t == '\t') t++; + c = *t ? *t : *s; + } + switch (c) + { + case 0: + case 0400: + return("`EOF'"); + case ' ': + return("`space'"); + case '\f': + return("`formfeed'"); + case '\n': + return("`newline'"); + case '\t': + return("`tab'"); + case '\v': + return("`vertical-tab'"); + case T_TOKCAT: + return("##"); + default: + if (iscntrl(c) || !isprint(c)) sfsprintf(buf, sizeof(buf), "`%03o'", c); + else if (s) return(s); + else sfsprintf(buf, sizeof(buf), "%c", c); + return(buf); + } +} + +#if DEBUG & TRACE_debug + +#include "ppdebug.h" + +/* + * return input stream name given index + */ + +char* +ppinstr(register struct ppinstk* p) +{ + register int i; + + static char buf[128]; + + for (i = 0; i < elementsof(ppinmap); i++) + if (p->type == ppinmap[i].val) + { + switch (p->type) + { + case IN_MACRO: +#if MACDEF + case IN_MULTILINE: +#endif + if (p->symbol) + { + sfsprintf(buf, sizeof(buf), "%s=%s", ppinmap[i].nam, p->symbol->name); + return(buf); + } + break; + } + return(ppinmap[i].nam); + } + sfsprintf(buf, sizeof(buf), "UNKNOWN[%d]", p->type); + return(buf); +} + +/* + * return string given fsm lex state + */ + +char* +pplexstr(register int lex) +{ + register int i; + int splice; + static char buf[64]; + + if (lex < 0) lex &= ~lex; + splice = (lex & SPLICE); + lex &= 0x7f; + for (i = 0; i < (elementsof(pplexmap) - 1) && (lex > pplexmap[i].val || lex == pplexmap[i+1].val); i++); + if (lex != pplexmap[i].val) + { + if (pplexmap[i].val < 0) sfsprintf(buf, sizeof(buf), "%s|0x%04x%s", pplexmap[i].nam, lex, splice ? "|SPLICE" : ""); + else sfsprintf(buf, sizeof(buf), "%s+%d", pplexmap[i-1].nam, lex - pplexmap[i-1].val, splice ? "|SPLICE" : ""); + return(buf); + } + if (splice) + { + sfsprintf(buf, sizeof(buf), "%s|SPLICE", pplexmap[i].nam); + return(buf); + } + return(pplexmap[i].nam); +} + +/* + * return string given map p of size n and flags + */ + +static char* +ppflagstr(register struct map* p, int n, register long flags) +{ + register int i; + register int k; + register char* s; + + static char buf[128]; + + s = buf; + for (i = 0; i < n; i++) + if (flags & p[i].val) + { + k = strlen(p[i].nam); + if ((elementsof(buf) - 2 - (s - buf)) > k) + { + if (s > buf) *s++ = '|'; + strcpy(s, p[i].nam); + s += k; + } + } + *s = 0; + return(buf); +} + +/* + * return string given pp.mode + */ + +char* +ppmodestr(register long mode) +{ + return(ppflagstr(ppmodemap, elementsof(ppmodemap), mode)); +} + +/* + * return string given pp.option + */ + +char* +ppoptionstr(register long option) +{ + return(ppflagstr(ppoptionmap, elementsof(ppoptionmap), option)); +} + +/* + * return string given pp.state + */ + +char* +ppstatestr(register long state) +{ + return(ppflagstr(ppstatemap, elementsof(ppstatemap), state)); +} + +#include <sig.h> + +/* + * io stream stack trace + * sig==0 registers the handler + */ + +void +pptrace(int sig) +{ + register char* s; + register char* x; + register struct ppinstk* p; + static int handling; + + if (!sig) + { +#ifdef SIGBUS + signal(SIGBUS, pptrace); +#endif +#ifdef SIGSEGV + signal(SIGSEGV, pptrace); +#endif +#ifdef SIGILL + signal(SIGILL, pptrace); +#endif + signal(SIGQUIT, pptrace); + return; + } + s = fmtsignal(sig); + if (handling) + { + sfprintf(sfstderr, "\n%s during io stack trace\n", s); + signal(handling, SIG_DFL); + sigunblock(handling); + kill(getpid(), handling); + pause(); + error(PANIC, "signal not redelivered"); + } + handling = sig; + sfprintf(sfstderr, "\n%s - io stack trace\n", s); + for (p = pp.in; p->prev; p = p->prev) + { + sfprintf(sfstderr, "\n[%s]\n", ppinstr(p)); + if ((s = pp.in->nextchr) && *s) + { + if (*s != '\n') sfputc(sfstderr, '\t'); + x = s + 256; + while (*s && s < x) + { + sfputc(sfstderr, *s); + if (*s++ == '\n' && *s && *s != '\n') sfputc(sfstderr, '\t'); + } + if (*s) sfprintf(sfstderr, " ..."); + } + } + sfprintf(sfstderr, "\n"); + handling = 0; + signal(sig, SIG_DFL); + sigunblock(sig); + kill(getpid(), sig); + pause(); + error(PANIC, "signal not redelivered"); +} + +#endif diff --git a/usr/src/lib/libpp/i386/Makefile b/usr/src/lib/libpp/i386/Makefile new file mode 100644 index 0000000000..f91f0270e9 --- /dev/null +++ b/usr/src/lib/libpp/i386/Makefile @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/libpp/i386/pp.req b/usr/src/lib/libpp/i386/pp.req new file mode 100644 index 0000000000..6c6437695b --- /dev/null +++ b/usr/src/lib/libpp/i386/pp.req @@ -0,0 +1,2 @@ + -lpp + -last diff --git a/usr/src/lib/libpp/i386/pp.yacc b/usr/src/lib/libpp/i386/pp.yacc new file mode 100644 index 0000000000..1de9080a7a --- /dev/null +++ b/usr/src/lib/libpp/i386/pp.yacc @@ -0,0 +1 @@ +%token /*generated from pp.h*/ T_DOUBLE 292 T_DOUBLE_L 293 T_FLOAT 294 T_DECIMAL 288 T_DECIMAL_L 289 T_DECIMAL_U 290 T_DECIMAL_UL 291 T_OCTAL 296 T_OCTAL_L 297 T_OCTAL_U 298 T_OCTAL_UL 299 T_HEXADECIMAL 304 T_HEXADECIMAL_L 305 T_HEXADECIMAL_U 306 T_HEXADECIMAL_UL 307 T_HEXDOUBLE 308 T_HEXDOUBLE_L 309 T_ID 257 T_INVALID 258 T_CHARCONST 260 T_WCHARCONST 261 T_STRING 262 T_WSTRING 263 T_PTRMEM 264 T_ADDADD 265 T_SUBSUB 266 T_LSHIFT 267 T_RSHIFT 268 T_LE 269 T_GE 270 T_EQ 271 T_NE 272 T_ANDAND 273 T_OROR 274 T_MPYEQ 275 T_DIVEQ 276 T_MODEQ 277 T_ADDEQ 278 T_SUBEQ 279 T_LSHIFTEQ 280 T_RSHIFTEQ 281 T_ANDEQ 282 T_XOREQ 283 T_OREQ 284 T_VARIADIC 286 T_DOTREF 320 T_PTRMEMREF 321 T_SCOPE 322 T_UMINUS 323 diff --git a/usr/src/lib/libpp/i386/ppdebug.h b/usr/src/lib/libpp/i386/ppdebug.h new file mode 100644 index 0000000000..9c9f29e795 --- /dev/null +++ b/usr/src/lib/libpp/i386/ppdebug.h @@ -0,0 +1,211 @@ +/* +* preprocessor library debug maps +*/ +struct map +{ + char* nam; + long val; +}; +static struct map pplexmap[] = +{ + "PROTO", PROTO, + "RES1", RES1, + "RES1a", RES1a, + "RES1e", RES1e, + "RES1f", RES1f, + "RES1h", RES1h, + "RES1l", RES1l, + "RES1n", RES1n, + "RES1o", RES1o, + "RES1t", RES1t, + "RES1x", RES1x, + "RES1y", RES1y, + "COM1", COM1, + "COM2", COM2, + "COM3", COM3, + "COM4", COM4, + "COM5", COM5, + "COM6", COM6, + "COM7", COM7, + "NID", NID, + "LIT", LIT, + "LIT1", LIT1, + "LIT2", LIT2, + "BAD1", BAD1, + "BAD2", BAD2, + "DOT", DOT, + "DOT2", DOT2, + "WS1", WS1, + "QUICK", QUICK, + "QTOK", QTOK, + "QNUM", QNUM, + "QEXP", QEXP, + "QCOM", QCOM, + "QID", QID, + "MAC0", MAC0, + "MACN", MACN, + "HIT0", HIT0, + "HITN", HITN, + "LIT0", LIT0, + "SHARP1", SHARP1, + "TOKEN", TOKEN, + "OCT1", OCT1, + "OCT2", OCT2, + "OCT3", OCT3, + "NOT1", NOT1, + "PCT1", PCT1, + "AND1", AND1, + "STAR1", STAR1, + "PLUS1", PLUS1, + "MINUS1", MINUS1, + "ARROW1", ARROW1, + "COLON1", COLON1, + "LT1", LT1, + "LSH1", LSH1, + "EQ1", EQ1, + "RSH1", RSH1, + "GT1", GT1, + "CIRC1", CIRC1, + "OR1", OR1, + "DEC1", DEC1, + "DEC2", DEC2, + "HEX1", HEX1, + "HEX2", HEX2, + "HEX3", HEX3, + "HEX4", HEX4, + "HEX5", HEX5, + "HEX6", HEX6, + "HEX7", HEX7, + "HEX8", HEX8, + "DBL1", DBL1, + "DBL2", DBL2, + "DBL3", DBL3, + "DBL4", DBL4, + "DBL5", DBL5, + "DOT1", DOT1, + "HDR1", HDR1, + "BIN1", BIN1, + "TERMINAL", TERMINAL, + "S_CHRB", S_CHRB, + "S_COMMENT", S_COMMENT, + "S_EOB", S_EOB, + "S_LITBEG", S_LITBEG, + "S_LITEND", S_LITEND, + "S_LITESC", S_LITESC, + "S_MACRO", S_MACRO, + "S_NL", S_NL, + "S_QUAL", S_QUAL, + "S_SHARP", S_SHARP, + "S_VS", S_VS, + "S_CHR", S_CHR, + "S_HUH", S_HUH, + "S_TOK", S_TOK, + "S_TOKB", S_TOKB, + "S_WS", S_WS, + "S_RESERVED", S_RESERVED, +}; +static struct map ppstatemap[] = +{ + "ADD", ADD, + "COLLECTING", COLLECTING, + "COMPATIBILITY", COMPATIBILITY, + "COMPILE", COMPILE, + "CONDITIONAL", CONDITIONAL, + "DEFINITION", DEFINITION, + "DIRECTIVE", DIRECTIVE, + "DISABLE", DISABLE, + "EOF2NL", EOF2NL, + "ESCAPE", ESCAPE, + "FILEPOP", FILEPOP, + "HEADER", HEADER, + "HIDDEN", HIDDEN, + "JOINING", JOINING, + "NEWLINE", NEWLINE, + "NOEXPAND", NOEXPAND, + "NOSPACE", NOSPACE, + "NOTEXT", NOTEXT, + "NOVERTICAL", NOVERTICAL, + "PASSEOF", PASSEOF, + "PASSTHROUGH", PASSTHROUGH, + "QUOTE", QUOTE, + "SKIPCONTROL", SKIPCONTROL, + "SKIPMACRO", SKIPMACRO, + "SPACEOUT", SPACEOUT, + "SQUOTE", SQUOTE, + "STANDALONE", STANDALONE, + "STRICT", STRICT, + "STRIP", STRIP, + "SYNCLINE", SYNCLINE, + "TRANSITION", TRANSITION, + "WARN", WARN, +}; +static struct map ppmodemap[] = +{ + "ALLMULTIPLE", ALLMULTIPLE, + "BUILTIN", BUILTIN, + "CATLITERAL", CATLITERAL, + "DUMP", DUMP, + "EXPOSE", EXPOSE, + "EXTERNALIZE", EXTERNALIZE, + "FILEDEPS", FILEDEPS, + "GENDEPS", GENDEPS, + "HEADERDEPS", HEADERDEPS, + "HOSTED", HOSTED, + "HOSTEDTRANSITION", HOSTEDTRANSITION, + "INACTIVE", INACTIVE, + "INIT", INIT, + "LOADING", LOADING, + "MARKC", MARKC, + "MARKHOSTED", MARKHOSTED, + "MARKMACRO", MARKMACRO, + "PEDANTIC", PEDANTIC, + "READONLY", READONLY, + "RELAX", RELAX, +}; +static struct map ppoptionmap[] = +{ + "ELSEIF", ELSEIF, + "FINAL", FINAL, + "HEADEREXPAND", HEADEREXPAND, + "HEADEREXPANDALL", HEADEREXPANDALL, + "IGNORELINE", IGNORELINE, + "INITIAL", INITIAL, + "KEEPNOTEXT", KEEPNOTEXT, + "KEYARGS", KEYARGS, + "MODERN", MODERN, + "NATIVE", NATIVE, + "NOHASH", NOHASH, + "NOISE", NOISE, + "NOISEFILTER", NOISEFILTER, + "NOPROTO", NOPROTO, + "PLUSCOMMENT", PLUSCOMMENT, + "PLUSPLUS", PLUSPLUS, + "PLUSSPLICE", PLUSSPLICE, + "PRAGMAEXPAND", PRAGMAEXPAND, + "PREDEFINED", PREDEFINED, + "PREDEFINITIONS", PREDEFINITIONS, + "PREFIX", PREFIX, + "PRESERVE", PRESERVE, + "PROTOTYPED", PROTOTYPED, + "REGUARD", REGUARD, + "SPLICECAT", SPLICECAT, + "SPLICESPACE", SPLICESPACE, + "STRINGSPAN", STRINGSPAN, + "STRINGSPLIT", STRINGSPLIT, + "TRUNCATE", TRUNCATE, + "ZEOF", ZEOF, +}; +static struct map ppinmap[] = +{ + "BUFFER", IN_BUFFER, + "COPY", IN_COPY, + "EXPAND", IN_EXPAND, + "FILE", IN_FILE, + "INIT", IN_INIT, + "MACRO", IN_MACRO, + "MULTILINE", IN_MULTILINE, + "QUOTE", IN_QUOTE, + "RESCAN", IN_RESCAN, + "SQUOTE", IN_SQUOTE, + "STRING", IN_STRING, +}; diff --git a/usr/src/lib/libpp/i386/ppdef.h b/usr/src/lib/libpp/i386/ppdef.h new file mode 100644 index 0000000000..6cb3481f8b --- /dev/null +++ b/usr/src/lib/libpp/i386/ppdef.h @@ -0,0 +1,220 @@ +/* + * + * Glenn Fowler + * AT&T Research + * + * @(#)pp.tab (AT&T Labs Research) 2006-05-09 + * + * C preprocessor tables and states + * + * + marks extensions to the standard + * + */ + +#define DEFINE 1 +#define ELIF 2 +#define ELSE 3 +#define ENDIF 4 +#define ENDMAC 5 +#define ERROR 6 +#define IF 7 +#define IFDEF 8 +#define IFNDEF 9 +#define INCLUDE 10 +#define LET 11 +#define LINE 12 +#define MACDEF 13 +#define PRAGMA 14 +#define RENAME 15 +#define UNDEF 16 +#define WARNING 17 + +#define X_ALLMULTIPLE 1 +#define X_ALLPOSSIBLE 2 +#define X_BUILTIN 3 +#define X_CATLITERAL 4 +#define X_CDIR 5 +#define X_CHECKPOINT 6 +#define X_CHOP 7 +#define X_COMPATIBILITY 8 +#define X_DEBUG 9 +#define X_ELSEIF 10 +#define X_EXTERNALIZE 11 +#define X_FINAL 12 +#define X_HIDE 13 +#define X_HEADEREXPAND 14 +#define X_HEADEREXPANDALL 15 +#define X_HOSTED 16 +#define X_HOSTEDTRANSITION 17 +#define X_HOSTDIR 18 +#define X_ID 19 +#define X_IGNORE 20 +#define X_INCLUDE 21 +#define X_INITIAL 22 +#define X_KEYARGS 23 +#define X_LINE 24 +#define X_LINEBASE 25 +#define X_LINEFILE 26 +#define X_LINEID 27 +#define X_LINETYPE 28 +#define X_MACREF 29 +#define X_MAP 30 +#define X_MAPINCLUDE 31 +#define X_MODERN 32 +#define X_MULTIPLE 33 +#define X_NATIVE 34 +#define X_NOTE 35 +#define X_OPSPACE 36 +#define X_PASSTHROUGH 37 +#define X_PEDANTIC 38 +#define X_PLUSCOMMENT 39 +#define X_PLUSPLUS 40 +#define X_PLUSSPLICE 41 +#define X_PRAGMAFLAGS 42 +#define X_PRAGMAEXPAND 43 +#define X_PREDEFINED 44 +#define X_PREFIX 45 +#define X_PRESERVE 46 +#define X_PROTO 47 +#define X_PROTOTYPED 48 +#define X_QUOTE 49 +#define X_READONLY 50 +#define X_REGUARD 51 +#define X_RESERVED 52 +#define X_SPACEOUT 53 +#define X_SPLICECAT 54 +#define X_SPLICESPACE 55 +#define X_STANDARD 56 +#define X_STATEMENT 57 +#define X_STRICT 58 +#define X_STRINGSPAN 59 +#define X_STRINGSPLIT 60 +#define X_SYSTEM_HEADER 61 +#define X_TEST 62 +#define X_TEXT 63 +#define X_TRANSITION 64 +#define X_TRUNCATE 65 +#define X_VENDOR 66 +#define X_VERSION 67 +#define X_WARN 68 +#define X_ZEOF 69 +#define X_last_option 69 + +#define X_DEFINED 70 +#define X_EXISTS 71 +#define X_INCLUDED 72 +#define X_MATCH 73 +#define X_NOTICED 74 +#define X_OPTION 75 +#define X_SIZEOF 76 +#define X_STRCMP 77 + +#define R_DEFINED 1 + +#define ADD (1<<0) +#define COLLECTING (1<<1) +#define COMPATIBILITY (1<<2) +#define COMPILE (1<<3) +#define CONDITIONAL (1<<4) +#define DEFINITION (1<<5) +#define DIRECTIVE (1<<6) +#define DISABLE (1<<7) +#define EOF2NL (1<<8) +#define ESCAPE (1<<9) +#define FILEPOP (1<<10) +#define HEADER (1<<11) +#define HIDDEN (1<<12) +#define JOINING (1<<13) +#define NEWLINE (1<<14) +#define NOEXPAND (1L<<15) +#define NOSPACE (1L<<16) +#define NOTEXT (1L<<17) +#define NOVERTICAL (1L<<18) +#define PASSEOF (1L<<19) +#define PASSTHROUGH (1L<<20) +#define QUOTE (1L<<21) +#define SKIPCONTROL (1L<<22) +#define SKIPMACRO (1L<<23) +#define SPACEOUT (1L<<24) +#define SQUOTE (1L<<25) +#define STANDALONE (1L<<26) +#define STRICT (1L<<27) +#define STRIP (1L<<28) +#define SYNCLINE (1L<<29) +#define TRANSITION (1L<<30) +#define WARN (1L<<31) + +#define ALLMULTIPLE (1<<0) +#define BUILTIN (1<<1) +#define CATLITERAL (1<<2) +#define DUMP (1<<3) +#define EXPOSE (1<<4) +#define EXTERNALIZE (1<<5) +#define FILEDEPS (1<<6) +#define GENDEPS (1<<7) +#define HEADERDEPS (1<<8) +#define HOSTED (1<<9) +#define HOSTEDTRANSITION (1<<10) +#define INACTIVE (1<<11) +#define INIT (1<<12) +#define LOADING (1<<13) +#define MARKC (1<<14) +#define MARKHOSTED (1L<<15) +#define MARKMACRO (1L<<16) +#define PEDANTIC (1L<<17) +#define READONLY (1L<<18) +#define RELAX (1L<<19) + +#define ALLPOSSIBLE (1<<0) +#define DEFINITIONS (1<<1) +#define ELSEIF (1<<2) +#define FINAL (1<<3) +#define HEADEREXPAND (1<<4) +#define HEADEREXPANDALL (1<<5) +#define IGNORELINE (1<<6) +#define INITIAL (1<<7) +#define KEEPNOTEXT (1<<8) +#define KEYARGS (1<<9) +#define MODERN (1<<10) +#define NATIVE (1<<11) +#define NOHASH (1<<12) +#define NOISE (1<<13) +#define NOISEFILTER (1<<14) +#define NOPROTO (1L<<15) +#define PLUSCOMMENT (1L<<16) +#define PLUSPLUS (1L<<17) +#define PLUSSPLICE (1L<<18) +#define PRAGMAEXPAND (1L<<19) +#define PREDEFINED (1L<<20) +#define PREDEFINITIONS (1L<<21) +#define PREFIX (1L<<22) +#define PRESERVE (1L<<23) +#define PROTOTYPED (1L<<24) +#define REGUARD (1L<<25) +#define SPLICECAT (1L<<26) +#define SPLICESPACE (1L<<27) +#define STRINGSPAN (1L<<28) +#define STRINGSPLIT (1L<<29) +#define TRUNCATE (1L<<30) +#define ZEOF (1L<<31) + +#define V__PRAGMA 78 +#define V_ARGC 79 +#define V_BASE 80 +#define V_DATE 81 +#define V_FILE 82 +#define V_FUNCTION 83 +#define V_LINE 84 +#define V_PATH 85 +#define V_SOURCE 86 +#define V_STDC 87 +#define V_TIME 88 +#define V_VERSION 89 +#define V_DEFAULT 90 +#define V_DIRECTIVE 91 +#define V_EMPTY 92 +#define V_GETENV 93 +#define V_GETMAC 94 +#define V_GETOPT 95 +#define V_GETPRD 96 +#define V_ITERATE 97 diff --git a/usr/src/lib/libpp/i386/pptab.h b/usr/src/lib/libpp/i386/pptab.h new file mode 100644 index 0000000000..d153e8e65c --- /dev/null +++ b/usr/src/lib/libpp/i386/pptab.h @@ -0,0 +1,152 @@ +/* + * + * Glenn Fowler + * AT&T Research + * + * @(#)pp.tab (AT&T Labs Research) 2006-05-09 + * + * C preprocessor tables and states + * + * + marks extensions to the standard + * + */ + +static struct ppkeyword directives[] = +{ + "define", DEFINE, + "elif", ELIF, + "else", ELSE, + "endif", ENDIF, + "+endmac", ENDMAC, + "error", ERROR, + "if", IF, + "ifdef", IFDEF, + "ifndef", IFNDEF, + "include", INCLUDE, + "+let", LET, + "line", LINE, + "+macdef", MACDEF, + "pragma", PRAGMA, + "+rename", RENAME, + "undef", UNDEF, + "+warning", WARNING, + 0, 0 +}; + +static struct ppkeyword options[] = +{ + "allmultiple", X_ALLMULTIPLE, + "allpossible", X_ALLPOSSIBLE, + "builtin", X_BUILTIN, + "catliteral", X_CATLITERAL, + "cdir", X_CDIR, + "checkpoint", X_CHECKPOINT, + "chop", X_CHOP, + "compatibility", X_COMPATIBILITY, + "debug", X_DEBUG, + "elseif", X_ELSEIF, + "externalize", X_EXTERNALIZE, + "final", X_FINAL, + "hide", X_HIDE, + "headerexpand", X_HEADEREXPAND, + "headerexpandall", X_HEADEREXPANDALL, + "hosted", X_HOSTED, + "hostedtransition", X_HOSTEDTRANSITION, + "hostdir", X_HOSTDIR, + "id", X_ID, + "ignore", X_IGNORE, + "include", X_INCLUDE, + "initial", X_INITIAL, + "keyargs", X_KEYARGS, + "line", X_LINE, + "linebase", X_LINEBASE, + "linefile", X_LINEFILE, + "lineid", X_LINEID, + "linetype", X_LINETYPE, + "macref", X_MACREF, + "map", X_MAP, + "mapinclude", X_MAPINCLUDE, + "modern", X_MODERN, + "multiple", X_MULTIPLE, + "native", X_NATIVE, + "note", X_NOTE, + "opspace", X_OPSPACE, + "passthrough", X_PASSTHROUGH, + "pedantic", X_PEDANTIC, + "pluscomment", X_PLUSCOMMENT, + "plusplus", X_PLUSPLUS, + "plussplice", X_PLUSSPLICE, + "pragmaflags", X_PRAGMAFLAGS, + "pragmaexpand", X_PRAGMAEXPAND, + "predefined", X_PREDEFINED, + "prefix", X_PREFIX, + "preserve", X_PRESERVE, + "proto", X_PROTO, + "prototyped", X_PROTOTYPED, + "quote", X_QUOTE, + "readonly", X_READONLY, + "reguard", X_REGUARD, + "reserved", X_RESERVED, + "spaceout", X_SPACEOUT, + "splicecat", X_SPLICECAT, + "splicespace", X_SPLICESPACE, + "standard", X_STANDARD, + "statement", X_STATEMENT, + "strict", X_STRICT, + "stringspan", X_STRINGSPAN, + "stringsplit", X_STRINGSPLIT, + "system_header", X_SYSTEM_HEADER, + "test", X_TEST, + "text", X_TEXT, + "transition", X_TRANSITION, + "truncate", X_TRUNCATE, + "vendor", X_VENDOR, + "version", X_VERSION, + "warn", X_WARN, + "zeof", X_ZEOF, + 0, 0 +}; + +static struct ppkeyword predicates[] = +{ + "defined", X_DEFINED, + "+exists", X_EXISTS, + "+included", X_INCLUDED, + "+match", X_MATCH, + "+noticed", X_NOTICED, + "+option", X_OPTION, + "sizeof", X_SIZEOF, + "+strcmp", X_STRCMP, + 0, 0 +}; + +static struct ppkeyword readonlys[] = +{ + "defined", R_DEFINED, + 0, 0 +}; + +static struct ppkeyword variables[] = +{ + "_Pragma", V__PRAGMA, + "+ARGC", V_ARGC, + "+BASE", V_BASE, + "DATE", V_DATE, + "FILE", V_FILE, + "+FUNCTION", V_FUNCTION, + "LINE", V_LINE, + "+PATH", V_PATH, + "+SOURCE", V_SOURCE, + "-STDC", V_STDC, + "TIME", V_TIME, + "+VERSION", V_VERSION, + "-default", V_DEFAULT, + "-directive", V_DIRECTIVE, + "-empty", V_EMPTY, + "-getenv", V_GETENV, + "-getmac", V_GETMAC, + "-getopt", V_GETOPT, + "-getprd", V_GETPRD, + "-iterate", V_ITERATE, + 0, 0 +}; diff --git a/usr/src/lib/libpp/mapfile-vers b/usr/src/lib/libpp/mapfile-vers new file mode 100644 index 0000000000..43e4584b85 --- /dev/null +++ b/usr/src/lib/libpp/mapfile-vers @@ -0,0 +1,39 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SUNWprivate_1.1 { + global: + pp; + ppop; + pplex; + ppinput; + ppargs; + + local: + *; +}; diff --git a/usr/src/lib/libpp/sparc/Makefile b/usr/src/lib/libpp/sparc/Makefile new file mode 100644 index 0000000000..f91f0270e9 --- /dev/null +++ b/usr/src/lib/libpp/sparc/Makefile @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/libpp/sparc/pp.req b/usr/src/lib/libpp/sparc/pp.req new file mode 100644 index 0000000000..6c6437695b --- /dev/null +++ b/usr/src/lib/libpp/sparc/pp.req @@ -0,0 +1,2 @@ + -lpp + -last diff --git a/usr/src/lib/libpp/sparc/pp.yacc b/usr/src/lib/libpp/sparc/pp.yacc new file mode 100644 index 0000000000..1de9080a7a --- /dev/null +++ b/usr/src/lib/libpp/sparc/pp.yacc @@ -0,0 +1 @@ +%token /*generated from pp.h*/ T_DOUBLE 292 T_DOUBLE_L 293 T_FLOAT 294 T_DECIMAL 288 T_DECIMAL_L 289 T_DECIMAL_U 290 T_DECIMAL_UL 291 T_OCTAL 296 T_OCTAL_L 297 T_OCTAL_U 298 T_OCTAL_UL 299 T_HEXADECIMAL 304 T_HEXADECIMAL_L 305 T_HEXADECIMAL_U 306 T_HEXADECIMAL_UL 307 T_HEXDOUBLE 308 T_HEXDOUBLE_L 309 T_ID 257 T_INVALID 258 T_CHARCONST 260 T_WCHARCONST 261 T_STRING 262 T_WSTRING 263 T_PTRMEM 264 T_ADDADD 265 T_SUBSUB 266 T_LSHIFT 267 T_RSHIFT 268 T_LE 269 T_GE 270 T_EQ 271 T_NE 272 T_ANDAND 273 T_OROR 274 T_MPYEQ 275 T_DIVEQ 276 T_MODEQ 277 T_ADDEQ 278 T_SUBEQ 279 T_LSHIFTEQ 280 T_RSHIFTEQ 281 T_ANDEQ 282 T_XOREQ 283 T_OREQ 284 T_VARIADIC 286 T_DOTREF 320 T_PTRMEMREF 321 T_SCOPE 322 T_UMINUS 323 diff --git a/usr/src/lib/libpp/sparc/ppdebug.h b/usr/src/lib/libpp/sparc/ppdebug.h new file mode 100644 index 0000000000..9c9f29e795 --- /dev/null +++ b/usr/src/lib/libpp/sparc/ppdebug.h @@ -0,0 +1,211 @@ +/* +* preprocessor library debug maps +*/ +struct map +{ + char* nam; + long val; +}; +static struct map pplexmap[] = +{ + "PROTO", PROTO, + "RES1", RES1, + "RES1a", RES1a, + "RES1e", RES1e, + "RES1f", RES1f, + "RES1h", RES1h, + "RES1l", RES1l, + "RES1n", RES1n, + "RES1o", RES1o, + "RES1t", RES1t, + "RES1x", RES1x, + "RES1y", RES1y, + "COM1", COM1, + "COM2", COM2, + "COM3", COM3, + "COM4", COM4, + "COM5", COM5, + "COM6", COM6, + "COM7", COM7, + "NID", NID, + "LIT", LIT, + "LIT1", LIT1, + "LIT2", LIT2, + "BAD1", BAD1, + "BAD2", BAD2, + "DOT", DOT, + "DOT2", DOT2, + "WS1", WS1, + "QUICK", QUICK, + "QTOK", QTOK, + "QNUM", QNUM, + "QEXP", QEXP, + "QCOM", QCOM, + "QID", QID, + "MAC0", MAC0, + "MACN", MACN, + "HIT0", HIT0, + "HITN", HITN, + "LIT0", LIT0, + "SHARP1", SHARP1, + "TOKEN", TOKEN, + "OCT1", OCT1, + "OCT2", OCT2, + "OCT3", OCT3, + "NOT1", NOT1, + "PCT1", PCT1, + "AND1", AND1, + "STAR1", STAR1, + "PLUS1", PLUS1, + "MINUS1", MINUS1, + "ARROW1", ARROW1, + "COLON1", COLON1, + "LT1", LT1, + "LSH1", LSH1, + "EQ1", EQ1, + "RSH1", RSH1, + "GT1", GT1, + "CIRC1", CIRC1, + "OR1", OR1, + "DEC1", DEC1, + "DEC2", DEC2, + "HEX1", HEX1, + "HEX2", HEX2, + "HEX3", HEX3, + "HEX4", HEX4, + "HEX5", HEX5, + "HEX6", HEX6, + "HEX7", HEX7, + "HEX8", HEX8, + "DBL1", DBL1, + "DBL2", DBL2, + "DBL3", DBL3, + "DBL4", DBL4, + "DBL5", DBL5, + "DOT1", DOT1, + "HDR1", HDR1, + "BIN1", BIN1, + "TERMINAL", TERMINAL, + "S_CHRB", S_CHRB, + "S_COMMENT", S_COMMENT, + "S_EOB", S_EOB, + "S_LITBEG", S_LITBEG, + "S_LITEND", S_LITEND, + "S_LITESC", S_LITESC, + "S_MACRO", S_MACRO, + "S_NL", S_NL, + "S_QUAL", S_QUAL, + "S_SHARP", S_SHARP, + "S_VS", S_VS, + "S_CHR", S_CHR, + "S_HUH", S_HUH, + "S_TOK", S_TOK, + "S_TOKB", S_TOKB, + "S_WS", S_WS, + "S_RESERVED", S_RESERVED, +}; +static struct map ppstatemap[] = +{ + "ADD", ADD, + "COLLECTING", COLLECTING, + "COMPATIBILITY", COMPATIBILITY, + "COMPILE", COMPILE, + "CONDITIONAL", CONDITIONAL, + "DEFINITION", DEFINITION, + "DIRECTIVE", DIRECTIVE, + "DISABLE", DISABLE, + "EOF2NL", EOF2NL, + "ESCAPE", ESCAPE, + "FILEPOP", FILEPOP, + "HEADER", HEADER, + "HIDDEN", HIDDEN, + "JOINING", JOINING, + "NEWLINE", NEWLINE, + "NOEXPAND", NOEXPAND, + "NOSPACE", NOSPACE, + "NOTEXT", NOTEXT, + "NOVERTICAL", NOVERTICAL, + "PASSEOF", PASSEOF, + "PASSTHROUGH", PASSTHROUGH, + "QUOTE", QUOTE, + "SKIPCONTROL", SKIPCONTROL, + "SKIPMACRO", SKIPMACRO, + "SPACEOUT", SPACEOUT, + "SQUOTE", SQUOTE, + "STANDALONE", STANDALONE, + "STRICT", STRICT, + "STRIP", STRIP, + "SYNCLINE", SYNCLINE, + "TRANSITION", TRANSITION, + "WARN", WARN, +}; +static struct map ppmodemap[] = +{ + "ALLMULTIPLE", ALLMULTIPLE, + "BUILTIN", BUILTIN, + "CATLITERAL", CATLITERAL, + "DUMP", DUMP, + "EXPOSE", EXPOSE, + "EXTERNALIZE", EXTERNALIZE, + "FILEDEPS", FILEDEPS, + "GENDEPS", GENDEPS, + "HEADERDEPS", HEADERDEPS, + "HOSTED", HOSTED, + "HOSTEDTRANSITION", HOSTEDTRANSITION, + "INACTIVE", INACTIVE, + "INIT", INIT, + "LOADING", LOADING, + "MARKC", MARKC, + "MARKHOSTED", MARKHOSTED, + "MARKMACRO", MARKMACRO, + "PEDANTIC", PEDANTIC, + "READONLY", READONLY, + "RELAX", RELAX, +}; +static struct map ppoptionmap[] = +{ + "ELSEIF", ELSEIF, + "FINAL", FINAL, + "HEADEREXPAND", HEADEREXPAND, + "HEADEREXPANDALL", HEADEREXPANDALL, + "IGNORELINE", IGNORELINE, + "INITIAL", INITIAL, + "KEEPNOTEXT", KEEPNOTEXT, + "KEYARGS", KEYARGS, + "MODERN", MODERN, + "NATIVE", NATIVE, + "NOHASH", NOHASH, + "NOISE", NOISE, + "NOISEFILTER", NOISEFILTER, + "NOPROTO", NOPROTO, + "PLUSCOMMENT", PLUSCOMMENT, + "PLUSPLUS", PLUSPLUS, + "PLUSSPLICE", PLUSSPLICE, + "PRAGMAEXPAND", PRAGMAEXPAND, + "PREDEFINED", PREDEFINED, + "PREDEFINITIONS", PREDEFINITIONS, + "PREFIX", PREFIX, + "PRESERVE", PRESERVE, + "PROTOTYPED", PROTOTYPED, + "REGUARD", REGUARD, + "SPLICECAT", SPLICECAT, + "SPLICESPACE", SPLICESPACE, + "STRINGSPAN", STRINGSPAN, + "STRINGSPLIT", STRINGSPLIT, + "TRUNCATE", TRUNCATE, + "ZEOF", ZEOF, +}; +static struct map ppinmap[] = +{ + "BUFFER", IN_BUFFER, + "COPY", IN_COPY, + "EXPAND", IN_EXPAND, + "FILE", IN_FILE, + "INIT", IN_INIT, + "MACRO", IN_MACRO, + "MULTILINE", IN_MULTILINE, + "QUOTE", IN_QUOTE, + "RESCAN", IN_RESCAN, + "SQUOTE", IN_SQUOTE, + "STRING", IN_STRING, +}; diff --git a/usr/src/lib/libpp/sparc/ppdef.h b/usr/src/lib/libpp/sparc/ppdef.h new file mode 100644 index 0000000000..6cb3481f8b --- /dev/null +++ b/usr/src/lib/libpp/sparc/ppdef.h @@ -0,0 +1,220 @@ +/* + * + * Glenn Fowler + * AT&T Research + * + * @(#)pp.tab (AT&T Labs Research) 2006-05-09 + * + * C preprocessor tables and states + * + * + marks extensions to the standard + * + */ + +#define DEFINE 1 +#define ELIF 2 +#define ELSE 3 +#define ENDIF 4 +#define ENDMAC 5 +#define ERROR 6 +#define IF 7 +#define IFDEF 8 +#define IFNDEF 9 +#define INCLUDE 10 +#define LET 11 +#define LINE 12 +#define MACDEF 13 +#define PRAGMA 14 +#define RENAME 15 +#define UNDEF 16 +#define WARNING 17 + +#define X_ALLMULTIPLE 1 +#define X_ALLPOSSIBLE 2 +#define X_BUILTIN 3 +#define X_CATLITERAL 4 +#define X_CDIR 5 +#define X_CHECKPOINT 6 +#define X_CHOP 7 +#define X_COMPATIBILITY 8 +#define X_DEBUG 9 +#define X_ELSEIF 10 +#define X_EXTERNALIZE 11 +#define X_FINAL 12 +#define X_HIDE 13 +#define X_HEADEREXPAND 14 +#define X_HEADEREXPANDALL 15 +#define X_HOSTED 16 +#define X_HOSTEDTRANSITION 17 +#define X_HOSTDIR 18 +#define X_ID 19 +#define X_IGNORE 20 +#define X_INCLUDE 21 +#define X_INITIAL 22 +#define X_KEYARGS 23 +#define X_LINE 24 +#define X_LINEBASE 25 +#define X_LINEFILE 26 +#define X_LINEID 27 +#define X_LINETYPE 28 +#define X_MACREF 29 +#define X_MAP 30 +#define X_MAPINCLUDE 31 +#define X_MODERN 32 +#define X_MULTIPLE 33 +#define X_NATIVE 34 +#define X_NOTE 35 +#define X_OPSPACE 36 +#define X_PASSTHROUGH 37 +#define X_PEDANTIC 38 +#define X_PLUSCOMMENT 39 +#define X_PLUSPLUS 40 +#define X_PLUSSPLICE 41 +#define X_PRAGMAFLAGS 42 +#define X_PRAGMAEXPAND 43 +#define X_PREDEFINED 44 +#define X_PREFIX 45 +#define X_PRESERVE 46 +#define X_PROTO 47 +#define X_PROTOTYPED 48 +#define X_QUOTE 49 +#define X_READONLY 50 +#define X_REGUARD 51 +#define X_RESERVED 52 +#define X_SPACEOUT 53 +#define X_SPLICECAT 54 +#define X_SPLICESPACE 55 +#define X_STANDARD 56 +#define X_STATEMENT 57 +#define X_STRICT 58 +#define X_STRINGSPAN 59 +#define X_STRINGSPLIT 60 +#define X_SYSTEM_HEADER 61 +#define X_TEST 62 +#define X_TEXT 63 +#define X_TRANSITION 64 +#define X_TRUNCATE 65 +#define X_VENDOR 66 +#define X_VERSION 67 +#define X_WARN 68 +#define X_ZEOF 69 +#define X_last_option 69 + +#define X_DEFINED 70 +#define X_EXISTS 71 +#define X_INCLUDED 72 +#define X_MATCH 73 +#define X_NOTICED 74 +#define X_OPTION 75 +#define X_SIZEOF 76 +#define X_STRCMP 77 + +#define R_DEFINED 1 + +#define ADD (1<<0) +#define COLLECTING (1<<1) +#define COMPATIBILITY (1<<2) +#define COMPILE (1<<3) +#define CONDITIONAL (1<<4) +#define DEFINITION (1<<5) +#define DIRECTIVE (1<<6) +#define DISABLE (1<<7) +#define EOF2NL (1<<8) +#define ESCAPE (1<<9) +#define FILEPOP (1<<10) +#define HEADER (1<<11) +#define HIDDEN (1<<12) +#define JOINING (1<<13) +#define NEWLINE (1<<14) +#define NOEXPAND (1L<<15) +#define NOSPACE (1L<<16) +#define NOTEXT (1L<<17) +#define NOVERTICAL (1L<<18) +#define PASSEOF (1L<<19) +#define PASSTHROUGH (1L<<20) +#define QUOTE (1L<<21) +#define SKIPCONTROL (1L<<22) +#define SKIPMACRO (1L<<23) +#define SPACEOUT (1L<<24) +#define SQUOTE (1L<<25) +#define STANDALONE (1L<<26) +#define STRICT (1L<<27) +#define STRIP (1L<<28) +#define SYNCLINE (1L<<29) +#define TRANSITION (1L<<30) +#define WARN (1L<<31) + +#define ALLMULTIPLE (1<<0) +#define BUILTIN (1<<1) +#define CATLITERAL (1<<2) +#define DUMP (1<<3) +#define EXPOSE (1<<4) +#define EXTERNALIZE (1<<5) +#define FILEDEPS (1<<6) +#define GENDEPS (1<<7) +#define HEADERDEPS (1<<8) +#define HOSTED (1<<9) +#define HOSTEDTRANSITION (1<<10) +#define INACTIVE (1<<11) +#define INIT (1<<12) +#define LOADING (1<<13) +#define MARKC (1<<14) +#define MARKHOSTED (1L<<15) +#define MARKMACRO (1L<<16) +#define PEDANTIC (1L<<17) +#define READONLY (1L<<18) +#define RELAX (1L<<19) + +#define ALLPOSSIBLE (1<<0) +#define DEFINITIONS (1<<1) +#define ELSEIF (1<<2) +#define FINAL (1<<3) +#define HEADEREXPAND (1<<4) +#define HEADEREXPANDALL (1<<5) +#define IGNORELINE (1<<6) +#define INITIAL (1<<7) +#define KEEPNOTEXT (1<<8) +#define KEYARGS (1<<9) +#define MODERN (1<<10) +#define NATIVE (1<<11) +#define NOHASH (1<<12) +#define NOISE (1<<13) +#define NOISEFILTER (1<<14) +#define NOPROTO (1L<<15) +#define PLUSCOMMENT (1L<<16) +#define PLUSPLUS (1L<<17) +#define PLUSSPLICE (1L<<18) +#define PRAGMAEXPAND (1L<<19) +#define PREDEFINED (1L<<20) +#define PREDEFINITIONS (1L<<21) +#define PREFIX (1L<<22) +#define PRESERVE (1L<<23) +#define PROTOTYPED (1L<<24) +#define REGUARD (1L<<25) +#define SPLICECAT (1L<<26) +#define SPLICESPACE (1L<<27) +#define STRINGSPAN (1L<<28) +#define STRINGSPLIT (1L<<29) +#define TRUNCATE (1L<<30) +#define ZEOF (1L<<31) + +#define V__PRAGMA 78 +#define V_ARGC 79 +#define V_BASE 80 +#define V_DATE 81 +#define V_FILE 82 +#define V_FUNCTION 83 +#define V_LINE 84 +#define V_PATH 85 +#define V_SOURCE 86 +#define V_STDC 87 +#define V_TIME 88 +#define V_VERSION 89 +#define V_DEFAULT 90 +#define V_DIRECTIVE 91 +#define V_EMPTY 92 +#define V_GETENV 93 +#define V_GETMAC 94 +#define V_GETOPT 95 +#define V_GETPRD 96 +#define V_ITERATE 97 diff --git a/usr/src/lib/libpp/sparc/pptab.h b/usr/src/lib/libpp/sparc/pptab.h new file mode 100644 index 0000000000..d153e8e65c --- /dev/null +++ b/usr/src/lib/libpp/sparc/pptab.h @@ -0,0 +1,152 @@ +/* + * + * Glenn Fowler + * AT&T Research + * + * @(#)pp.tab (AT&T Labs Research) 2006-05-09 + * + * C preprocessor tables and states + * + * + marks extensions to the standard + * + */ + +static struct ppkeyword directives[] = +{ + "define", DEFINE, + "elif", ELIF, + "else", ELSE, + "endif", ENDIF, + "+endmac", ENDMAC, + "error", ERROR, + "if", IF, + "ifdef", IFDEF, + "ifndef", IFNDEF, + "include", INCLUDE, + "+let", LET, + "line", LINE, + "+macdef", MACDEF, + "pragma", PRAGMA, + "+rename", RENAME, + "undef", UNDEF, + "+warning", WARNING, + 0, 0 +}; + +static struct ppkeyword options[] = +{ + "allmultiple", X_ALLMULTIPLE, + "allpossible", X_ALLPOSSIBLE, + "builtin", X_BUILTIN, + "catliteral", X_CATLITERAL, + "cdir", X_CDIR, + "checkpoint", X_CHECKPOINT, + "chop", X_CHOP, + "compatibility", X_COMPATIBILITY, + "debug", X_DEBUG, + "elseif", X_ELSEIF, + "externalize", X_EXTERNALIZE, + "final", X_FINAL, + "hide", X_HIDE, + "headerexpand", X_HEADEREXPAND, + "headerexpandall", X_HEADEREXPANDALL, + "hosted", X_HOSTED, + "hostedtransition", X_HOSTEDTRANSITION, + "hostdir", X_HOSTDIR, + "id", X_ID, + "ignore", X_IGNORE, + "include", X_INCLUDE, + "initial", X_INITIAL, + "keyargs", X_KEYARGS, + "line", X_LINE, + "linebase", X_LINEBASE, + "linefile", X_LINEFILE, + "lineid", X_LINEID, + "linetype", X_LINETYPE, + "macref", X_MACREF, + "map", X_MAP, + "mapinclude", X_MAPINCLUDE, + "modern", X_MODERN, + "multiple", X_MULTIPLE, + "native", X_NATIVE, + "note", X_NOTE, + "opspace", X_OPSPACE, + "passthrough", X_PASSTHROUGH, + "pedantic", X_PEDANTIC, + "pluscomment", X_PLUSCOMMENT, + "plusplus", X_PLUSPLUS, + "plussplice", X_PLUSSPLICE, + "pragmaflags", X_PRAGMAFLAGS, + "pragmaexpand", X_PRAGMAEXPAND, + "predefined", X_PREDEFINED, + "prefix", X_PREFIX, + "preserve", X_PRESERVE, + "proto", X_PROTO, + "prototyped", X_PROTOTYPED, + "quote", X_QUOTE, + "readonly", X_READONLY, + "reguard", X_REGUARD, + "reserved", X_RESERVED, + "spaceout", X_SPACEOUT, + "splicecat", X_SPLICECAT, + "splicespace", X_SPLICESPACE, + "standard", X_STANDARD, + "statement", X_STATEMENT, + "strict", X_STRICT, + "stringspan", X_STRINGSPAN, + "stringsplit", X_STRINGSPLIT, + "system_header", X_SYSTEM_HEADER, + "test", X_TEST, + "text", X_TEXT, + "transition", X_TRANSITION, + "truncate", X_TRUNCATE, + "vendor", X_VENDOR, + "version", X_VERSION, + "warn", X_WARN, + "zeof", X_ZEOF, + 0, 0 +}; + +static struct ppkeyword predicates[] = +{ + "defined", X_DEFINED, + "+exists", X_EXISTS, + "+included", X_INCLUDED, + "+match", X_MATCH, + "+noticed", X_NOTICED, + "+option", X_OPTION, + "sizeof", X_SIZEOF, + "+strcmp", X_STRCMP, + 0, 0 +}; + +static struct ppkeyword readonlys[] = +{ + "defined", R_DEFINED, + 0, 0 +}; + +static struct ppkeyword variables[] = +{ + "_Pragma", V__PRAGMA, + "+ARGC", V_ARGC, + "+BASE", V_BASE, + "DATE", V_DATE, + "FILE", V_FILE, + "+FUNCTION", V_FUNCTION, + "LINE", V_LINE, + "+PATH", V_PATH, + "+SOURCE", V_SOURCE, + "-STDC", V_STDC, + "TIME", V_TIME, + "+VERSION", V_VERSION, + "-default", V_DEFAULT, + "-directive", V_DIRECTIVE, + "-empty", V_EMPTY, + "-getenv", V_GETENV, + "-getmac", V_GETMAC, + "-getopt", V_GETOPT, + "-getprd", V_GETPRD, + "-iterate", V_ITERATE, + 0, 0 +}; |