#! /usr/bin/perl -w # # Module name: BlockParse # Synopsis: Block parser code # # Last Updated: $Date: 2014/03/05 14:20:14 $ # # Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved. # # @APPLE_LICENSE_HEADER_START@ # # This file contains Original Code and/or Modifications of Original Code # as defined in and that are subject to the Apple Public Source License # Version 2.0 (the 'License'). You may not use this file except in # compliance with the License. Please obtain a copy of the License at # http://www.opensource.apple.com/apsl/ and read it before using this # file. # # The Original Code and all software distributed under the License are # distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER # EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, # INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. # Please see the License for the specific language governing rights and # limitations under the License. # # @APPLE_LICENSE_HEADER_END@ # ###################################################################### # /*! # @header # @abstract # Block parser package File # @discussion # This file contains the BlockParse package, a group of # functions that are used for parsing declarations in # every supported language except Python. # # For details, see the package documentation. # @indexgroup HeaderDoc Parser Pieces # */ # /*! # @abstract # Core parser routines and parser interfaces # @discussion # The BlockParse package is a group of functions that # are used for parsing declarations in every supported # language except Python. (Support functions in this # package are used when parsing Python, but the actual # parsing of Python declarations happens in the # {@link //apple_ref/perl/cl/HeaderDoc::PythonParse PythonParse} # package.) # # The main entry points are {@link blockParse} (used for # parsing a declaration and returning information about # what was parsed) and {@link blockParseOutside} (used for # taking both a declaration and a HeaderDoc comment and # reconciling them into a HeaderDoc object (descended from # {@link //apple_ref/perl/cl/HeaderDoc::HeaderElement HeaderElement}). # # Other important functions are {@link cpp_add} (adds a C # preprocessor macro from a parse tree), {@link cpp_add_string} # (adds a C preprocessor macro from a string), and # {@link blockParseReturnState} (used for handling APIs inside # classes — interprets a # {@link //apple_ref/perl/cl/HeaderDoc::ParserState ParserState} # object hidden away inside the parse tree for the class, # returning the same results that {@link blockParse} would have # returned had been called on the individual declaration). # */ package HeaderDoc::BlockParse; # /*! @abstract # Tells the block parser to include the function body # in the parse tree. # */ $HeaderDoc::includeFunctionContents = 0; BEGIN { foreach (qw(Mac::Files)) { $MOD_AVAIL{$_} = eval "use $_; 1"; } } use Carp qw(cluck); use HeaderDoc::TypeHelper; use Exporter; foreach (qw(Mac::Files Mac::MoreFiles)) { eval "use $_"; } # /*! @abstract Stores whether Objective-C protocol methods are optional or required. */ $HeaderDoc::OptionalOrRequired = ""; # $HeaderDoc::disable_parms = 0; @ISA = qw(Exporter); @EXPORT = qw(blockParse nspaces blockParseOutside getAndClearCPPHash cpp_remove buildCommentFromFields bracematching peekmatch cpp_add_cl pbs); @EXPORT_OK = qr(blockParseReturnState); # Used by Python parser. use HeaderDoc::Utilities qw(findRelativePath safeName printArray printHash parseTokens isKeyword warnHDComment classTypeFromFieldAndBPinfo casecmp addAvailabilityMacro printFields objectForUID peek isStandardAvailability); use HeaderDoc::HashObject; use HeaderDoc::PythonParse qw(pythonParse); my $cpp_debug_file = ""; $cpp_debug_file = "/tmp/cpp_debug"; my $cpp_debug_lastfile = ""; use strict; use vars qw($VERSION @ISA); use File::Basename qw(basename); # /*! # @abstract # The revision control revision number for this module. # @discussion # In the git repository, contains the number of seconds since # January 1, 1970. # */ $HeaderDoc::BlockParse::VERSION = '$Revision: 1394058014 $'; ################ Portability ################################### my $isMacOS; my $pathSeparator; if ($^O =~ /MacOS/io) { $pathSeparator = ":"; $isMacOS = 1; } else { $pathSeparator = "/"; $isMacOS = 0; } # /*! # @abstract # C preprocessor token hash for the current header. # @discussion # The token hash contains a mapping of C preprocessor tokens # to their values. For example, if you have the following define: # #
# #define FOO(x, y) (x + (3 * y)) ## # then the C preprocessor token hash would contain a key called #
FOO with a (string) value of (x + (3 * y)).
# */
my %CPP_HASH = ();
# /*!
# @abstract
# C preprocessor argument hash for the current header.
# @discussion
# The token hash contains a mapping of C preprocessor token
# names to their argument lists. For example, if you have
# the following define:
#
# # #define FOO(x, y) (x + (3 * y)) ## # then the C preprocessor argument hash would contain a key called #
FOO with a (string) value of x, y.
# */
my %CPP_ARG_HASH = ();
# 0, 1, or 2.
my $cppDebugDefault = 0;
my $cppDebug = 0;
my $cppAddDebug = 0;
my $cppDebugFromToken = "";
my $nestedcommentwarn = 0;
my $warnAllMultipleDefinitions = 1;
my $modules_are_special = 1;
# /*!
# @abstract
# Change this to 0 if you want to hide the parameter name
# for unlabeled parameters (old behavior).
# @discussion
# Historically, HeaderDoc left out unlabeled parameters
# in constructing Objective-C method names. If you
# want that behavior, change this value. This is not
# an end-user-tunable parameter (without changing the
# code) because it doesn't seem likely that many
# people will want to change this behavior.
# */
$HeaderDoc::useParmNameForUnlabeledParms = 1;
# /*!
# @abstract
# Global variable that turns on input counter debugging in
# various parts of the code.
# */
$HeaderDoc::inputCounterDebug = 0;
my $tempDebug = 1;
# /*!
# @abstract
# Controls whether IDL attributes (e.g. [foo]) should be hidden
# in HTML output.
# @discussion
# By default, these tokens are hidden. Because this switch
# is unlikely to ever be used by anyone, it can be set only
# by changing the default value in BlockParse.pm
# from 1 to 0.
# */
$HeaderDoc::hideIDLAttributes = 1;
# /* Forward reference. This is not a HeaderDoc comment, but looks enough
# like one to fool the API coverage tool. */
sub cpp_subparse($);
################ Code ###################################
# /*!
# @abstract
# Returns the new language and language dialect based on the
# token that began a class declaration.
#
# @param classtype
# The class token.
#
# @discussion
# This function takes a class token (class,
# \@class, \@interface, etc.) and returns
# a lang and sublang value. Pretty trivial,
# but critical....
# */
sub getLangAndSublangFromClassType
{
my $classtype = shift;
my $outerlang = shift;
my $outersublang = shift;
# print STDERR "OUTERLANG: $outerlang OUTERSUBLANG: $outersublang\n";
if ($outerlang ne "C" && $outerlang ne "Csource") {
# This should never change for java/javascript/php. :-)
return ($outerlang, $outersublang);
}
my $lang = "C";
my $sublang = "C";
if ($classtype =~ /\@/) {
$sublang = "occ";
} elsif ($classtype =~ /class/) {
$sublang = "cpp";
} elsif ($classtype =~ /interface/) {
$sublang = "IDL";
} elsif ($classtype =~ /module/) {
$sublang = "IDL";
}
return ($lang, $sublang);
}
# /*!
# @abstract
# Returns the closing token that matches the token at the top
# of the brace stack.
# @param ref
# A reference to the brace stack array.
# @param fullpath
# The path of the current header. Used for error
# messages.
# @param linenum
# The current line number within the header. Used for error
# messages.
# @discussion
# This is a variant of {@link //apple_ref/perl/instm/HeaderDoc::Utilities/peek//() peek}.
# */
sub peekmatch
{
my $ref = shift;
my $lang = shift;
my $fullpath = shift;
my $linenum = shift;
my @stack = @{$ref};
my $tos = pop(@stack);
push(@stack, $tos);
if (!$tos) {
# popped off top of stack. Outside a macro, this is an error.
return "";
}
return bracematching($tos, $lang, $fullpath, $linenum);
}
# /*!
# @abstract
# Returns the closing token to match a given
# opening token.
# @param tos
# The opening symbol.
# @param calledByParser
# If 1, returns the original symbol and prints a warning
# message on error. If 0, returns an empty string on error (with
# no warning).
# @discussion
# This is used by peekmatch (and by other bits of code) to find the
# ending token that matches a starting token for braces, parentheses,
# and various other tokens that behave similarly.
# */
sub bracematching
{
my $tos = shift;
my $lang = shift;
my $calledByParser = 0;
my $fullpath = "";
my $linenum = "";
if (@_) {
$calledByParser = 1;
$fullpath = shift;
$linenum = shift;
}
SWITCH: {
($tos eq "{") && do {
return "}";
};
($tos eq "#") && do {
return "#";
};
($tos eq "(") && do {
return ")";
};
($tos eq "/") && do {
return "/";
};
($tos eq "|") && do {
return "|";
};
($tos eq "'") && do {
return "'";
};
($tos eq "\"") && do {
return "\"";
};
($tos eq "`") && do {
return "`";
};
($tos eq "<") && do {
return ">";
};
($tos eq "[") && do {
return "]";
};
($tos eq "\@interface") && do {
return "\@end";
};
($tos eq "\@implementation") && do {
return "\@end";
};
($tos eq "\@protocol") && do {
return "\@end";
};
(($lang eq "applescript") && $tos =~ /(if|repeat|try|tell)/) && do {
return "end";
};
(($lang eq "ruby") && $tos =~ /(for|while|if|until|begin)/) && do {
return "end";
};
{
# default case
if ($calledByParser) {
# The parser would prefer to always get something back here.
warn "$fullpath:$linenum: warning: Unknown block delimiter \"$tos\". Please file a bug.\n";
return $tos;
}
# Other code would prefer an error (an empty return value).
return "";
};
}
}
# /*! @abstract
# The core of HeaderDoc's parse engine.
# @param fullpath
# The path to the file being parsed.
# @param fileoffset
# The line number where the current block begins. The
# line number printed is (fileoffset + inputCounter).
# @param inputLinesRef
# A reference to an array of code lines.
# @param inputCounter
# The offset within the array. This is added to fileoffset
# when printing the line number.
# @param argparse
# Set to 1 for parsing function arguments, enum constants,
# or struct fields, 2 for reparsing embedded
# HeaderDoc markup in a class, 0 otherwise.
#
# This has the following effects:
#
# $parseTokens{assignmentwithcolon} = 2 in
# AppleScript.of and in
# tokens and label keywords in AppleScript.$HeaderDoc::outerNamesOnly) if
# argpase is 2.\@ignore
# headerdoc comments.
# @param perheaderignorefuncmacrosref
# A reference to a hash of tokens, generated from
# \@ignorefunmacro headerdoc comments.
# @param keywordhashref
# A reference to a hash of keywords.
# @param case_sensitive
# Boolean value that controls whether keywords should
# be processed in a case-sensitive fashion.
# @param lang
# The language family to use in parsing. Overrides
# HeaderDoc::lang.
# @param sublang
# The language variant to use in parsing. Overrides
# HeaderDoc::sublang.
# @result
# Returns the array ($inputCounter, $declaration, $typelist, $namelist, $posstypes, $value, \@pplStack, $returntype, $privateDeclaration, $treeTop, $simpleTDcontents, $availability) to the caller.
#
# @discussion
#
# Most of the variables used by this parser are things that are
# used for determining what type of declaration we just parsed.
# Such variables are stored as keys in the $parserState
# variable. For more information about these variables, see
# the documentation for the
# {@link //apple_ref/perl/cl/HeaderDoc::ParserState ParserState} class.
#
# This parser consists of three parsers running in parallel:
#
# namePending parser — looks for names a certain number of
# non-keyword tokens after keyword tokens like struct. Used mainly for
# data structures.startOfDec parser — looks for names based on the number of
# tokens since the start of the declaration (SOD/SODEC). Used for
# functions, etc.if/else
# statements. Not used by HeaderDoc; used by other
# tools that share this parser.
# @var HeaderDoc::fileDebug
# Set to 1 by the outer layers when the filename
# matches a particular filename. This is useful
# when you need to enable lots of debugging for a
# single file. When 1, enables lots of debugging.
# @var HeaderDoc::lang
# The programming language being parsed. This is
# deprecated, and is used only if you do not pass
# in a value for the lang parameter.
# @var HeaderDoc::sublang
# The programming language dialect being parsed
# (e.g. cpp for C++). This is
# deprecated, and is used only if you do not pass
# in a value for the sublang parameter.
# @var HeaderDoc::AccessControlState
# The current access control state (public, private,
# protected, etc.). When a permanent access control
# change (with a colon after it) occurs, this global
# variable is modified. After a declaration, the
# temporary (per-declaration) access control state is
# restored from this variable.
# @var HeaderDoc::parsing_man_pages
# Set to 1 if (in C) you want a function declaration
# to end after the closing parenthesis even if there
# is no trailing semicolon. Do NOT set this for
# normal parsing; it will break many typedef
# declarations and similar. This also enables
# some broken man page detection for deleting lines
# that say or and and.
#
# @vargroup Key parser state variables
#
# @var continue
# Indicates that parsing should continue. Upon receiving a terminating token,
# this gets set to zero, and parsing ends at the end of the line.
# @var continue_no_return
# This gets high when we see an opening brace at the start of parsing. If the
# parser returned, you would get a bogus declaration, so instead, the parser
# reboots itself, starting parsing from scratch at the next line.
# @var lang
# The programming language being parsed. Set from
# HeaderDoc::lang.
# @var sublang
# The programming language dialect being parsed (e.g. cpp for C++).
# Set from HeaderDoc::sublang.
# @var callback_typedef_and_name_on_one_line
# Legacy formatting cruft variable.
# @var inRegexp
# Indicates whether the parser is in a regular expression. Values are:
# inRegexp
# variable only indicates how many pieces remain in the regexp. Although
# this is vital information, it is insufficient for this purpose.
# For a single-part regexp, you would have to look for 1, but for a two-part
# regexp, a 1 would indicate the last part instead of the first.
# This variable solves that problem.
#
# Values are:
#
# inRegexpCharClass has
# several values:
#
# inRegexpFirstPart to 0.
# @var leavingRegexp
# In the trailing part of a regular expression.
# @var inParen
# Indicates the number of levels of nested parentheses the current
# token is within.
# @var inPType
# Indicates that the parser is currently processing a Pascal type declaration.
# @var ppSkipOneToken
# Used to tell the parameter parsing code to skip the end-of-comment
# character. (The value of inComment (in the
# parserState object) goes to 0 before that code, so
# without this, it would end up at the start of the next parameter.)
# @var asConcat
# In AppleScript parsing, set to 1 when a vertical pipe operator (|) is
# encountered to protect an identifier. Set to 0 when the next vertical
# pipe operator is encountered.
#
# @vargroup Parameter parsing
#
# @var inPrivateParamTypes
# In the cruft after a colon in a C++ method declaration.
#
# @vargroup Token variables
#
# @var curline
# The (input) line being parsed.
# @var part
# The current token being processed (from curline).
# @var nextpart
# The token after the token being processed (from curline).
# @var treepart
# In some cases, it is necessary to drop a token for formatting purposes but keep it in
# the parse tree. When this is needed, the treepart variable contains
# the original token, and the part variable contains a placeholder value
# (generally a space).
# @var lastchar
# This variable is rather odd. The last token in this string is the last character,
# but it may contain multiple characters. This should probably not be used in the
# parser, but it is used in a few spots.
# @var lastnspart
# The last non-space token encountered.
# @var lasttoken
# The last token encountered (though newlines and carriage returns may be
# replaced by a space).
#
# @vargroup Parser states and parser state insertion
#
# @var parserState
# The {@link //apple_ref/perl/cl/HeaderDoc::ParserState ParserState}
# object used for storing most of the parser state variables.
#
# @var sethollow
# This variable is normally 0. It gets set to 1 to tell the hollow insertion code
# (at the bottom of the token loop) to set the value of the hollow
# variable (in the parserState object) to the tree node for the current
# token (which has not been created yet at the time this variable gets set).
# @var hollowskip
# Indicates that in spite of sethollow being set to 1, the current node is a bad place
# to insert the parser state because it is one of the access control tokens (e.g.
# public/private) or because it isn't really being inserted into the tree.
#
# @var pushParserStateAfterToken
# Normally 0. Set to 1 if the parser state should be pushed onto the stack
# after this token.
#
# @var pushParserStateAfterWordToken
# Normally 0. Set to 1 if the parser state should be pushed onto the stack
# after the next word token. May also be set to 2 if the parser state
# should be pushed at the word token after the next word token.
#
# @var pushParserStateAtBrace
# Normally 0. Set to 1 if the parser state should be pushed onto the stack
# after the next opening brace.
#
# @var occPushParserStateOnWordTokenAfterNext
# Normally 0. The name of this variable is slightly misleading. When used,
# the variable is initially set to 2. On the next word token (and only a word
# token), this variable is decremented to 1.
#
# At this point, matching behavior changes, and the parser state is pushed
# at the first token that is either a word token, an at sign (\@), a
# minus sign (-), or a plus sign (+).
#
# @vargroup Tree management
#
# @var treeTop
# The top of the current parse tree.
# @var treeCur
# The current position in the parse tree.
# @var treeNest
# Used to control whether the code at the bottom of the token loop should trigger a loop
# nesting after the current token.
#
# treeStack stack after the next newline character.
# @var trailingHide
# Indicates that this is a token that follows a state change to a new state in which
# the seenBraces flag was previously set, and that this token should be treated as
# though seenBraces were still set. This flag is only supported in bits of code after
# where it is first set (in the right closing brace code).
#
# @vargroup Parser stacks
#
# @var regexpStack
# Stack for regular expression characters.
# @var braceStack
# Stack for brace tokens, including the left curly brace, the start-of-template
# (sotemplate) value, the left square bracket, the left parenthesis
# and the opening class marker for class markers that aren't followed by a left
# curly brace (Objective-C \@interface, for example).
# @var parsedParamParseStack
# A stack containing values from parsedParamParse (in
# the parserState object). These are
# pushed and popped on curly braces, parentheses, etc. This is basically used
# for keeping track of which split character to use as the parser goes into
# deeper nesting levels (e.g. when dropping into a function pointer/callback
# inside a struct).
# @var treeStack
# A stack of parse trees. These are pushed and popped at various points during
# the parse process as braces, colons, parentheses, etc. The behavior is
# controlled by the variables treeNest, treeSkip,
# treePopTwo (in parserState, and
# treePopOnNewLine.
#
# @vargroup Legacy junk variables
#
# @var prespace
# Temporary variable used for leading space during formatting.
# @var prespaceadjust
# Temporary variable used for leading space during formatting.
# @var scratch
# Temporary storage used during formatting.
# @var curstring
# The string currently being parsed. Was at one time used
# for checking for quoting, but no longer.
# @var continuation
# An obscure spacing workaround.
# @var forcenobreak
# An obscure spacing workaround.
# @var setNoInsert
# When set to a nonzero value, the noInsert variable in the ParseTree
# object created after the next open curly brace gets set to this value.
# */
sub blockParse
{
my $fullpath = shift;
my $fileoffset = shift;
my $inputLinesRef = shift;
my $inputCounter = shift;
my $argparse = shift;
my $ignoreref = shift;
my $perheaderignoreref = shift;
my $perheaderignorefuncmacrosref = shift;
my $keywordhashref = shift;
my $case_sensitive = shift;
my $lang = shift;
my $sublang = shift;
if (!$lang) {
print STDERR "WARNING: Old API use detected. Please update your\ncode to call blockParse with a lang argument.\nThis will break in a future version of HeaderDoc.\n";
cluck("Backtrace:\n");
$lang = $HeaderDoc::lang;
}
if (!$sublang) {
$sublang = $HeaderDoc::sublang;
print STDERR "WARNING: Old API use detected. Please update your\ncode to call blockParse with a sublang argument.\nThis will break in a future version of HeaderDoc.\n";
cluck("Backtrace:\n");
}
# print STDERR "AP: $argparse\n";
# print STDERR "LANG: $lang\n";
# print STDERR "SUBLANG: $sublang\n";
if ($lang eq "python") {
return pythonParse($fullpath, $fileoffset, $inputLinesRef, $inputCounter,
$argparse, $ignoreref, $perheaderignoreref, $perheaderignorefuncmacrosref,
$keywordhashref, $case_sensitive, $lang, $sublang);
}
my $apwarn = 0;
if ($argparse && $apwarn) {
print STDERR "argparse\n";
}
# Initialize stuff
my @inputLines = @{$inputLinesRef};
my $declaration = "";
my $publicDeclaration = "";
# $HeaderDoc::fileDebug = 1;
# Debugging switches
my $retDebug = 0;
my $localDebug = 0 || $HeaderDoc::fileDebug;
my $operatorDebug = 0;
my $listDebug = 0;
my $parseDebug = 0 || $HeaderDoc::fileDebug;
my $sodDebug = 0 || $HeaderDoc::fileDebug;
my $valueDebug = 0;
my $parmDebug = 0;
my $bitfieldDebug = 0;
my $cbnDebug = 0;
my $macroDebug = 0;
my $apDebug = 0;
my $tsDebug = 0;
my $treeDebug = 0;
my $ilcDebug = 0;
my $regexpDebug = 0; # 0, 1, 2
my $parserStackDebug = 0 || $HeaderDoc::fileDebug; # 0, 1, 2
my $braceDebug = 0 || $HeaderDoc::fileDebug;
my $hangDebug = 0;
my $offsetDebug = 0;
my $classDebug = 0; # prints changes to inClass, etc.
my $gccAttributeDebug = 0; # also for availability macro argument handling.
my $occMethodNameDebug = 0;
my $moduleDebug = 0; # prints changes to INMODULE
my $lineDebug = 0 || $HeaderDoc::fileDebug; # Just prints the lines.
my $liteDebug = 0 || $HeaderDoc::fileDebug; # Just prints the tokens.
my $tokenDebug = 0;
my $functionContentsDebug = 0;
my $continueDebug = 0;
my $parserStateInsertDebug = 0;
my $rubyDebug = 0;
my $asDebug = 0;
my $reMarkDebug = 0;
if ($asDebug && (!$HeaderDoc::AppleScriptDebug)) { $HeaderDoc::AppleScriptDebug = 1; }
$cppDebug = $cppDebugDefault ? $cppDebugDefault : $HeaderDoc::fileDebug;
# State variables (part 1 of 3)
# my $typestring = "";
my $continue = 1; # set low when we're done.
my $continue_no_return = 0; # set high if should restart block parser from the next line.
# my $parserState->{parsedParamParse} = 0; # set high when current token is part of param. * now in state *
# my @parsedParamList = (); # currently active parsed parameter list.
# my @pplStack = (); # stack of parsed parameter lists. Used to handle
# fields and parameters in nested callbacks/structs.
# my @freezeStack = (); # copy of pplStack when frozen.
# my $frozensodname = "";
# my $stackFrozen = 0; # set to prevent fake parsed params with inline funcs
# my $lang = $HeaderDoc::lang;
# my $sublang = $HeaderDoc::sublang;
my $callback_typedef_and_name_on_one_line = 1; # deprecated
# my $returntype = "";
# my $freezereturn = 0; # set to prevent fake return types with inline funcs
my $treeNest = 0; # 1: nest future content under this node.
# 2: used if you want to nest, but have already
# inserted the contents of the node.
my $sethollow = 0;
my $setNoInsert = 0;
my $treepart = ""; # There are some cases where you want to drop a token
# for formatting, but keep it in the parse tree.
# In that case, treepart contains the original token,
# while part generally contains a space.
# my $availability = ""; # holds availability string if we find an av macro.
# my $seenTilde = 0; # set to 1 for C++ destructor.
if ($argparse && $tsDebug) { $tsDebug = 0; }
# Configure the parse tree output.
my $treeTop = HeaderDoc::ParseTree->new(); # top of parse tree.
my $treeCur = $treeTop; # current position in parse tree
my $treeSkip = 0; # set to 1 if "part" should be dropped in tree.
# my $treePopTwo = 0; # set to 1 for tokens that nest, but have no
# explicit ending token ([+-:]).
my $treePopOnNewLine = 0; # set to 1 for single-line comments, macros.
my @treeStack = (); # stack of parse trees. Used for popping
# our way up the tree to simplify tree structure.
# Leak a node here so that every real node has a parent.
$treeCur = $treeCur->addChild("");
$treeTop = $treeCur;
# print STDERR "TREE TOP GOING IN IS $treeTop\n" if ($localDebug);
my $lastACS = "";
# The argparse switch is a trigger....
if ($argparse && $apDebug) {
$localDebug = 1;
$retDebug = 1;
$listDebug = 1;
$parseDebug = 1;
$sodDebug = 1;
$valueDebug = 1;
$parmDebug = 1;
$cbnDebug = 1;
$macroDebug = 1;
# $apDebug = 1;
$tsDebug = 1;
$treeDebug = 1;
$ilcDebug = 1;
$regexpDebug = 1;
}
my $spaceDebug = 0;
if ($localDebug || $apDebug || $liteDebug || $parseDebug) {
print STDERR "ENTERED BLOCKPARSE\n";
}
my $disable_cpp = 0;
if ($argparse && ($localDebug || $apDebug || $liteDebug)) {
print STDERR "ARGPARSE MODE!\n";
print STDERR "IPC: $inputCounter\nNLINES: ".$#inputLines."\n";
cluck("Call backtrace\n");
}
print STDERR "INBP\n" if ($localDebug);
if ($argparse) {
# Avoid double-processing macro inclusions.
$disable_cpp = 1;
}
if (($lang ne "C" && $lang ne "Csource") || $sublang eq "php") { # || $sublang eq "IDL")
$disable_cpp = 1;
}
print STDERR "INITIAL LANG: $lang INITIAL SUBLANG: $sublang\n" if ($localDebug);
# warn("in BlockParse\n");
# State variables (part 2 of 3)
my $parserState = HeaderDoc::ParserState->new( "FULLPATH" => $fullpath, "lang" => $lang, "sublang" => $sublang );
# $parserState->{hollow} = $treeTop;
$parserState->setHollowWithLineNumbers($treeTop, $fileoffset, $inputCounter);
$parserState->{inputCounter} = $inputCounter;
$parserState->{initbsCount} = 0; # included for consistency....
my @parserStack = ();
# print STDERR "TEST: ";
# if (defined($parserState->{parsedParamList})) {
# print STDERR "defined\n"
# } else { print STDERR "undefined.\n"; }
# print STDERR "\n";
# my $inComment = 0;
# my $inInlineComment = 0;
# my $inString = 0;
# my $inChar = 0;
# my $inTemplate = 0;
my @braceStack = ();
my @parsedParamParseStack = ();
# my $inOperator = 0;
my $inPrivateParamTypes = 0; # after a colon in a C++ function declaration.
# my $onlyComments = 1; # set to 0 to avoid switching to macro parse.
# mode after we have seen a code token.
# my $inMacro = 0;
# my $inMacroLine = 0; # for handling macros in middle of data types.
# my $seenMacroPart = 0; # used to control dropping of macro body.
# my $macroNoTrunc = 1; # used to avoid truncating body of macros
# that don't begin with parenthesis or brace.
# my $inBrackets = 0; # square brackets ([]).
my $inPType = 0; # in pascal types.
my $inRegexp = 0; # in regexp.
my $leavingRegexp = 0; # inRegexp just went to zero, but don't process
# this symbol differently in case it's a brace
# or parenthesis.
my $inRegexpFirstPart = 0; # 2 if in leading chars, 1 after first / or
# whatever, 0 after second / or outside regexp.
my $inRegexpCharClass = 0; # 3 until end of loop.
# 2 for first char of regexp character class,
# 1 elsewhere in character class, 0 otherwise.
my $regexpNoInterpolate = 0; # Don't interpolate (e.g. tr)
my $inRegexpTrailer = 0; # in the cruft at the end of a regexp.
my $hollowskip = 0;
my $ppSkipOneToken = 0; # Comments are always dropped from parsed
# parameter lists. However, inComment goes
# to 0 on the end-of-comment character.
# This prevents the end-of-comment character
# itself from being added....
#### my $regexppattern = ""; # optional characters at start of regexp
#### my $singleregexppattern = ""; # members of regexppattern that take only
#### # one argument instead of two.
#### my $regexpcharpattern = ""; # legal chars to start a regexp.
my @regexpStack = (); # stack of RE tokens (since some can nest).
# Get the parse tokens from Utilities.pm.
# my ($parseTokens{sotemplate}, $parseTokens{eotemplate}, $parseTokens{operator}, $parseTokens{soc}, $parseTokens{eoc}, $parseTokens{ilc}, $parseTokens{ilc_b}, $parseTokens{sofunction},
# $parseTokens{soprocedure}, $parseTokens{sopreproc}, $parseTokens{lbrace}, $parseTokens{rbrace}, $parseTokens{unionname}, $parseTokens{structname},
# $parseTokens{enumname},
# $parseTokens{typedefname}, $parseTokens{varname}, $parseTokens{constname}, $parseTokens{structisbrace}, $parseTokens{macronames},
# $NOCHANGEclassregexp, $NOCHANGEclassbraceregexp, $NOCHANGEclassclosebraceregexp, $NOCHANGEaccessregexp,
# $NOCHANGErequiredregexp, $parseTokens{propname}, $parseTokens{objcdynamicname}, $parseTokens{objcsynthesizename}, $NOCHANGEmoduleregexp, $parseTokens{definename},
# $parseTokens{functionisbrace}, $parseTokens{classisbrace}, $parseTokens{lbraceconditionalre}, $parseTokens{lbraceunconditionalre}, $parseTokens{assignmentwithcolon},
# $NOCHANGElabelregexp, $parseTokens{parmswithcurlybraces}, $parseTokens{superclasseswithcurlybraces}, $parseTokens{soconstructor}) = parseTokens($lang, $sublang);
my %parseTokens = %{parseTokens($lang, $sublang)};
my $labelregexp = $parseTokens{labelregexp};
my $classregexp = $parseTokens{classregexp};
my $classbraceregexp = $parseTokens{classbraceregexp};
my $classclosebraceregexp = $parseTokens{classclosebraceregexp};
my $accessregexp = $parseTokens{accessregexp};
my $requiredregexp = $parseTokens{requiredregexp};
my $moduleregexp = $parseTokens{moduleregexp};
my $regexppattern = $parseTokens{regexppattern};
my $singleregexppattern = $parseTokens{singleregexppattern};
my $regexpfirstcharpattern = $parseTokens{regexpfirstcharpattern};
my $regexpcharpattern = $parseTokens{regexpcharpattern};
my $regexpAllowedAfter = $parseTokens{regexpAllowedAfter};
my $TCLregexpcommand = $parseTokens{TCLregexpcommand};
# print STDERR "SOCONSTRUCTOR: \"$parseTokens{soconstructor}\"\n";
if ($argparse && $lang eq "applescript") {
$parseTokens{assignmentwithcolon} = 2;
}
my $macrore_pound = macroRegexpFromList($parseTokens{macronames}, 1);
my $macrore_nopound = macroRegexpFromList($parseTokens{macronames}, 2);
# print STDERR "LANG: $lang SUBLANG: $sublang";
print STDERR "MACRORE_POUND: \"$macrore_pound\"\n" if ($localDebug || $parseDebug);
print STDERR "MACRORE_NOPOUND: \"$macrore_nopound\"\n" if ($localDebug || $parseDebug);
# print STDERR "INITIAL PROPNAME $parseTokens{propname}\n";
if ($parseDebug) {
print STDERR "SOT: $parseTokens{sotemplate} EOF: $parseTokens{eotemplate} OP: $parseTokens{operator} SOC: $parseTokens{soc} EOC: $parseTokens{eoc} ILC: $parseTokens{ilc} ILC_B: $parseTokens{ilc_b}\n";
print STDERR "SOFUNC: $parseTokens{sofunction} SOPROC: $parseTokens{soprocedure} SOPREPROC: $parseTokens{sopreproc} LBRACE: $parseTokens{lbrace} RBRACE: $parseTokens{rbrace}\n";
print STDERR "UNION: $parseTokens{unionname} STRUCT: $parseTokens{structname} TYPEDEF: $parseTokens{typedefname} VAR: $parseTokens{varname} CONST: $parseTokens{constname}\n";
print STDERR "STRUCTISBRACE: $parseTokens{structisbrace} MACRONAMEREF: $parseTokens{macronames} CLASSRE: $classregexp\n";
print STDERR "CLASSBRACERE: $classbraceregexp CLASSCLOSEBRACERE: $classclosebraceregexp ACCESSRE: $accessregexp\n";
print STDERR "MODULERE: $moduleregexp\n";
}
# Set up regexp patterns for perl, variable for perl or shell.
if ($lang eq "perl" || $lang eq "shell" || $lang eq "tcl") {
if ($lang eq "perl") {
#### # $regexpcharpattern = '\\{|\\#\\(|\\/|\\\'|\\"|\\<|\\[|\\`';
#### # "}" vi bug workaround for previous line
#### $regexpcharpattern = "[[|{#(/'\"<`]";
#### # "}" vi bug workaround for previous line
#### $regexppattern = "qq|qr|qx|qw|q|m|s|tr|y";
#### $singleregexppattern = "qq|qr|qx|qw|q|m";
}
}
my $pascal = 0; my $ruby = 0;
if ($lang eq "pascal") { $pascal = 1; }
if ($lang eq "ruby") { $ruby = 1; }
# State variables (part 3 of 3)
# my $lastsymbol = ""; # Name of the last token, wiped by braces,
# parens, etc. This is not what you are
# looking for. It is used mostly for
# handling names of typedefs.
# my $name = ""; # Name of a basic data type.
# my $callbackNamePending = 0; # 1 if callback name could be here. This is
# only used for typedef'ed callbacks. All
# other callbacks get handled by the parameter
# parsing code. (If we get a second set of
# parsed parameters for a function, the first
# one becomes the callback name.)
# my $callbackName = ""; # Name of this callback.
# my $callbackIsTypedef = 0; # 1 if the callback is wrapped in a typedef---
# sets priority order of type matching (up
# one level in headerdoc2HTML.pl).
# my $namePending = 0; # 1 if name of func/variable is coming up.
# my $basetype = ""; # The main name for this data type.
# my $posstypes = ""; # List of type names for this data type.
# my $posstypesPending = 1; # If this token could be one of the
# type names of a typedef/struct/union/*
# declaration, this should be 1.
# my $sodtype = ""; # 'start of declaration' type.
# my $sodname = ""; # 'start of declaration' name.
# my $sodclass = ""; # 'start of declaration' "class". These
# bits allow us keep track of functions and
# callbacks, mostly, but not the name of a
# callback.
# my $simpleTypedef = 0; # High if it's a typedef w/o braces.
# my $simpleTDcontents = ""; # Guts of a one-line typedef. Don't ask.
# my $seenBraces = 0; # Goes high after initial brace for inline
# functions and macros -only-. We
# essentially stop parsing at this point.
# my $kr_c_function = 0; # Goes high if we see a K&R C declaration.
# my $kr_c_name = ""; # The name of a K&R function (which would
# otherwise get lost).
my $lastchar = ""; # Ends with the last token, but may be longer.
my $lastnspart = ""; # The last non-whitespace token.
my $lasttoken = ""; # The last token seen (though [\n\r] may be
# replaced by a space in some cases.
# my $startOfDec = 1; # Are we at the start of a declaration?
my $prespace = 0; # Used for indentation (deprecated).
my $prespaceadjust = 0; # Indentation is now handled by the parse
# tree (colorizer) code.
my $scratch = ""; # Scratch space.
my $curline = ""; # The current line. This is pushed onto
# the declaration at a newline and when we
# enter/leave certain constructs. This is
# deprecated in favor of the parse tree.
my $curstring = ""; # The string we're currently processing.
my $continuation = 0; # An obscure spacing workaround. Deprecated.
my $forcenobreak = 0; # An obscure spacing workaround. Deprecated.
# my $occmethod = 0; # 1 if we're in an ObjC method.
my $occspace = 0; # An obscure spacing workaround. Deprecated.
# my $occmethodname = ""; # The name of an objective C method (which
# gets augmented to be this:that:theother).
# my $preTemplateSymbol = ""; # The last symbol prior to the start of a
# C++ template. Used to determine whether
# the type returned should be a function or
# a function template.
# my $preEqualsSymbol = ""; # Used to get the name of a variable that
# is followed by an equals sign.
# my $valuepending = 0; # True if a value is pending, used to
# return the right value.
# my $value = ""; # The current value.
my $parsedParam = ""; # The current parameter being parsed.
my $postPossNL = 0; # Used to force certain newlines to be added
# to the parse tree (to end macros, etc.)
# my $followingrubyrbrace = 0; # A while or other statement right after
# an end statement (on the same line) does
# not get treated as an opening brace.
# Set to 1 when end is encounered, 0 at
# following newline.
# my $categoryClass = "";
# my $classtype = "";
# my $inClass = 0;
my $asConcat = "";
my $pushParserStateAfterToken = 0;
my $pushParserStateAfterWordToken = 0;
my $pushParserStateAtBrace = 0;
my $occPushParserStateOnWordTokenAfterNext = 0;
if (!$disable_cpp && (1 || $HeaderDoc::enable_cpp)) {
if ($cpp_debug_file) {
if (basename($fullpath) ne $cpp_debug_lastfile) {
open(CPP_DEBUG_FILE, ">>$cpp_debug_file");
print CPP_DEBUG_FILE "DUMPING CPP INFORMATION FOR $fullpath\n";
close(CPP_DEBUG_FILE);
my $filename = basename($fullpath);
$cpp_debug_lastfile = $filename;
}
}
}
$HeaderDoc::hidetokens = 0;
# Loop unti the end of file or until we've found a declaration,
# processing one line at a time.
my $nlines = $#inputLines;
my $incrementoffsetatnewline = 0;
print STDERR "INCOMING INPUTCOUNTER: $inputCounter\n" if ($HeaderDoc::inputCounterDebug);
print STDERR "IL[0]: ".$inputLines[0]."\n" if ($hangDebug);
while ($continue && ($inputCounter <= $nlines)) {
print STDERR "IC: $inputCounter NLINES: $nlines\n" if ($hangDebug);
$HeaderDoc::CurLine = $inputCounter + $fileoffset;
my $line = $inputLines[$inputCounter++];
print STDERR "GOT LINE: $line\n" if (($localDebug && $apDebug) || $lineDebug || $HeaderDoc::inputCounterDebug);
print STDERR "INCREMENTED INPUTCOUNTER [1]\n" if ($HeaderDoc::inputCounterDebug);
my @parts = ();
# $line =~ s/^\s*//go; # Don't strip leading spaces, please.
$line =~ s/\s*$//go;
# $scratch = nspaces($prespace);
# $line = "$scratch$line\n";
# $curline .= $scratch;
$line .= "\n";
if ($lang eq "C" && $sublang eq "IDL") {
if ($line =~ /cpp_quote\s*\(\s*\"(.*)\"\s*\)\s*$/) {
print STDERR "CHANGED LINE FROM \"$line\" to " if ($localDebug || $liteDebug);
$line = $1."\n";
$line =~ s/\\\"/"/sg;
print STDERR "\"$line\"\n" if ($localDebug || $liteDebug);
}
}
print STDERR "LINE[$inputCounter] : $line\n" if ($offsetDebug);
# The tokenizer
if ($lang eq "perl") {
@parts = split(/(->|=>|\&\&|\|\||"|'|\#|\{|\}|\(|\)|\s|;;|;|::|\\|\<\<|\W)/, $line);
} elsif ($lang eq "shell") {
@parts = split(/("|'|\#|\{|\}|\(|\)|\s|;;|;|::|\\|\<\<|\W)/, $line);
} elsif ($lang eq "tcl") {
@parts = split(/("|'|\#|\{|\}|\(|\)|\s|;|\\|::|\/\*|\*\/|\W)/, $line);
} elsif ($ruby) {
@parts = split(/(=begin|=end|\%\{|\%\/|\%Q\{|\<\<\-|"|'|\/\/|\/\*|\*\/|::|\-\-|\+\+|==|<=|>=|!=|\<\<|\>\>|\{|\}|\(|\)|\s|;|\\|\^|\W)/, $line);
} elsif ($lang eq "applescript") {
# Easier to have the tokenizer combine these multi-word tokens than
# to do it later.
# Because this regexp terrifies mere mortals, here's an explanation:
# The (?<=\s) causes whatever is after it to match only if what
# preceded it was whitespace, but does not include the whitespace
# as part of the token itself. This is very important to avoid
# strange behavior. Similarly, the (?!\s) does the same thing for
# whitespace at the end of the token.
@parts = split(/((?<=\s)apart\s+from(?!\s)|(?<=\s)aside\s+from(?!\s)|(?<=\s)instead\s+of(?!\s)|(?<=\s)out\s+of(?!\s)|"|'|\/\/|\(\*|\*\)|::|\-\-|\+\+|==|<=|>=|!=|\<\<|\>\>|\{|\}|\(|\)|\s|;|\\|\^|\W)/, $line);
} else {
@parts = split(/("|'|\/\/|\/\*|\*\/|\.\.\.|::|\-\-|\+\+|==|<=|>=|!=|\<\<|\>\>|\{|\}|\(|\)|\s|;|\\|\^|\W)/, $line);
}
# See note about similar block below. This block is for fixing the
# "missing newline" problem, which otherwise would cause line numbers
# to sometimes be wrong.
push(@parts, "BOGUSBOGUSBOGUSBOGUSBOGUS");
my $xpart = "";
foreach my $nextxpart (@parts) {
if (!length($nextxpart)) { next; }
if (!length($xpart)) { $xpart = $nextxpart; next; }
if ($xpart eq "\n" && $nextxpart ne "BOGUSBOGUSBOGUSBOGUSBOGUS") {
print STDERR "FOUND EXTRA NEWLINE\n" if ($offsetDebug);
# $fileoffset++;
$incrementoffsetatnewline++;
}
$xpart = $nextxpart;
}
pop(@parts);
$parserState->{inInlineComment} = 0;
print STDERR "inInlineComment -> 0\n" if ($ilcDebug);
# warn("line $inputCounter\n");
if ($localDebug || $cppDebug || $spaceDebug || $cppDebugFromToken) {
foreach my $partlist (@parts) {
print STDERR "PARTLIST: \"$partlist\"\n";
if ($partlist eq $cppDebugFromToken && length($cppDebugFromToken)) {
$cppDebug = 1; $parseDebug = 1; $macroDebug = 1;
}
}
}
# We have to do the C preprocessing work up front because token substitution
# must occur prior to actual parsing in order to do any good. This block does
# the work.
my $cpp_in_argparse = 0;
if (!$disable_cpp && (1 || $HeaderDoc::enable_cpp)) {
my $newrawline = "";
my $incppargs = 0;
my $cppstring = "";
my $cppname = "";
my $lastcpppart = "";
my @cppargs = ();
my $inChar = 0; my $inString = 0; my $inComment = $parserState->{inComment}; my $inSLC = $parserState->{inInlineComment};
my $inParen = 0;
my $inMacro = $parserState->{inMacro};
my $inCPPSpecial = $parserState->{inMacro} || $parserState->{inMacroLine};
my $inMacroTail = 0;
if ($parserState->{sodname} && ($parserState->{sodname} ne "")) {
$inMacroTail = 1;
}
print STDERR "INMACROTAIL: $inMacroTail\n" if ($cppDebug);
my @cpptrees;
my $cpptreecur = HeaderDoc::ParseTree->new();
my $cpptreetop = $cpptreecur;
my $definename = $parseTokens{definename};
print STDERR "CHECK LINE $line\n" if ($cppDebug || $hangDebug);
if ($line =~ /^\s*#(include|import)\s(.*)$/) {
print STDERR "IS INCLUDE OR IMPORT\n" if ($cppDebug);
my $token = $1;
my $rest = $2;
$rest =~ s/^\s*//s;
$rest =~ s/\s*$//s;
if ($rest !~ s/^\<(.*)\>$/$1/s) {
$rest =~ s/^\"(.*)\"$/$1/s;
}
my $filename = basename($rest);
if ($HeaderDoc::HeaderFileCPPHashHash{$filename}) {
my $includehash = HeaderDoc::IncludeHash->new();
$includehash->{FILENAME} = $filename;
$includehash->{LINENUM} = $inputCounter + $fileoffset;
$includehash->{HASHREF} = $HeaderDoc::HeaderFileCPPHashHash{$filename};
push(@HeaderDoc::cppHashList, $includehash);
# print STDERR "PUSH HASH\n";
push(@HeaderDoc::cppArgHashList, $HeaderDoc::HeaderFileCPPArgHashHash{$filename});
}
} elsif ($line =~ /^\s*$definename\s+/) {
print STDERR "IS DEFINE\n" if ($cppDebug);
# print STDERR "inMacro -> 1\n";
# print STDERR "inMacro -> 1\n" if ($macroDebug || $cppDebug);
# This is a throwaway line.
$inMacro = 1;
}
if ($macrore_pound ne "" && $line =~ /^\s*\#\s*$macrore_pound\s+/) {
print STDERR "CPPSPECIAL -> 1\n" if ($macroDebug || $cppDebug);
$inCPPSpecial = 1;
}
my $cppleaddebug = 0;
do {
my $pos = 0;
my $dropargs = 0;
print STDERR "ENTERING CPP LOOP\n" if ($hangDebug);
while ($pos < scalar(@parts)) {
my $part = $parts[$pos];
my $noCPPThisToken = 0;
print STDERR "IN CPP LOOP. PART IS $part INCPPARGS: $incppargs\n" if ($cppDebug || $hangDebug);
if (length($part)) {
if (!$inChar && !$inString && !$inComment && !$inSLC) {
if ($parserState->{NEXTTOKENNOCPP} == 1) {
print STDERR "In an \"if\" block (NTNCPP=1)\n" if ($cppDebug);
# We're in an "if" block.
if ($part eq "defined") {
$parserState->{NEXTTOKENNOCPP} = 3;
}
} elsif ($parserState->{NEXTTOKENNOCPP} == 2) {
print STDERR "In an \"ifdef/ifndef\" block\n" if ($cppDebug);
# We're in an "ifdef"/"ifndef" block, so first word token
# ends this mode completely.
if ($part !~ /(\s|\()/) {
$parserState->{NEXTTOKENNOCPP} = 0;
$noCPPThisToken = 1;
}
} elsif ($parserState->{NEXTTOKENNOCPP} == 3) {
print STDERR "In an \"if\" block (NTNCPP=3)\n" if ($cppDebug);
# We're in an "if" block, so first word token
# drops us back to default "if" block state.
if ($part !~ /(\s|\()/) {
$parserState->{NEXTTOKENNOCPP} = 1;
$noCPPThisToken = 1;
}
}
if ($inCPPSpecial && $part =~ /^(ifdef|ifndef)$/) {
print STDERR "CPPSpecial: ifdef/ifndef\n" if ($cppDebug);
$parserState->{NEXTTOKENNOCPP} = 2;
} elsif ($inCPPSpecial && $part =~ /^if$/) {
print STDERR "CPPSpecial: if\n" if ($cppDebug);
$parserState->{NEXTTOKENNOCPP} = 1;
}
}
print STDERR "TOKEN: $part NEXTTOKENNOCPP: ".$parserState->{NEXTTOKENNOCPP}." INMACRO: $inMacro INCPPSPECIAL: $inCPPSpecial\n" if ($cppleaddebug || $macroDebug || $cppDebug);
print STDERR "CPPLEADPART: $part\n"if ($cppleaddebug);
if (!$inString && !$inChar) {
if ($inComment && $part eq $parseTokens{eoc}) {
print STDERR "EOC\n"if ($cppleaddebug);
$inComment = 0;
} elsif ($inSLC && $part =~ /[\r\n]/) {
# Handle newline in single-line comments.
print STDERR "EOSLC\n"if ($cppleaddebug);
$inSLC = 0;
} elsif (!$inSLC && $part eq $parseTokens{soc}) {
print STDERR "SOC\n"if ($cppleaddebug);
$inComment = 1;
} elsif (!$inComment && ($part eq $parseTokens{ilc} || $part eq $parseTokens{ilc_b})) {
print STDERR "INSLC\n"if ($cppleaddebug);
$inSLC = 1;
}
}
my $skip = 0;
if (!$incppargs) {
my $newpart = $part;
my $hasargs = 0;
if (!$inComment && !$inSLC && !$noCPPThisToken) {
my $tempstring = "";
($newpart, $hasargs, $tempstring) = cpp_preprocess($part, $HeaderDoc::CurLine);
# Don't drop tokens in macros.
if ($hasargs == 2 && $inMacro) {
$newpart = $part;
$hasargs = 0;
}
# Don't change the macro name. (If a
# macro gets redefined, ignore it.)
if ($inMacro && !$inMacroTail) {
$newpart = $part;
$hasargs = 0;
}
}
if ($hasargs) {
print STDERR "HAS ARGS!\n" if ($cppDebug);
$incppargs = 1;
$cppname = $part;
if ($hasargs == 2) {
$dropargs = 1;
print STDERR "Dropping arguments for ignored macro \"$part\"\n" if ($cppDebug);
}
} else {
my $newpartnl = $newpart;
my $newpartnlcount = ($newpartnl =~ tr/\n//);
my $partnl = $part;
my $partnlcount = ($partnl =~ tr/\n//);
my $nlchange = ($newpartnlcount - $partnlcount);
print STDERR "NLCHANGE: $nlchange (FILEOFFSET = $fileoffset)\n" if ($offsetDebug);
$fileoffset -= $nlchange;
if ($inMacro) {
if ($newpart ne $part) {
print STDERR "CHANGING NEWPART FROM \"$newpart\" TO " if ($cppDebug);
$newpart =~ s/^\s*/ /s;
$newpart =~ s/\s*$//s;
$newpart =~ s/(.)\n/$1 \\\n/sg;
$newpart =~ s/\\$/ /s;
print STDERR "$newpart\n" if ($cppDebug);
}
}
$newrawline .= $newpart;
}
} elsif ($incppargs == 1) {
if ($part eq "(") {
# Don't do anything until leading parenthesis.
$incppargs = 3;
$inParen++;
}
} elsif ($incppargs == 3) {
if ($part eq '\\') {
if (!$inMacro && ($lastcpppart eq '\\')) { $lastcpppart = ""; } # @@@ CHECKME. inMacro test may not be needed.
# else {
# $lastcpppart = $part;
# if ($inMacro) {
# print STDERR "IMTEST\n" if ($cppDebug > 1);
# my $npos = $pos + 1;
# while ($npos < scalar(@parts)) {
# my $npart = $parts[$npos];
# if (length($npart)) {
# print STDERR "NEXTPART: \"".$parts[$npos]."\"\n" if ($cppDebug > 1);
# if ($npart =~ /\s/) {
# if ($npart =~ /[\n\r]/) {
# print STDERR "SKIP1\n" if ($cppDebug > 1);
# $skip = 1; last;
# } else {
# print STDERR "SPC\n" if ($cppDebug > 1);
# }
# } else {
# print STDERR "LAST\n" if ($cppDebug > 1);
# last;
# }
# }
# $npos++;
# }
# }
# }
} elsif ($part eq '"') {
if ($lastcpppart ne '\\') {
if (!$inChar && !$inComment && !$inSLC) {
$inString = !$inString;
}
}
$lastcpppart = $part;
} elsif ($part eq "'") {
if ($lastcpppart ne '\\') {
if (!$inString && !$inComment && !$inSLC) {
$inChar = !$inChar;
}
}
$lastcpppart = $part;
} elsif (!$inChar && !$inString && !$inComment && !$inSLC) {
if ($part eq "(") {
# Put in the token first, then nest.
$cpptreecur = $cpptreecur->next(HeaderDoc::ParseTree->new());
$cpptreecur->token($part);
$skip = 1;
$inParen++;
push(@cpptrees, $cpptreecur);
$cpptreecur = $cpptreecur->firstchild(HeaderDoc::ParseTree->new());
} elsif ($part eq ")") {
$inParen--;
# Go out one nesting level, then
# insert the token.
if (scalar(@cpptrees)) {
$cpptreecur = pop(@cpptrees);
while ($cpptreecur && $cpptreecur->next()) {
$cpptreecur = $cpptreecur->next();
}
}
if (!$inParen) {
push(@cppargs, $cpptreetop);
$cppstring = "";
$cpptreetop = HeaderDoc::ParseTree->new();
$cpptreecur = $cpptreetop;
$skip = 1;
$incppargs = 0;
if (!$dropargs) {
print STDERR "CALLING ARGPARSE FROM blockParse() [1].\n" if ($cppDebug);
my $addon = cpp_argparse($cppname, $HeaderDoc::CurLine, \@cppargs);
if ($inMacro) {
print STDERR "CHANGING ADDON FROM:\n\"$addon\"\nTO:\n" if ($cppDebug);
$addon =~ s/^\s*/ /s;
$addon =~ s/\s*$//s;
$addon =~ s/(.)\n/$1 \\\n/sg;
$addon =~ s/\\$/ /s;
print STDERR "\"$addon\"\n" if ($cppDebug);
}
$newrawline .= $addon;
}
$dropargs = 0;
}
} elsif (($inParen == 1) && (!$inChar && !$inString && !$inComment && !$inSLC) && ($part eq ",")) {
push(@cppargs, $cpptreetop);
$cpptreetop = HeaderDoc::ParseTree->new();
$cpptreecur = $cpptreetop;
$cppstring = "";
$skip = 1;
} elsif (($part =~ /\s/) && (!$inParen)) {
$incppargs = 0;
if (!$dropargs) {
print STDERR "CALLING ARGPARSE FROM blockParse() [2].\n" if ($cppDebug);
my $addon = cpp_argparse($cppname, $HeaderDoc::CurLine, \@cppargs);
if ($inMacro) {
print STDERR "CHANGING ADDON FROM \"$addon\" TO " if ($cppDebug);
$addon =~ s/^\s*/ /s;
$addon =~ s/\s*$//s;
$addon =~ s/(.)\n/$1 \\\n/sg;
$addon =~ s/\\$/ /s;
print STDERR "$addon\n" if ($cppDebug);
}
$newrawline .= $addon;
}
$dropargs = 0;
}
$lastcpppart = $part;
}
if ($skip) { $skip = 0; }
else {
my $xpart = $part;
# Strip newline in CPP argument list.
if ($part =~ /[\r\n]/) { $xpart = " "; }
$cpptreecur = $cpptreecur->next(HeaderDoc::ParseTree->new());
$cpptreecur->token($xpart);
}
$cppstring .= $part;
}
if ($inMacro && $part ne "define" &&
$part =~ /\w/ && !$inParen) {
$inMacroTail = 1;
}
}
$pos++;
}
if ($incppargs) {
# print STDERR "YO\n";
if ($parserState->{inMacro} || $inMacro) {
# print STDERR "YOYO\n";
if ($cppstring !~ s/\\\s*$//s) {
warn "Non-terminated macro.\n";
print STDERR "CPPS: \"$cppstring\"\n";
$incppargs = 0;
}
}
}
if ($incppargs || $inComment) {
print STDERR "Fetching new line ($incppargs, $inComment)\n" if ($cppleaddebug);
$HeaderDoc::CurLine = $inputCounter + $fileoffset;
$line = $inputLines[$inputCounter++];
if ($lang eq "C" && $sublang eq "IDL") {
if ($line =~ /cpp_quote\s*\(\s*\"(.*)\"\s*\)\s*$/) {
print STDERR "CHANGED LINE FROM \"$line\" to " if ($localDebug || $liteDebug);
$line = $1."\n";
$line =~ s/\\\"/"/sg;
print STDERR "\"$line\"\n" if ($localDebug || $liteDebug);
}
}
print STDERR "INCREMENTED INPUTCOUNTER [2]\n" if ($HeaderDoc::inputCounterDebug);
# @parts = split(/(\W)/, $line);
# Perform a minimal tokenization of the new line for C preprocessing purposes.
if ($lang eq "perl" || $lang eq "shell") {
@parts = split(/("|'|\#|\{|\}|\(|\)|\s|;|\\|\W)/, $line);
} elsif ($lang eq "tcl") {
@parts = split(/("|'|\#|\{|\}|\(|\)|\s|;|\\|::|\/\*|\*\/|\W)/, $line);
} else {
@parts = split(/("|'|\/\/|\/\*|\*\/|::|==|<=|>=|!=|\<\<|\>\>|\{|\}|\(|\)|\s|;|\\|\W)/, $line);
}
}
print STDERR "LOOPBOTTOM: $incppargs, $inComment\n" if ($hangDebug);
} until (!$incppargs && !$inComment);
# Perform a minimal tokenization of the new line for C preprocessing purposes.
if ($lang eq "perl" || $lang eq "shell") {
@parts = split(/("|'|\#|\{|\}|\(|\)|\s|;|\\|::|\W)/, $newrawline);
} elsif ($lang eq "tcl") {
@parts = split(/("|'|\#|\{|\}|\(|\)|\s|;|\\|::|\/\*|\*\/|\W)/, $newrawline);
} else {
@parts = split(/("|'|\/\/|\/\*|\*\/|::|==|<=|>=|!=|\<\<|\>\>|\{|\}|\(|\)|\s|;|\\|\W)/, $newrawline);
}
while (scalar(@cpptrees)) {
my $temptree = pop(@cpptrees);
if ($temptree != $cpptreetop) {
$temptree->dispose();
}
}
$cpptreetop->dispose();
}
if (!$parserState->{inMacro}) {
$parserState->{NEXTTOKENNOCPP} = 0;
}
# Throw away any empty entries caused by Perl seeing two
# adjacent tokens that match the split regexp. We don't
# want them or care about them, and they break things
# rather badly if we don't....
my @stripparts = @parts;
@parts = ();
print STDERR "BEGIN PARTLIST 2:\n" if ($spaceDebug);
foreach my $strippart (@stripparts) {
if (length($strippart)) {
print STDERR "MYPART: \"$strippart\"\n" if ($spaceDebug);
push(@parts, $strippart);
}
}
print STDERR "END PARTLIST 2.\n" if ($spaceDebug);
if (!$disable_cpp && (1 || $HeaderDoc::enable_cpp)) {
if ($cpp_debug_file) {
open(CPP_DEBUG_FILE, ">>$cpp_debug_file");
# print CPP_DEBUG_FILE "DUMPING CPP INFORMATION FOR $fullpath\n";
foreach my $part (@parts) {
print CPP_DEBUG_FILE $part;
}
close(CPP_DEBUG_FILE);
}
}
# This bit of code needs a bit of explanation, I think.
# We need to be able to see the token that follows the one we
# are currently processing. To do this, we actually keep track
# of the current token, and the previous token, but name then
# $nextpart and $part. We do processing on $part, which gets
# assigned the value from $nextpart at the end of the loop.
#
# To avoid losing the last part of the declaration (or needing
# to unroll an extra copy of the entire loop code) we push a
# bogus entry onto the end of the stack, which never gets
# used (other than as a bogus "next part") because we only
# process the value in $part.
#
# To avoid problems, make sure that you don't ever have a regexp
# that would match against this bogus token.
#
my $part = "";
push(@parts, "BOGUSBOGUSBOGUSBOGUSBOGUS");
if ($localDebug || $cppDebug) {foreach my $partlist (@parts) {print STDERR "POSTCPPPARTLIST: \"$partlist\"\n"; }}
foreach my $nextpart (@parts) {
my $hideTokenAndMaybeContents = 0;
my $bshandled = 0;
my $setIsAvailable = 0;
my $trailingHide = 0;
$treeSkip = 0;
my $reMark = "";
print "PARSER STATE COUNT: ".scalar(@parserStack)."\n" if ($parserStackDebug > 1);
$parserState->print() if ($parserStackDebug > 1);
print STDERR "INMACROLINE: ".$parserState->{inMacroLine}."\n" if ($localDebug || $parseDebug || $parmDebug);
if ($part) { $leavingRegexp = 0; } # Reset to 0 at the top of the loop.
print STDERR "********************************************************\n" if ($localDebug || $parseDebug);
# $treePopTwo = 0;
# $treePopOnNewLine = 0;
# The current token is now in "part", and the literal next
# token in "nextpart". We can't just work with this as-is,
# though, because you can have multiple spaces, null
# tokens when two of the tokens in the split list occur
# consecutively, etc.
print STDERR "MYPART: \"$part\"\n" if ($localDebug || $spaceDebug);
if ($braceDebug) {
print STDERR "TOBS: \"".peek(\@braceStack)."\"\n";
}
# print STDERR "pushedfuncbrace: ".$parserState->{pushedfuncbrace}."\n";
$forcenobreak = 0;
# Convert CR/LF or LF/CR pair to LF
if ($part eq "\r" && $nextpart eq "\n") { $part = $nextpart ; next; }
if ($part eq "\n" && $nextpart eq "\r") { next; }
# Convert bare CR to LF
if ($nextpart eq "\r") { $nextpart = "\n"; }
if ($localDebug && $nextpart eq "\n") { print STDERR "NEXTPART IS NEWLINE!\n"; }
my $partIsNL = 0;
if ($part eq "\n") {
$partIsNL = 1;
if ($localDebug) { print STDERR "PART IS NEWLINE!\n"; }
}
### if ($nextpart ne "\n" && $nextpart =~ /\s/o) {
### # Replace tabs with spaces.
### $nextpart = " ";
### }
# Replace tabs with spaces.
$part =~ s/\t/ /g;
$nextpart =~ s/\t/ /g;
if ($part ne "\n" && $part =~ /\s/o && $nextpart ne "\n" &&
$nextpart =~ /\s/o) {
# we're a space followed by a space. Join the tokens.
print STDERR "MERGED \"$part\" and \"$nextpart\" into " if ($spaceDebug);
$nextpart = $part.$nextpart;
print STDERR "\"$nextpart\".\n" if ($spaceDebug);
$part = $nextpart;
next;
}
print STDERR "PART IS \"$part\"\n" if ($localDebug || $parserStackDebug || $parseDebug || $liteDebug || $spaceDebug || $tokenDebug);
print STDERR "SPS: ".scalar(@parserStack)." BSC: ".(scalar(@braceStack))." IBSC: ".$parserState->{initbsCount}."\n" if ($parserStackDebug);
print STDERR "QUOTED: ".$parserState->isQuoted($lang, $sublang)."\n" if ($localDebug || $parserStackDebug || $parseDebug || $liteDebug || $spaceDebug);
print STDERR "CURLINE IS \"$curline\"\n" if ($localDebug || $hangDebug || $liteDebug);
# print STDERR "RETURNTYPE IS \"$parserState->{returntype}\"\n" if ($localDebug || $hangDebug || $liteDebug);
print STDERR "INOP: ".$parserState->{inOperator}."\n" if ($operatorDebug);
if (!length($nextpart)) {
print STDERR "SKIP NP\n" if ($localDebug);
next;
}
if (!length($part)) {
print STDERR "SKIP PART\n" if ($localDebug);
$part = $nextpart;
next;
}
if ($occPushParserStateOnWordTokenAfterNext > 1) {
if ($part =~ /\w/) {
$occPushParserStateOnWordTokenAfterNext--;
print STDERR "occPushParserStateOnWordTokenAfterNext -> $occPushParserStateOnWordTokenAfterNext (--)\n" if ($localDebug || $parseDebug);
print STDERR "OCCParse Case 1\n" if ($liteDebug);
}
} elsif ($occPushParserStateOnWordTokenAfterNext) {
# if ($part !~ /(\s|<)/)
print STDERR "OCCParse Case 2\n" if ($liteDebug);
if (($part =~ /(#|\-|\+|\w|\@)/ || ($part eq "/*" && $nextpart eq "!")) && !$parserState->{inComment} && !$parserState->{inInlineComment}) {
# die("PART: $part NP: $nextpart\n");
print STDERR "OCCParse Case 2a\n" if ($liteDebug);
print STDERR "Last tree node set to $treeCur [1]\n" if ($parserStateInsertDebug);
$parserState->{lastTreeNode} = $treeCur;
print STDERR "parserState pushed onto stack[occPushParserStateOnWordTokenAfterNext]\n" if ($parserStackDebug);
$curline = "";
$parserState->{storeDec} = $declaration;
$parserState->{freezereturn} = 1;
$declaration = "";
push(@parserStack, $parserState);
$parserState = HeaderDoc::ParserState->new( "FULLPATH" => $fullpath, "lang" => $lang, "sublang" => $sublang );
$parserState->{skiptoken} = 0;
$parserState->{inputCounter} = $inputCounter;
$parserState->{initbsCount} = scalar(@braceStack);
$parserState->{noInsert} = $setNoInsert;
$setNoInsert = 0;
$pushParserStateAtBrace = 0;
$occPushParserStateOnWordTokenAfterNext = 0;
}
}
# If we get here, we aren't skipping a null or whitespace token.
# Let's print a bunch of noise if debugging is enabled.
# if ($part eq "\n" && $nextpart ne "BOGUSBOGUSBOGUSBOGUSBOGUS") {
# $fileoffset++;
# }
if ($part eq "\n" && $incrementoffsetatnewline) {
$incrementoffsetatnewline--;
$fileoffset++;
}
if ($treeDebug > 1) {
print STDERR "TREE DUMP\n";
$treeTop->dbprint();
print STDERR "\nEND TREE DUMP\n";
}
print STDERR "IN LOOP LANG: $lang INITIAL SUBLANG: $sublang\n" if ($localDebug || $parseDebug);
if ($parseDebug) {
print STDERR "PART: $part, type: $parserState->{typestring}, inComment: $parserState->{inComment}, inInlineComment: $parserState->{inInlineComment}, inChar: $parserState->{inChar}.\n" if ($localDebug);
print STDERR "PART: inBrackets: $parserState->{inBrackets}\n" if ($localDebug);
print STDERR "PART: onlyComments: $parserState->{onlyComments}, inClass: $parserState->{inClass}\n";
print STDERR "PART: cbsodname: $parserState->{cbsodname}\n";
print STDERR "PART: classIsObjC: $parserState->{classIsObjC}, PPSAT: $pushParserStateAfterToken, PPSAWordT: $pushParserStateAfterWordToken, PPSABrace: $pushParserStateAtBrace, occPPSOnWordTokenAfterNext: $occPushParserStateOnWordTokenAfterNext\n";
print STDERR "PART: bracecount: " . scalar(@braceStack) . " (init was $parserState->{initbsCount}).\n";
print STDERR "PART: inString: $parserState->{inString}, callbackNamePending: $parserState->{callbackNamePending}, namePending: $parserState->{namePending}, lastsymbol: $parserState->{lastsymbol}, lasttoken: $lasttoken, lastchar: $lastchar, SOL: $parserState->{startOfDec}\n" if ($localDebug);
print STDERR "PART: sodclass: $parserState->{sodclass} sodname: $parserState->{sodname}\n";
print STDERR "PART: sodtype: $parserState->{sodtype}\n";
print STDERR "PART: simpleTypedef: $parserState->{simpleTypedef}\n";
print STDERR "PART: posstypes: $parserState->{posstypes}\n";
print STDERR "PART: seenBraces: $parserState->{seenBraces}\n";
print STDERR "SEENIF: ".$parserState->{seenIf}." INIF: ".$parserState->{INIF}."\n";
} elsif ($parserStateInsertDebug) {
print STDERR "PART: seenBraces: $parserState->{seenBraces}\n";
}
if ($parseDebug || $regexpDebug) {
print STDERR "PART: inRegexp: $inRegexp inRegexpCharClass: $inRegexpCharClass\n";
print STDERR "PART: inRegexpTrailer: $inRegexpTrailer inRegexpFirstPart: $inRegexpFirstPart\n";
print STDERR "PART: leavingRegexp: $leavingRegexp regexpNoInterpolate: $regexpNoInterpolate\n";
print STDERR "PART: inTCLRegExpCommand: ".$parserState->{inTCLRegExpCommand}." afterNL: ".$parserState->{afterNL}."\n";
}
if ($parseDebug) {
print STDERR "PART: seenTilde: $parserState->{seenTilde}\n";
print STDERR "PART: CBN: $parserState->{callbackName}\n";
print STDERR "PART: regexpStack is:";
foreach my $token (@regexpStack) { print STDERR " $token"; }
print STDERR "\n";
print STDERR "PART: npplStack: ".scalar(@{$parserState->{pplStack}})." nparsedParamList: ".scalar(@{$parserState->{parsedParamList}})." nfreezeStack: ".scalar(@{$parserState->{freezeStack}})." frozen: $parserState->{stackFrozen}\n";
print STDERR "PART: inMacro: $parserState->{inMacro} treePopOnNewLine: $treePopOnNewLine\n";
print STDERR "PART: occmethod: $parserState->{occmethod} occmethodname: $parserState->{occmethodname}\n";
print STDERR "PART: returntype is $parserState->{returntype}\n";
print STDERR "length(declaration) = " . length($declaration) ."; length(curline) = " . length($curline) . "\n";
print STDERR "REQUIREDREGEXP IS \"$requiredregexp\"\n";
print STDERR "DEC: $declaration\n$curline\n";
} elsif ($tsDebug || $treeDebug) {
print STDERR "BPPART: $part\n";
}
if ($parseDebug || $parmDebug) {
print STDERR "PARSED PARAM IS NOW: $parsedParam\n";
}
if ($parserStackDebug) {
print STDERR "parserState: STACK CONTAINS ".scalar(@parserStack)." STATES\n";
print STDERR "parserState is $parserState\n";
}
# The ignore function returns either null, an empty string,
# or a string that gives the text equivalent of an availability
# macro. If the token is non-null and the length is non-zero,
# it's an availability macro, so blow it in as if the comment
# contained an @availability tag.
#
my $tempavail = ignore($part, $ignoreref, $perheaderignoreref);
if ($disable_cpp || $parserState->{inString} ||
$parserState->{inComment} || $parserState->{inInlineComment} ||
$parserState->{inChar} || $inRegexp) {
if ($tempavail == 2 || $tempavail == 3) {
print STDERR "Forcing ignore state to zero. TOKEN: $part TA: $tempavail INSTRING: $parserState->{inString}\n" if ($parseDebug || $regexpDebug);
$tempavail = 0;
}
} elsif ($parserState->{inMacro} == 3 && !$parserState->{inMacroTail}) {
print STDERR "Forcing ignore state to zero in macro name. TOKEN: $part TA: $tempavail INSTRING: $parserState->{inString}\n" if ($parseDebug || $regexpDebug);
if ($tempavail) {
$parserState->{ignoreAvailabilityMacros} = 1;
$tempavail = 0;
}
}
if ($parserState->{ignoreAvailabilityMacros}) { $tempavail = 0; }
printf("PART: $part TEMPAVAIL: $tempavail\n") if ($localDebug || $gccAttributeDebug);
if ($tempavail && ($tempavail ne "1") && ($tempavail ne "2") && ($tempavail ne "3")) {
$parserState->{availability} = $tempavail;
$setIsAvailable = 1;
# print STDERR "SET IS AVAILABLE[1] FOR PART $part\n";
} elsif ($tempavail eq "2" || $tempavail eq "3") {
# Reusing the GCC attribute handling code because that does exactly what we need.
print STDERR "Attribute-like Availabilitymacro\n" if ($liteDebug);
print STDERR "Function-like availability macro detected. Collecting.\n" if ($localDebug || $gccAttributeDebug);
$parserState->{attributeState} = 1;
# Add __attribute__ as the next token.
my $hidden = 0;
if ($tempavail eq "3") {
$hidden = 3;
}
$treeCur = $treeCur->addSibling($part, $hidden);
if ($HeaderDoc::includeFunctionContents && $reMark) {
$treeCur->{RE_STATE} = $reMark;
}
$treeCur->isAvailabilityMacro(1);
# print STDERR "SET IS AVAILABLE[2] FOR PART $part\n";
# print STDERR "PUSHED $treeCur onto tree stack (__OSX_AVAIL...).\n";
push(@treeStack, $treeCur);
my @tempAvailabilityNodesArray = ();
if ($parserState->{availabilityNodesArray}) {
@tempAvailabilityNodesArray = @{$parserState->{availabilityNodesArray}};
}
push(@tempAvailabilityNodesArray, $treeCur);
# print STDERR "ADDED $treeCur\n";
# $treeCur->dbprint();
$parserState->{availabilityNodesArray} = \@tempAvailabilityNodesArray;
# Nest all contents one level lower.
$treeCur = $treeCur->addChild("", 0);
$part = $nextpart;
next;
}
print "IC: $parserState->{inClass} TOK: $part\n" if ($parseDebug || $classDebug);
my $externCDebug = 0;
my $iskw = isKeyword($part, $keywordhashref, $case_sensitive);
if ($HeaderDoc::includeFunctionContents || !$parserState->{seenBraces}) {
# Handle the GCC "__attribute__" extension outside the context of
# the parser because it isn't part of the language and massively
# breaks the syntax.
# Same for asm
if (($iskw == 8) && !$parserState->{attributeState} &&
!$parserState->{parsedParamParse} &&
!$parserState->{inBrackets} &&
!$parserState->{inTemplate} &&
!$parserState->{inChar} &&
!$parserState->{inString} &&
!$parserState->{inComment} &&
!$parserState->{inInlineComment} &&
!$parserState->{inImplements} &&
!$parserState->{inExtends} &&
!$parserState->{inClassConformingToProtocol} &&
!$parserState->{inRuby} &&
!$parserState->{seenBraces} &&
!$parserState->{classNameFound} &&
!$parserState->{inMacro} &&
!$parserState->{inMacroLine} &&
!$parserState->{preEqualsSymbol}) {
print STDERR "Attribute CASE 1\n" if ($liteDebug);
$parserState->{isStatic} = 1;
} elsif (($lang eq "C" || $lang eq "Csource") && ($iskw == 2 || $iskw == 5 || $iskw == 6)) {
print STDERR "Attribute CASE 2\n" if ($liteDebug);
print STDERR "GCC attribute/asm detected. Collecting.\n" if ($localDebug || $gccAttributeDebug);
$parserState->{attributeState} = 1;
# Add __attribute__ as the next token.
$treeCur = $treeCur->addSibling($part, 0);
if ($HeaderDoc::includeFunctionContents && $reMark) {
$treeCur->{RE_STATE} = $reMark;
}
push(@treeStack, $treeCur);
# Nest all contents one level lower.
$treeCur = $treeCur->addChild("", 0);
$part = $nextpart;
next;
} elsif (($lang eq "C" || $lang eq "Csource") && ($iskw == 7)) {
print STDERR "Attribute CASE 3 (Extern C)\n" if ($liteDebug);
$parserState->rollbackSet();
print STDERR "EXTERN C -> 1\n" if ($externCDebug);
$parserState->{externC} = 1;
$parserState->{preExternCcurline} = $curline;
$parserState->{preExternCdeclaration} = $declaration;
# $parserState->{preExternCsodname} = $parserState->{sodname};
# $parserState->{preExternCsodclass} = $parserState->{sodclass};
# $parserState->{preExternCsodtype} = $parserState->{sodtype};
# $parserState->{preExternCreturntype} = $parserState->{returntype};
} elsif ($parserState->{attributeState} == 1) {
print STDERR "Attribute CASE 4\n" if ($liteDebug);
if ($part eq "(") {
print STDERR "GCC attribute open paren\n" if ($localDebug || $gccAttributeDebug);
$parserState->{attributeState} = -1;
}
$treeCur = $treeCur->addSibling($part, 0);
if ($HeaderDoc::includeFunctionContents && $reMark) {
$treeCur->{RE_STATE} = $reMark;
}
$part = $nextpart;
next;
} elsif ($parserState->{attributeState} < 0) {
print STDERR "Attribute CASE 5\n" if ($liteDebug);
if ($part eq "(") {
print STDERR "Attribute OPAREN\n" if ($liteDebug);
$parserState->{attributeState}--;
print STDERR "GCC attribute open paren, count=".(0-$parserState->{attributeState})."\n" if ($localDebug || $gccAttributeDebug);
} elsif ($part eq ")") {
print STDERR "Attribute CPAREN\n" if ($liteDebug);
$parserState->{attributeState}++;
print STDERR "GCC attribute close paren, count=".(0-$parserState->{attributeState})."\n" if ($localDebug || $gccAttributeDebug);
}
$treeCur = $treeCur->addSibling($part, 0);
if ($HeaderDoc::includeFunctionContents && $reMark) {
$treeCur->{RE_STATE} = $reMark;
}
if (!$parserState->{attributeState}) {
print STDERR "GCC attribute: done collecting.\n" if ($localDebug || $gccAttributeDebug);
# Get back to where we started.
$treeCur = pop(@treeStack);
# print STDERR "GOT TC: $treeCur\n";
}
$part = $nextpart;
next;
} elsif ($parserState->{externC} == 1) {
print STDERR "Attribute CASE 6\n" if ($liteDebug);
if ($part =~ /"/) {
print STDERR "EXTERN C -> 2\n" if ($externCDebug);
$parserState->{externC} = 2;
} elsif ($part !~ /\s/) {
print STDERR "EXTERN C -> 0[1]\n" if ($externCDebug);
$parserState->{externC} = 0;
}
} elsif ($parserState->{externC} == 2) {
print STDERR "Attribute CASE 7\n" if ($liteDebug);
if ($part =~ /C/) {
print STDERR "EXTERN C -> 3\n" if ($externCDebug);
$parserState->{externC} = 3;
} elsif ($part !~ /\s/) {
print STDERR "EXTERN C -> 0[2]\n" if ($externCDebug);
$parserState->{externC} = 0;
}
} elsif ($parserState->{externC} == 3) {
print STDERR "Attribute CASE 8\n" if ($liteDebug);
if ($part =~ /"/) {
print STDERR "EXTERN C -> 0[Success]\n" if ($externCDebug);
$parserState->{externC} = 0;
$parserState->{onlyComments} = 1;
$parserState->{rollbackPending} = 1;
# $curline = $parserState->{preExternCcurline};
# $declaration = $parserState->{preExternCdeclaration};
# $parserState->{sodname} = $parserState->{preExternCsodname};
# $parserState->{sodclass} = $parserState->{preExternCsodclass};
# $parserState->{sodtype} = $parserState->{preExternCsodtype};
# $parserState->{returntype} = $parserState->{preExternCreturntype};
} elsif ($part !~ /\s/) {
print STDERR "EXTERN C -> 0[3]\n" if ($externCDebug);
$parserState->{externC} = 0;
}
}
}
# Here be the parser. Abandon all hope, ye who enter here.
$treepart = "";
my $tempInIf = 0;
if ((!$parserState->{inComment}) && (!$parserState->{inInlineComment}) && ($part ne $parseTokens{ilc}) && (($part ne $parseTokens{soc}) || $nextpart eq "!")) {
if ($parserState->{inProtocol} == 1) {
print STDERR "INPROTOCOL: 1\n" if ($parseDebug || $classDebug);
if ($part =~ /\w/) {
print STDERR "INPROTOCOL: 1 -> 2\n" if ($parseDebug || $classDebug);
$parserState->{inProtocol} = 2;
}
} elsif ($parserState->{inProtocol} == 2) {
print STDERR "INPROTOCOL: 2\n" if ($parseDebug || $classDebug);
if ($part eq "<") {
print STDERR "INPROTOCOL: 2 -> 3\n" if ($parseDebug || $classDebug);
$parserState->{extendsProtocol} = "";
$parserState->{inProtocol} = 3;
} elsif ($part =~ /\S/) {
# PUSH PARSER STATE
# Don't do this if the next thing is a non-HeaderDoc
# comment, though.
print STDERR "parserState pushed onto stack[PROTOCOL]\n" if ($parserStackDebug);
$parserState->{inProtocol} = -1;
print STDERR "Last tree node set to $treeCur [2]\n" if ($parserStateInsertDebug);
$parserState->{lastTreeNode} = $treeCur;
$curline = "";
$parserState->{storeDec} = $declaration;
$parserState->{freezereturn} = 1;
$declaration = "";
push(@parserStack, $parserState);
$parserState = HeaderDoc::ParserState->new( "FULLPATH" => $fullpath, "lang" => $lang, "sublang" => $sublang );
$parserState->{skiptoken} = 1;
$parserState->{inputCounter} = $inputCounter;
$parserState->{initbsCount} = scalar(@braceStack);
$pushParserStateAfterWordToken = 0;
}
} elsif ($parserState->{inProtocol} == 3) {
print STDERR "INPROTOCOL: 3\n" if ($parseDebug || $classDebug);
if ($part eq ">") {
print STDERR "INPROTOCOL: 3 -> 2\n" if ($parseDebug || $classDebug);
$parserState->{inProtocol} = 2;
} else {
$parserState->{extendsProtocol} .= $part;
}
}
if ($parserState->{inClass} == 3) {
print STDERR "INCLASS3\n" if ($parseDebug || $classDebug);
if ($part eq ")") {
$parserState->{inClass} = 1;
print STDERR "inClass -> 1 [1]\n" if ($classDebug);
$parserState->{categoryClass} .= $part;
print STDERR "parserState will be pushed onto stack[cparen3]\n" if ($parserStackDebug);
# print STDERR "Last tree node set to $treeCur [2a]\n" if ($parserStateInsertDebug);
# $parserState->{lastTreeNode} = $treeCur;
# push(@parserStack, $parserState);
# $parserState = HeaderDoc::ParserState->new( "FULLPATH" => $fullpath, "lang" => $lang, "sublang" => $sublang );
# $parserState->{inputCounter} = $inputCounter;
# $parserState->{initbsCount} = scalar(@braceStack);
$pushParserStateAfterToken = 1;
} elsif ($part eq ":") {
$parserState->{inClass} = 1;
print STDERR "inClass -> 1 [2]\n" if ($classDebug);
if ($parserState->{classIsObjC}) {
print STDERR "occPushParserStateOnWordTokenAfterNext -> 2\n" if ($localDebug || $parseDebug);
$occPushParserStateOnWordTokenAfterNext = 2;
} else {
$pushParserStateAfterWordToken = 1;
}
# if ($sublang eq "occ") {
# $pushParserStateAtBrace = 2;
# }
} elsif ($part =~ / && $parserState->{classIsObjC}) {
print STDERR "pushParserStateAfterWordToken -> 0 (Conforming)\n" if ($localDebug || $parseDebug);
print STDERR "inClassConformingToProtocol -> 1\n" if ($localDebug || $parseDebug);
$pushParserStateAfterWordToken = 0;
$parserState->{inClassConformingToProtocol} = 1;
$occPushParserStateOnWordTokenAfterNext = 0;
} elsif ($part =~ />/ && $parserState->{classIsObjC} && $parserState->{inClassConformingToProtocol}) {
print STDERR "inClassConformingToProtocol -> 0\n" if ($localDebug || $parseDebug);
$pushParserStateAfterToken = 1;
print STDERR "pushParserStateAfterWordToken -> 1 (Conforming)\n" if ($localDebug || $parseDebug);
$parserState->{inClassConformingToProtocol} = 0;
} else {
$parserState->{categoryClass} .= $part;
}
} elsif ($parserState->{inClass} == 2) {
print STDERR "INCLASS2\n" if ($parseDebug || $classDebug);
if ($part eq ")") {
$parserState->{inClass} = 1;
print STDERR "inClass -> 1 [3]\n" if ($classDebug);
print STDERR "Last tree node set to $treeCur [3]\n" if ($parserStateInsertDebug);
$parserState->{lastTreeNode} = $treeCur;
print STDERR "parserState pushed onto stack[cparen2]\n" if ($parserStackDebug);
$curline = "";
$parserState->{storeDec} = $declaration;
$parserState->{freezereturn} = 1;
$declaration = "";
push(@parserStack, $parserState);
$parserState = HeaderDoc::ParserState->new( "FULLPATH" => $fullpath, "lang" => $lang, "sublang" => $sublang );
$parserState->{skiptoken} = 1;
$parserState->{inputCounter} = $inputCounter;
$parserState->{initbsCount} = scalar(@braceStack);
} elsif ($part eq ":") {
$parserState->{inClass} = 1;
print STDERR "inClass -> 1 [4]\n" if ($classDebug);
if ($parserState->{classIsObjC}) {
print STDERR "occPushParserStateOnWordTokenAfterNext -> 2\n" if ($localDebug || $parseDebug);
$occPushParserStateOnWordTokenAfterNext = 2;
} else {
$pushParserStateAfterWordToken = 2;
}
} elsif ($part =~ /\w/) {
# skip the class name itself.
$parserState->{inClass} = 3;
print STDERR "inClass -> 3 [5]\n" if ($classDebug);
}
} elsif ($parserState->{inClass} == 1) {
print STDERR "INCLASS1\n" if ($parseDebug || $classDebug);
# print STDERR "inclass Part is $part\n";
print STDERR "IK: $part => ".isKeyword($part, $keywordhashref, $case_sensitive)."\n" if ($parseDebug || $classDebug);;
if ($part eq "::") {
print STDERR "INCLASS DOUBLE-COLON\n" if ($classDebug);
$parserState->{classNameFound} = 0;
if ($parserState->{perlClassName}) {
$parserState->{perlClassName} .= $parserState->{sodname}."::";
} else {
$parserState->{perlClassName} = $parserState->{sodname}."::";
}
$parserState->{startOfDec} = 1; # Skip the :: token; the name is after it.
print STDERR "PCN: ".$parserState->{perlClassName}."\n" if ($classDebug);
} elsif ($part eq "." && !($parserState->{forceClassDone} || $parserState->{inExtends} ||
$parserState->{inImplements} ||
$parserState->{inClassConformingToProtocol} ||
$parserState->{forceClassSuper})) {
print STDERR "INCLASS DOT\n" if ($parseDebug || $classDebug);
$parserState->{classNameConcat} = 1;
# print STDERR "XSUPER: $parserState->{forceClassSuper}\n";
} elsif ($part eq ":") {
print STDERR "INCLASS COLON\n" if ($parseDebug || $classDebug);
if (!$parserState->{forceClassName}) {
$parserState->{forceClassName} = $parserState->{sodname};
$parserState->{forceClassSuper} = "";
}
# print STDERR "XSUPER: $parserState->{forceClassSuper}\n";
} elsif (isKeyword($part, $keywordhashref, $case_sensitive) == 3) {
if (!$parserState->{forceClassName}) {
$parserState->{forceClassName} = $parserState->{sodname};
}
$parserState->{inExtends} = 1;
$parserState->{inImplements} = 0;
if ($parserState->{extendsClass}) {
$parserState->{extendsClass} .= " ";
} else {
$parserState->{extendsClass} = "";
}
} elsif (isKeyword($part, $keywordhashref, $case_sensitive) == 4) {
if (!$parserState->{forceClassName}) {
$parserState->{forceClassName} = $parserState->{sodname};
}
$parserState->{inImplements} = 1;
$parserState->{inExtends} = 0;
if ($parserState->{implementsClass}) {
$parserState->{implementsClass} .= " ";
} else {
$parserState->{implementsClass} = "";
}
} elsif ($parserState->isLeftBrace($part, $lang, \%parseTokens, $case_sensitive, scalar(@braceStack)) || $part eq ";") {
# $part eq "{"
print STDERR "INCLASS BRCSEMI\n" if ($parseDebug || $classDebug);
$parserState->{forceClassDone} = 1;
if ($parserState->{classIsObjC} && $part eq "{") {
$parserState->{ISFORWARDDECLARATION} = 0;
print STDERR "Last tree node set to $treeCur [4]\n" if ($parserStateInsertDebug);
$parserState->{lastTreeNode} = $treeCur;
print STDERR "parserState pushed onto stack[OCC-BRCSEMI]\n" if ($parserStackDebug);
$curline = "";
$parserState->{storeDec} = $declaration;
$parserState->{freezereturn} = 1;
$declaration = "";
push(@parserStack, $parserState);
$parserState = HeaderDoc::ParserState->new( "FULLPATH" => $fullpath, "lang" => $lang, "sublang" => $sublang );
$parserState->{skiptoken} = 0;
$parserState->{inputCounter} = $inputCounter;
$parserState->{initbsCount} = scalar(@braceStack) + 1; # NOTE: add one here because it will change in the SWITCH to follow.
$parserState->{noInsert} = $setNoInsert;
$setNoInsert = 0;
$pushParserStateAtBrace = 0;
$occPushParserStateOnWordTokenAfterNext = 0;
$pushParserStateAfterToken = 1;
} elsif ($part eq ";") {
if (!defined($parserState->{ISFORWARDDECLARATION})) {
print STDERR "FORWARD DECLARATION DETECTED\n" if ($parseDebug || $localDebug || $liteDebug);
# print STDERR "PREVIOUS FD STATE: ".$parserState->{ISFORWARDDECLARATION}."\n";
$parserState->{ISFORWARDDECLARATION} = 1;
}
$pushParserStateAtBrace = 0;
$occPushParserStateOnWordTokenAfterNext = 0;
$pushParserStateAfterToken = 0;
}
} elsif ($parserState->{forceClassName} && !$parserState->{forceClassDone} && !$parserState->{inImplements} && !$parserState->{inExtends}) {
print STDERR "INCLASS ADD\n" if ($parseDebug || $classDebug);
if ($part =~ /[\n\r]/) {
$parserState->{forceClassSuper} .= " ";
} else {
$parserState->{forceClassSuper} .= $part;
}
# print STDERR "SUPER IS $parserState->{forceClassSuper}\n";
} elsif ($part =~ / && $parserState->{classIsObjC} && $occPushParserStateOnWordTokenAfterNext) {
print STDERR "INCLASS <\n" if ($parseDebug || $classDebug);
print STDERR "pushParserStateAfterWordToken -> 0 (Conforming)\n" if ($localDebug || $parseDebug);
print STDERR "inClassConformingToProtocol -> 1\n" if ($localDebug || $parseDebug);
$pushParserStateAfterWordToken = 0;
$parserState->{inClassConformingToProtocol} = 1;
$occPushParserStateOnWordTokenAfterNext = 0;
} elsif ($part =~ />/ && $parserState->{classIsObjC} && $parserState->{inClassConformingToProtocol}) {
print STDERR "INCLASS >\n" if ($parseDebug || $classDebug);
print STDERR "inClassConformingToProtocol -> 0\n" if ($localDebug || $parseDebug);
$pushParserStateAfterToken = 1;
print STDERR "pushParserStateAfterWordToken -> 1 (Conforming)\n" if ($localDebug || $parseDebug);
$parserState->{inClassConformingToProtocol} = 0;
} elsif ($occPushParserStateOnWordTokenAfterNext && $part =~ /\w/) {
print STDERR "INCLASS OCCSUPER\n" if ($parseDebug || $classDebug);
$parserState->{occSuper} = $part;
# $occPushParserStateOnWordTokenAfterNext = 0;
# $pushParserStateAfterToken = 1;
} elsif ($parserState->{inExtends}) {
print STDERR "INCLASS INEXTENDS (PART: \"$part\")\n" if ($parseDebug || $classDebug);
$parserState->{extendsClass} .= $part;
} elsif ($parserState->{inImplements}) {
print STDERR "INCLASS INIMPLEMENTS (PART: \"$part\")\n" if ($parseDebug || $classDebug);
$parserState->{implementsClass} .= $part;
} elsif (!$parserState->{classIsObjC}) {
print STDERR "INCLASS NOTOBJC (OTHER)\n" if ($parseDebug || $classDebug);
if (!(scalar(@braceStack) - $parserState->{initbsCount})) {
if ($part =~ /[*(^]/) {
print STDERR "INCLASS DROP\n" if ($parseDebug || $classDebug);
$parserState->{inClass} = 0; # We're an instance. Either a variable or a function.
print STDERR "inClass -> 0 [6]\n" if ($classDebug);
$parserState->{sodtype} = $parserState->{preclasssodtype} . $parserState->{sodtype};
} elsif ($part =~ /\w/) {
print STDERR "INCLASS GOT WORD TOKEN\n" if ($parseDebug || $classDebug);
if ($parserState->{classNameFound} && !$parserState->{forceClassName} && !$parserState->{classNameConcat}) {
print STDERR "INCLASS NOT A CLASS. IT IS A VARIABLE OR TYPEDEF.\n" if ($parseDebug || $classDebug);
$parserState->{inClass} = 0;
} elsif ($parserState->{classNameConcat}) {
# Once per dot.
# $parserState->dbprint();
$parserState->{classNameConcat} = 0;
$parserState->{forceClassName} = $parserState->{sodtype}.".".$part;
} else {
print STDERR "INCLASS WORD TOKEN IS CLASS NAME\n" if ($parseDebug || $classDebug);
$parserState->{classNameFound} = 1;
}
}
}
# } else {
# print STDERR "BUG\n";
}
};
if ($parserState->{inClassConformingToProtocol} == 1) {
$parserState->{inClassConformingToProtocol} = 2;
} elsif ($parserState->{inClassConformingToProtocol}) {
$parserState->{conformsToList} .= $part;
}
if ($macroDebug) {
print STDERR "MNT: ".$parserState->{macroNoTrunc}."\n";
}
# if (($part eq $parseTokens{ilc} || $part eq $parseTokens{ilc_b}) && ($lang ne "perl" || $lasttoken ne "\$")) {
# print STDERR "should be ILC?\n";
# } else {
# print STDERR "NO CHANEC: PART \"$part\" ILC \"$parseTokens{ilc}\" ILC_B: \"$parseTokens{ilc_b}\" LANG: \"$lang\" LASTTOKEN: \"$lasttoken\"\n";
# }
$parserState->dbprint() if ($regexpDebug == 2);
print STDERR "LASTNSPART: $lastnspart\n" if ($regexpDebug == 2);
print STDERR "\n
(($inRegexp &&\n
(length($regexpcharpattern) &&\n
$part =~ /^($regexpcharpattern)$/ &&\n
(!$inRegexpCharClass) &&\n
(!scalar(\@regexpStack) || $part eq peekmatch(\\\@regexpStack, $lang, $fullpath, $inputCounter))\n
)\n
) || (\n
(!$inRegexp) &&\n
($parserState->{lastsymbol} =~ /$regexpAllowedAfter/ ||\n
$parserState->{inTCLRegExpCommand} ||\n
($parserState->{lastsymbol} eq \"\" && $lastnspart eq \"(\" && peek(\\\@braceStack) eq \"(\")\n
) && $part =~ /\// && !$parserState->{inTemplate} &&\n
length($regexpfirstcharpattern) &&\n
(!($inRegexp || $inRegexpTrailer ||\n
$parserState->{inString} || $parserState->{inComment} ||\n
$parserState->{inInlineComment} || $parserState->{inChar})) &&\n
(!$parserState->isRubyOpenQuote($part) || $parserState->isRubyCloseQuote($part)) &&\n
(length($regexpfirstcharpattern) &&\n
$part =~ /^($regexpfirstcharpattern)$/ &&\n
(!$inRegexpCharClass) &&\n
(!scalar(\@regexpStack) || $part eq peekmatch(\\\@regexpStack, $lang, $fullpath, $inputCounter))\n
)\n
\n" if ($regexpDebug == 2);
if ($HeaderDoc::parseIfElse && (!$parserState->{inMacro} && !$parserState->{inMacroLine} && !($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}))) {
if (!(scalar(@braceStack) - $parserState->{initbsCount})) {
if ($part eq "if" || $part eq "else") {
print STDERR "INIF OUTSIDE CHANGE -> 1 FOR PART \"$part\" IN $parserState\n" if ($continueDebug);
if ($part eq "if") {
$parserState->{seenIf} = 1; # Hint for code that uses results.
$parserState->{INIF} = 1;
} else {
# print STDERR "SETTING IFCONTENTS TO ".$parserState->{functionContents}."\n";
$parserState->{ifContents} = $parserState->{functionContents};
$parserState->{functionContents} = "";
$parserState->{seenElse} = 1; # Hint for code that uses results.
$parserState->{INIF} = 1;
}
print STDERR "CONTINUE -> 1 [INIF]\n" if ($parseDebug || $cppDebug || $macroDebug || $localDebug || $continueDebug);
$continue = 1;
# $pushParserStateAtBrace = 1;
} elsif ($part eq ";") {
# Not in "if" after the close curly brace.
print STDERR "INIF OUTSIDE CHANGE -> 0 FOR PART \"$part\" IN $parserState\n" if ($continueDebug);
$parserState->{INIF} = 0;
} elsif ($part eq "{") {
# Not in "if" after the close curly brace.
print STDERR "INIF OUTSIDE CHANGE -> 0 FOR PART \"$part\" IN $parserState\n" if ($continueDebug);
$tempInIf = $parserState->{INIF};
print STDERR "TEMPINIF: $tempInIf\n" if ($continueDebug);
$parserState->{INIF} = 0;
} elsif ($part =~ /\S/ && $part ne "(" && $parserState->{INIF}) {
$parserState->{INIF}++;
$parserState->{seenBraces} = 1;
print STDERR "seenBraces -> 1 [1]\n" if ($parseDebug || $braceDebug);
} else {
print STDERR "INIF OUTSIDE NC (".$parserState->{INIF}.") FOR PART \"$part\" IN $parserState\n" if ($continueDebug);
}
# print STDERR "DEBUG $pushParserStateAfterToken $pushParserStateAfterWordToken $pushParserStateAtBrace $occPushParserStateOnWordTokenAfterNext\n";
} else {
print STDERR "INIF INSIDE NC (".$parserState->{INIF}.") FOR PART \"$part\" IN $parserState\n" if ($continueDebug);
# print STDERR "DEBUG $pushParserStateAfterToken $pushParserStateAfterWordToken $pushParserStateAtBrace $occPushParserStateOnWordTokenAfterNext\n";
}
}
if ($part ne ":" && $parserState->{inBitfield}) {
print STDERR "BITFIELD CONFIRMED.\n" if ($parmDebug || $parseDebug || $localDebug || $bitfieldDebug);
$parserState->{startOfDec} = 0;
delete $parserState->{inBitfield};
}
}
# print STDERR "VARCHECK: $parseTokens{varname} :: $part eq $parseTokens{varname} :: $inRegexp :: $inRegexpTrailer :: $parserState->{inString} :: $parserState->{inComment} :: $parserState->{inInlineComment} :: $parserState->{inChar} :: $parserState->{sodclass}\n";
# The phrase "foo.bar" is a valid name in these languages.
# This code handles that....
if ( ( ($lang eq "C" && $sublang eq "IDL") ||
$lang eq "javascript" ||
$lang eq "java") &&
($parserState->{callbackNamePending} || $parserState->{namePending} || $parserState->{startOfDec} == 2) &&
$part eq "." &&
!$parserState->{classNameConcat} &&
!$parserState->{variableNameConcat}) {
print STDERR "IDL/JS/Java CONCAT -> 1\n" if ($liteDebug);
$parserState->{variableNameConcat} = 2;
};
# The phrase "foo::bar" is a valid name in these languages.
# This code handles that....
if ( ($lang eq "perl") &&
($parserState->{callbackNamePending} || $parserState->{namePending} || $parserState->{startOfDec} == 2) &&
$part eq "::" &&
!$parserState->{classNameConcat} &&
!$parserState->{variableNameConcat} &&
($HeaderDoc::includeFunctionContents || !$parserState->{seenBraces})) {
print STDERR "Perl CONCAT -> 1\n" if ($liteDebug);
$parserState->{variableNameConcat} = 2;
};
if ($part =~ /[\n\r]/) {
# 2 until first non-space token.
$parserState->{afterNL} = 2;
if ($lang eq "tcl") {
if ($parserState->{inTCLRegExpCommand}) {
$parserState->{inTCLRegExpCommand} = 0;
}
}
} elsif ($parserState->{afterNL} == 1) {
# 0 after first non-space token.
$parserState->{afterNL} = 0;
} elsif ($parserState->{afterNL} == 2 && $part =~ /\S/) {
# 1 during first non-space token.
$parserState->{afterNL} = 1;
}
SWITCH: {
# Blank declaration handlers (mostly for misuse of
# OSMetaClassDeclareReservedUsed and similar)
(($lang eq "applescript") && !$argparse && ($part eq "|") &&
!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} ||
$parserState->{inChar})) && do {
print STDERR "APPLESCRIPT CONCAT: CASE AS_00a\n" if ($liteDebug);
if ($asConcat) {
$part = $asConcat . $part;
$asConcat = "";
# Fall through.
} else {
$asConcat = $part;
$part = "";
last SWITCH;
}
};
(($lang eq "applescript") && !$argparse && ($asConcat) &&
!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} ||
$parserState->{inChar})) && do {
print STDERR "APPLESCRIPT CONCAT: CASE AS_00b\n" if ($liteDebug);
$asConcat .= $part;
$part = "";
last SWITCH;
};
(($lang eq "applescript") && !$argparse && ($part =~ /^(of|in)$/) &&
!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} ||
$parserState->{inChar})) && do {
print STDERR "APPLESCRIPT OF/IN: CASE AS_00A\n" if ($liteDebug);
print STDERR "IN APPLESCRIPT OF/IN: SET TO $part\n" if ($asDebug);
$parserState->{inOfIn} = 1;
$parserState->{OfIn} = $part;
last SWITCH;
};
(($lang eq "applescript") &&
!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} ||
$parserState->{inChar}) &&
$parserState->{inOfIn} && ($part =~ /\w/)) && do {
print STDERR "APPLESCRIPT OF/IN: CASE AS_00B\n" if ($liteDebug);
print STDERR "IN APPLESCRIPT OF/IN: ADDING $part\n" if ($asDebug);
$parserState->{OfIn} .= " ".$part;
$parserState->{inOfIn} = 0;
last SWITCH;
};
(($lang eq "applescript") &&
!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} ||
$parserState->{inChar}) &&
!$argparse && $labelregexp && ($part =~ /$labelregexp/) && ($parserState->{startOfDec} != 1)) && do {
print STDERR "APPLESCRIPT LABEL: CASE AS_00C\n" if ($liteDebug);
print STDERR "IN APPLESCRIPT LABEL: SET TO $part SOD=".$parserState->{startOfDec}."\n" if ($asDebug);
$parserState->{inLabel} = 1;
$parserState->{ASlabel} = $part;
last SWITCH;
};
(($lang eq "applescript") &&
!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} ||
$parserState->{inChar}) &&
$labelregexp && $parserState->{inLabel} && ($part =~ /\w/)) && do {
print STDERR "APPLESCRIPT LABEL: CASE AS_00D\n" if ($liteDebug);
print STDERR "IN APPLESCRIPT LABEL: ADDING $part\n" if ($asDebug);
$parserState->{ASlabel} .= " ".$part;
$parserState->{inLabel} = 0;
last SWITCH;
};
(($lang eq "applescript") &&
!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} ||
$parserState->{inChar}) &&
($part eq "given")) && do {
print STDERR "APPLESCRIPT GIVEN: CASE AS_00E\n" if ($liteDebug);
print STDERR "IN APPLESCRIPT GIVEN ($part)\n" if ($asDebug);
$parserState->{inGiven} = 1;
$parserState->{inLabel} = 0;
last SWITCH;
};
(($lang eq "applescript") && $parserState->{inGiven} &&
!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} ||
$parserState->{inChar}) &&
($part !~ /[\r\n]/)) && do {
print STDERR "APPLESCRIPT GIVEN: CASE AS_00F\n" if ($liteDebug);
print STDERR "IN APPLESCRIPT GIVEN\n" if ($asDebug);
if ($part eq ",") {
print STDERR "IN APPLESCRIPT GIVEN COMMA\n" if ($asDebug);
print STDERR "PUSHING \"$parsedParam\" onto parsed parameters list (comma)\n" if ($parseDebug || $asDebug);
if (length($parsedParam)) { push(@{$parserState->{parsedParamList}}, $parsedParam); }
$parsedParam = "";
} else {
print STDERR "IN APPLESCRIPT GIVEN TOKEN: $part\n" if ($asDebug);
$parsedParam .= $part;
}
last SWITCH;
};
# (($lang eq "applescript") && $argparse && ($part eq ":")) && do {
# print STDERR "APPLESCRIPT OF/IN: CASE AS_00G\n" if ($liteDebug);
# print STDERR "IN APPLESCRIPT GIVEN: IGNORING COLON\n" if ($asDebug);
# $treepart = "";
# last SWITCH;
# };
(($iskw == 9) && ($parserState->{afterSemi} || $parserState->{firstpastnl})) && do {
print STDERR "ISKEYWORD == 9: CASE KW_0A\n" if ($liteDebug);
$parserState->{inCase}++;
print STDERR "inCase -> ".$parserState->{inCase}."\n" if ($parseDebug || $localDebug || $braceDebug);
};
(($iskw == 10) && ($parserState->{afterSemi} == 2)) && do { # && ($parserState->{afterSemi} >= 2)) && do {
print STDERR "ISKEYWORD == 10: CASE KW_0B\n" if ($liteDebug);
# print "AFTERSEMI: ".$parserState->{afterSemi}."\n" if ($parseDebug || $localDebug || $braceDebug);
$parserState->{inCase}--;
print STDERR "inCase -> ".$parserState->{inCase}."\n" if ($parseDebug || $localDebug || $braceDebug);
};
(($part eq ";") && ($parserState->{startOfDec} == 1) && !$parserState->{inMacro} && !$parserState->{inMacroLine} && !($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) && do {
print STDERR "LEADING SEMICOLON: CASE 01\n" if ($liteDebug);
print STDERR "Dropping empty declaration\n" if ($localDebug || $parseDebug);
$part = "";
last SWITCH;
};
(length($TCLregexpcommand) && ($part =~ /^$TCLregexpcommand$/) &&
($parserState->{lastsymbol} eq ";" || $parserState->{afterNL} ||
$lasttoken eq "["
) &&
(!($inRegexp || $inRegexpTrailer || $parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}))) && do {
print STDERR "TCL REGEXP: CASE 01A\n" if ($liteDebug);
$parserState->{inTCLRegExpCommand} = 1;
# print STDERR "LS: $parserState->{lastsymbol} ANL: $parserState->{afterNL} LT: $lasttoken\n";
# Fall through
};
(($lang eq "perl" || $lang eq "shell") && $part eq "<<" && !$parserState->{attributeState} &&
!$parserState->{parsedParamParse} &&
!$parserState->{inBrackets} &&
!$parserState->{inTemplate} &&
!$parserState->{inChar} &&
!$parserState->{inString} &&
!$parserState->{inComment} &&
!$parserState->{inInlineComment} &&
!$parserState->{inImplements} &&
!$parserState->{inExtends} &&
!$parserState->{inClassConformingToProtocol} &&
!$parserState->{inRuby} &&
!$parserState->{seenBraces} &&
!$parserState->{classNameFound} &&
!$parserState->{inMacro} &&
!$parserState->{inMacroLine}) && do {
print STDERR "PERL OR SHELL MULTI-LINE STRING: CASE 01B\n" if ($liteDebug);
$parserState->{inString} = 13;
$parserState->{endOfString} = "";
# print STDERR "Aha\n";
$treeNest = 1;
last SWITCH;
};
(($lang eq "perl" || $lang eq "shell") && ($parserState->{inString} == 13) && ($parserState->{endOfString} eq "") && $part =~ /\S/) && do {
print STDERR "PERL OR SHELL MULTI-LINE STRING: CASE 01C\n" if ($liteDebug);
$parserState->{endOfString} = $part;
last SWITCH;
};
(($lang eq "perl" || $lang eq "shell") && ($parserState->{inString} == 13) && ($part =~ /[\n\r]/)) && do {
print STDERR "PERL OR SHELL MULTI-LINE STRING: CASE 01D\n" if ($liteDebug);
$parserState->{firstpastnl} = 1;
last SWITCH;
};
(($lang eq "perl" || $lang eq "shell") && ($parserState->{inString} == 13) && ($part eq $parserState->{endOfString}) && $parserState->{firstpastnl}) && do {
print STDERR "PERL OR SHELL MULTI-LINE STRING: CASE 01E\n" if ($liteDebug);
my $tempCur = $treeCur->addSibling($part, 0); $treeSkip = 1;
if ($HeaderDoc::includeFunctionContents && $reMark) {
$tempCur->{RE_STATE} = $reMark;
}
$treeCur = pop(@treeStack) || $treeTop;
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
$treeCur = $treeCur->lastSibling();
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
print STDERR "TSPOP [3]: now $treeCur\n" if ($tsDebug || $treeDebug);
bless($treeCur, "HeaderDoc::ParseTree");
last SWITCH;
};
(($lang eq "perl" || $lang eq "shell") && ($parserState->{inString} == 13) && $part =~ /\S/ && $parserState->{firstpastnl}) && do {
print STDERR "PERL OR SHELL MULTI-LINE STRING: CASE 01F\n" if ($liteDebug);
$parserState->{firstpastnl} = 0;
last SWITCH;
};
(($lang eq "perl" || $lang eq "shell") && ($parserState->{inString} == 13)) && do {
print STDERR "PERL OR SHELL MULTI-LINE STRING: CASE 01G\n" if ($liteDebug);
last SWITCH;
};
# Macro handlers
(($parserState->{inMacro} == 1) && ($part eq "define")) && do {
print STDERR "INMACRO/DEFINE: CASE 02\n" if ($liteDebug);
# define may be a multi-line macro
print STDERR "INMACRO AND DEFINE\n" if ($parseDebug || $localDebug);
$parserState->{inMacro} = 3;
print STDERR "inMacro -> 3\n" if ($macroDebug || $cppDebug);
$parserState->{sodname} = "";
my $pound = $treeCur->token();
if ($pound eq $parseTokens{sopreproc}) {
$treeNest = 2;
if ($treeDebug) { print STDERR "TS TREENEST -> 2 [1]\n"; }
$treePopOnNewLine = 2;
$pound .= $part;
$treeCur->token($pound);
}
last SWITCH;
};
# (($parserState->{inMacro} == 1 && $macrore_pound ne "" && $part =~ /(if|ifdef|ifndef|endif|else|undef|elif|error|warning|pragma|import|include)/ && ($part ne $parseTokens{definename})) || ($parserState->{inMacro} == 0 && $macrore_nopound ne "" && $part =~ /$macrore_nopound/))
# (($parserState->{inMacro} == 1 && $part =~ /(if|ifdef|ifndef|endif|else|undef|elif|error|warning|pragma|import|include)/ )) && do
(!$parserState->{inComment} && (($parserState->{inMacro} == 1 && $macrore_pound ne "" && $part =~ /^$macrore_pound$/ && ($part ne $parseTokens{definename})) || ($parserState->{inMacro} == 0 && $macrore_nopound ne "" && $part =~ /^$macrore_nopound$/))) && do {
print STDERR "MACRORE-v: \"$macrore_pound\"\n" if ($macroDebug);
print STDERR "MACRORE-r: \"(if|ifdef|ifndef|endif|else|undef|elif|error|warning|pragma|import|include)\"\n" if ($macroDebug);
print STDERR "MACRORE-n: \"$macrore_nopound\"\n" if ($macroDebug);
print STDERR "INMACRO/IF: CASE 03\n" if ($liteDebug);
print STDERR "INMACRO AND IF/IFDEF/IFNDEF/ENDIF/ELSE/PRAGMA/IMPORT/INCLUDE\n" if ($parseDebug || $localDebug);
# these are all single-line macros
$parserState->{inMacro} = 4;
print STDERR "inMacro -> 4\n" if ($macroDebug || $cppDebug);
$parserState->{sodname} = "";
my $pound = $treeCur->token();
if ($pound eq $parseTokens{sopreproc}) {
$treeNest = 2;
if ($treeDebug) { print STDERR "TS TREENEST -> 2 [2]\n"; }
$treePopOnNewLine = 1;
$pound .= $part;
$treeCur->token($pound);
if ($part eq "endif") {
# the rest of the line is not part of the macro
# NOTE: Do not change treeCur in the
# next line.
$treeCur->addChild("\n", 0);
$treeNest = 0;
if ($treeDebug) { print STDERR "TS TREENEST -> 0 [3]\n"; }
$treePopOnNewLine = 0;
$treeSkip = 1;
}
}
last SWITCH;
};
(($parserState->{inMacroLine} == 1) && ($part =~ /(if|ifdef|ifndef|endif|else|undef|elif|error|warning|pragma|import|include|define)/o)) && do {
print STDERR "INMACROLINE/IF: CASE 04\n" if ($liteDebug);
print STDERR "INMACROLINE AND IF/IFDEF/IFNDEF/ENDIF/ELSE/PRAGMA/IMPORT/INCLUDE\n" if ($parseDebug || $localDebug);
my $pound = $treeCur->token();
if ($pound eq $parseTokens{sopreproc}) {
$pound .= $part;
$treeCur->token($pound);
if ($part =~ /define/o) {
$treeNest = 2;
if ($treeDebug) { print STDERR "TS TREENEST -> 2 [4]\n"; }
$treePopOnNewLine = 2;
} elsif ($part eq "endif") {
# the rest of the line is not part of the macro
# NOTE: Do not change treeCur in the
# next line.
$treeCur->addChild("\n", 0);
$treeNest = 0;
if ($treeDebug) { print STDERR "TS TREENEST -> 0 [5]\n"; }
$treePopOnNewLine = 0;
$treeSkip = 1;
} else {
$treeNest = 2;
if ($treeDebug) { print STDERR "TS TREENEST -> 2 [6]\n"; }
$treePopOnNewLine = 1;
}
}
last SWITCH;
};
($parserState->{inMacro} == 1 && ($part ne $parseTokens{soc}) && ($part ne $parseTokens{eoc}) && $part =~ /\s/) && do {
print STDERR "INMACRO SPACE: CASE 04A\n" if ($liteDebug);
$treepart = $part; $part = "";
last SWITCH;
};
($parserState->{inMacro} == 1 && ($part ne $parseTokens{soc}) && ($part ne $parseTokens{eoc})) && do {
print STDERR "INMACRO PPTOKEN: CASE 05\n" if ($liteDebug);
print STDERR "INMACRO IS 1, CHANGING TO 2 (NO PROCESSING)\n" if ($parseDebug || $localDebug);
# error case.
$parserState->{inMacro} = 2;
print STDERR "inMacro -> 2\n" if ($macroDebug || $cppDebug);
last SWITCH;
};
($parserState->{inMacro} > 1 && $part ne "//" && $part !~ /[\n\r]/ && ($part ne $parseTokens{soc}) && ($part ne $parseTokens{eoc})) && do {
print STDERR "INMACRO OTHERTOKEN: CASE 06\n" if ($liteDebug);
if ($part eq "(") {
# print STDERR "HERE\n";
if ($parserState->{inMacro} == 3 && !$parserState->{inMacroTail}) {
$parserState->{cppMacroHasArgs} = 1;
}
}
print STDERR "INMACRO > 1, PART NE //" if ($parseDebug || $localDebug);
if ($cppDebug || $parseDebug) {
print STDERR "\nISQUOTED: ".$parserState->isQuoted($lang, $sublang)."\n" if ($parseDebug || $localDebug || $cppDebug || $macroDebug);
}
if ($part eq "\\") {
print STDERR "BS ADD\n" if ($parseDebug || $localDebug || $cppDebug || $macroDebug);
$parserState->addBackslash();
$bshandled = 1;
print STDERR "ISQUOTED NOW: ".$parserState->isQuoted($lang, $sublang)."\n" if ($parseDebug || $localDebug || $cppDebug || $macroDebug);
} elsif ($part !~ /[ \t]/) {
print STDERR "BS RESET\n" if ($parseDebug || $localDebug || $cppDebug || $macroDebug);
$parserState->resetBackslash();
$bshandled = 1;
print STDERR "ISQUOTED NOW: ".$parserState->isQuoted($lang, $sublang)."\n" if ($parseDebug || $localDebug || $cppDebug || $macroDebug);
}
print STDERR "PART: $part\n" if ($macroDebug);
if ($parserState->{seenMacroPart}) {
print STDERR "MACRO: SMP&TI\n" if ($macroDebug);
if (!(scalar(@braceStack) - $parserState->{initbsCount})) {
print STDERR "MACRO: NOSTACK\n" if ($macroDebug);
if ($part =~ /\s/o && $parserState->{macroNoTrunc} == 1) {
print STDERR "MACRO: ENDOFNAME\n" if ($macroDebug);
$parserState->{macroNoTrunc} = 0;
$treeCur->{HIDEMACROLASTTOKEN} = 1;
} elsif ($part =~ /[\{\(]/o) {
print STDERR "MACRO: BRACE\n" if ($macroDebug);
if (!$parserState->{macroNoTrunc}) {
# $parserState->{seenBraces} = 1;
print STDERR "END OF MACRO\n" if ($macroDebug);
if ($HeaderDoc::truncate_inline) {
$HeaderDoc::hidetokens = 3;
} else {
$treeCur->{HIDEMACROLASTTOKEN} = 2;
}
}
} else {
print STDERR "MACRO: OTHERTOKEN\n" if ($macroDebug);
$parserState->{macroNoTrunc} = 2;
}
}
}
if ($part =~ /[\{\(]/o) {
push(@braceStack, $part);
push(@parsedParamParseStack, $parserState->{parsedParamParse});
print STDERR "PUSHED $part ONTO BRACESTACK [1]\n" if ($macroDebug || $braceDebug);
} elsif ($part =~ /[\}\)]/o) {
if ($part ne peekmatch(\@braceStack, $lang, $fullpath, $inputCounter)) {
if ($parserState->{macroNoTrunc} == 1) {
# We haven't reached the end of the first part of the declaration, so this is an error.
warn("$fullpath:$inputCounter: warning: Initial braces in macro name do not match.\nWe may have a problem.\n");
}
}
my $temp = pop(@braceStack);
$parserState->{parsedParamParse} = pop(@parsedParamParseStack);
print STDERR "POPPED $temp FROM BRACESTACK [1]\n" if ($macroDebug || $braceDebug);
}
if ($part =~ /\S/o) {
$parserState->{seenMacroPart} = 1;
$parserState->{lastsymbol} = $part;
if (($parserState->{sodname} eq "") && ($parserState->{inMacro} == 3)) {
print STDERR "DEFINE NAME IS $part\n" if ($macroDebug);
$parserState->{sodname} = $part;
}
}
$lastchar = $part;
last SWITCH;
};
# Regular expression handlers
(length($parseTokens{varname}) && $part eq $parseTokens{varname} && !($inRegexp || $inRegexpTrailer || $parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !$parserState->{sodclass}) && do {
print "VARNAME: CASE 06A\n" if ($liteDebug);
$parserState->{sodclass} = "variable";
$parserState->{onlyComments} = 0;
if ($lang eq "applescript" || $lang eq "tcl") {
print STDERR "declarationEndsAtNewLine -> 1 [AS]\n" if ($parseDebug || $asDebug);
$parserState->{declarationEndsAtNewLine} = 1;
}
print STDERR "sodclass -> variable (explicit[1])\n" if ($sodDebug);
print STDERR "DETECTED VARIABLE KEYWORD\n" if ($localDebug || $parseDebug);
# Fall through.
};
(length($parseTokens{constname}) && $part eq $parseTokens{constname} && !($inRegexp || $inRegexpTrailer || $parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && (!(scalar(@braceStack) - $parserState->{initbsCount}))) && do {
print STDERR "CONST: CASE 06B\n" if ($liteDebug);
$parserState->{constKeywordFound} = 1;
print STDERR "DETECTED CONSTANT KEYWORD\n" if ($localDebug || $parseDebug);
# Fall through.
};
# print STDERR "IRE: $inRegexp IRT: $inRegexpTrailer IS: $parserState->{inString} ICo $parserState->{inComment} ILC: $parserState->{inInlineComment} ICh $parserState->{inChar}\n";
# print STDERR "IRE: $inRegexp IRT: $inRegexpTrailer IS: $parserState->{inString} ICo $parserState->{inComment} ILC: $parserState->{inInlineComment} ICh $parserState->{inChar}\n";
(length($regexppattern) && $part ne $parseTokens{soc} && $part ne $parseTokens{eoc} && $part ne $parseTokens{ilc} && $part ne $parseTokens{ilc_b} && $parserState->{lastsymbol} ne "\$" && $part =~ /^($regexppattern)$/ && !($inRegexp || $inRegexpTrailer || $parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) && do {
print STDERR "REGEXP PATTERN: CASE 07\n" if ($liteDebug);
my $match = $1;
print STDERR "REGEXP WITH PREFIX\n" if ($regexpDebug);
$regexpNoInterpolate = 0;
if ($match =~ /^($singleregexppattern)$/) {
# e.g. perl PATTERN?
print STDERR "SINGLE REGEXP\n" if ($regexpDebug);
print STDERR "INREGEXP -> 2 [1]\n" if ($regexpDebug);
$inRegexp = 2;
} else {
print STDERR "INREGEXP -> 4 [2]\n" if ($regexpDebug);
$inRegexp = 4;
print STDERR "DOUBLE REGEXP\n" if ($regexpDebug);
# print STDERR "REGEXP PART IS \"$part\"\n";
if ($part eq "tr") { $regexpNoInterpolate = 1; }
# if ($part =~ /tr/) { $regexpNoInterpolate = 1; }
}
$reMark = "RE_PREFIX";
if ($reMarkDebug) { print STDERR "REMARK: $reMark\n"; }
$inRegexpFirstPart = 2;
last SWITCH;
}; # end regexppattern
(($inRegexp &&
(length($regexpcharpattern) &&
$part =~ /^($regexpcharpattern)$/ &&
(!$inRegexpCharClass) &&
(!scalar(@regexpStack) || $part eq peekmatch(\@regexpStack, $lang, $fullpath, $inputCounter))
)
) || (
(!$inRegexp) && $part ne $parseTokens{soc} && $part ne $parseTokens{eoc} && $part ne $parseTokens{ilc} && $part ne $parseTokens{ilc_b} &&
($parserState->{lastsymbol} =~ /$regexpAllowedAfter/ ||
($parseTokens{regexpAllowedAtStartOfLine} && $parserState->{afterNL}) ||
$parserState->{inTCLRegExpCommand} ||
($parserState->{lastsymbol} eq "" && $lastnspart eq "(" && peek(\@braceStack) eq "(")
) &&
length($regexpfirstcharpattern) &&
$part =~ /$regexpfirstcharpattern/ && !$parserState->{inTemplate} &&
(!($inRegexp || $inRegexpTrailer ||
$parserState->{inString} || $parserState->{inComment} ||
$parserState->{inInlineComment} || $parserState->{inChar})) &&
(!$parserState->isRubyOpenQuote($part) || $parserState->isRubyCloseQuote($part)) &&
(!$inRegexpCharClass) &&
(!scalar(@regexpStack) || $part eq peekmatch(\@regexpStack, $lang, $fullpath, $inputCounter))
)
) && do {
print STDERR "REGEXP CHARACTER: CASE 08\n" if ($liteDebug);
print STDERR "REGEXP?\n" if ($regexpDebug);
if ($parserState->{inTCLRegExpCommand}) {
$parserState->{inTCLRegExpCommand} = 0;
}
# if ($lasttoken eq "\\")
if ($parserState->isQuoted($lang, $sublang) ||
((!$inRegexp) && $lasttoken eq "\$")) {
# jump to next match if quoted in a regexp
# or if it's $/
$lasttoken = $part;
$parserState->{lastsymbol} = $part;
} else {
print STDERR "REGEXP POINT A\n" if ($regexpDebug);
print STDERR "INREGEXP is $inRegexp\n" if ($regexpDebug);
if (!$inRegexp) {
print STDERR "INREGEXP -> 3 [3]\n" if ($regexpDebug);
$inRegexp = 2;
print STDERR "IRFP -> 1\n" if ($regexpDebug);
$inRegexpFirstPart = 1;
$reMark = "RE_START";
if ($reMarkDebug) { print STDERR "REMARK: $reMark\n"; }
} elsif ($inRegexpFirstPart != 2) {
print STDERR "IRFP -> 0\n" if ($regexpDebug);
$inRegexpFirstPart = 0;
$reMark = "RE_PARTSEP";
if ($reMarkDebug) { print STDERR "REMARK: $reMark\n"; }
} else {
print STDERR "IRFP -> 1\n" if ($regexpDebug);
$inRegexpFirstPart = 1;
$reMark = "RE_START";
if ($reMarkDebug) { print STDERR "REMARK: $reMark\n"; }
}
$lasttoken = $part;
$parserState->{lastsymbol} = $part;
my $is_a_comment = 0;
if ($part eq "#" &&
((scalar(@regexpStack) != 1) ||
(peekmatch(\@regexpStack, $lang, $fullpath, $inputCounter) ne "#"))) {
if ($nextpart =~ /^\s/o) {
# it's a comment. jump to next match.
$is_a_comment = 1;
}
}
if (!$is_a_comment) {
my $fall_through = 0;
print STDERR "REGEXP POINT B\n" if ($regexpDebug);
if (!scalar(@regexpStack)) {
print STDERR "PUSHING $part ONTO REGEXPSTACK [1]\n" if ($localDebug || $parseDebug || $regexpDebug);
push(@regexpStack, $part);
$inRegexp--;
if (!$inRegexp) {
$leavingRegexp = 1;
$reMark = "RE_END";
if ($reMarkDebug) { print STDERR "REMARK: $reMark\n"; }
}
print STDERR "INREGEXP -> $inRegexp [4]\n" if ($regexpDebug);
} else {
my $match = peekmatch(\@regexpStack, $lang, $fullpath, $inputCounter);
my $tos = pop(@regexpStack);
print STDERR "popped $tos FROM REGEXPSTACK\n" if ($localDebug || $parseDebug || $regexpDebug);
if (!scalar(@regexpStack) && ($match eq $part)) {
$inRegexp--;
if (!$inRegexp) {
$leavingRegexp = 1;
$reMark = "RE_END";
if ($reMarkDebug) { print STDERR "REMARK: $reMark\n"; }
}
print STDERR "INREGEXP -> $inRegexp [5]\n" if ($regexpDebug);
if ($inRegexp == 2 && ($tos eq "/" || $tos eq "|")) {
# we don't double the slash or vertical bar in the
# middle of a s/foo/bar/g style
# expression.
$inRegexp--;
if (!$inRegexp) {
$leavingRegexp = 1;
$reMark = "RE_END";
if ($reMarkDebug) { print STDERR "REMARK: $reMark\n"; }
}
print STDERR "INREGEXP -> $inRegexp [6]\n" if ($regexpDebug);
}
if ($inRegexp) {
print STDERR "PUSHING $tos ONTO REGEXPSTACK [2]\n" if ($localDebug || $parseDebug || $regexpDebug);
push(@regexpStack, $tos);
}
} elsif (scalar(@regexpStack) == 1) {
print STDERR "PUSHING $tos ONTO REGEXPSTACK [3]\n" if ($localDebug || $parseDebug || $regexpDebug);
push(@regexpStack, $tos);
if ($tos =~ /['"`|{}]/o || $regexpNoInterpolate) {
# these don't interpolate.
$fall_through = 1;
}
} else {
print STDERR "PUSHING $tos ONTO REGEXPSTACK [4]\n" if ($localDebug || $parseDebug || $regexpDebug);
push(@regexpStack, $tos);
if ($tos =~ /['"`|{}]/o || $regexpNoInterpolate) {
# these don't interpolate.
$fall_through = 1;
} else {
print STDERR "PUSHING $part ONTO REGEXPSTACK [5]\n" if ($localDebug || $parseDebug || $regexpDebug);
push(@regexpStack, $part);
}
}
}
if (!$fall_through) {
print STDERR "REGEXP POINT C\n" if ($regexpDebug);
if (!$inRegexp) {
$inRegexpTrailer = 2;
}
last SWITCH;
}
}
}
}; # end regexpcharpattern
# Start of preprocessor macros
($part eq $parseTokens{sopreproc}) && do {
print STDERR "SOPREPROC: CASE 09\n" if ($liteDebug);
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) {
if ($parserState->{onlyComments}) {
print STDERR "inMacro -> 1\n" if ($macroDebug || $cppDebug);
$parserState->{inMacro} = 1;
## @@@ FIXME DAG NEXT TWO LINES NEEDED FOR IDL TO AVOID
## "warning: Declaration starts with # but is not preprocessor macro"
## ERROR MESSAGE, BUT THIS BREAKS C/C++.
## WHY !?!?!
##
## if ($$treepart = " ";
## $nextpart = $part.$nextpart;
##
## END IDL-ONLY BLOCK
# $continue = 0;
# print STDERR "CONTINUE -> 0 [1]\n" if ($localDebug || $macroDebug || $continueDebug);
} elsif ($curline =~ /^\s*$/o) {
$parserState->{inMacroLine} = 1;
print STDERR "IML\n" if ($localDebug);
} elsif ($postPossNL) {
print STDERR "PRE-IML \"$curline\"\n" if ($localDebug || $macroDebug);
$treeCur = $treeCur->addSibling("\n", 0);
bless($treeCur, "HeaderDoc::ParseTree");
$parserState->{inMacroLine} = 1;
$postPossNL = 0;
}
}
};
# Start of token-delimited functions and procedures (e.g.
# Pascal and PHP)
(($part eq $parseTokens{sofunction} || $part eq $parseTokens{soprocedure} || $part eq $parseTokens{soconstructor}) &&
(($lang ne "applescript") || $parserState->appleScriptFunctionLegalHere(\@braceStack)) &&
!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) &&
!(scalar(@braceStack)-$parserState->{initbsCount}) && !$parserState->{seenBraces}) && do {
# print STDERR "(($part eq $parseTokens{sofunction} || $part eq $parseTokens{soprocedure} || $part eq $parseTokens{soconstructor}) &&".
# "!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})\n";
# print STDERR "AFTERNL: ".$parserState->{afterNL}."\n";
print STDERR "SOFUNC: CASE 10\n" if ($liteDebug);
if ($part eq $parseTokens{soconstructor}) {
$parserState->{isConstructor} = 1;
}
if ($lang eq "tcl" && scalar(@parserStack)) {
print STDERR "declarationEndsAtNewLine -> 1 (SOPROC/FUNC/CONS)\n" if ($parseDebug);
$parserState->{declarationEndsAtNewLine} = 1;
}
$parserState->{sodclass} = "function";
$parserState->{onlyComments} = 0;
$parserState->{lastsymbol} = $part;
# $parserState->{sodname} = $part;
print STDERR "sodclass -> function (explicit[2])\n" if ($sodDebug);
print STDERR "FUNCTION OR PROCEDURE FOUND [1].\n" if ($localDebug);
if (!$pascal && !$ruby && ($lang ne "tcl") && ($lang ne "applescript") && $lang ne "perl") {
$parserState->{kr_c_function} = 1;
}
$parserState->{typestring} = "function";
$parserState->{startOfDec} = 2;
print STDERR "startOfDec -> 2 [1]\n" if ($localDebug);
$parserState->{namePending} = 1;
# if (!$parserState->{seenBraces}) { # TREEDONE
# $treeNest = 1;
# $treePopTwo++;
# push(@treeStack, $treeCur);
# $treeCur = $treeCur->addChild($part, 0); $treeSkip = 1;
# bless($treeCur, "HeaderDoc::ParseTree");
# }
print STDERR "namePending -> 1 [1]\n" if ($parseDebug);
if ($parseTokens{functionisbrace} && $parserState->{sodclass} eq "function" &&
!$parserState->{pushedfuncbrace}) {
$parserState->{pushedfuncbrace} = 1;
}
if ($parseTokens{parmswithcurlybraces}) {
$parserState->{pendingBracedParameters} = 1;
}
if ($parseTokens{functionisapiowner}) {
$pushParserStateAtBrace = 1;
}
last SWITCH;
};
# C++ destructor handler.
($part =~ /\~/o && ($lang eq "C" || $lang eq "Csource") && $sublang eq "cpp" && !($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) && do {
print STDERR "C++ DESTRUCTOR: CASE 11\n" if ($liteDebug);
print STDERR "TILDE\n" if ($localDebug);
$parserState->{seenTilde} = 2;
$lastchar = $part;
$parserState->{onlyComments} = 0;
# $name .= '~';
last SWITCH;
};
# Objective-C method handler.
($part =~ /[-+]/o && ($lang eq "C" || $lang eq "Csource") && $parserState->{onlyComments}) && do {
print STDERR "OBJC METHOD: CASE 12\n" if ($liteDebug);
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) {
print STDERR "OCCMETHOD\n" if ($localDebug);
# Objective C Method.
$parserState->{occmethod} = 1;
$parserState->{occmethodtype} = $part;
$parserState->{occmethodreturntype} = "";
$lastchar = $part;
$parserState->{onlyComments} = 0;
print STDERR "[a]onlyComments -> 0\n" if ($macroDebug);
if (!$parserState->{seenBraces}) { # TREEDONE
if (!$parserState->{hollow}) {
print STDERR "SETHOLLOW -> 1\n" if ($parserStackDebug);
$sethollow = 1;
}
$treeNest = 1;
if ($treeDebug) { print STDERR "TS TREENEST -> 1 [7]\n"; }
$parserState->{treePopTwo} = 1;
}
}
last SWITCH;
};
# newline handler.
($part =~ /[\n\r]/o && ($parserState->{inString} != 13) &&
(!($parseTokens{classisbrace} && $parserState->{sodclass} eq "class" && (!$parserState->{inRubyClass}))) &&
(!($parseTokens{functionisbrace} && $parserState->{pushedfuncbrace} == 1)) &&
($parserState->isQuoted($lang, $sublang) || (!$parserState->{newlineIsSemi}))) && do {
my $precursor = $parserState->clearLeftBracePrecursor();
if ($precursor) {
push(@braceStack, $precursor);
print STDERR "Pushing $precursor onto the brace stack [clearLeftBracePrecursor]\n" if ($HeaderDoc::AppleScriptDebug || $braceDebug || $parseDebug);
}
if ($lang eq "shell") {
if ($part eq ";;") {
$parserState->{afterSemi} = 2;
} elsif (!$parserState->{afterSemi}) {
$parserState->{afterSemi} = 1;
}
}
print STDERR "NEWLINE: CASE 13\n" if ($liteDebug);
# NEWLINE FOUND
my $prev_inInlineComment = $parserState->{inInlineComment};
$parserState->{inInlineComment} = 0;
print STDERR "inInlineComment -> 0\n" if ($ilcDebug);
if ($ruby) {
$parserState->{followingrubyrbrace} = 0;
}
if ($parserState->{pushedfuncbrace}) {
# Ensure we get a token after the closing parenthesis
# (if applicable) to set as the end of the declaration.
print STDERR "OOH. We are in a function now.\n" if ($parseDebug);
$parserState->{inOfIn} = 0;
$parserState->{inLabel} = 0;
$parserState->{inGiven} = 0;
$treeCur = $treeCur->addSibling("", 0);
bless($treeCur, "HeaderDoc::ParseTree");
$parserState->{startOfDec} = 0;
}
$treepart = $part;
if ($inRegexp) {
warn "$fullpath:$inputCounter: warning: multi-line regular expression\n";
print STDERR "DECTODATE: $declaration".$line."\n";
}
print STDERR "NLCR\n" if ($tsDebug || $treeDebug || $localDebug);
# print "LASTCHAR: $lastchar\n";
if ($lastchar !~ /[\,\;\{\(\)\}]/o && $nextpart !~ /[\{\}\(\)]/o) {
if ($lastchar ne "*/" && $nextpart ne "/*") {
if (!$parserState->{inMacro} && !$parserState->{inMacroLine} && !$treePopOnNewLine) {
print STDERR "NL->SPC\n" if ($localDebug);
$part = " ";
print STDERR "LC: $lastchar\n" if ($localDebug);
print STDERR "NP: $nextpart\n" if ($localDebug);
$postPossNL = 2;
} elsif ($treePopOnNewLine && $prev_inInlineComment) {
# print STDERR "TPONL: $treePopOnNewLine\n";
if ($parserState->{inMacroLine}) {
print STDERR "skipped pushing CPP directive $parsedParam into parsedParamList [0]\n" if ($parmDebug || $cppDebug || $localDebug);
$parserState->{inMacroLine} = 0;
$parsedParam = "";
} else {
print STDERR "Keeping parsed parameter $parsedParam because we're leaving a single-line comment.\n" if ($parmDebug || $cppDebug || $localDebug);
}
} else {
if ($parserState->{inMacroLine}) {
print STDERR "skipped pushing CPP directive $parsedParam into parsedParamList [1]\n" if ($parmDebug || $cppDebug || $localDebug);
} else {
print STDERR "cleared parsed parameter $parsedParam"." [1]\n" if ($parmDebug || $cppDebug || $localDebug);
}
$parserState->{inMacroLine} = 0;
# Don't push parsed parameter here. Just clear it.
# push(@{$parserState->{parsedParamList}}, $parsedParam);
# print STDERR "pushed $parsedParam into parsedParamList [1]\n" if ($parmDebug);
$parsedParam = "";
}
} elsif ($parserState->{inMacroLine}) {
$parserState->{inMacroLine} = 0;
print STDERR "skipped pushing CPP directive $parsedParam into parsedParamList [2]\n" if ($parmDebug || $cppDebug || $localDebug);
$parsedParam = "";
}
} elsif ($parserState->{inMacroLine}) {
$parserState->{inMacroLine} = 0;
print STDERR "skipped pushing CPP directive $parsedParam into parsedParamList [3]\n" if ($parmDebug || $cppDebug || $localDebug);
$parsedParam = "";
}
if (($lang eq "shell" && $parserState->{sodclass} ne "function") ||
($ruby && ($parserState->{sodclass} ne "class" && $parserState->{sodclass} ne "function") && !scalar(@parserStack))) {
print STDERR "SC: ".$parserState->{sodclass}."\n" if ($localDebug || $parseDebug || $rubyDebug);
if (!($parserState->{inString} || $parserState->{inChar})) {
if (!$parserState->isQuoted($lang, $sublang)) {
print STDERR "LS: ".$parserState->{lastsymbol}."\n" if ($localDebug || $parseDebug);
print STDERR "CONTINUE -> 0 [1aa]\n" if ($parseDebug || $cppDebug || $macroDebug || $localDebug || $continueDebug);
$continue = 0;
}
}
}
print STDERR "TPONL: $treePopOnNewLine\n" if ($liteDebug);
if ($treePopOnNewLine < 0) {
# pop once for //, possibly again for macro
$treePopOnNewLine = 0 - $treePopOnNewLine;
$treeCur = $treeCur->addSibling($treepart, 0);
if ($HeaderDoc::includeFunctionContents && $reMark) {
$treeCur->{RE_STATE} = $reMark;
}
bless($treeCur, "HeaderDoc::ParseTree");
# push(@treeStack, $treeCur);
$treeSkip = 1;
$treeCur = pop(@treeStack);
if (!$treeCur) {
$treeCur = $treeTop;
warn "$fullpath:$inputCounter: warning: Attempted to pop off top of tree";
}
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
$treeCur = $treeCur->lastSibling();
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
print STDERR "TSPOP [1]: now $treeCur\n" if ($tsDebug || $treeDebug);
bless($treeCur, "HeaderDoc::ParseTree");
}
if ($treePopOnNewLine == 1 || ($treePopOnNewLine && !$parserState->isQuoted($lang, $sublang))) {
# $parserState->{lastsymbol} ne "\\"
$treeCur = $treeCur->addSibling($treepart, 0);
if ($HeaderDoc::includeFunctionContents && $reMark) {
$treeCur->{RE_STATE} = $reMark;
}
bless($treeCur, "HeaderDoc::ParseTree");
# push(@treeStack, $treeCur);
$treeSkip = 1;
$treeCur = pop(@treeStack);
if (!$treeCur) {
$treeCur = $treeTop;
warn "$fullpath:$inputCounter: warning: Attempted to pop off top of tree";
}
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
$treeCur = $treeCur->lastSibling();
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
$treeCur = $treeCur->addSibling("", 0); # empty token
print STDERR "TSPOP [1a]: now $treeCur\n" if ($tsDebug || $treeDebug);
bless($treeCur, "HeaderDoc::ParseTree");
$treePopOnNewLine = 0;
$HeaderDoc::hidetokens = 0;
} else {
print STDERR "Not popping from tree. Probably quoted.\n" if ($localDebug || $parseDebug);
}
next SWITCH;
};
# C++ template handlers
($part eq $parseTokens{sotemplate} && (($lang eq "perl" && $parserState->{lastsymbol} eq "=" && !$inRegexp) || ($lang ne "perl" && ($HeaderDoc::includeFunctionContents || !$parserState->{seenBraces}) && (!$parserState->{inMacroLine}) && (!$parserState->{inMacro}) && (!$parserState->{INIF}))) && ($parserState->{inOperator} != 1)) && do {
print STDERR "C++ TEMPLATE: CASE 14\n" if ($liteDebug);
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) {
if ($HeaderDoc::hideIDLAttributes && $lang eq "C" && $sublang eq "IDL") { $hideTokenAndMaybeContents = 3; }
print STDERR "inTemplate -> ".($parserState->{inTemplate}+1)."\n" if ($localDebug);
print STDERR "SBS: " . scalar(@braceStack) . ".\n" if ($localDebug);
$parserState->{inTemplate}++;
if (!(scalar(@braceStack) - $parserState->{initbsCount})) {
$parserState->{preTemplateSymbol} = $parserState->{lastsymbol};
}
$parserState->{lastsymbol} = "";
$lastchar = $part;
$parserState->{onlyComments} = 0;
push(@parsedParamParseStack, $parserState->{parsedParamParse});
push(@braceStack, $part); pbs(@braceStack);
print STDERR "PUSHED $part ONTO BRACESTACK [2]\n" if ($macroDebug || $braceDebug);
print STDERR "LINE: $line\n" if ($regexpDebug && $braceDebug);
if ($HeaderDoc::includeFunctionContents || !$parserState->{seenBraces}) { # TREEDONE
$treeNest = 1;
if (!$parserState->{seenBraces}) {
if (!$parserState->{hollow}) { $sethollow = 1; } # IDL can have this at the start of declaration.
}
if ($treeDebug) { print STDERR "TS TREENEST -> 1 [8]\n"; }
# push(@treeStack, $treeCur);
# $treeCur = $treeCur->addChild($part, 0); $treeSkip = 1;
# bless($treeCur, "HeaderDoc::ParseTree");
}
print STDERR "[b]onlyComments -> 0\n" if ($macroDebug);
}
last SWITCH;
};
($part eq $parseTokens{eotemplate} && (($lang eq "perl" && $parserState->{inTemplate} && !$inRegexp) || ($lang ne "perl" && ($HeaderDoc::includeFunctionContents || !$parserState->{seenBraces}) && (!$parserState->{inMacroLine}) && (!$parserState->{inMacro}) && (!$parserState->{INIF}))) && ($parserState->{inOperator} != 1)) && do {
print STDERR "C++ TEMPLATE END: CASE 15\n" if ($liteDebug);
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && (!(scalar(@braceStack)-$parserState->{initbsCount}) || $parserState->{inTemplate})) {
if ($parserState->{inTemplate}) {
print STDERR "parserState->{inTemplate} -> ".($parserState->{inTemplate}-1)."\n" if ($localDebug);
$parserState->{inTemplate}--;
$parserState->{lastsymbol} = "";
$lastchar = $part;
$curline .= " ";
$parserState->{onlyComments} = 0;
print STDERR "[c]onlyComments -> 0\n" if ($macroDebug);
}
my $top = pop(@braceStack);
$parserState->{parsedParamParse} = pop(@parsedParamParseStack);
print STDERR "POPPED $top FROM BRACESTACK [2]\n" if ($macroDebug || $braceDebug);
if ($HeaderDoc::includeFunctionContents || !$parserState->{seenBraces}) { # TREEDONE
my $tempCur = $treeCur->addSibling($part, 0); $treeSkip = 1;
if ($HeaderDoc::includeFunctionContents && $reMark) {
$tempCur->{RE_STATE} = $reMark;
}
$treeCur = pop(@treeStack) || $treeTop;
if (!$parserState->{seenBraces}) { # TREEDONE
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
}
$treeCur = $treeCur->lastSibling();
if (!$parserState->{seenBraces}) { # TREEDONE
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
}
print STDERR "TSPOP [2]: now $treeCur\n" if ($tsDebug || $treeDebug);
bless($treeCur, "HeaderDoc::ParseTree");
}
if ($top ne $parseTokens{sotemplate}) {
# Because of the way the code (ab)uses these,
# legitimate constructs like => would otherwise
# set this off.
if ($lang eq "perl") {
push(@braceStack, $top);
print STDERR "PUSHED $top ONTO BRACESTACK [2A]\n" if ($macroDebug || $braceDebug);
} else {
warn("$fullpath:$inputCounter: warning: Template (angle) brackets do not match.\nWe may have a problem.\n");
}
}
}
last SWITCH;
};
($ruby && ($part eq "<") && ($parserState->{sodclass} eq "class")) && do {
print STDERR "RUBY LEFT ANGLE BRACE: CASE 15A\n" if ($liteDebug);
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && (!(scalar(@braceStack)-$parserState->{initbsCount}))) {
$parserState->{waitingForExceptions} = 1;
}
};
#
# Handles C++ access control state, e.g. "public:"
#
($part eq ":" && (!$parseTokens{assignmentwithcolon})) && do {
print STDERR "Access control colon: CASE 16\n" if ($liteDebug);
print STDERR "TS IS \"$parserState->{typestring}\"\n" if ($localDebug || $parseDebug);
# fall through to next colon handling case if we fail.
if ($inRegexp && $inRegexpCharClass && ($inRegexpCharClass != 2) && ($inRegexpCharClass < 4) && $lasttoken eq "[") {
print STDERR "In regexp nested character class (e.g. [:space:]).\n" if ($regexpDebug || $parseDebug);
$inRegexpCharClass = 4;
} elsif ($inRegexp && ($inRegexpCharClass >= 4)) {
print STDERR "In regexp nested character class (e.g. [:space:]).\n" if ($regexpDebug || $parseDebug);
$inRegexpCharClass = 6;
} elsif (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) {
if ($pascal && (!(scalar(@braceStack)-$parserState->{initbsCount}))) {
print STDERR "Clearing SOD (pascal variable)\n" if ($sodDebug || $localDebug);
$parserState->{startOfDec} = 1;
print STDERR "startOfDec -> 1 [2]\n" if ($localDebug);
print STDERR "SODCLASS: \"$parserState->{sodclass}\"\n" if ($sodDebug || $localDebug);
if ($parserState->{sodclass} ne "function") {
print STDERR "sodclass -> function (implicit)[3]\n" if ($sodDebug);
$parserState->{sodclass} = "variable";
}
$parserState->{nameList} = $parserState->{sodtype}." ".$parserState->{sodname};
print STDERR "NL: $parserState->{nameList}\n" if ($sodDebug || $localDebug);
$parserState->{sodname} = "";
$parserState->{sodtype} = "";
$parserState->{waitingForTypeInformation} = 2;
print STDERR "CLEARING CURLINE ($curline)\n" if ($sodDebug || $localDebug);
$curline = "";
}
if (length($accessregexp) && ($lastnspart =~ /$accessregexp/)) {
# We're special.
print STDERR "PERMANENT ACS CHANGE from $HeaderDoc::AccessControlState to $1\n" if ($localDebug);
$parserState->{sodname} = "";
$parserState->{typestring} = "";
print STDERR "RESET HOLLOW at $part\n" if ($parserStackDebug);
if ($parserState->{hollow}) {
my $node = $parserState->{hollow};
$node->{BLOCKOFFSET} = undef;
$node->{INPUTCOUNTER} = undef;
}
$parserState->{hollow} = undef;
$parserState->{returntype} = ""; # @@@ DELETE THIS LINE IF IT CAUSES TEST FAILURES.
$curline = "";
$parserState->{onlyComments} = 1;
print STDERR "SET onlyComments to 1\n" if ($parserStateInsertDebug || $parseDebug);
print STDERR "hollowskip -> 1 (ACS)\n" if ($parserStateInsertDebug);
$hollowskip = 1;
$HeaderDoc::AccessControlState = $1;
$lastACS = $1;
last SWITCH;
} elsif ($parseTokens{structname} && $parserState->{typestring} eq $parseTokens{structname}) {
print STDERR "STRUCT CASE\n" if ($parmDebug || $localDebug);
if (!(scalar(@braceStack) - $parserState->{initbsCount})) {
print STDERR "STRUCT CASE OUTER\n" if ($parmDebug || $localDebug);
if (!$parserState->{structClassName}) {
print STDERR "STRUCT NAME BLANK\n" if ($parmDebug || $localDebug);
$parserState->{structClassName} = $parserState->{lastsymbol};
$parserState->{bracePending} = 2;
}
}
} elsif ($parserState->{inBitfield}) {
print STDERR "NOT IN BITFIELD (::)\n" if ($parmDebug || $parseDebug || $localDebug || $bitfieldDebug);
delete $parserState->{inBitfield};
} elsif ($parserState->{sodclass} ne "class" &&
!$parserState->{occmethod} && !$parserState->{inMacro} &&
!$parserState->{inEnum} && !$parserState->{inClass} &&
!$parserState->{seenBraces} && ($lang eq "C" || $lang eq "Csource") && ($sublang ne "MIG")) {
print STDERR "SC: $parserState->{sodclass} ST: $parserState->{sodtype}\n" if ($localDebug || $parseDebug);
print STDERR "IN BITFIELD?\n" if ($parmDebug || $parseDebug || $localDebug || $bitfieldDebug);
$parserState->{inBitfield} = 1;
}
}
};
(length($accessregexp) && ($part =~ /$accessregexp/)) && do {
print STDERR "Access regexp: CASE 17\n" if ($liteDebug);
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) {
# We're special.
if ($part =~ /^\@(.*)$/) {
print STDERR "PERMANENT ACS CHANGE from $HeaderDoc::AccessControlState to $1\n" if ($localDebug);
$parserState->{sodname} = "";
$parserState->{typestring} = "";
print STDERR "RESET HOLLOW at $part\n" if ($parserStackDebug);
$parserState->{hollow} = undef;
$parserState->{onlyComments} = 1;
$hollowskip = 1;
print STDERR "hollowskip -> 1 (\@ACS)\n" if ($parserStateInsertDebug);
$HeaderDoc::AccessControlState = $1;
$lastACS = $1;
last SWITCH;
} else {
print STDERR "TEMPORARY ACS CHANGE from $HeaderDoc::AccessControlState to $1\n" if ($localDebug);
$parserState->{sodname} = "";
$lastACS = $HeaderDoc::AccessControlState;
$HeaderDoc::AccessControlState = $1;
}
} else {
next SWITCH;
}
};
(length($requiredregexp) && $part =~ /$requiredregexp/) && do {
print STDERR "REQUIRED REGEXP: CASE 17A\n" if ($liteDebug);
print STDERR "REQUIRED REGEXP MATCH: \"$part\"\n" if ($localDebug || $parseDebug);
$hollowskip = 1;
print STDERR "hollowskip -> 1 (requiredregexp)\n" if ($parserStateInsertDebug);
$HeaderDoc::OptionalOrRequired = $part;
$parserState->{optionalOrRequired} = $part;
last SWITCH;
};
#
# C++ copy constructor handler. For example:
#
# char *class(void *a, void *b) :
# class(pri_type, pri_type);
#
($part eq ":" && (!$parseTokens{assignmentwithcolon})) && do {
print STDERR "Copy constructor: CASE 18\n" if ($liteDebug);
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) {
if ($parserState->{occmethod}) {
$parserState->{name} = $parserState->{lastsymbol};
if ($parserState->{occparmlabelfound}) {
$parserState->{occmethodname} .= "$parserState->{lastsymbol}:";
if ($occMethodNameDebug) {
print STDERR "OCC method name now ".$parserState->{occmethodname}." (lastsymbol was \"".$parserState->{lastsymbol}."\").\n";
}
$parserState->{occparmlabelfound} = -1; # next token is name of this parameter, followed by label for next parameter.
} else {
if ($occMethodNameDebug) {
print STDERR "OCC method name missing.\n";
print STDERR "OCC method name still ".$parserState->{occmethodname}." (lastsymbol was \"".$parserState->{lastsymbol}."\").\n";
}
$parserState->{occparmlabelfound} = -2; # Special case: grab the parameter name instead because parameter has no label.
}
# Start doing line splitting here.
# Also, capture the method's name.
if ($parserState->{occmethod} == 1) {
$parserState->{occmethod} = 2;
if (!$prespace) { $prespaceadjust = 4; }
$parserState->{onlyComments} = 0;
print STDERR "[d]onlyComments -> 0\n" if ($macroDebug);
}
} else {
if (($lang eq "C" || $lang eq "Csource") && $sublang eq "cpp") {
if (!(scalar(@braceStack)-$parserState->{initbsCount}) && $parserState->{sodclass} eq "function") {
$inPrivateParamTypes = 1;
$declaration .= "$curline";
$publicDeclaration = $declaration;
$declaration = "";
} else {
next SWITCH;
}
if (!$parserState->{stackFrozen}) {
if (scalar(@{$parserState->{parsedParamList}})) {
foreach my $node (@{$parserState->{parsedParamList}}) {
$node =~ s/^\s*//so;
$node =~ s/\s*$//so;
if (length($node)) {
push(@{$parserState->{pplStack}}, $node)
}
}
@{$parserState->{parsedParamList}} = ();
print STDERR "parsedParamList pushed [1]\n" if ($parmDebug);
}
# print STDERR "SEOPPLS\n";
# for my $item (@{$parserState->{pplStack}}) {
# print STDERR "PPLS: $item\n";
# }
# print STDERR "OEOPPLS\n";
@{$parserState->{freezeStack}} = @{$parserState->{pplStack}};
$parserState->{frozensodname} = $parserState->{sodname};
$parserState->{stackFrozen} = 1;
}
} else {
next SWITCH;
}
}
if (($HeaderDoc::includeFunctionContents || !$parserState->{seenBraces}) && !$parserState->{occmethod}) { # TREEDONE
# $treeCur->addSibling($part, 0); $treeSkip = 1;
$treeNest = 1;
if ($treeDebug) { print STDERR "TS TREENEST -> 1 [9]\n"; }
$parserState->{treePopTwo} = 1;
# $treeCur = pop(@treeStack) || $treeTop;
# bless($treeCur, "HeaderDoc::ParseTree");
}
last SWITCH;
} else {
print STDERR "NOPE\n" if ($liteDebug);
next SWITCH;
}
};
# Non-newline, non-carriage-return whitespace handler.
($part =~ /\s/o && $part !~ /[\n\r]/o) && do {
print STDERR "Whitespace: CASE 19\n" if ($liteDebug);
# Maybe push parsed parameter (lang = tcl)
if ($parserState->{parsedParamParse} == 5) {
print STDERR "PUSHED \"$parsedParam\" onto parsedParamList\n" if ($parmDebug);
if (length($parsedParam)) { push(@{$parserState->{parsedParamList}}, $parsedParam); }
$parsedParam = "";
}
# otherwise just add white space silently.
# if ($part eq "\n") { $parserState->{lastsymbol} = ""; };
$lastchar = $part;
last SWITCH;
};
# backslash handler (largely useful for macros, strings).
($part =~ /\\/o) && do {
print STDERR "BACKSLASH: CASE 20\n" if ($liteDebug);
$parserState->{lastsymbol} = $part; $lastchar = $part;
$parserState->addBackslash();
};
# quote and bracket handlers.
($part eq "\"" ||
($ruby && ($parserState->isRubyOpenQuote($part) ||
$parserState->isRubyCloseQuote($part)))) && do {
print STDERR "DOUBLE QUOTE: CASE 21\n" if ($liteDebug);
print STDERR "dquo\n" if ($localDebug);
# print STDERR "QUOTEDEBUG: CURSTRING IS '$curstring'\n";
# print STDERR "QUOTEDEBUG: CURLINE IS '$curline'\n";
if ((!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar} || $inRegexp)) && ($parserState->isRubyCloseQuote($part) || !$parserState->{inRuby})) {
if ($ruby) {
$parserState->{inRuby} = $parserState->isRubyOpenQuote($part);
# print STDERR "RUBYQUOTE: ".$parserState->{inRuby}."\n";
}
$parserState->{onlyComments} = 0;
print STDERR "[e]onlyComments -> 0\n" if ($macroDebug);
print STDERR "LASTTOKEN: $lasttoken\nCS: $curstring\n" if ($localDebug);
# if (($lasttoken !~ /\\$/o) && ($curstring !~ /\\$/o))
if (!$parserState->isQuoted($lang, $sublang)) {
if (!$parserState->{inString}) {
if ($HeaderDoc::includeFunctionContents || !$parserState->{seenBraces}) { # TREEDONE
$treeNest = 1;
if ($treeDebug) { print STDERR "TS TREENEST -> 1 [10]\n"; }
# push(@treeStack, $treeCur);
# $treeCur = $treeCur->addChild($part, 0); $treeSkip = 1;
# bless($treeCur, "HeaderDoc::ParseTree");
}
} else {
if ($HeaderDoc::includeFunctionContents || !$parserState->{seenBraces}) { # TREEDONE
my $tempCur = $treeCur->addSibling($part, 0); $treeSkip = 1;
if ($HeaderDoc::includeFunctionContents && $reMark) {
$tempCur->{RE_STATE} = $reMark;
}
$treeCur = pop(@treeStack) || $treeTop;
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
$treeCur = $treeCur->lastSibling();
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
print STDERR "TSPOP [3]: now $treeCur\n" if ($tsDebug || $treeDebug);
bless($treeCur, "HeaderDoc::ParseTree");
}
}
$parserState->{inString} = (1-$parserState->{inString});
print STDERR "INSTRING -> ".$parserState->{inString} ."\n" if ($liteDebug || $parseDebug || $localDebug);
}
}
$lastchar = $part;
$parserState->{lastsymbol} = "";
last SWITCH;
};
($part eq "[") && do {
print STDERR "LEFT BRACKET: CASE 22\n" if ($liteDebug);
# left square bracket (square brace)
my $fall_through = 0;
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) {
if ($inRegexp && $inRegexpCharClass) {
# jump to next match.
$lasttoken = $part;
$parserState->{lastsymbol} = $part;
$fall_through = 1;
} elsif (!$parserState->isQuoted($lang, $sublang)) {
if ($inRegexp && $inRegexpFirstPart == 1) {
print STDERR "inRegexpCharClass -> 3\n" if ($regexpDebug);
$inRegexpCharClass = 3;
$reMark = "RE_CCSTART";
if ($reMarkDebug) { print STDERR "REMARK: $reMark\n"; }
}
print STDERR "lbracket\n" if ($localDebug);
print STDERR "LBRACKET DEBUG TRACE: SODNAME: ".$parserState->{sodname}." SODTYPE: ".$parserState->{sodtype}." SIMPLETDCONTENTS: ".$parserState->{simpleTDcontents}."\n" if ($localDebug);
if (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inString})) {
$parserState->{onlyComments} = 0;
print STDERR "[f]onlyComments -> 0\n" if ($macroDebug);
}
push(@parsedParamParseStack, $parserState->{parsedParamParse});
push(@braceStack, $part); pbs(@braceStack);
print STDERR "PUSHED $part ONTO BRACESTACK [3]\n" if ($macroDebug || $braceDebug);
if ($HeaderDoc::includeFunctionContents || !$parserState->{seenBraces}) { # TREEDONE
$treeNest = 1;
if ($treeDebug) { print STDERR "TS TREENEST -> 1 [11]\n"; }
# push(@treeStack, $treeCur);
# $treeCur = $treeCur->addChild($part, 0); $treeSkip = 1;
# bless($treeCur, "HeaderDoc::ParseTree");
}
$curline = spacefix($curline, $part, $lastchar);
$parserState->{lastsymbol} = "";
$parserState->{inBrackets} += 1;
} else {
print STDERR "FALLING THROUGH (QUOTED)\n" if ($localDebug);
$fall_through = 1;
}
}
if (!$fall_through) {
$lastchar = $part;
if ($parserState->{startOfDec} == 2) {
if (!$parserState->{inTemplate}) {
if (!$parserState->{sodbrackets}) {
$parserState->{sodbrackets} = $part;
} else {
$parserState->{sodbrackets} .= $part;
}
print STDERR "sodbrackets set to ".$parserState->{sodbrackets}."\n" if ($sodDebug);
} else {
print STDERR "Not adjusting startOfDec or sodname because in template.\n" if ($localDebug || $sodDebug);
}
}
last SWITCH;
}
};
($part eq "]") && do {
print STDERR "CLOSE BRACKET: CASE 23\n" if ($liteDebug);
# right square bracket (square brace)
if ($inRegexp && ($inRegexpCharClass == 5)) {
# Got :] after a [: in s character class.
print STDERR "Leaving nested character class.\n" if ($localDebug || $parseDebug || $regexpDebug);
$inRegexpCharClass = 1;
$lasttoken = $part;
$parserState->{lastsymbol} = $part;
} elsif ($inRegexp && ($inRegexpCharClass == 2)) {
print STDERR "First in character class. Treating as literal.\n" if ($localDebug || $parseDebug || $regexpDebug);
# A close bracket as first character in a
# character class is treated as a literal.
# jump to next match.
$lasttoken = $part;
$parserState->{lastsymbol} = $part;
} elsif ($inRegexp && ($parserState->isQuoted($lang, $sublang))) {
# At least in Perl, \] is treated as a literal...
# even in a character class....
my $place = "regular expression";
if ($inRegexpCharClass) { $place = "character class"; }
print STDERR "Quoted ] in $place. Treating as literal.\n" if ($localDebug || $parseDebug || $regexpDebug);
$lasttoken = $part;
$parserState->{lastsymbol} = $part;
} else {
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) {
print STDERR "rbracket\n" if ($localDebug || $regexpDebug);
if (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inString})) {
$parserState->{onlyComments} = 0;
print STDERR "[g]onlyComments -> 0\n" if ($macroDebug);
}
my $top = pop(@braceStack);
$parserState->{parsedParamParse} = pop(@parsedParamParseStack);
print STDERR "POPPED $top FROM BRACESTACK [3]\n" if ($macroDebug || $braceDebug);
if ($HeaderDoc::includeFunctionContents || !$parserState->{seenBraces}) { # TREEDONE
my $tempCur = $treeCur->addSibling($part, 0); $treeSkip = 1;
if ($HeaderDoc::includeFunctionContents && $reMark) {
$tempCur->{RE_STATE} = $reMark;
}
$treeCur = pop(@treeStack) || $treeTop;
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
$treeCur = $treeCur->lastSibling();
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
print STDERR "TSPOP [4]: now $treeCur\n" if ($tsDebug || $treeDebug);
bless($treeCur, "HeaderDoc::ParseTree");
}
if ($top ne "[") {
warn("$fullpath:$inputCounter: warning: Square brackets do not match.\nWe may have a problem.\n");
warn("Declaration to date: $declaration$curline\n");
}
pbs(@braceStack);
$curline = spacefix($curline, $part, $lastchar);
$parserState->{lastsymbol} = "";
$parserState->{inBrackets} -= 1;
}
print "RECC: $inRegexpCharClass\n" if ($regexpDebug);
if ($inRegexpCharClass) {
if ($inRegexpCharClass != 4) {
print STDERR "Leaving character class.\n" if ($localDebug || $parseDebug || $regexpDebug);
$inRegexpCharClass = 0;
$reMark = "RE_CCEND";
if ($reMarkDebug) { print STDERR "REMARK: $reMark\n"; }
}
}
$lastchar = $part;
if ($parserState->{startOfDec} == 2) {
if (!$parserState->{inTemplate}) {
if (!$parserState->{sodbrackets}) {
$parserState->{sodbrackets} = $part;
} else {
$parserState->{sodbrackets} .= $part;
}
print STDERR "sodbrackets set to ".$parserState->{sodbrackets}."\n" if ($sodDebug);
} else {
print STDERR "Not adjusting startOfDec or sodname because in template.\n" if ($localDebug || $sodDebug);
}
}
last SWITCH;
}
};
($part eq "'" && $lang ne "applescript") && do {
print STDERR "SINGLE QUOTE: CASE 24\n" if ($liteDebug);
print STDERR "squo\n" if ($localDebug);
if (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inString} || $inRegexp)) {
# if (($lasttoken !~ /\\$/o) && ($curstring !~ /\\$/o))
if (!$parserState->isQuoted($lang, $sublang)) {
$parserState->{onlyComments} = 0;
print STDERR "[h]onlyComments -> 0\n" if ($macroDebug);
if (!$parserState->{inChar}) {
if ($HeaderDoc::includeFunctionContents || !$parserState->{seenBraces}) { # TREEDONE
$treeNest = 1;
if ($treeDebug) { print STDERR "TS TREENEST -> 1 [12]\n"; }
# push(@treeStack, $treeCur);
# $treeCur = $treeCur->addChild($part, 0); $treeSkip = 1;
# bless($treeCur, "HeaderDoc::ParseTree");
}
} else {
if ($HeaderDoc::includeFunctionContents || !$parserState->{seenBraces}) { # TREEDONE
my $tempCur = $treeCur->addSibling($part, 0); $treeSkip = 1;
if ($HeaderDoc::includeFunctionContents && $reMark) {
$tempCur->{RE_STATE} = $reMark;
}
$treeCur = pop(@treeStack) || $treeTop;
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
$treeCur = $treeCur->lastSibling();
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
print STDERR "TSPOP [5]: now $treeCur\n" if ($tsDebug || $treeDebug);
bless($treeCur, "HeaderDoc::ParseTree");
}
}
$parserState->{inChar} = !$parserState->{inChar};
}
if ($lastchar =~ /\=$/o) {
$curline .= " ";
}
}
$parserState->{lastsymbol} = "";
$lastchar = $part;
last SWITCH;
};
# Inline comment (two slashes in c++, hash in perl/shell)
# handler.
(($part eq $parseTokens{ilc} || $part eq $parseTokens{ilc_b}) && ($lang ne "perl" || $lasttoken ne "\$")) && do {
print STDERR "SINGLE LINE COMMENT: CASE 25\n" if ($liteDebug);
print STDERR "ILC\n" if ($localDebug || $ilcDebug);
if (!($parserState->{inComment} || $parserState->{inChar} || $parserState->{inString} || $inRegexp ||
$parserState->{inInlineComment})) {
$parserState->{inInlineComment} = 4;
print STDERR "inInlineComment -> 1\n" if ($ilcDebug);
$curline = spacefix($curline, $part, $lastchar, $parseTokens{soc}, $parseTokens{eoc}, $parseTokens{ilc}, $parseTokens{ilc_b});
if ($HeaderDoc::includeFunctionContents || !$parserState->{seenBraces}) { # TREEDONE
$treeNest = 1;
if ($treeDebug) { print STDERR "TS TREENEST -> 1 [13]\n"; }
if (!$treePopOnNewLine) {
$treePopOnNewLine = 1;
} else {
$treePopOnNewLine = 0 - $treePopOnNewLine;
}
print STDERR "treePopOnNewLine -> $treePopOnNewLine\n" if ($ilcDebug);
# $treeCur->addSibling($part, 0); $treeSkip = 1;
# $treePopOnNewLine = 1;
# $treeCur = pop(@treeStack) || $treeTop;
# bless($treeCur, "HeaderDoc::ParseTree");
}
} elsif ($parserState->{inComment}) {
my $linenum = $inputCounter + $fileoffset;
if (!$cpp_in_argparse) {
# We've already seen these.
if ($nestedcommentwarn) {
warn("$fullpath:$linenum: warning: Nested comment found [1]. Ignoring.\n");
}
# This isn't really a problem.
# Don't warn to avoid bogus
# warnings for apple_ref and
# URL markup in comments.
}
# warn("XX $cpp_in_argparse XX $inputCounter XX $fileoffset XX\n");
}
$parserState->{lastsymbol} = "";
$lastchar = $part;
last SWITCH;
};
# Standard comment handlers: soc = start of comment,
# eoc = end of comment.
($part eq $parseTokens{soc}) && do {
print STDERR "START OF MULTILINE COMMENT: CASE 26\n" if ($liteDebug);
print STDERR "SOC\n" if ($localDebug);
if (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar} || $parserState->{inString})) {
$parserState->{inComment} = 4;
$curline = spacefix($curline, $part, $lastchar);
if ($HeaderDoc::includeFunctionContents || !$parserState->{seenBraces}) {
$treeNest = 1;
if ($treeDebug) { print STDERR "TS TREENEST -> 1 [14]\n"; }
# print STDERR "TSPUSH\n" if ($tsDebug || $treeDebug);
# push(@treeStack, $treeCur);
# $treeCur = $treeCur->addChild("", 0);
# bless($treeCur, "HeaderDoc::ParseTree");
}
} elsif ($parserState->{inComment}) {
my $linenum = $inputCounter + $fileoffset;
# Modern compilers shouldn't have trouble with this. It occurs |
# frequently in apple_ref markup (e.g. //apple_ref/C/instm/ \|/
# IOFireWireDeviceInterface/AddIsochCallbackDispatcherToRunLoop/*Add
# IsochCallbackDispatcherToRunLoopIOFireWireLibDeviceRefCFRunLoopRef)
if ($nestedcommentwarn) {
warn("$fullpath:$linenum: warning: Nested comment found [2]. Ignoring.\n");
}
}
$parserState->{lastsymbol} = "";
$lastchar = $part;
last SWITCH;
};
($part eq $parseTokens{eoc}) && do {
print STDERR "END OF MULTILINE COMMENT: CASE 27\n" if ($liteDebug);
print STDERR "EOC\n" if ($localDebug);
if ($parserState->{inComment} && !($parserState->{inInlineComment} || $parserState->{inChar} || $parserState->{inString})) {
$parserState->{inComment} = 0;
$parserState->{leavingComment} = 1;
$curline = spacefix($curline, $part, $lastchar);
$ppSkipOneToken = 1;
if ($HeaderDoc::includeFunctionContents || !$parserState->{seenBraces}) {
my $tempCur = $treeCur->addSibling($part, 0); $treeSkip = 1;
if ($HeaderDoc::includeFunctionContents && $reMark) {
$tempCur->{RE_STATE} = $reMark;
}
$treeCur = pop(@treeStack) || $treeTop;
if (!$parserState->{seenBraces}) {
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
}
$treeCur = $treeCur->lastSibling();
if (!$parserState->{seenBraces}) {
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
}
print STDERR "TSPOP [6]: now $treeCur\n" if ($tsDebug || $treeDebug);
bless($treeCur, "HeaderDoc::ParseTree");
}
} elsif (!$parserState->{inComment} && !$parserState->{inInlineComment} && !$parserState->{inString} && !$parserState->{inChar} && !$inRegexp) {
my $linenum = $inputCounter + $fileoffset;
warn("$fullpath:$linenum: warning: Unmatched close comment tag found. Ignoring.\n");
} elsif ($parserState->{inInlineComment}) {
my $linenum = $inputCounter + $fileoffset;
# We'll leave this one on for now.
if ((1 || $nestedcommentwarn) && (!$HeaderDoc::running_test)) {
warn("$fullpath:$linenum: warning: Nested comment found [3]. Ignoring.\n");
}
}
$parserState->{lastsymbol} = "";
$lastchar = $part;
last SWITCH;
};
# Parenthesis and brace handlers.
((($part eq "(" && (!$parserState->{inCase})) || (($parserState->{pendingBracedParameters} == 1) && casecmp($part, $parseTokens{lbrace}, $case_sensitive)))) && do {
print STDERR "OPEN PAREN: CASE 28\n" if ($liteDebug);
# if ($liteDebug) { $localDebug = 1; $parseDebug = 1; }
my @tempppl = undef;
# print STDERR "(!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && ($regexpNoInterpolate || ($inRegexpFirstPart != 1))))\n";
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && ($regexpNoInterpolate || ($inRegexpFirstPart != 1)))) {
# print STDERR "OPAREN 1\n" if ($parseDebug || 1);
if ((!$parserState->isQuoted($lang, $sublang)) && (!$inRegexpCharClass)) {
# print STDERR "OPAREN 2\n" if ($parseDebug || 1);
my $oldParsedParamParse = $parserState->{parsedParamParse};
if ((!(scalar(@braceStack)-$parserState->{initbsCount})) && (!$parserState->{valuepending})) {
# print STDERR "OPAREN 3\n" if ($parseDebug || 1);
if ($parserState->{pendingBracedParameters}) {
$parserState->{startOfDec} = 0;
# Only the first set of braces.
print STDERR "SET pendingBracedParameters -> 2\n" if ($parseDebug);
$parserState->{pendingBracedParameters} = 2;
}
# start parameter parsing after this token
# print STDERR "SUBLANG: \"$sublang\"\n";
# print STDERR "SODCLASS: \"".$parserState->{sodclass}."\"\n";
if ($parserState->{occmethod} && !$parserState->{occmethodreturntype}) {
$parserState->{gatheringObjCReturnType}++;
} elsif ($pascal && $parserState->{sodclass} eq "function") {
# Pascal fuction parameters are semicolon-delimited.
$parserState->{parsedParamParse} = 2;
} elsif ($sublang eq "tcl") {
# MIG fuction parameters are space-delimited
$parserState->{parsedParamParse} = 6;
} elsif ($sublang eq "MIG") {
# MIG fuction parameters are semicolon-delimited.
$parserState->{parsedParamParse} = 2;
} else {
$parserState->{parsedParamParse} = 4;
}
print STDERR "parsedParamParse -> $parserState->{parsedParamParse}"."[lparen]\n" if ($parmDebug);
print STDERR "parsedParamList wiped\n" if ($parmDebug);
@tempppl = @{$parserState->{parsedParamList}};
@{$parserState->{parsedParamList}} = ();
$parsedParam = "";
}
$parserState->{onlyComments} = 0;
print STDERR "[i]onlyComments -> 0\n" if ($macroDebug);
if ($parserState->{simpleTypedef} && !(scalar(@braceStack)- $parserState->{initbsCount})) {
$parserState->{simpleTypedef} = 0;
$parserState->{simpleTDcontents} = "";
print STDERR "Setting typedef sodname to ".$parserState->{lastsymbol}."\n" if ($localDebug || $sodDebug);
$parserState->{sodname} = $parserState->{lastsymbol};
$parserState->{sodclass} = "function";
print STDERR "sodclass -> function (implicit)[4]\n" if ($sodDebug);
# DAG: changed to respect freezereturn
# and hollow, but in the unlikely event
# that we should start seeing any weird
# "missing return type info" bugs,
# this next line might need to be
# put back in rather than the lines
# that follow it.
# $parserState->{returntype} = "$declaration$curline";
if (!$parserState->{freezereturn} && $parserState->{hollow} && !$parserState->{inComment} && !$parserState->{leavingComment}) {
$parserState->{returntype} = "$declaration$curline";
print STDERR "APPENDING TO RETURNTYPE: NOW \"$parserState->{returntype}\".\n" if ($retDebug);
} elsif (!$parserState->{freezereturn} && !$parserState->{hollow} && !$parserState->{inComment} && !$parserState->{leavingComment}) {
$parserState->{returntype} = "$curline";
print STDERR "REPLACING RETURNTYPE: NOW \"$parserState->{returntype}\".\n" if ($retDebug);
$declaration = "";
}
}
$parserState->{posstypesPending} = 0;
if ($parserState->{callbackNamePending} == 2) {
$parserState->{callbackNamePending} = 3;
print STDERR "callbackNamePending -> 3\n" if ($localDebug || $cbnDebug);
}
print STDERR "lparen\n" if ($localDebug);
print STDERR "WFTI: ".$parserState->{waitingForTypeInformation}."\n" if ($localDebug || $parseDebug);
if ($pascal && ($parserState->{waitingForTypeInformation} == 1) && ((scalar(@braceStack)-$parserState->{initbsCount}) == 0)) {
print STDERR "Setting sodclass to 'enum'." if ($sodDebug || $localDebug);
$parserState->{waitingForTypeInformation} = 3;
$parserState->{sodclass} = "enum";
print STDERR "sodclass -> enum (implicit)[5]\n" if ($sodDebug);
}
if ($parserState->{cbsodname} && (scalar(@braceStack)-$parserState->{initbsCount}) == 0) {
if (!$parserState->{functionReturnsCallback}) {
# At the top level, if we see a second open parenthesis after setting a callback
# name, the first token in the first set of open parentheses is the name of
# the callback, so clear cbsodname.
#
# Until this point, the value in cbsodname was a copy of the already-cleared
# sodname field, and would replace the callbackName field at the end of
# processing.
$parserState->{cbsodname} = "";
} else {
# If we are in a function that returns a callback, everything from here on
# is a list of parameters for the callback, not the function, so the
# previous parameter list should be discarded (though it is useful to
# add these parameters as valid things to comment about).
@{$parserState->{parsedParamList}} = @tempppl;
$parserState->{functionReturnsCallback}--;
print STDERR "parsedParamList restored\n" if ($parmDebug);
}
}
if ((scalar(@braceStack)-$parserState->{initbsCount}) == 1) {
if ($parserState->{callbackName}) {
$parserState->{cbsodname} = $parserState->{callbackName};
$parserState->{sodclass} = "function";
print STDERR "sodclass -> function (implicit)[6]\n" if ($sodDebug);
# $parserState->{callbackName} = "";
$parserState->{functionReturnsCallback}++;
print STDERR "Function returning callback. NAME: $parserState->{cbsodname}\n" if ($parmDebug || $localDebug || $parseDebug);
print STDERR "parsedParamParse -> 4[callback]\n" if ($parmDebug);
$parserState->{parsedParamParse} = 4;
print STDERR "parsedParamList wiped\n" if ($parmDebug);
@tempppl = @{$parserState->{parsedParamList}};
@{$parserState->{parsedParamList}} = ();
$parsedParam = "";
}
}
if ($parserState->{inOperator} == 1) {
$parserState->{inOperator} = 2;
}
push(@parsedParamParseStack, $oldParsedParamParse);
push(@braceStack, $part); pbs(@braceStack);
print STDERR "PUSHED $part ONTO BRACESTACK [4]\n" if ($macroDebug || $braceDebug);
if ($HeaderDoc::includeFunctionContents || !$parserState->{seenBraces}) { # TREEDONE
$treeNest = 1;
if ($treeDebug) { print STDERR "TS TREENEST -> 1 [15]\n"; }
# push(@treeStack, $treeCur);
# $treeCur = $treeCur->addChild($part, 0); $treeSkip = 1;
# bless($treeCur, "HeaderDoc::ParseTree");
}
$curline = spacefix($curline, $part, $lastchar);
print STDERR "LASTCHARCHECK: \"$lastchar\" \"$lastnspart\" \"$curline\".\n" if ($localDebug);
if ($lastnspart eq ")") { # || $curline =~ /\)\s*$/so
print STDERR "HERE: DEC IS $declaration\nENDDEC\nCURLINE IS $curline\nENDCURLINE\n" if ($localDebug);
# print STDERR "CALLBACKMAYBE: $parserState->{callbackNamePending} $parserState->{sodclass} ".scalar(@braceStack)."\n";
print STDERR "SBS: ".scalar(@braceStack)."\n" if ($localDebug);
### if (!$parserState->{callbackNamePending} && ($parserState->{sodclass} eq "function") && ((scalar(@braceStack)-$parserState->{initbsCount}) == 1)) { # && $argparse
### # Guess it must be a callback anyway.
### my $temp = pop(@tempppl);
### $parserState->{callbackName} = $temp;
### $parserState->{name} = "";
### $parserState->{sodclass} = "";
### $parserState->{sodname} = "";
### print STDERR "CALLBACKHERE ($temp)!\n" if ($cbnDebug || $parseDebug);
### }
if ($declaration =~ /.*\n(.*?)\n$/so) {
my $lastline = $1;
print STDERR "LL: $lastline\nLLDEC: $declaration" if ($localDebug);
$declaration =~ s/(.*)\n(.*?)\n$/$1\n/so;
$curline = "$lastline $curline";
$curline =~ s/^\s*//so;
$prespace -= 4;
$prespaceadjust += 4;
$forcenobreak = 1;
print STDERR "NEWDEC: $declaration\nNEWCURLINE: $curline\n" if ($localDebug);
} elsif (length($declaration) && $callback_typedef_and_name_on_one_line) {
print STDERR "SCARYCASE\n" if ($localDebug);
$declaration =~ s/\n$//so;
$curline = "$declaration $curline";
$declaration = "";
$prespace -= 4;
$prespaceadjust += 4;
$forcenobreak = 1;
}
} else { print STDERR "OPARENLC: \"$lastchar\"\nCURLINE IS: \"$curline\"\n" if ($localDebug);}
$parserState->{lastsymbol} = "";
$lastchar = $part;
if ($parserState->{startOfDec} == 2) {
if ($HeaderDoc::parsing_man_pages) {
# Some bad man pages leave out
# the trailing semicolon.
$parserState->{declarationEndsAtNewLine} = 1;
}
$parserState->{sodclass} = "function";
print STDERR "sodclass -> function (implicit)[7]\n" if ($sodDebug);
$parserState->{freezereturn} = 1;
$parserState->{returntype} =~ s/^\s*//so;
$parserState->{returntype} =~ s/\s*$//so;
}
$parserState->{startOfDec} = 0;
print STDERR "startOfDec -> 0 [3]\n" if ($localDebug);
if ($curline !~ /\S/o) {
# This is the first symbol on the line.
# adjust immediately
$prespace += 4;
print STDERR "PS: $prespace immediate\n" if ($localDebug);
} else {
$prespaceadjust += 4;
print STDERR "PSA: $prespaceadjust\n" if ($localDebug);
}
# print STDERR "IRE: $inRegexp\n";
if ($inRegexp) {
print STDERR "PUSHING $part ONTO REGEXPSTACK [6]\n" if ($localDebug || $parseDebug || $regexpDebug);
push(@regexpStack, $part);
}
}
}
print STDERR "OUTGOING CURLINE: \"$curline\"\n" if ($localDebug);
last SWITCH;
};
((($part eq ")" && (!$parserState->{inCase})) || ($parserState->isRightBrace($part, $lang, \%parseTokens, $case_sensitive) && ($parserState->{pendingBracedParameters} == 2)))) && do {
print STDERR "CLOSE PAREN: CASE 29\n" if ($liteDebug);
# print STDERR "TOBS: \"".peek(\@braceStack)."\"\n";
print STDERR "TOP OF RE STACK IS: \"".peek(\@regexpStack)."\"\n" if ($localDebug || $parseDebug);
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && ($regexpNoInterpolate || ($inRegexpFirstPart != 1)) && (peek(\@regexpStack) ne "("))) {
print STDERR "PAST FIRST CHECK\n" if ($localDebug || $parseDebug);
if ((!$parserState->isQuoted($lang, $sublang)) && (!$inRegexpCharClass)) {
my $opentoken = "(";
if (((scalar(@braceStack)-$parserState->{initbsCount} - $parserState->{functionReturnsCallback}) == 1)) {
if ($parserState->{pendingBracedParameters}) {
$parserState->{pendingBracedParameters} = 0;
$opentoken = "{";
}
# stop parameter parsing
if ($parserState->{gatheringObjCReturnType}) {
$parserState->{gatheringObjCReturnType}--;
if ($parserState->{gatheringObjCReturnType} == 1) {
$parserState->{gatheringObjCReturnType} = 0;
}
}
if ($parserState->{parsedParamParse}) {
$parserState->{parsedParamParse} = 0;
print STDERR "parsedParamParse -> 0[rparen]\n" if ($parmDebug);
$parsedParam =~ s/^\s*//so; # trim leading space
$parsedParam =~ s/\s*$//so; # trim trailing space
if ($parsedParam ne "void") {
# ignore foo(void)
push(@{$parserState->{parsedParamList}}, $parsedParam);
print STDERR "pushed $parsedParam into parsedParamList [1]\n" if ($parmDebug);
}
$parsedParam = "";
}
}
$parserState->{onlyComments} = 0;
print STDERR "[j]onlyComments -> 0\n" if ($macroDebug);
print STDERR "rparen\n" if ($localDebug);
my $test = "";
my $parenRegexp = 0;
# If the first node in the regexp stack is
# an open parenthesis, it isn't on the
# brace stack, so don't pop it off.
if ($inRegexp && ($regexpStack[0] eq "(")) {
$parenRegexp = 0;
}
if (!$parenRegexp) {
$test = pop(@braceStack); pbs(@braceStack);
$parserState->{parsedParamParse} = pop(@parsedParamParseStack);
print STDERR "POPPED $test FROM BRACESTACK [4]\n" if ($macroDebug || $braceDebug);
}
print STDERR "RPAREN SEENBRACES: ".$parserState->{seenBraces}."\n" if ($localDebug || $parserStateInsertDebug);
if ($HeaderDoc::includeFunctionContents || !$parserState->{seenBraces}) { # TREEDONE
my $tempCur = $treeCur->addSibling($part, 0); $treeSkip = 1;
if ($HeaderDoc::includeFunctionContents && $reMark) {
$tempCur->{RE_STATE} = $reMark;
}
$treeCur = pop(@treeStack) || $treeTop;
if (!$parserState->{seenBraces}) {
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
}
$treeCur = $treeCur->lastSibling();
if (!$parserState->{seenBraces}) {
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
}
print STDERR "TSPOP [6a]: now $treeCur\n" if ($tsDebug || $treeDebug);
bless($treeCur, "HeaderDoc::ParseTree");
}
if (!$parenRegexp) {
if (!($test eq $opentoken)) {
warn("$fullpath:$inputCounter: warning: Parentheses do not match.\nWe may have a problem.\n");
warn("Declaration to date: $declaration$curline\n");
# cluck("backtrace follows\n");
}
}
$curline = spacefix($curline, $part, $lastchar);
$parserState->{lastsymbol} = "";
$lastchar = $part;
$parserState->{startOfDec} = 0;
print STDERR "startOfDec -> 0 [4]\n" if ($localDebug);
if ($curline !~ /\S/o) {
# This is the first symbol on the line.
# adjust immediately
$prespace -= 4;
print STDERR "PS: $prespace immediate\n" if ($localDebug);
} else {
$prespaceadjust -= 4;
print STDERR "PSA: $prespaceadjust\n" if ($localDebug);
}
if ($inRegexp && (!$regexpNoInterpolate || ($inRegexpFirstPart == 1))) {
my $temp = pop(@regexpStack);
print STDERR "popped $temp FROM REGEXPSTACK\n" if ($localDebug || $parseDebug || $regexpDebug);
if ($temp ne "(") {
warn("Parentheses do not match in regular expression. We may have a problem.\n");
warn("Line is \"$line\"\n") if ($regexpDebug);
}
}
last SWITCH;
}
}
};
(($lang ne "perl" || !($parserState->{inTemplate} || $inRegexp || $leavingRegexp)) && $parserState->isLeftBrace($part, $lang, \%parseTokens, $case_sensitive, scalar(@braceStack))) && do {
my $brctoken = $part;
print STDERR "IRC ".$parserState->{inRubyClass}."\n" if ($rubyDebug || $parseDebug);
if ($parseTokens{classisbrace} && $parserState->{sodclass} eq "class" && (!$parserState->{inRubyClass}) && $part =~ /[\n\r]/) {
print STDERR "SET IRC -> 1\n" if ($rubyDebug || $parseDebug);;
$parserState->{inRubyClass} = 1;
$brctoken = "class";
} elsif ($parseTokens{functionisbrace} && $parserState->{pushedfuncbrace} == 1) {
$parserState->{pushedfuncbrace} = 2;
$brctoken = $parseTokens{sofunction};
}
my $oldParsedParamParse = $parserState->{parsedParamParse};
print STDERR "LEFT BRACE: CASE 30\n" if ($liteDebug);
if ($lang eq "applescript" && $pushParserStateAtBrace) {
$pushParserStateAtBrace = 0;
$pushParserStateAfterToken = 1;
}
if ($parserState->{onlyComments} && !$parserState->{inComment} && !$parserState->{inInlineComment} && !$parserState->{inChar} && !$inRegexp && !scalar(@parserStack) && !$parserState->{INIF} && !$tempInIf && ($lang ne "applescript")) {
print STDERR "BAILING NOW\n" if ($externCDebug);
$continue_no_return = 1;
print STDERR "CONTINUE -> 0 [NORETURN]\n" if ($parseDebug || $cppDebug || $macroDebug || $localDebug || $continueDebug);
$continue = 0;
}
if ($parserState->{inGiven}) {
if (length($parsedParam)) { push(@{$parserState->{parsedParamList}}, $parsedParam); }
print STDERR "PUSHING \"$parsedParam\" onto parsed parameters list ()\n" if ($parseDebug || $asDebug);
$parsedParam = "";
}
if ($parserState->{onlyComments} && !$parserState->{inComment} && !$parserState->{inInlineComment} && !$parserState->{inChar} && !$inRegexp && scalar(@parserStack) && $lang ne "applescript") {
# Somebody put in a brace in the middle of
# a class or else we're seeing ObjC private
# class bits. Either way, throw away the
# curly brace.
print STDERR "NOINSERT\n" if ($parserStackDebug);
$pushParserStateAtBrace = 1;
# $setNoInsert = 1;
$parserState->{noInsert} = 1;
}
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar} || $inRegexp)) {
$parserState->{bracePending} = 0;
print STDERR "bracePending -> 0 [brace]\n" if ($localDebug);
$parserState->{onlyComments} = 0;
print STDERR "[k]onlyComments -> 0\n" if ($macroDebug);
push(@{$parserState->{parsedParamStateAtBrace}}, $parserState->{parsedParamParse});
push(@{$parserState->{parsedParamAtBrace}}, $parsedParam);
$parsedParam = "";
if (scalar(@{$parserState->{parsedParamList}})) {
foreach my $node (@{$parserState->{parsedParamList}}) {
$node =~ s/^\s*//so;
$node =~ s/\s*$//so;
if (length($node)) {
push(@{$parserState->{pplStack}}, $node)
}
}
@{$parserState->{parsedParamList}} = ();
print STDERR "parsedParamList pushed [2]\n" if ($parmDebug);
}
# start parameter parsing after this token
if (!$pushParserStateAtBrace && !$parserState->{inClass}) {
if ($parserState->{inEnum}) {
$parserState->{parsedParamParse} = 4;
} else {
$parserState->{parsedParamParse} = 2;
}
print STDERR "parsedParamParse -> $parserState->{parsedParamParse}"."[lbrace]\n" if ($parmDebug);
}
# print STDERR "statecheck: ".$parserState->{inClass}."X".$parserState->{sodclass}."X".$parserState->{inOperator}."X".$parserState->{occmethod}."\n"; # @@@ CHECKME - Do this for Obj-C methods too?
if (!$parserState->{inClass} && ($parserState->{sodclass} eq "function" || $parserState->{inOperator} || $parserState->{occmethod})) {
# This is the opening brace of a function. Start ignoring everything
# until the matching brace is encountered.
print STDERR "seenBraces -> 1 [2]\n" if ($parseDebug || $braceDebug);
$parserState->{seenBraces} = 1;
if (!$parserState->{stackFrozen}) {
@{$parserState->{freezeStack}} = @{$parserState->{pplStack}};
$parserState->{frozensodname} = $parserState->{sodname};
$parserState->{stackFrozen} = 1;
}
@{$parserState->{pplStack}} = ();
}
$parserState->{posstypesPending} = 0;
$parserState->{namePending} = 0;
$parserState->{callbackNamePending} = -1;
$parserState->{simpleTypedef} = 0;
$parserState->{simpleTDcontents} = "";
print STDERR "callbackNamePending -> -1\n" if ($localDebug || $cbnDebug);
print STDERR "lbrace\n" if ($localDebug);
push(@parsedParamParseStack, $oldParsedParamParse);
push(@braceStack, $brctoken); pbs(@braceStack);
print STDERR "PUSHED $brctoken ONTO BRACESTACK [5]\n" if ($macroDebug || $braceDebug);
if ($HeaderDoc::includeFunctionContents || !$parserState->{seenBraces}) { # TREEDONE
$treeNest = 1;
if ($treeDebug) { print STDERR "TS TREENEST -> 1 [16]\n"; }
print STDERR "TN -> 1\n" if ($localDebug);
# push(@treeStack, $treeCur);
# $treeCur = $treeCur->addChild($part, 0); $treeSkip = 1;
# bless($treeCur, "HeaderDoc::ParseTree");
}
$curline = spacefix($curline, $part, $lastchar);
$parserState->{lastsymbol} = "";
$lastchar = $part;
if ($parserState->{INMODULE} == 2) {
# Drop token on the floor.
$treepart = " ";
}
$parserState->{startOfDec} = 0;
print STDERR "startOfDec -> 0 [5]\n" if ($localDebug);
if ($curline !~ /\S/o) {
# This is the first symbol on the line.
# adjust immediately
$prespace += 4;
print STDERR "PS: $prespace immediate\n" if ($localDebug);
} else {
$prespaceadjust += 4;
print STDERR "PSA: $prespaceadjust\n" if ($localDebug);
}
}
last SWITCH;
};
(($parserState->isRightBrace($part, $lang, \%parseTokens, $case_sensitive) || $parserState->{inrbraceargument}) && ($parserState->{pendingBracedParameters} != 2) && ($lang ne "perl" || !($parserState->{inTemplate} || $inRegexp || $leavingRegexp))) && do {
# {Treat } within <> as ordinary character in Perl.
print STDERR "RIGHT BRACE: CASE 31\n" if ($liteDebug);
print STDERR "INBRACEARGUMENT: ".$parserState->{inrbraceargument}."\n" if ($parserStateInsertDebug);
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar} || $inRegexp)) {
my $oldOC = $parserState->{onlyComments};
print STDERR "rbrace???\n" if ($localDebug);
# $parserState->{onlyComments} = 0; # If this is all we've seen, there's either a bug or we're
# unrolling a class or similar anyway.
print STDERR "[l]onlyComments -> 0\n" if ($macroDebug);
if ($ruby) { $parserState->{followingrubyrbrace} = 1; }
if (($parseTokens{rbracetakesargument}) && (!$parserState->{inrbraceargument})) {
$parserState->{inrbraceargument} = 1;
# $treePopOnNewLine = 1;
# $parserState->{newlineIsSemi} = 1;
} elsif ($parserState->{inrbraceargument} && $part =~ /\w/) {
$parserState->{inrbraceargument}--;
if ($parserState->{seenBraces}) { $trailingHide = 1; }
}
if ($parserState->{inrbraceargument}) {
print STDERR "Waiting for rbrace argument\n" if ($asDebug || $parserStackDebug || $parseDebug || $braceDebug);
} else {
print STDERR "INRBRACEARGUMENT: ".$parserState->{inrbraceargument}."\n" if ($asDebug || $parserStackDebug || $parseDebug || $braceDebug);
my $bsCount = scalar(@braceStack);
print STDERR "SPS: ".scalar(@parserStack)." BSC: ".$bsCount." IBSC: ".$parserState->{initbsCount}."\n" if ($rubyDebug || $parseDebug);
if (scalar(@parserStack) && !($bsCount - $parserState->{initbsCount})) {
print STDERR "parserState: ENDOFSTATE\n" if ($parserStackDebug);
if ($parserState->{inrbraceargument}) {
print STDERR "parserState insertion skipped[RBRACE, INARG]\n" if ($parserStackDebug || $parserStateInsertDebug);
# $parserState->{newlineIsSemi} = 1; # @@@ THIS ISN'T RIGHT.
} elsif ($parserState->{noInsert} || $oldOC) {
print STDERR "parserState insertion skipped[RBRACE]\n" if ($parserStackDebug || $parserStateInsertDebug);
} elsif ($parserState->{hollow}) {
print STDERR "inserted parser state into tree [RBRACE]\n" if ($parserStateInsertDebug);
my $treeRef = $parserState->{hollow};
print STDERR "Last tree node set to $treeCur [5]\n" if ($parserStateInsertDebug);
$parserState->{lastTreeNode} = $treeCur;
$treeRef->addRawParsedParams(\@{$parserState->{parsedParamList}});
$treeRef->parserState($parserState);
} else {
warn "Couldn't insert info into parse tree[1].\n";
}
print STDERR "parserState popped from parserStack[rbrace]\n" if ($parserStackDebug);
# print STDERR "PREINMODULE: ".$parserState->{INMODULE}."\n";
$parserState = pop(@parserStack) || $parserState;
$declaration = $parserState->{storeDec}.$declaration;
# $HeaderDoc::module = $parserState->{MODULE};
# print STDERR "INMODULE: ".$parserState->{INMODULE}."\n";
if ($parserState->{INMODULE} == 2) {
# Drop token on the floor.
print STDERR "CURRENT: ".$treeCur->{TOKEN}."\n" if ($localDebug);
$part = "";
print STDERR "INMODULE -> 3\n" if ($localDebug || $moduleDebug);
$parserState->{INMODULE} = 3;
print STDERR "CONTINUE -> 0 [1aMODULE]\n" if ($parseDebug || $cppDebug || $macroDebug || $localDebug || $continueDebug);
$parserState->{noInsert} = 0;
$continue = 0;
# print STDERR "AT END: REALPS IS ".$parserState->{REALPS}."\n" if ($parserStackDebug || $localDebug);
print STDERR "AT END. STACK COUNT: ".scalar(@parserStack)."\n" if ($parserStackDebug || $localDebug);
}
# print STDERR "HERE\n";
if ($lang eq "php" || ($lang eq "C" && $sublang eq "IDL") || ($lang eq "java" && $sublang eq "java") || $ruby || ($lang eq "tcl") || ($lang eq "applescript")) {
# print STDERR "PHP OUT OF BRACES?: ".scalar(@braceStack)."\n";
if (scalar(@braceStack) == 1) {
# PHP, IDL, Ruby, TCL, and Java classes end at
# the brace.
print STDERR "CONTINUE -> 0 [1aOutOfBraces]\n" if ($parseDebug || $cppDebug || $macroDebug || $localDebug || $continueDebug);
$continue = 0;
} elsif ($lang eq "applescript" && (scalar(@braceStack)-$parserState->{initbsCount}) == 1) {
# AppleScript allows nested classes and does not have a semicolon to
# indicate the point at which we should stop parsing a class.
print STDERR "Terminating nested class at newline.\n" if ($localDebug || $parseDebug || $asDebug); # @@@
$parserState->{declarationEndsAtNewLine} = 1;
}
}
if ($parserState->{noInsert} && scalar(@parserStack)) {
# This is to handle the end of
# the private vars in an
# Objective C class.
print STDERR "parserState: Hit me.\n" if ($localDebug);
$parserState = HeaderDoc::ParserState->new( "FULLPATH" => $fullpath, "lang" => $lang, "sublang" => $sublang );
$parserState->{skiptoken} = 1;
$parserState->{inputCounter} = $inputCounter;
# It's about to go down by 1.
$parserState->{initbsCount} = scalar(@braceStack) - 1;
}
# $parserState->{onlyComments} = 1;
} else {
print STDERR "NO CHANGE IN PARSER STATE STACK (nPARSERSTACK = ".scalar(@parserStack).", $bsCount != $parserState->{initbsCount})\n" if ($parseDebug || $parserStackDebug);
}
print STDERR "Ruby stopcheck: ".scalar(@braceStack)." - ".$parserState->{initbsCount}."\n" if ($rubyDebug || $parseDebug);
if ((scalar(@braceStack)-$parserState->{initbsCount}) == 1) {
# stop parameter parsing
if ($ruby) {
print STDERR "Ruby stopearly: ".scalar(@braceStack)." - ".$parserState->{initbsCount}."\n" if ($rubyDebug || $parseDebug);;
$parserState->{newlineIsSemi} = 1;
}
$parserState->{parsedParamParse} = 0;
print STDERR "parsedParamParse -> 0[rbrace]\n" if ($parmDebug);
$parsedParam =~ s/^\s*//so; # trim leading space
$parsedParam =~ s/\s*$//so; # trim trailing space
if (length($parsedParam)) {
# ignore foo(void)
push(@{$parserState->{parsedParamList}}, $parsedParam);
print STDERR "pushed $parsedParam into parsedParamList [1b]\n" if ($parmDebug);
}
$parsedParam = "";
# if ($ruby && ($parserState->{sodclass} eq "class")) {
# print STDERR "CONTINUE -> 0 [1a_ruby]\n" if ($parseDebug || $cppDebug || $macroDebug || $localDebug || $continueDebug);
# $continue = 0;
# } else {
# print STDERR "checkpoint SC: ".$parserState->{sodclass}."\n";
# }
} else {
# start parameter parsing after this token
# grabbing end names for typedefs.
$parserState->{parsedParamParse} = pop(@{$parserState->{parsedParamStateAtBrace}}); # 4;
$parsedParam = pop(@{$parserState->{parsedParamAtBrace}});
print STDERR "parsedParamParse -> $parserState->{parsedParamParse}"."[rbrace2]\n" if ($parmDebug);
}
if (scalar(@{$parserState->{parsedParamList}})) {
foreach my $node (@{$parserState->{parsedParamList}}) {
$node =~ s/^\s*//so;
$node =~ s/\s*$//so;
if (length($node)) {
push(@{$parserState->{pplStack}}, $node)
}
}
@{$parserState->{parsedParamList}} = ();
print STDERR "parsedParamList pushed [3]\n" if ($parmDebug);
}
print STDERR "rbrace\n" if ($localDebug);
my $test = pop(@braceStack); pbs(@braceStack);
my $temp = pop(@parsedParamParseStack);
if ($temp) {
if ($temp == 1) { $temp = 2; }
elsif ($temp == 3) { $temp = 4; }
if ($temp != $parserState->{parsedParamParse} && $parmDebug) {
warn("Changing PPP from ".$parserState->{parsedParamParse}." to $temp\n");
}
$parserState->{parsedParamParse} = $temp;
}
print STDERR "POPPED $test FROM BRACESTACK [5]\n" if ($macroDebug || $braceDebug);
if (($HeaderDoc::includeFunctionContents || !($parserState->{seenBraces} || $trailingHide)) && (!$parserState->{inrbraceargument})) { # TREEDONE
warn("TSPOP FOR NOT SEEN BRACES\n") if ($parserStateInsertDebug || $treeDebug);
my $tempCur = $treeCur->addSibling($part, 0); $treeSkip = 1;
if ($HeaderDoc::includeFunctionContents && $reMark) {
$tempCur->{RE_STATE} = $reMark;
}
$treeCur = pop(@treeStack) || $treeTop;
if (!($parserState->{seenBraces} || $trailingHide)) {
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
}
$treeCur = $treeCur->lastSibling();
if (!($parserState->{seenBraces} || $trailingHide)) {
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
}
print STDERR "TSPOP [7]: now $treeCur\n" if ($tsDebug || $treeDebug);
bless($treeCur, "HeaderDoc::ParseTree");
}
if (!($test eq "$parseTokens{lbrace}") && (!length($parseTokens{structname}) || (!($test eq $parseTokens{structname}) && $parseTokens{structisbrace}))) {
warn("$fullpath:$inputCounter: warning: Braces do not match (top of brace stack\nis \"$test\").We may have a problem.\n");
warn("Declaration to date: $declaration$curline\n");
}
$curline = spacefix($curline, $part, $lastchar);
$parserState->{lastsymbol} = "";
$lastchar = $part;
$parserState->{startOfDec} = 0;
print STDERR "startOfDec -> 0 [6]\n" if ($localDebug);
if ($curline !~ /\S/o) {
# This is the first symbol on the line.
# adjust immediately
$prespace -= 4;
print STDERR "PS: $prespace immediate\n" if ($localDebug);
} else {
$prespaceadjust -= 4;
print STDERR "PSA: $prespaceadjust\n" if ($localDebug);
}
}
}
last SWITCH;
};
# Typedef, struct, enum, and union handlers.
# Merge the '@' symbol onto @protocol, @property, @public, and similar.
(length($part) && length($nextpart) && ((length($parseTokens{propname}) && $parseTokens{propname} =~ /\@/) || length($parseTokens{objcdynamicname}) || length($parseTokens{objcsynthesizename}) || length($classregexp) || (length($accessregexp) && $accessregexp =~ /\@/)) && $part =~ /^\@$/ && !$parserState->{inComment} && !$parserState->{inChar} && !$parserState->{inString} && !$parserState->{inInlineComment}) && do {
print STDERR "PROPERTY PREPEND AT (\@): CASE 32\n" if ($liteDebug);
my $temp = "\@".$nextpart;
# print STDERR "TEMP IS $temp PROPNAME is $parseTokens{propname}\n";
if ($temp =~ /$accessregexp/) {
print STDERR "MERGE $part $nextpart\n" if ($localDebug);
$nextpart = "\@".$nextpart;
$parserState->{classIsObjC} = 1;
} elsif ($temp =~ /$classregexp/) {
$nextpart = "\@".$nextpart;
$parserState->{classIsObjC} = 1;
} elsif ($temp =~ /$classclosebraceregexp/) {
$nextpart = "\@".$nextpart;
} elsif ($temp eq $parseTokens{propname}) {
# This shows up in a declaration, so delete the token
$part = "";
print STDERR "MERGE $part $nextpart\n" if ($localDebug);
$nextpart = "\@".$nextpart;
} elsif (length($requiredregexp) && $temp =~ /$requiredregexp/) {
# This shows up in a declaration, so delete the token
$part = "";
print STDERR "MERGE $part $nextpart\n" if ($localDebug);
$nextpart = "\@".$nextpart;
} elsif ($temp eq $parseTokens{objcdynamicname}) {
# This shows up in a declaration, so delete the token
$part = "";
print STDERR "MERGE $part $nextpart\n" if ($localDebug);
$nextpart = "\@".$nextpart;
} elsif ($temp eq $parseTokens{objcsynthesizename}) {
# This shows up in a declaration, so delete the token
$part = "";
print STDERR "MERGE $part $nextpart\n" if ($localDebug);
$nextpart = "\@".$nextpart;
}
next SWITCH;
};
($modules_are_special && !$parserState->{inTemplate} && !$parserState->{inComment} && !$parserState->{inInlineComment} && !$parserState->{inString} && !$parserState->{inChar} && length($moduleregexp) && $part =~ /$moduleregexp/) && do {
print STDERR "INMODULE -> 1\n" if ($localDebug || $moduleDebug);
$parserState->{INMODULE} = 1;
print STDERR "MODULE START TOKEN: CASE 32-M-1\n" if ($localDebug || $liteDebug);
};
(length($classclosebraceregexp) && ($part =~ /$classclosebraceregexp/) && !$parserState->{inComment} && !$parserState->{inChar} && !$parserState->{inString} && !$parserState->{inInlineComment}) && do {
print STDERR "CLASS CLOSE BRACE: CASE 33\n" if ($liteDebug);
if ($part ne peekmatch(\@braceStack, $lang, $fullpath, $inputCounter)) {
warn("$fullpath:inputCounter: warning: Class braces do not match.\nWe may have a problem.\n");
}
print STDERR "seenBraces -> 1 [3]\n" if ($parseDebug || $braceDebug);
$parserState->{seenBraces} = 1;
my $temp = pop(@braceStack);
$parserState->{parsedParamParse} = pop(@parsedParamParseStack);
print STDERR "POPPED $temp FROM BRACESTACK [6]\n" if ($macroDebug || $braceDebug);
my $tempCur = $treeCur->addSibling($part, 0); $treeSkip = 1;
if ($HeaderDoc::includeFunctionContents && $reMark) {
$tempCur->{RE_STATE} = $reMark;
}
$treeCur = pop(@treeStack) || $treeTop;
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
$treeCur = $treeCur->lastSibling();
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
print STDERR "TSPOP [6]: now $treeCur\n" if ($tsDebug || $treeDebug);
bless($treeCur, "HeaderDoc::ParseTree");
$part =~ s/^\@//s;
if ( 1 || $nextpart ne ";") {
# Objective C protocol/interface declarations end at the close curly brace.
# No ';' necessary (though we'll eat it if it's there.
# No, we won't. Deal with it.
if (scalar(@parserStack) == 1) {
# Throw away current parser state, since
# it will always be empty anyway.
$parserState = pop(@parserStack) || $parserState;
$declaration = $parserState->{storeDec}.$declaration;
# $HeaderDoc::module = $parserState->{MODULE};
$continue = 0;
print STDERR "CONTINUE -> 0 [occend]\n" if ($parseDebug || $cppDebug || $macroDebug || $localDebug || $continueDebug);
} else {
if (!$parserState->{onlyComments}) {
# Process entry here
if ($parserState->{noInsert}) {
print STDERR "parserState insertion skipped[\@end]\n" if ($parserStackDebug);
} elsif ($parserState->{hollow}) {
print STDERR "inserted parser state into tree [\@end]\n" if ($parserStateInsertDebug);
my $treeRef = $parserState->{hollow};
print STDERR "Last tree node set to $treeCur [6]\n" if ($parserStateInsertDebug);
$parserState->{lastTreeNode} = $treeCur;
$treeRef->addRawParsedParams(\@{$parserState->{parsedParamList}});
$treeRef->parserState($parserState);
} else {
warn "Couldn't insert info into parse tree[2].\n";
}
print STDERR "parserState: Created parser state[1].\n" if ($parserStackDebug);
print STDERR "CURLINE CLEAR[PRS2]\n" if ($localDebug);
$curline = "";
$parserState = HeaderDoc::ParserState->new( "FULLPATH" => $fullpath, "lang" => $lang, "sublang" => $sublang );
$parserState->{skiptoken} = 1;
$parserState->{inputCounter} = $inputCounter;
$parserState->{initbsCount} = scalar(@braceStack);
}
print STDERR "parserState popped from parserStack[\@end]\n" if ($parserStackDebug);
$parserState = pop(@parserStack) || $parserState;
$declaration = $parserState->{storeDec}.$declaration;
# $HeaderDoc::module = $parserState->{MODULE};
}
}
# fall through to next case. WHY???
};
(!$parserState->{inTemplate} && !$parserState->{inComment} && !$parserState->{inInlineComment} && !$parserState->{inString} && !$parserState->{inChar} && length($classregexp) && $part =~ /$classregexp/) && do {
print STDERR "START OF CLASS: CASE 34\n" if ($liteDebug);
### if ($parserState->{classIsObjC}) { $sublang = "occ"; }
### else { $sublang = "cpp"; }
### print STDERR "LANG $lang SUBLANG $sublang\n" if ($localDebug || $parseDebug || $classDebug);
### # Update the class regular expressions because our language has changed.
### ($parseTokens{sotemplate}, $parseTokens{eotemplate}, $parseTokens{operator}, $parseTokens{soc}, $parseTokens{eoc}, $parseTokens{ilc}, $parseTokens{ilc_b}, $parseTokens{sofunction},
### $parseTokens{soprocedure}, $parseTokens{sopreproc}, $parseTokens{lbrace}, $parseTokens{rbrace}, $parseTokens{unionname}, $parseTokens{structname},
### $parseTokens{enumname},
### $parseTokens{typedefname}, $parseTokens{varname}, $parseTokens{constname}, $parseTokens{structisbrace}, $parseTokens{macronames},
### $classregexp, $classbraceregexp, $classclosebraceregexp, $accessregexp,
### $requiredregexp, $parseTokens{propname}, $parseTokens{objcdynamicname}, $parseTokens{objcsynthesizename}, $moduleregexp, $parseTokens{definename}, $parseTokens{functionisbrace}, $parseTokens{classisbrace}, $parseTokens{lbraceconditionalre}, $parseTokens{lbraceunconditionalre}, $parseTokens{assignmentwithcolon},
### $labelregexp, $parseTokens{parmswithcurlybraces}, $parseTokens{superclasseswithcurlybraces}, $parseTokens{soconstructor}) = parseTokens($lang, $sublang);
### print STDERR "PROPNAME NOW $parseTokens{propname}\n" if ($localDebug || $parseDebug || $classDebug);
if ($parseTokens{superclasseswithcurlybraces}) {
$parserState->{pendingBracedParameters} = 1;
}
print STDERR "INCLASSCHECK AFTERNL: ".$parserState->{afterNL}."\n" if ($parseDebug);
my $localclasstype = $1;
if ($part =~ /^\@/) { $part =~ s/^\@//s; }
if ((($lang eq "applescript") && $parserState->{afterNL}) || (($lang ne "applescript") && !(scalar(@braceStack)-$parserState->{initbsCount}))) {
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || ($parserState->{inChar} && $lang ne "applescript"))) {
print STDERR "ITISACLASS\n" if ($localDebug || $classDebug);
if (!length($parserState->{sodclass}) && !$parserState->{inTypedef}) {
print STDERR "GOOD.\n" if ($localDebug);
$parserState->{inClass} = 1;
print STDERR "inClass -> 1 [7]\n" if ($classDebug);
$pushParserStateAtBrace = 1;
if ($localclasstype =~ /\@interface/) {
$parserState->{inClass} = 2;
print STDERR "inClass -> 2 [8]\n" if ($classDebug);
$pushParserStateAtBrace = 0;
} elsif ($localclasstype =~ /\@protocol/) {
$pushParserStateAtBrace = 0;
$pushParserStateAfterWordToken = 0;
$parserState->{inClass} = 0;
print STDERR "inClass -> 0 [9]\n" if ($classDebug);
$parserState->{inProtocol} = 1;
} elsif ($localclasstype =~ /\@implementation/) {
$pushParserStateAtBrace = 0;
$pushParserStateAfterWordToken = 2;
}
$parserState->{sodclass} = "class";
print STDERR "sodclass -> class (explicit)[8]\n" if ($sodDebug);
$parserState->{classtype} = $localclasstype;
if (length($parserState->{sodtype})) {
$parserState->{preclasssodtype} = $parserState->{sodtype} . " " . $part;
} else {
$parserState->{preclasssodtype} = $part;
}
$parserState->{sodtype} = "";
$parserState->{startOfDec} = 1;
$parserState->{sodtypeclasstoken} = $part;
print STDERR "startOfDec -> 1 [7]\n" if ($localDebug);
$parserState->{onlyComments} = 0;
print STDERR "[m]onlyComments -> 0\n" if ($macroDebug);
$continuation = 1;
# Get the parse tokens from Utilities.pm.
if (length($classbraceregexp) && ($localclasstype =~ /$classbraceregexp/)) {
print STDERR "CLASS ($localclasstype) IS A BRACE.\n" if ($localDebug);
push(@parsedParamParseStack, $parserState->{parsedParamParse});
push(@braceStack, $localclasstype); pbs(@braceStack);
print STDERR "PUSHED $localclasstype ONTO BRACESTACK [6]\n" if ($macroDebug || $braceDebug);
$treeNest = 1;
if ($treeDebug) { print STDERR "TS TREENEST -> 1 [17]\n"; }
# } else {
# print STDERR "CBRE: \"$classbraceregexp\"\n";
}
($lang, $sublang) = getLangAndSublangFromClassType($localclasstype, $lang, $sublang);
$HeaderDoc::lang = $lang;
$HeaderDoc::sublang = $sublang;
# ($parseTokens{sotemplate}, $parseTokens{eotemplate}, $parseTokens{operator}, $parseTokens{soc}, $parseTokens{eoc}, $parseTokens{ilc}, $parseTokens{ilc_b}, $parseTokens{sofunction},
# $parseTokens{soprocedure}, $parseTokens{sopreproc}, $parseTokens{lbrace}, $parseTokens{rbrace}, $parseTokens{unionname}, $parseTokens{structname},
# $parseTokens{enumname},
# $parseTokens{typedefname}, $parseTokens{varname}, $parseTokens{constname}, $parseTokens{structisbrace}, $parseTokens{macronames},
# $classregexp, $classbraceregexp, $classclosebraceregexp, $accessregexp,
# $requiredregexp, $parseTokens{propname}, $parseTokens{objcdynamicname}, $parseTokens{objcsynthesizename}, $moduleregexp, $parseTokens{definename},
# $parseTokens{functionisbrace}, $parseTokens{classisbrace}, $parseTokens{lbraceconditionalre}, $parseTokens{lbraceunconditionalre}, $parseTokens{assignmentwithcolon},
# $labelregexp, $parseTokens{parmswithcurlybraces}, $parseTokens{superclasseswithcurlybraces}, $parseTokens{soconstructor}) = parseTokens($lang, $sublang);
%parseTokens = %{parseTokens($lang, $sublang)};
$labelregexp = $parseTokens{labelregexp};
$classregexp = $parseTokens{classregexp};
# print STDERR "PROPNAME2: $parseTokens{propname}\n";
$classbraceregexp = $parseTokens{classbraceregexp};
$classclosebraceregexp = $parseTokens{classclosebraceregexp};
$accessregexp = $parseTokens{accessregexp};
$requiredregexp = $parseTokens{requiredregexp};
$moduleregexp = $parseTokens{moduleregexp};
# $macrore = macroRegexpFromList($parseTokens{macronames});
$macrore_pound = macroRegexpFromList($parseTokens{macronames}, 1);
$macrore_nopound = macroRegexpFromList($parseTokens{macronames}, 2);
$regexppattern = $parseTokens{regexppattern};
$singleregexppattern = $parseTokens{singleregexppattern};
$regexpfirstcharpattern = $parseTokens{regexpfirstcharpattern};
$regexpcharpattern = $parseTokens{regexpcharpattern};
$regexpAllowedAfter = $parseTokens{regexpAllowedAfter};
$TCLregexpcommand = $parseTokens{TCLregexpcommand};
print STDERR "ARP: $accessregexp\n" if ($localDebug);
last SWITCH;
} else {
($lang, $sublang) = getLangAndSublangFromClassType($localclasstype, $lang, $sublang);
$HeaderDoc::lang = $lang;
$HeaderDoc::sublang = $sublang;
# print STDERR "ELSE CASE: $lang $sublang\n";
# ($parseTokens{sotemplate}, $parseTokens{eotemplate}, $parseTokens{operator}, $parseTokens{soc}, $parseTokens{eoc}, $parseTokens{ilc}, $parseTokens{ilc_b}, $parseTokens{sofunction},
# $parseTokens{soprocedure}, $parseTokens{sopreproc}, $parseTokens{lbrace}, $parseTokens{rbrace}, $parseTokens{unionname}, $parseTokens{structname},
# $parseTokens{enumname},
# $parseTokens{typedefname}, $parseTokens{varname}, $parseTokens{constname}, $parseTokens{structisbrace}, $parseTokens{macronames},
# $classregexp, $classbraceregexp, $classclosebraceregexp, $accessregexp,
# $requiredregexp, $parseTokens{propname}, $parseTokens{objcdynamicname}, $parseTokens{objcsynthesizename}, $moduleregexp, $parseTokens{definename},
# $parseTokens{functionisbrace}, $parseTokens{classisbrace}, $parseTokens{lbraceconditionalre}, $parseTokens{lbraceunconditionalre}, $parseTokens{assignmentwithcolon},
# $labelregexp, $parseTokens{parmswithcurlybraces}, $parseTokens{superclasseswithcurlybraces}, $parseTokens{soconstructor}) = parseTokens($lang, $sublang);
%parseTokens = %{parseTokens($lang, $sublang)};
$labelregexp = $parseTokens{labelregexp};
$classregexp = $parseTokens{classregexp};
$classbraceregexp = $parseTokens{classbraceregexp};
$classclosebraceregexp = $parseTokens{classclosebraceregexp};
$accessregexp = $parseTokens{accessregexp};
# print STDERR "PROPNAME2: $parseTokens{propname}\n";
$requiredregexp = $parseTokens{requiredregexp};
$moduleregexp = $parseTokens{moduleregexp};
# $macrore = macroRegexpFromList($parseTokens{macronames});
$macrore_pound = macroRegexpFromList($parseTokens{macronames}, 1);
$macrore_nopound = macroRegexpFromList($parseTokens{macronames}, 2);
$regexppattern = $parseTokens{regexppattern};
$singleregexppattern = $parseTokens{singleregexppattern};
$regexpfirstcharpattern = $parseTokens{regexpfirstcharpattern};
$regexpcharpattern = $parseTokens{regexpcharpattern};
$regexpAllowedAfter = $parseTokens{regexpAllowedAfter};
$TCLregexpcommand = $parseTokens{TCLregexpcommand};
print STDERR "ARP: $accessregexp\n" if ($localDebug);
last SWITCH;
}
} else {
print STDERR "STR: ".$parserState->{inString}." COM: ".$parserState->{inComment}." ILC: ".$parserState->{inInlineComment}." CHAR: ".$parserState->{inChar}." LANG: ".$lang."\n";
}
}
};
($part eq $parseTokens{objcdynamicname}) && do {
print STDERR "PROPERTY: CASE 35\n" if ($liteDebug);
print STDERR "PROPERTY FOUND\n" if ($localDebug);
$parserState->{isProperty} = 1; # Basically treat it like a normal variable, but flag it.
last SWITCH;
};
($part eq $parseTokens{objcsynthesizename}) && do {
print STDERR "PROPERTY: CASE 35\n" if ($liteDebug);
print STDERR "PROPERTY FOUND\n" if ($localDebug);
$parserState->{isProperty} = 1; # Basically treat it like a normal variable, but flag it.
last SWITCH;
};
($part eq $parseTokens{propname}) && do {
print STDERR "PROPERTY: CASE 35\n" if ($liteDebug);
print STDERR "PROPERTY FOUND\n" if ($localDebug);
$parserState->{isProperty} = 1; # Basically treat it like a normal variable, but flag it.
last SWITCH;
};
($part eq $parseTokens{structname} || $part eq $parseTokens{enumname} || $part eq $parseTokens{unionname}) && do {
print STDERR "STRUCT/ENUM/UNION: CASE 36\n" if ($liteDebug);
if ((!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) &&
(!(scalar(@braceStack)-$parserState->{initbsCount}))) {
if ($parseTokens{structisbrace}) {
if ($parserState->{sodclass} eq "function") {
print STDERR "seenBraces -> 1 [4]\n" if ($parseDebug || $braceDebug);
$parserState->{seenBraces} = 1;
if (!$parserState->{stackFrozen}) {
@{$parserState->{freezeStack}} = @{$parserState->{pplStack}};
$parserState->{frozensodname} = $parserState->{sodname};
$parserState->{stackFrozen} = 1;
}
@{$parserState->{pplStack}} = ();
}
$parserState->{posstypesPending} = 0;
$parserState->{callbackNamePending} = -1;
$parserState->{simpleTypedef} = 0;
$parserState->{simpleTDcontents} = "";
print STDERR "callbackNamePending -> -1\n" if ($localDebug || $cbnDebug);
print STDERR "lbrace\n" if ($localDebug);
push(@parsedParamParseStack, $parserState->{parsedParamParse});
push(@braceStack, $part); pbs(@braceStack);
print STDERR "PUSHED $part ONTO BRACESTACK [7]\n" if ($macroDebug || $braceDebug);
if ($HeaderDoc::includeFunctionContents || !($parserState->{seenBraces} || $trailingHide)) { # TREEDONE
$treeNest = 1;
if ($treeDebug) { print STDERR "TS TREENEST -> 1 [18]\n"; }
# push(@treeStack, $treeCur);
# $treeCur = $treeCur->addChild($part, 0); $treeSkip = 1;
# bless($treeCur, "HeaderDoc::ParseTree");
}
$curline = spacefix($curline, $part, $lastchar);
$parserState->{lastsymbol} = "";
$lastchar = $part;
$parserState->{startOfDec} = 0;
print STDERR "startOfDec -> 0 [8]\n" if ($localDebug);
if ($curline !~ /\S/o) {
# This is the first symbol on the line.
# adjust immediately
$prespace += 4;
print STDERR "PS: $prespace immediate\n" if ($localDebug);
} else {
$prespaceadjust += 4;
print STDERR "PSA: $prespaceadjust\n" if ($localDebug);
}
} else {
if (!$parserState->{simpleTypedef}) {
print STDERR "simpleTypedef -> 2\n" if ($localDebug);
$parserState->{simpleTypedef} = 2;
}
# if ($HeaderDoc::includeFunctionContents || !$parserState->{seenBraces}) { # TREEDONE
# $treePopTwo++;
# $treeNest = 1;
# push(@treeStack, $treeCur);
# $treeCur = $treeCur->addChild($part, 0); $treeSkip = 1;
# bless($treeCur, "HeaderDoc::ParseTree");
# }
}
if ($part eq $parseTokens{enumname}) {
$parserState->{inEnum} = 1;
$parserState->{inUnion} = 0;
} elsif ($part eq $parseTokens{unionname}) {
$parserState->{inEnum} = 0;
$parserState->{inUnion} = 1;
} else {
$parserState->{inEnum} = 0;
$parserState->{inUnion} = 0;
}
$parserState->{onlyComments} = 0;
print STDERR "[n]onlyComments -> 0\n" if ($macroDebug);
$continuation = 1;
# $parserState->{simpleTypedef} = 0;
if ($parserState->{basetype} eq "") { $parserState->{basetype} = $part; }
if ($parserState->{typestring} eq "") { $parserState->{typestring} = $part; }
# fall through to default case when we're done.
if (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inString} || $parserState->{inChar})) {
$parserState->{namePending} = 2;
print STDERR "namePending -> 2 [2]\n" if ($parseDebug);
if ($parserState->{posstypesPending}) { $parserState->{posstypes} .=" $part"; }
}
if ($parserState->{sodclass} eq "") {
$parserState->{startOfDec} = 0; $parserState->{sodname} = "";
print STDERR "startOfDec -> 0 [9]\n" if ($localDebug);
print STDERR "sodname cleared (seu)\n" if ($sodDebug);
}
$lastchar = $part;
}; # end if
}; # end do
($part eq $parseTokens{typedefname}) && do {
print STDERR "TYPEDEF: CASE 37\n" if ($liteDebug);
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) {
if (!(scalar(@braceStack)-$parserState->{initbsCount})) { $parserState->{callbackIsTypedef} = 1; $parserState->{inTypedef} = 1; }
$parserState->{onlyComments} = 0;
print STDERR "[o]onlyComments -> 0\n" if ($macroDebug);
$continuation = 1;
if ($parserState->{typestring} eq "") { $parserState->{typestring} = $part; }
$parserState->{simpleTypedef} = 1; print STDERR "simpleTypedef -> 1\n" if ($localDebug);
# previous case falls through, so be explicit.
if ($part eq $parseTokens{typedefname}) {
if (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inString} || $parserState->{inChar})) {
if ($pascal) {
$parserState->{namePending} = 2;
$inPType = 1;
print STDERR "namePending -> 2 [3]\n" if ($parseDebug);
}
if ($parserState->{posstypesPending}) { $parserState->{posstypes} .=" $part"; }
if (!($parserState->{callbackNamePending})) {
print STDERR "callbackNamePending -> 1\n" if ($localDebug || $cbnDebug);
$parserState->{callbackNamePending} = 1;
}
}
}
if ($parserState->{sodclass} eq "") {
$parserState->{startOfDec} = 0; $parserState->{sodname} = "";
print STDERR "startOfDec -> 0 [10]\n" if ($localDebug);
print STDERR "sodname cleared ($parseTokens{typedefname})\n" if ($sodDebug);
}
$lastchar = $part;
}; # end if
}; # end do
# C++ operator keyword handler
($part eq $parseTokens{operator}) && do {
print STDERR "OPERATOR KEYWORD: CASE 38\n" if ($liteDebug);
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) {
$parserState->{inOperator} = 1;
$parserState->{sodname} = "";
$parserState->{sodtype} = $parserState->{returntype};
}
$parserState->{lastsymbol} = $part;
$lastchar = $part;
last SWITCH;
# next;
};
# Punctuation handlers
($part =~ /;/o || ($parserState->{newlineIsSemi} && (!$parserState->isQuoted($lang, $sublang)) && $part =~ /[\n\r]/)) && do {
# semicolon handler.
print STDERR "SEMICOLON: CASE 39\n" if ($liteDebug);
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) {
if ($lang eq "shell") {
if ($part eq ";;") {
$parserState->{afterSemi} = 2;
} elsif (!$parserState->{afterSemi}) {
$parserState->{afterSemi} = 1;
}
}
if ($parserState->{inTCLRegExpCommand}) {
$parserState->{inTCLRegExpCommand} = 0;
}
print STDERR "NOT IN STRING, CHAR, COMMENT, etc.\n" if ($localDebug);
if ($parserState->{parsedParamParse}) {
print STDERR "PPP IS $parserState->{parsedParamParse}.\n" if ($localDebug);
$parsedParam =~ s/^\s*//so; # trim leading space
$parsedParam =~ s/\s*$//so; # trim trailing space
if (length($parsedParam)) { push(@{$parserState->{parsedParamList}}, $parsedParam); }
print STDERR "pushed $parsedParam into parsedParamList [2semi]\n" if ($parmDebug);
$parsedParam = "";
}
# skip this token
print STDERR "PPP AT SEMI: $parserState->{parsedParamParse}\n" if ($parseDebug || $localDebug || $parmDebug);
if ($parserState->{parsedParamParse} <= 2) {
$parserState->{parsedParamParse} = 2;
print STDERR "parsedParamParse -> 2[semi]\n" if ($parmDebug);
$parserState->{freezereturn} = 1;
# $parserState->{onlyComments} = 0; # If this is all we've seen, there's either a bug or we're
# unrolling a class or similar anyway.
$parserState->{temponlyComments} = $parserState->{onlyComments};
print STDERR "[p]onlyComments -> 0\n" if ($macroDebug);
print STDERR "valuepending -> 0\n" if ($valueDebug);
$parserState->{valuepending} = 0;
} else {
if ($parmDebug) {
warn "WARNING: PPP AT SEMI NOT <= 2!\n";
}
}
$continuation = 1;
if ($parserState->{occmethod}) {
$prespaceadjust = -$prespace;
}
# previous case falls through, so be explicit.
# print STDERR "PRE\n" if ($rubyDebug || $parseDebug);;
if (($part =~ /;/o && !$parserState->{inMacroLine} && !$parserState->{inMacro}) ||
($parserState->{newlineIsSemi} && $part =~ /[\n\r]/)) {
if ($parserState->{newlineIsSemi}) { $parserState->{newlineIsSemi} = 0; }
my $bsCount = scalar(@braceStack)-$parserState->{initbsCount};
print STDERR "INHERE BSC $bsCount\n" if ($rubyDebug || $parseDebug);
# print STDERR "KRC: ".$parserState->{kr_c_function}."\n";
if (!$bsCount && !$parserState->{kr_c_function}) {
if ($parserState->{startOfDec} == 2 && !$pascal) {
$parserState->{sodclass} = "variable";
print STDERR "sodclass -> variable (implicit)[9]\n" if ($sodDebug);
$parserState->{startOfDec} = 1;
print STDERR "startOfDec -> 1 [11]\n" if ($localDebug);
} elsif (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar} || $parserState->{inString})) {
$parserState->{startOfDec} = 1;
print STDERR "startOfDec -> 1 [12]\n" if ($localDebug);
}
# $parserState->{lastsymbol} .= $part;
}
if (!$bsCount) {
print STDERR "HERE BSC: $bsCount\n" if ($rubyDebug || $parseDebug);
$treeCur = $treeCur->addSibling($part); $treepart = " "; # $treeSkip = 1;
if ($HeaderDoc::includeFunctionContents && $reMark) {
$treeCur->{RE_STATE} = $reMark;
}
if (0) {
$treeCur = pop(@treeStack) || $treeTop;
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
$treeCur = $treeCur->lastSibling();
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
print STDERR "TSPOP [8]: now $treeCur\n" if ($tsDebug || $treeDebug);
bless($treeCur, "HeaderDoc::ParseTree");
}
# print STDERR "Last tree node set to $treeCur [6a]\n" if ($parserStateInsertDebug);
# $parserState->{lastTreeNode} = $treeCur;
# print STDERR "LASTTREENODE -> $treeCur (".$treeCur->token().")\n";
while ($parserState->{treePopTwo}--) {
$treeCur = pop(@treeStack) || $treeTop;
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
$treeCur = $treeCur->lastSibling();
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
print STDERR "TSPOP [9]: now $treeCur\n" if ($tsDebug || $treeDebug);
bless($treeCur, "HeaderDoc::ParseTree");
}
$parserState->{treePopTwo} = 0;
# } else {
# print STDERR "Not adding sibling. BSCOUNT: rbsCount\n";
}
}
$lastchar = $part;
}; # end if
}; # end do
((($part eq "=" && (!$parseTokens{assignmentwithcolon})) ||
($part eq ":" && ($parseTokens{assignmentwithcolon} == 1))) &&
($parserState->{lastsymbol} ne $parseTokens{operator}) && (!(($parserState->{inOperator} == 1) && $parserState->{lastsymbol} =~ /\W/ && $parserState->{lastsymbol} =~ /\S/)) && !($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) && do {
print STDERR "EQUALS: CASE 40\n" if ($liteDebug);
$parserState->{onlyComments} = 0;
# print STDERR "EQUALSCHECK: if ((($part eq \"=\" && (!$parseTokens{assignmentwithcolon})) ||
# ($part eq \":\" && ($parseTokens{assignmentwithcolon} ))) &&
# !(".scalar(@braceStack)."-$parserState->{initbsCount}) &&
# $nextpart !~ /=/o && $lastchar !~ /=/o &&
# $parserState->{sodclass} ne \"function\" && !$inPType)\n";
print STDERR "[q]onlyComments -> 0\n" if ($macroDebug);
if ((($part eq "=" && (!$parseTokens{assignmentwithcolon})) ||
($part eq ":" && ($parseTokens{assignmentwithcolon} == 1))) &&
!(scalar(@braceStack)-$parserState->{initbsCount}) &&
$nextpart !~ /=/o && $lastchar !~ /=/o &&
$parserState->{sodclass} ne "function" && !$inPType) {
print STDERR "valuepending -> 1\n" if ($valueDebug);
$parserState->{valuepending} = 1;
if ($parserState->{sodname}) {
$parserState->{preEqualsSymbol} = $parserState->{sodname};
} else {
$parserState->{preEqualsSymbol} = $parserState->{lastsymbol};
}
$parserState->{sodclass} = "variable";
print STDERR "sodclass -> variable (implicit)[10]\n" if ($sodDebug);
$parserState->{startOfDec} = 0;
print STDERR "startOfDec -> 0 [13]\n" if ($localDebug);
}; # end if
}; # end do
($part =~ /,/o) && do {
print STDERR "COMMA: CASE 41\n" if ($liteDebug);
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) {
$parserState->{onlyComments} = 0;
print STDERR "[r]onlyComments -> 0\n" if ($macroDebug);
}
print STDERR "PPP AT COMMA: $parserState->{parsedParamParse}\n" if ($parseDebug || $localDebug || $parmDebug);
if ($part =~ /,/o && !($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) {
if (($parserState->{parsedParamParse} == 3 || $parserState->{parsedParamParse} == 4) && ((scalar(@braceStack)-$parserState->{initbsCount}-$parserState->{functionReturnsCallback}) == 1) && (peek(\@braceStack) eq '(' || peek(\@braceStack) eq '{')) {
print STDERR "$part is a comma\n" if ($localDebug || $parseDebug);
$parsedParam =~ s/^\s*//so; # trim leading space
$parsedParam =~ s/\s*$//so; # trim trailing space
if (length($parsedParam)) { push(@{$parserState->{parsedParamList}}, $parsedParam); }
print STDERR "pushed $parsedParam into parsedParamList [2]\n" if ($parmDebug);
$parsedParam = "";
# skip this token
$parserState->{parsedParamParse} = 4;
print STDERR "parsedParamParse -> 4[comma]\n" if ($parmDebug);
} elsif ($parserState->{parsedParamParse}) {
if ($parmDebug) {
warn "WARNING: PPP AT COMMA NOT 3 or 4 (or maybe in string, comment, etc.)!\n";
}
}
# print STDERR "PPP: ".$parserState->{parsedParamParse}." SC: ".$parserState->{sodclass}."\n";
# $parserState->dbprint();
if ((!$parserState->{parsedParamParse}) && ($parserState->{sodclass} eq "variable" ||
$parserState->{sodclass} eq "constant" || $parserState->{sodclass} eq "") &&
($lang eq "C" || $lang eq "Csource" || $lang eq "java" || $lang eq "perl") && $parserState->{sodname} &&
(!(scalar(@braceStack)-$parserState->{initbsCount}))) {
print STDERR "PARSER STATE: $parserState\n" if ($parseDebug || $localDebug);
print STDERR "VARIABLE SODNAME ".$parserState->{sodname}."\n" if ($parseDebug || $localDebug);
print STDERR "VARIABLE RETURNTYPE \"".$parserState->{returntype}."\"\n" if ($parseDebug || $localDebug);
print STDERR "VARIABLE SODTYPE \"".$parserState->{sodtype}."\"\n" if ($parseDebug || $localDebug);
if ($parserState->{variablenames}) {
my $basetype = $parserState->{sodtype};
my $stars = $parserState->{curvarstars};
print STDERR "ADDED STARS: $stars\n" if ($parseDebug || $localDebug);
my %temp = %{$parserState->{variablenames}};
$parserState->{variablenames} = \%temp;
$temp{$parserState->{sodname}} = $parserState->{value};
my %tempb = %{$parserState->{variablestars}};
$parserState->{variablestars} = \%tempb;
$tempb{$parserState->{sodname}} = $stars;
$parserState->{curvarstars} = "";
} else {
my %temp = ();
my %tempb = ();
my $basetype = $parserState->{sodtype};
my $stars = "";
if ($basetype =~ s/(\**)\s*$//s) {
$stars = $1;
}
print STDERR "NEW SET STARS: $stars\n" if ($parseDebug || $localDebug);
$parserState->{variabletype} = $basetype;
$temp{$parserState->{sodname}} = $parserState->{value};
$tempb{$parserState->{sodname}} = $stars;
$parserState->{variablenames} = \%temp;
$parserState->{variablestars} = \%tempb;
$parserState->{curvarstars} = "";
}
# $parserState->{sodclass} = "";
# $parserState->{sodtype} = "";
# $parserState->{sodname} = "";
$parserState->{bracePending} = 1;
# $parserState->{returntype} = "";
# $declaration = "";
# $curline = "";
}
}; # end if
}; # end do
($part =~ /[*^]/) && do {
print STDERR "PUNCTUATION: CASE 41A\n" if ($liteDebug);
if ($part =~ /[*]/) { $parserState->{curvarstars} .= $part; }
if ($lastnspart eq "(" && # ")"
!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) &&
!$parserState->{callbackNamePending} &&
((scalar(@braceStack)-$parserState->{initbsCount}) == 1)) {
# print STDERR "CBNP\n";
$parserState->{callbackNamePending} = 3;
}
# Fall through to the default case.
}; # end star/asterisk/caret case
{ # SWITCH default case
print STDERR "DEFAULT CASE: CASE 42\n" if ($liteDebug);
# Handler for all other text (data types, string contents,
# comment contents, character contents, etc.)
print STDERR "DEFAULT CASE\n" if ($localDebug || $parseDebug);
# print STDERR "TEST CURLINE IS \"$curline\".\n";
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) {
my $tempavail = ignore($part, $ignoreref, $perheaderignoreref);
if ($parserState->{inMacro} == 3 && !$parserState->{inMacroTail}) { $tempavail = 0; }
if ($parserState->{ignoreAvailabilityMacros}) { $tempavail = 0; }
if (!$tempavail) {
if ($part =~ /\S/o) {
$parserState->{onlyComments} = 0;
print STDERR "[s]onlyComments -> 0\n" if ($macroDebug);
}
if (!$continuation && !$occspace) {
$curline = spacefix($curline, $part, $lastchar);
} else {
$continuation = 0;
$occspace = 0;
}
# print STDERR "BAD CURLINE IS \"$curline\".\n";
if (length($part) && !($parserState->{inComment} || $parserState->{inInlineComment})) {
if ($localDebug && $lastchar eq ")") {print STDERR "LC: $lastchar\nPART: $part\n";}
# print STDERR "XXX LC: $lastchar SC: $parserState->{sodclass} LG: $lang\n";
if ($lastchar eq ")" && $parserState->{sodclass} eq "function" && ($lang eq "C" || $lang eq "Csource") && !(scalar(@braceStack)-$parserState->{initbsCount})) {
if ($part !~ /^\s*;/o) {
# warn "K&R C FUNCTION FOUND.\n";
# warn "NAME: $parserState->{sodname}\n";
if (!isKeyword($part, $keywordhashref, $case_sensitive)) {
my $tempavail = ignore($part, $ignoreref, $perheaderignoreref);
if ($parserState->{inMacro} == 3 && !$parserState->{inMacroTail}) { $tempavail = 0; }
if ($parserState->{ignoreAvailabilityMacros}) { $tempavail = 0; }
if (!$tempavail) {
print STDERR "K&R C FUNCTION FOUND [2].\n" if ($localDebug);
print STDERR "TOKEN: \"$part\"\n" if ($localDebug);
print STDERR "TA: \"$tempavail\"\n" if ($localDebug);
$parserState->{kr_c_function} = 1;
$parserState->{kr_c_name} = $parserState->{sodname};
$parserState->{parsedParamParse} = 1;
print STDERR "parsedParamParse -> 1[default1]\n" if ($parmDebug);
}
}
}
}
$lastchar = $part;
if ($part =~ /\w/o || $part eq "::") {
if ($parserState->{callbackNamePending} == 1) {
if (!($part eq $parseTokens{structname} || $part eq $parseTokens{enumname} || $part eq $parseTokens{unionname} || $part eq $parseTokens{typedefname})) {
# we've seen the initial type. The name of
# the callback is after the next open
# parenthesis.
print STDERR "callbackNamePending -> 2\n" if ($localDebug || $cbnDebug);
$parserState->{callbackNamePending} = 2;
}
} elsif ($parserState->{callbackNamePending} == 3) {
print STDERR "callbackNamePending -> 4\n" if ($localDebug || $cbnDebug);
$parserState->{callbackNamePending} = 4;
$parserState->{callbackName} = $part;
$parserState->{name} = "";
$parserState->{sodclass} = "";
print STDERR "sodclass -> \"\" (callback name pending)[11]\n" if ($sodDebug);
$parserState->{cbsodname} = $parserState->{sodname};
$parserState->{sodname} = "";
} elsif ($parserState->{callbackNamePending} == 4) {
if ($part eq "::") {
print STDERR "callbackNamePending -> 5\n" if ($localDebug || $cbnDebug);
$parserState->{callbackNamePending} = 5;
$parserState->{callbackName} .= $part;
} elsif ($part !~ /\s/o) {
print STDERR "callbackNamePending -> 0\n" if ($localDebug || $cbnDebug);
$parserState->{callbackNamePending} = 0;
}
} elsif ($parserState->{callbackNamePending} == 5) {
if ($part !~ /\s/o) {
print STDERR "callbackNamePending -> 4\n" if ($localDebug || $cbnDebug);
if ($part !~ /\*/ && $part !~ /\^/) {
$parserState->{callbackNamePending} = 4;
}
$parserState->{callbackName} .= $part;
}
}
if ($parserState->{namePending} == 2) {
$parserState->{namePending} = 1;
print STDERR "namePending -> 1 [4]\n" if ($parseDebug);
if (!(scalar(@braceStack)-$parserState->{initbsCount}) && ($parserState->{simpleTypedef} == 2)) {
print STDERR "bracePending -> 1\n" if ($localDebug);
$parserState->{bracePending} = 1;
}
} elsif ($parserState->{namePending}) {
if ($parserState->{name} eq "") { $parserState->{name} = $part; }
$parserState->{namePending} = 0;
print STDERR "namePending -> 0 [5]\n" if ($parseDebug);
} elsif ($parserState->{bracePending} == 1) {
if ($part eq "::") {
# struct foo::bar ....
# "foo::bar" is the name of
# the struct and should not
# trigger this (though we might
# trigger it on the following
# word.
print STDERR "bracePending -> 2 [classmember]\n" if ($localDebug);
$parserState->{bracePending} = 2;
} else {
# Word token when brace pending. It's
# a variable.
print STDERR "IT'S A VARIABLE! NAME WAS \"$part\".\n" if ($localDebug);
print STDERR "Word token before brace. Setting sodname to ".$parserState->{lastsymbol}."\n" if ($localDebug || $sodDebug);
$parserState->{sodname} = $part;
# $parserState->{sodtype} = $parserState->{returntype}; # . " " . $parserState->{name};
$parserState->{sodtype} = "$declaration$curline";
# print STDERR "SET SODTYPE TO ".$parserState->{sodtype}."\n";
$parserState->{sodclass} = "variable";
print STDERR "sodclass -> variable (implicit)[12]\n" if ($sodDebug);
$parserState->{frozensodname} = $part;
print STDERR "bracePending -> 0 [word]\n" if ($localDebug);
$parserState->{bracePending} = 0;
}
} elsif ($parserState->{bracePending} == 2) {
$parserState->{bracePending}--;
}
} # end if ($part =~ /\w/o)
if ($part !~ /[][,;\n\r]/o && !$parserState->{inBrackets}) {
my $opttilde = "";
if ($parserState->{seenTilde}) { $opttilde = "~"; }
if ($parserState->{sodbrackets}) {
print STDERR "SODNAME: $parserState->{sodname} SODTYPE: $parserState->{sodtype}\n" if ($sodDebug);
# This is counterintuitive. We append to sodname because it contain the
# value that is about to be appended to sodtype. The new, incoming word
# token will eventually end up in sodname, but it isn't there yet.
$parserState->{sodname} .= $parserState->{sodbrackets};
$parserState->{sodbrackets} = "";
print STDERR "sodbrackets appended and cleared\n" if ($sodDebug);
}
print STDERR "CHECKPOINT: INTEMPLATE IS ".$parserState->{inTemplate}." SOD IS ".$parserState->{startOfDec}."\n" if ($localDebug || $sodDebug);
if ($parserState->{startOfDec} == 1) { # @@@ FIXME DAG. This should not set sodname, but otherwise, we're losing classes!!!
if (!$parserState->{inTemplate}) {
if (!length($accessregexp) || ($part !~ /$accessregexp/)) {
if (!isKeyword($part, $keywordhashref, $case_sensitive)) {
print STDERR "Setting sodname (maybe type) to \"$part\"\n" if ($sodDebug);
$parserState->{sodname} = $opttilde.$part;
if ($part =~ /\w/o) {
$parserState->{startOfDec}++;
}
} else {
# If we're here, this is the first symbol on the
# line s, it's safe to put it straight into sodtype.
$parserState->{sodtype} = " ".$opttilde.$part;
$parserState->{startOfDec}++;
}
} else {
print STDERR "Not adjusting startOfDec or sodname because in access (e.g. public/private/*).\n" if ($localDebug || $sodDebug);
}
} else {
print STDERR "Not adjusting startOfDec or sodname because in template.\n" if ($localDebug || $sodDebug);
}
} elsif ($parserState->{startOfDec} == 2) {
if ($part =~ /\w/o && !$parserState->{inTemplate}) {
$parserState->{preTemplateSymbol} = "";
}
if (!$parserState->{inTemplate} && !$parserState->{waitingForExceptions}) {
if (isKeyword($part, $keywordhashref, $case_sensitive)) {
print STDERR "ISKEYWORD: $part. Setting prekeywordsodname to ".$parserState->{sodname}."\n" if ($sodDebug || $parseDebug || $localDebug);
print STDERR "ISKEYWORD: $part. Setting prekeywordsodtype to ".$parserState->{sodtype}."\n" if ($sodDebug || $parseDebug || $localDebug);
$parserState->{prekeywordsodname} = $parserState->{sodname};
$parserState->{prekeywordsodtype} = $parserState->{sodtype};
} else {
$parserState->{prekeywordsodname} = "";
$parserState->{prekeywordsodtype} = "";
}
if ($parserState->{inOperator} == 1) {
$parserState->{sodname} .= $part;
} else {
if ($parserState->{variableNameConcat}) {
$parserState->{sodname} .= $opttilde.$part;
$parserState->{variableNameConcat}--;
} else {
if (length($parserState->{sodname})) {
my $spc = "";
if ($parserState->{sodname} !~ /[][()]/) { $spc = " "; }
$parserState->{sodtype} .= "$spc$parserState->{sodname}";
}
$parserState->{sodname} = $opttilde.$part;
}
}
print STDERR "sodname set to $part\n" if ($sodDebug);
} else {
print STDERR "Not adjusting startOfDec or sodname because in template.\n" if ($localDebug || $sodDebug);
}
} else {
$parserState->{startOfDec} = 0;
print STDERR "startOfDec -> 0 [14]\n" if ($localDebug);
}
} elsif ($part eq "[") { # if ($part !~ /[;\[\]]/o)
$parserState->{inBrackets} += 1;
print STDERR "inBrackets -> $parserState->{inBrackets}\n" if ($sodDebug);
print STDERR "SOD AT BRACKET: ".$parserState->{startOfDec}."\n" if ($sodDebug);
} elsif ($part eq "]") {
$parserState->{inBrackets} -= 1;
print STDERR "inBrackets -> $parserState->{inBrackets}\n" if ($sodDebug);
} # end if ($part !~ /[;\[\]]/o)
if (!($part eq $parseTokens{eoc})) {
print STDERR "SETTING LS ($part)\n" if ($parseDebug);
# if ($parserState->{typestring} eq "") { $parserState->{typestring} = $part; }
if ($parserState->{lastsymbol} =~ /\,\s*$/o) {
$parserState->{lastsymbol} .= $part;
} elsif ($parserState->{inTypedef} && !(scalar(@braceStack)-$parserState->{initbsCount}) && $part =~ /,/) {
$parserState->{lastsymbol} .= $part;
} elsif ($part =~ /^\s*\;\s*$/o) {
$parserState->{lastsymbol} .= $part;
} elsif (length($part)) {
# warn("replacing lastsymbol with \"$part\"\n");
$parserState->{lastsymbol} = $part;
}
} # end if (!($part eq $parseTokens{eoc}))
} # end if (length($part) && !($parserState->{inComment} || $parserState->{inInlineComment}))
}
} # end if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}))
} # end SWITCH default case
} # end SWITCH
if ($part =~ /\S/ && $part ne ";" && $part ne ";;" && $parserState->{afterSemi}) {
$parserState->{afterSemi} = 0;
}
print STDERR "INMACRO: ".$parserState->{inMacro}." AT TOKEN $part\n" if ($cppDebug);
if ($parserState->{inMacro} == 3 && !$parserState->{seenMacroStart}) {
if ($part =~ /\S/) {
print STDERR "seenMacroStart -> 1 at token $part\n" if ($cppDebug);
$parserState->{seenMacroStart} = 1;
}
} elsif ($parserState->{inMacro} == 3 && !$parserState->{seenMacroName}) {
if ($part =~ /\S/) {
print STDERR "PARSER seenMacroName -> 1 at token $part\n" if ($cppDebug);
$parserState->{seenMacroName} = 1;
}
} elsif ($parserState->{inMacro} == 3 && !$parserState->{inMacroTail}) {
# Note that a space after the macro name means the name is
# done. Thus, any token, including a space, puts us in the
# macro's tail.
print STDERR "PARSER inMacroTail -> 1 at token $part\n" if ($cppDebug);
$parserState->{inMacroTail} = 1;
}
if (($part =~ /\S/ && $part ne "<<") && ($parserState->{inRuby} == 3) && $parserState->{inRubyBlock} eq "") {
# print STDERR "IRB: $part\n";
$parserState->{inRubyBlock} = $part;
}
if ($parserState->{occmethod} && $parserState->{gatheringObjCReturnType} == 1) {
$parserState->{gatheringObjCReturnType} = 2;
} elsif ($parserState->{occmethod} && $parserState->{gatheringObjCReturnType} == 2) {
$parserState->{occmethodreturntype} .= $part;
}
if ($parserState->{waitingForTypeInformation} == 1 && $part !~ /\s/) {
$parserState->{waitingForTypeInformation} = -1;
} elsif ($parserState->{waitingForTypeInformation} == 2) {
$parserState->{waitingForTypeInformation} = 1;
}
if ($inRegexpCharClass > 1 && $inRegexpCharClass != 4) {
$inRegexpCharClass--;
}
# Note: don't check tempInIf here. We want the open brace included because
# the close brace is included.
if (($parserState->{seenBraces} || $trailingHide) && !$HeaderDoc::includeFunctionContents && ($parserState->{INIF} != 1)) {
# print STDERR "SEENBRACES. TP: $treepart PT: $part\n";
if ($treepart) {
print STDERR "ADDED \"$treepart\" to function contents\n" if ($functionContentsDebug);
$parserState->{functionContents} .= $treepart;
} else {
print STDERR "ADDED \"$part\" to function contents\n" if ($functionContentsDebug);
$parserState->{functionContents} .= $part;
}
# print STDERR "SEENBRACES. FC: ".$parserState->{functionContents}."\n";
} elsif (($parserState->{seenBraces} || $trailingHide) && !$HeaderDoc::includeFunctionContents) {
print STDERR "NOT ADDING \"$part\" to function contents (INIF: ".$parserState->{INIF}." TEMPINIF: $tempInIf\n" if ($functionContentsDebug);
} else {
print STDERR "NOT ADDING \"$part\" to function contents (!seenBraces)\n" if ($functionContentsDebug);
}
if ($part !~ /\\/o) {
if (!($parserState->{inMacro} || $parserState->{inMacroLine}) || $part !~ /\s/) {
$parserState->resetBackslash();
}
}
if (length($part)) { $lasttoken = $part; }
if (length($part) && $inRegexpTrailer) { --$inRegexpTrailer; }
if ($postPossNL) { --$postPossNL; }
if (($parserState->{simpleTypedef} == 1) && ($part ne $parseTokens{typedefname}) &&
!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar} ||
$inRegexp)) {
# print STDERR "NP: $parserState->{namePending} PTP: $parserState->{posstypesPending} PART: $part\n";
$parserState->{simpleTDcontents} .= $part;
}
my $ignoretoken = ignore($part, $ignoreref, $perheaderignoreref);
if ($parserState->{inMacro} == 3 && !$parserState->{inMacroTail}) { $ignoretoken = 0; }
if ($parserState->{ignoreAvailabilityMacros}) { $ignoretoken = 0; }
my $hide = ( $hideTokenAndMaybeContents ||
( $ignoretoken &&
!( $parserState->{inString} || $parserState->{inComment} ||
$parserState->{inInlineComment} || $parserState->{inChar}
)
)
);
print STDERR "TPONL: $treePopOnNewLine TPTWO: ".$parserState->{treePopTwo}."\n" if ($tsDebug);
print STDERR "TN: $treeNest TS: $treeSkip nTS: ".scalar(@treeStack)."\n" if ($tsDebug || $parserStateInsertDebug);
print STDERR "sethollow: $sethollow\n" if ($parserStateInsertDebug);
if (!$treeSkip) {
if ($HeaderDoc::includeFunctionContents || !($parserState->{seenBraces} || $trailingHide)) { # TREEDONE
if ($treeNest != 2) {
# If we really want to skip and nest, set treeNest to 2.
if (length($treepart)) {
if ((($parserState->{inComment} == 1) || ($parserState->{inInlineComment} == 1)) && $treepart !~ /[\r\n!]/) {
$treeCur->token($treeCur->token() . $treepart);
# print STDERR "SHORT\n";
} else {
$treeCur = $treeCur->addSibling($treepart, $hide);
if ($HeaderDoc::includeFunctionContents && $reMark) {
$treeCur->{RE_STATE} = $reMark;
}
}
$treepart = "";
} else {
if ((($parserState->{inComment} == 1) || ($parserState->{inInlineComment} == 1)) && $treepart !~ /[\r\n!]/) {
$treeCur->token($treeCur->token() . $part);
# print STDERR "SHORT\n";
} else {
$treeCur = $treeCur->addSibling($part, $hide);
if ($HeaderDoc::includeFunctionContents && $reMark) {
$treeCur->{RE_STATE} = $reMark;
}
}
}
bless($treeCur, "HeaderDoc::ParseTree");
}
# print STDERR "TC IS $treeCur\n";
# $treeCur = %{$treeCur};
if ($treeNest) {
if ($sethollow) {
print STDERR "WILL INSERT STATE $parserState (SETHOLLOW) at ".$treeCur->token()."\n" if ($parserStackDebug);
# $parserState->{hollow} = $treeCur;
$parserState->setHollowWithLineNumbers($treeCur, $fileoffset, $inputCounter);
$sethollow = 0;
}
print STDERR "TSPUSH\n" if ($tsDebug || $treeDebug);
push(@treeStack, $treeCur);
$treeCur = $treeCur->addChild("", 0);
bless($treeCur, "HeaderDoc::ParseTree");
}
}
} else {
print STDERR "Not adding sibling (seenBraces)\n" if ($treeDebug);
}
if ($setIsAvailable) {
$treeCur->isAvailabilityMacro(1);
}
if ($parserState->{inComment} > 1) { $parserState->{inComment}--; }
if ($parserState->{inInlineComment} > 1) { $parserState->{inInlineComment}--; }
if (($parserState->{inComment} == 1) && $treepart eq "!") {
$parserState->{inComment} = 3;
}
if (($parserState->{inInlineComment} == 1) && $treepart eq "!") {
$parserState->{inInlineComment} = 3;
}
$treeNest = 0;
if ($treeDebug) { print STDERR "TS TREENEST -> 0 [19]\n"; }
if (!$parserState->{freezereturn} && $parserState->{hollow} && !$parserState->{inComment} && !$parserState->{leavingComment}) {
# print STDERR "WARNING: RETURN TYPE CHANGE[A]".$parserState->{returntype}." CHANGED TO $declaration$curline.\n";
$parserState->{returntype} = "$declaration$curline";
print STDERR "APPENDING TO RETURNTYPE[2]: NOW \"$parserState->{returntype}\".\n" if ($retDebug);
} elsif (!$parserState->{freezereturn} && !$parserState->{hollow} && !$parserState->{inComment} && !$parserState->{leavingComment}) {
# print STDERR "WARNING: RETURN TYPE CHANGE[B]".$parserState->{returntype}." CHANGED TO $curline.\n";
$parserState->{returntype} = "$curline";
print STDERR "REPLACING RETURNTYPE[2]: NOW \"$parserState->{returntype}\".\n" if ($retDebug);
$declaration = "";
# } else {
# print STDERR "WARNING: LEAVING RETURN TYPE ALONE: ".$parserState->{returntype}." NOT CHANGED TO $curline.\n";
}
if ($pascal && $parserState->{waitingForTypeInformation}) {
print STDERR "PASCAL END CASE RT: $parserState->{returntype}\nCL: $curline\n" if ($parseDebug || $localDebug || $retDebug);
$parserState->{returntype} = $curline;
print STDERR "REPLACING RETURNTYPE[3]: NOW \"$parserState->{returntype}\".\n" if ($retDebug);
}
print STDERR "AT MIDPOINT, TREECUR IS $treeCur (".$treeCur->token().")\n" if ($localDebug || $parserStateInsertDebug);
# From here down is... magic. This is where we figure out how
# to handle parsed parameters, K&R C types, and in general,
# determine whether we've received a complete declaration or not.
#
# About 90% of this is legacy code to handle proper spacing.
# Those bits got effectively replaced by the parseTree class.
# The only way you ever see this output is if you don't have
# any styles defined in your config file.
print STDERR "TOKEN $part parsedParamParse going into end is $parserState->{parsedParamParse}\n" if ($parmDebug);
if (($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) ||
!$ignoretoken) {
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) &&
!$ppSkipOneToken) {
if ($parserState->{parsedParamParse} == 1 || $parserState->{parsedParamParse} == 3 ||
$parserState->{parsedParamParse} == 5) {
$parsedParam .= $part;
print STDERR "PARSED PARAM IS NOW $parsedParam\n" if ($parmDebug);
} elsif ($parserState->{parsedParamParse} == 2 || $parserState->{parsedParamParse} == 4 ||
$parserState->{parsedParamParse} == 6) {
$parserState->{parsedParamParse}--;
print STDERR "parsedParamParse -> $parserState->{parsedParamParse}"."[endgame]\n" if ($parmDebug);
}
}
if ($ppSkipOneToken) {
$hollowskip = $ppSkipOneToken;
print STDERR "hollowskip -> $ppSkipOneToken (ppSkipOneToken)\n" if ($parserStateInsertDebug);
}
$ppSkipOneToken = 0;
print STDERR "MIDPOINT CL: $curline\nDEC:$declaration\nSCR: \"$scratch\"\n" if ($localDebug);
if ($HeaderDoc::includeFunctionContents || !($parserState->{seenBraces} || $trailingHide)) {
# Add to current line (but don't put inline function/macro
# declarations in.
if ($parserState->{inString}) {
$curstring .= $part;
} else {
if (length($curstring)) {
if (length($curline) + length($curstring) >
$HeaderDoc::maxDecLen) {
$scratch = nspaces($prespace);
# Was != /\n/ which is clearly
# wrong. Suspect the next line
# if we start losing leading spaces
# where we shouldn't (or don't where
# we should). Also was just /g.
if ($curline !~ /^\s*\n/so) { $curline =~ s/^\s*//sgo; }
# NEWLINE INSERT
print STDERR "CURLINE CLEAR [1]\n" if ($localDebug);
$declaration .= "$scratch$curline\n";
$curline = "";
$prespace += $prespaceadjust;
$prespaceadjust = 0;
$prespaceadjust -= 4;
$prespace += 4;
} else {
# no wrap, so maybe add a space.
if ($lastchar =~ /\=$/o) {
$curline .= " ";
}
}
$curline .= $curstring;
$curstring = "";
}
if ((length($curline) + length($part) > $HeaderDoc::maxDecLen)) {
$scratch = nspaces($prespace);
# Was != /\n/ which is clearly
# wrong. Suspect the next line
# if we start losing leading spaces
# where we shouldn't (or don't where
# we should). Also was /g instead of /sg.
if ($curline !~ /^\s*\n/so) { $curline =~ s/^\s*//sgo; }
# NEWLINE INSERT
$declaration .= "$scratch$curline\n";
print STDERR "CURLINE CLEAR [2]\n" if ($localDebug);
$curline = "";
$prespace += $prespaceadjust;
$prespaceadjust = 0;
$prespaceadjust -= 4;
$prespace += 4;
}
if (length($curline) || $part ne " ") {
# Add it to curline unless it's a space that
# has inadvertently been wrapped to the
# start of a line.
$curline .= $part;
}
}
if (peek(\@braceStack) ne "<") {
if ($part =~ /\n/o || ($part =~ /[\(;,]/o && $nextpart !~ /\n/o &&
!$parserState->{occmethod}) ||
($part =~ /[:;.]/o && $nextpart !~ /\n/o &&
$parserState->{occmethod})) {
if ($curline !~ /\n/o && !($parserState->{inMacro} || ($pascal && (scalar(@braceStack)-$parserState->{initbsCount})) || $parserState->{inInlineComment} || $parserState->{inComment} || $parserState->{inString})) {
# NEWLINE INSERT
$curline .= "\n";
}
# Add the current line to the declaration.
$scratch = nspaces($prespace);
if ($curline !~ /\n/o) { $curline =~ s/^\s*//go; }
if ($declaration !~ /\n\s*$/o) {
$scratch = " ";
if ($localDebug) {
my $zDec = $declaration;
$zDec = s/ /z/sg;
$zDec = s/\t/Z/sg;
print STDERR "ZEROSCRATCH\n";
print STDERR "zDec: \"$zDec\"\n";
}
}
$declaration .= "$scratch$curline";
print STDERR "CURLINE CLEAR [3]\n" if ($localDebug);
$curline = "";
# $curline = nspaces($prespace);
print STDERR "PS: $prespace -> " . $prespace + $prespaceadjust . "\n" if ($localDebug);
$prespace += $prespaceadjust;
$prespaceadjust = 0;
} elsif ($part =~ /[\(;,]/o && $nextpart !~ /\n/o &&
($parserState->{occmethod} == 1)) {
print STDERR "SPC\n" if ($localDebug);
$curline .= " "; $occspace = 1;
} else {
print STDERR "NOSPC: $part:$nextpart:$parserState->{occmethod}\n" if ($localDebug);
}
}
}
if ($parserState->{temponlyComments}) {
# print STDERR "GOT TOC: ".$parserState->{temponlyComments}."\n";
$parserState->{onlyComments} = $parserState->{temponlyComments};
$parserState->{temponlyComments} = undef;
}
print STDERR "CURLINE IS \"$curline\".\n" if ($localDebug);
my $bsCount = scalar(@braceStack);
print STDERR "ENDTEST: $bsCount \"$parserState->{lastsymbol}\"\n" if ($localDebug || $continueDebug);
print STDERR "KRC: $parserState->{kr_c_function} SB: $parserState->{seenBraces}\n" if ($localDebug || $continueDebug);
print STDERR "DEANL: ".$parserState->{declarationEndsAtNewLine}." PART: \"$treepart\"\n" if ($parseDebug || $asDebug || $continueDebug);
if (!($bsCount - $parserState->{initbsCount}) && ($parserState->{lastsymbol} =~ /;\s*$/o || ($parserState->{declarationEndsAtNewLine} && $partIsNL))) {
if ($parserState->{declarationEndsAtNewLine} && $partIsNL) {
print STDERR "CREATING NEW PARSER STATE NOW.\n" if ($parseDebug || $asDebug);
$parserState->{declarationEndsAtNewLine} = 0;
}
# print STDERR "DPA\n";
if ((!$parserState->{kr_c_function} || $parserState->{seenBraces}) && !$parserState->{inMacro}) {
print STDERR "DPB\n" if ($parserStateInsertDebug || $continueDebug);
if (!scalar(@parserStack)) {
$continue = 0;
print STDERR "CONTINUE -> 0 [3]\n" if ($parseDebug || $cppDebug || $macroDebug || $localDebug || $continueDebug);
} elsif (!$parserState->{onlyComments}) {
# Process entry here
if ($parserState->{noInsert}) {
print STDERR "parserState insertion skipped[SEMI-1]\n" if ($parserStateInsertDebug);
} elsif ($parserState->{hollow}) {
my $treeRef = $parserState->{hollow};
print STDERR "inserted parser state into tree [semi]\n" if ($parserStateInsertDebug);
print STDERR "Last tree node set to $treeCur [7]\n" if ($parserStateInsertDebug);
$parserState->{lastTreeNode} = $treeCur;
$treeRef->addRawParsedParams(\@{$parserState->{parsedParamList}});
$treeRef->parserState($parserState);
} elsif ($parserState->{classtype} && length($parserState->{classtype})) {
warn "Couldn't insert info into parse tree[3class].\n" if ($localDebug);
} else {
warn "Couldn't insert info into parse tree[3].\n";
print STDERR "Printing tree.\n";
$parserState->print();
$treeTop->dbprint();
}
print STDERR "parserState: Created parser state[2].\n" if ($parserStackDebug);
$parserState = HeaderDoc::ParserState->new( "FULLPATH" => $fullpath, "lang" => $lang, "sublang" => $sublang );
$parserState->{skiptoken} = 1;
$parserState->{inputCounter} = $inputCounter;
$parserState->{initbsCount} = scalar(@braceStack);
print STDERR "NEWRETURNTYPE: $parserState->{returntype}\n" if ($localDebug);
print STDERR "CURLINE CLEAR[PRS2]\n" if ($localDebug);
$curline = "";
} else {
print STDERR "parserState insertion skipped[ONLY COMMENTS]\n" if ($parserStateInsertDebug);
}
}
} else {
print STDERR "bsCount: $bsCount - $parserState->{initbsCount}, ls: $parserState->{lastsymbol}\n" if ($localDebug);
pbs(@braceStack);
}
# print STDERR "BSCOUNT: $bsCount IBS: $parserState->{initbsCount}\n";
if (!($bsCount - $parserState->{initbsCount}) && ($parserState->{seenBraces} || $trailingHide) && ($parserState->{sodclass} eq "function" || $parserState->{inOperator}) &&
($nextpart ne ";")) {
# Function declarations end at the close curly brace.
# No ';' necessary (though we'll eat it if it's there.
if ($parserState->{treePopTwo} || $ruby || $parseTokens{functionisbrace}) {
# Fix nesting.
# print STDERR "LASTTREENODE -> $treeCur (".$treeCur->token().")\n";
while ($parserState->{treePopTwo}--) {
$treeCur = pop(@treeStack) || $treeTop;
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
$treeCur = $treeCur->lastSibling();
$treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}, $lang, $sublang);
print STDERR "TSPOP [13]: now $treeCur\n" if ($tsDebug || $treeDebug);
bless($treeCur, "HeaderDoc::ParseTree");
}
if ($ruby || $parseTokens{functionisbrace}) {
$treeCur = $treeCur->addSibling("", 0);
} else {
$treeCur = $treeCur->addSibling(";", 0);
}
if ($HeaderDoc::includeFunctionContents && $reMark) {
$treeCur->{RE_STATE} = $reMark;
}
print STDERR "parser state lastTreeNode reset [treePopTwo]\n" if ($parserStateInsertDebug);
print STDERR "Last tree node set to $treeCur [8]\n" if ($parserStateInsertDebug);
$parserState->{lastTreeNode} = $treeCur;
$parserState->{treePopTwo} = 0;
}
print STDERR "CHECKINIF: ".$parserState->{INIF}."\n" if ($continueDebug);
if (!scalar(@parserStack) && !$parserState->{INIF} && !$tempInIf) {
$continue = 0;
print STDERR "CONTINUE -> 0 [4]\n" if ($parseDebug || $cppDebug || $macroDebug || $localDebug || $continueDebug);
} elsif ($parserState->{inrbraceargument}) {
print STDERR "parserState insertion skipped[inrbraceargument]\n" if ($parserStackDebug);
} elsif (!$parserState->{onlyComments} && !$parserState->{INIF} && !$tempInIf) {
# Process entry here
if ($parserState->{noInsert}) {
print STDERR "parserState insertion skipped[SEMI-2]\n" if ($parserStackDebug);
} elsif ($parserState->{hollow}) {
my $treeRef = $parserState->{hollow};
print STDERR "inserted parser state into tree [rbrace]\nEOD: $treeCur\n" if ($parserStateInsertDebug);
print STDERR "Last tree node set to $treeCur [9] (token: \"".$treeCur->token()."\")\n" if ($parserStateInsertDebug);
$parserState->{lastTreeNode} = $treeCur;
$treeRef->addRawParsedParams(\@{$parserState->{parsedParamList}});
$treeRef->parserState($parserState);
} else {
warn "Couldn't insert info into parse tree[4].\n";
}
print STDERR "parserState: Created parser state[3].\n" if ($parserStackDebug);
$parserState = HeaderDoc::ParserState->new( "FULLPATH" => $fullpath, "lang" => $lang, "sublang" => $sublang );
$parserState->{skiptoken} = 1;
$parserState->{inputCounter} = $inputCounter;
$parserState->{initbsCount} = scalar(@braceStack);
print STDERR "CURLINE CLEAR[PRS3]\n" if ($localDebug);
$curline = "";
}
}
print STDERR "INMACRO: ".$parserState->{inMacro}."\n" if ($localDebug || $cppDebug || $cppDebug);
# $parserState->{lastsymbol} ne "\\"
print STDERR "IM: ".$parserState->{inMacro}." IQ: ".$parserState->isQuoted($lang, $sublang)."\n" if ($localDebug);
if (($parserState->{inMacro} == 3 && !$parserState->isQuoted($lang, $sublang)) || $parserState->{inMacro} == 4) {
print STDERR "CHECKPART \"$part\" AGAINST NEWLINE\n" if ($localDebug || $cppDebug);
if ($part =~ /[\n\r]/o && !$parserState->{inComment}) {
print STDERR "MLS: $parserState->{lastsymbol}\n" if ($macroDebug);
print STDERR "PARSER STACK CONTAINS ".scalar(@parserStack)." FRAMES\n" if ($cppDebug || $parserStackDebug);
if (!scalar(@parserStack)) {
$continue = 0;
print STDERR "CONTINUE -> 0 [5]\n" if ($parseDebug || $cppDebug || $macroDebug || $localDebug || $continueDebug);
} elsif (!$parserState->{onlyComments}) {
# Process entry here
print STDERR "NOT setting continue to 0 for macro: parser stack nonempty\n" if ($liteDebug);
print STDERR "DONE WITH MACRO. HANDLING.\n" if ($localDebug || $parseDebug);
if ($parserState->{inMacro} == 3) {
if (!$HeaderDoc::skipNextPDefine) {
cpp_add($parserState->{hollow}, 0, $lang, $sublang);
} else {
cpp_add($parserState->{hollow}, 1, $lang, $sublang);
$HeaderDoc::skipNextPDefine = 0;
}
}
if ($parserState->{noInsert}) {
print STDERR "parserState insertion skipped\n" if ($parserStackDebug);
} elsif ($parserState->{hollow}) {
my $treeRef = $parserState->{hollow};
print STDERR "inserted parser state into tree [macro]\n" if ($parserStateInsertDebug);
print STDERR "Last tree node set to $treeCur [10]\n" if ($parserStateInsertDebug);
$parserState->{lastTreeNode} = $treeCur;
$treeRef->addRawParsedParams(\@{$parserState->{parsedParamList}});
$treeRef->parserState($parserState);
} else {
warn "Couldn't insert info into parse tree[5].\n";
}
print STDERR "parserState: Created parser state[4].\n" if ($parserStackDebug);
$parserState = HeaderDoc::ParserState->new( "FULLPATH" => $fullpath, "lang" => $lang, "sublang" => $sublang );
$parserState->{skiptoken} = 1;
$parserState->{inputCounter} = $inputCounter;
$parserState->{initbsCount} = scalar(@braceStack);
print STDERR "CURLINE CLEAR[PRS4]\n" if ($localDebug);
$curline = "";
}
}
} elsif ($parserState->{inMacro} == 2) {
my $linenum = $inputCounter + $fileoffset;
warn "$fullpath:$linenum: warning: Declaration starts with # but is not preprocessor macro\n";
warn "PART: $part\n";
} elsif ($parserState->{inMacro} == 3 && $parserState->isQuoted($lang, $sublang)) {
# $parserState->{lastsymbol} eq "\\"
print STDERR "TAIL BACKSLASH ($continue)\n" if ($localDebug || $macroDebug);
}
if ($parserState->{valuepending} == 2) {
# skip the "=" part;
$parserState->{value} .= $part;
} elsif ($parserState->{valuepending}) {
$parserState->{valuepending} = 2;
print STDERR "valuepending -> 2\n" if ($valueDebug);
}
} # end if "we're not ignoring this token"
print STDERR "OOGABOOGA\n" if ($parserStackDebug);
if ($pushParserStateAfterToken == 1) {
if ($parserState->{inClass}) { configureAccessControlStateForClass($parserState); }
print STDERR "parserState pushed onto stack[token]\n" if ($parserStackDebug);
print STDERR "Last tree node set to $treeCur [11]\n" if ($parserStateInsertDebug);
$parserState->{lastTreeNode} = $treeCur;
if ($lang eq "applescript") {
# AppleScript needs a little help because functions can contain other things.
if (!$parserState->{lastDisplayNode}) {
$parserState->{lastDisplayNode} = $treeCur;
}
if (!$treeTop->{lastDisplayNode}) {
$treeTop->{lastDisplayNode} = $treeCur;
}
if (!$parserState->{lastDisplayNode}) {
$parserState->{lastDisplayNode} = $treeCur;
}
if (!$treeTop->{lastDisplayNode}) {
$treeTop->{lastDisplayNode} = $treeCur;
}
# print STDERR "CUR: $treeCur\n";
# print STDERR "FOR PS: $parserState\n";
# $treeCur->dbprint();
# print STDERR "TOP:\n";
# $treeTop->dbprint();
# print STDERR "SET TN: $treeTop\n";
# print STDERR "TTLDN: ".$treeTop->{lastDisplayNode}."\n";
}
$curline = "";
$parserState->{storeDec} = $declaration;
$parserState->{freezereturn} = 1;
$declaration = "";
push(@parserStack, $parserState);
$parserState = HeaderDoc::ParserState->new( "FULLPATH" => $fullpath, "lang" => $lang, "sublang" => $sublang );
$parserState->{skiptoken} = 1;
$parserState->{inputCounter} = $inputCounter;
$parserState->{initbsCount} = scalar(@braceStack);
$pushParserStateAfterToken = 0;
$pushParserStateAtBrace = 0;
} elsif ($pushParserStateAfterWordToken == 1) {
if ($part =~ /\w/) {
print STDERR "parserState pushed onto stack[word]\n" if ($parserStackDebug);
print STDERR "Last tree node set to $treeCur [12]\n" if ($parserStateInsertDebug);
if ($parserState->{inClass}) { configureAccessControlStateForClass($parserState); }
$parserState->{lastTreeNode} = $treeCur;
$curline = "";
$parserState->{storeDec} = $declaration;
$parserState->{freezereturn} = 1;
$declaration = "";
push(@parserStack, $parserState);
$parserState = HeaderDoc::ParserState->new( "FULLPATH" => $fullpath, "lang" => $lang, "sublang" => $sublang );
$parserState->{skiptoken} = 1;
$parserState->{inputCounter} = $inputCounter;
$parserState->{initbsCount} = scalar(@braceStack);
$pushParserStateAfterWordToken = 0;
}
} elsif ($pushParserStateAfterWordToken) {
print STDERR "PPSAFTERWT CHANGED $pushParserStateAfterWordToken -> " if ($parserStackDebug);
$pushParserStateAfterWordToken--;
print STDERR "$pushParserStateAfterWordToken\n" if ($parserStackDebug);
} elsif ($pushParserStateAtBrace) {
print STDERR "PPSatBrace?\n" if ($parserStackDebug);
# if (casecmp($part, $parseTokens{lbrace}, $case_sensitive))
print STDERR "check: ".$parserState->isLeftBrace($part, $lang, \%parseTokens, $case_sensitive, scalar(@braceStack))."\n" if ($rubyDebug || $parseDebug || $HeaderDoc::AppleScriptDebug);
if ($parserState->isLeftBrace($part, $lang, \%parseTokens, $case_sensitive, scalar(@braceStack))) {
if ($part =~ /[\n\r]/) { $parserState->{inRubyClass} = 2; }
$parserState->{ISFORWARDDECLARATION} = 0;
if ($parserState->{inClass}) { configureAccessControlStateForClass($parserState); }
print STDERR "parserState pushed onto stack[brace]\n" if ($parserStackDebug);
# if ($pushParserStateAtBrace == 2) {
# print STDERR "NOINSERT parserState: $parserState\n" if ($parserStackDebug);
# $parserState->{hollow} = undef;
# $parserState->{noInsert} = 1;
# }
print STDERR "Last tree node set to $treeCur [13]\n" if ($parserStateInsertDebug);
$parserState->{lastTreeNode} = $treeCur;
$curline = "";
$parserState->{storeDec} = $declaration;
$parserState->{freezereturn} = 1;
$declaration = "";
push(@parserStack, $parserState);
$parserState = HeaderDoc::ParserState->new( "FULLPATH" => $fullpath, "lang" => $lang, "sublang" => $sublang );
$parserState->{skiptoken} = 1;
$parserState->{inputCounter} = $inputCounter;
$parserState->{initbsCount} = scalar(@braceStack);
$parserState->{noInsert} = $setNoInsert;
$setNoInsert = 0;
$pushParserStateAtBrace = 0;
} elsif ($pushParserStateAtBrace) {
if ($part =~ /\;/) {
# It's a class instance declaration. Whoops.
$pushParserStateAtBrace = 0;
$parserState->{inClass} = 0;
print STDERR "inClass -> 0 [10]\n" if ($classDebug);
}
# if ($part =~ /\S/) { $pushParserStateAtBrace = 0; }
}
if (!$parserState->{hollow}) {
my $tok = $part; # $treeCur->token();
print STDERR "parserState: NOT HOLLOW [1]\n" if ($parserStackDebug);
print STDERR "IS: $parserState->{inString}\nICom: $parserState->{inComment}\nISLC: $parserState->{inInlineComment}\nIChar: $parserState->{inChar}\nSkipToken: $parserState->{skiptoken}\nHollowSkip: $hollowskip\n" if ($parserStackDebug);
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar} || $parserState->{skiptoken} || $hollowskip)) {
print STDERR "parserState: NOT STRING/CHAR/COMMENT\n" if ($parserStackDebug);
if ($tok =~ /\S/) {
print STDERR "parserState: PS IS $parserState\n" if ($parserStackDebug);
print STDERR "parserState: NOT WHITESPACE : ".$parserState->{hollow}." -> $treeCur\n" if ($parserStackDebug);
if (!$parserState->isRightBrace($tok, $lang, \%parseTokens, $case_sensitive) && $part !~ /\)/) {
# $parserState->{hollow} = $treeCur;
$parserState->setHollowWithLineNumbers($treeCur, $fileoffset, $inputCounter);
# $HeaderDoc::curParserState = $parserState;
print STDERR "parserState: WILL INSERT STATE $parserState (HOLLOW-AUTO-1) AT TOKEN \"$part\"/\"".$treeCur->token()."\"\n" if ($parserStackDebug);
}
}
}
$hollowskip = 0;
print STDERR "hollowskip -> 0 (NOTHOLLOW - 1)\n" if ($parserStateInsertDebug);
$parserState->{skiptoken} = 0;
}
} else {
if (!$parserState->{hollow}) {
my $tok = $part; # $treeCur->token();
print STDERR "parserState: NOT HOLLOW [2]\n" if ($parserStackDebug);
print STDERR "IS: $parserState->{inString}\nICom: $parserState->{inComment}\nISLC: $parserState->{inInlineComment}\nIChar: $parserState->{inChar}\nSkipToken: $parserState->{skiptoken}\nHollowSkip: $hollowskip\n" if ($parserStackDebug);
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar} || $parserState->{skiptoken} || $hollowskip)) {
print STDERR "parserState: NOT STRING/CHAR/COMMENT\n" if ($parserStackDebug);
if ($tok =~ /\S/) {
print STDERR "parserState: PS IS $parserState\n" if ($parserStackDebug);
print STDERR "parserState: NOT WHITESPACE : ".$parserState->{hollow}." -> $treeCur\n" if ($parserStackDebug);
if (!$parserState->isRightBrace($tok, $lang, \%parseTokens, $case_sensitive) && $part !~ /\)/) {
$parserState->setHollowWithLineNumbers($treeCur, $fileoffset, $inputCounter);
# $HeaderDoc::curParserState = $parserState;
print STDERR "parserState: WILL INSERT STATE $parserState (HOLLOW-AUTO-2) AT TOKEN \"$part\"/\"".$treeCur->token()."\"\n" if ($parserStackDebug);
}
}
}
$hollowskip = 0;
print STDERR "hollowskip -> 0 (NOTHOLLOW - 2)\n" if ($parserStateInsertDebug);
$parserState->{skiptoken} = 0;
}
}
if ($part =~ /\w+/) {
if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar} || $parserState->{skiptoken} || $hollowskip)) {
if ($parserState->{occparmlabelfound} == -2) {
if (!($parserState->{initbsCount} - scalar(@braceStack) )) { # Skip types
$parserState->{occparmlabelfound} = 0; # Next token is the label for the next parameter.
if ($HeaderDoc::useParmNameForUnlabeledParms) {
$parserState->{occmethodname} .= "$part:";
} else {
$parserState->{occmethodname} .= ":";
}
if ($occMethodNameDebug) {
print STDERR "OCC parameter name substituted; OCC method name now ".$parserState->{occmethodname}." (lastsymbol was \"".$parserState->{lastsymbol}."\", part was \"".$part."\").\n";
}
}
} else {
if (!($parserState->{initbsCount} - scalar(@braceStack) )) { # Skip types
$parserState->{occparmlabelfound}++;
if ($occMethodNameDebug && ($parserState->{occparmlabelfound} > 0)) {
print STDERR "OCC possible label: \"$part\".\n";
}
}
}
}
}
if (length($part) && $part =~ /\S/o) { $lastnspart = $part; }
if ($parserState->{seenTilde} && length($part) && $part !~ /\s/o) { $parserState->{seenTilde}--; }
$part = $nextpart;
if ($parserState->{leavingComment}) {
$parserState->{leavingComment} = 0;
}
# Do this at the end so it does not affect continuation handling.
if ($parserState->{inMacro} > 1 && !$bshandled) {
if ($part !~ /[ \t]/) {
print STDERR "BS RESET\n" if ($parseDebug || $localDebug || $cppDebug || $macroDebug);
$parserState->resetBackslash();
print STDERR "ISQUOTED NOW: ".$parserState->isQuoted($lang, $sublang)."\n" if ($parseDebug || $localDebug || $cppDebug || $macroDebug);;
}
# Fall through.
};
if ($parserState->{rollbackPending}) {
$curline = $parserState->{preExternCcurline};
$declaration = $parserState->{preExternCdeclaration};
$parserState->rollback();
}
} # end foreach (parts of the current line)
if ($HeaderDoc::inputCounterDebug) {
print STDERR "continue: $continue IC: $inputCounter NLINES: $nlines\n";
}
} # end while (continue && ...)
if ($continue_no_return) {
return blockParse($fullpath, $fileoffset, $inputLinesRef, $inputCounter, $argparse, $ignoreref,
$perheaderignoreref, $perheaderignorefuncmacrosref, $keywordhashref, $case_sensitive, $lang, $sublang);
}
print STDERR "RETURNING DECLARATION\n" if ($localDebug);
# Format and insert curline into the declaration. This handles the
# trailing line. (Deprecated.)
if ($curline !~ /\n/) { $curline =~ s/^\s*//go; }
if ($curline =~ /\S/o) {
$scratch = nspaces($prespace);
$declaration .= "$scratch$curline\n";
}
print STDERR "($parserState->{typestring}, $parserState->{basetype})\n" if ($localDebug || $listDebug);
print STDERR "LS: $parserState->{lastsymbol}\n" if ($localDebug);
print STDERR "Last tree node set to $treeCur [14]\n" if ($parserStateInsertDebug);
$parserState->{lastTreeNode} = $treeCur;
$parserState->{inputCounter} = $inputCounter;
print STDERR "PARSERSTATE: $parserState\n" if ($localDebug);
if ($parserState->{inMacro} == 3) {
if (!$HeaderDoc::skipNextPDefine) {
cpp_add($treeTop, 0, $lang, $sublang);
} else {
cpp_add($treeTop, 1, $lang, $sublang);
$HeaderDoc::skipNextPDefine = 0;
}
}
print STDERR "LEFTBPMAIN\n" if ($localDebug || $hangDebug);
if ($argparse && $apwarn) {
print STDERR "end argparse\n";
}
# Return the top parser context even if we got interrupted.
my $tempParserState = pop(@parserStack);
$declaration = $parserState->{storeDec}.$declaration;
while ($tempParserState) {
$parserState = $tempParserState;
print STDERR "Last tree node set to $treeCur [15]\n" if ($parserStateInsertDebug);
$parserState->{lastTreeNode} = $treeCur;
$parserState->{inputCounter} = $inputCounter;
$tempParserState = pop(@parserStack);
$declaration = $parserState->{storeDec}.$declaration;
}
# $HeaderDoc::module = $parserState->{MODULE};
if ($localDebug || $apDebug || $liteDebug || $parseDebug || $hangDebug) {
print STDERR "LEAVING BLOCKPARSE\n";
}
if (0) {
print STDERR "Returning the following parse tree:\n";
$treeTop->dbprint();
print STDERR "End of parse tree.\n";
}
# print STDERR "FC: ".$parserState->{functionContents}."\n";
# print STDERR "DEFINENAME: \"$parseTokens{definename}\"\n";
return blockParseReturnState($parserState, $treeTop, $argparse, $declaration, $inPrivateParamTypes, $publicDeclaration, $lastACS, $retDebug, $fileoffset, 0, $parseTokens{definename}, $inputCounter, $lang, $sublang);
}
# /*!
# @abstract
# The magic box.
# @discussion
# The block parser consists of a fairly complex
# state machine. Inside it lies a complex state
# object that requires further interpretation if
# you want to derive any useful information from
# it.
#
# This code was originally part of the
# {@link blockParse} function itself. However,
# to improve class handling performance, the
# code was modified to reuse the previous class
# parse and extract information about each
# embedded method, etc. To support this, the
# parser state nformation needed to be stored
# in the parse tree and interpreted later.
# Thus, this portion was split off from the
# parser to interpret the structure when needed.
#
# This function is called in three main places:
# at the end of {@link blockParse}, in the
# {@link blockParseOutside} function when
# reprocessing a parse tree, and at the end of
# {@link //apple_ref/perl/instm/HeaderDoc::PythonParse/pythonParse//() pythonParse}.
#
# @param parserState
# The topmost parser state context object from {@link blockParse}.
# @param treeTop
# The top of the parser tree object from {@link blockParse}.
# @param argparse
# Set to 1 for parsing function arguments, enum constants,
# or struct fields, 2 for reparsing embedded
# HeaderDoc markup in a class, 0 otherwise. For more details,
# see {@link blockParse}.
# @param declaration
# The declaration returned by {@link blockParse}. If you pass
# an empty string, the declaration is obtained from the parse tree.
# @param inPrivateParamTypes
# Set to 1 if a C++ method with private parameters has been parsed
# and the public declaration needs to be restored.
# @param publicDeclaration
# The public declaration to restore.
# @param lastACS
# The access control state when the block parser finished, including
# any access control changes parsed this round.
# @param forcedebug
# Set to 1 to dump lots of debug information.
# @param fileoffset
# The base line number of the
# {@link //apple_ref/perl/cl/HeaderDoc::LineRange LineRange}
# object containing this declaration. In subparse mode (reprocessing
# a declaration embedded in a class), this value gets overwritten with
# the correct value from the tree. Thus, this value is only relevant
# when this function is called from {@link blockParse} itself.
# @param subparse
# Set to 0 when this is called from {@link blockParse}. Set to 1
# when reinterpreting a parse tree obtained from a declaration within
# a class.
# @param definename
# The token for #define. Used to determine whether to run a
# separate parser to extract the #define macro parameters.
# @param inputCounter
# The line number relative to the start of the
# {@link //apple_ref/perl/cl/HeaderDoc::LineRange LineRange}
# object containing this declaration. In subparse mode (reprocessing
# a declaration embedded in a class), this value gets overwritten with
# the correct value from the tree. Thus, this value is only relevant
# when this function is called from {@link blockParse} itself.
#
# @vargroup External variables
#
# @var HeaderDoc::outerNamesOnly
# Set by the -O flag.
# */
sub blockParseReturnState
{
my $parserState = shift;
my $treeTop = shift;
my $argparse = shift;
my $declaration = shift; # optional
my $inPrivateParamTypes = shift; # optional
my $publicDeclaration = shift; # optional
my $lastACS = shift; # optional
my $forcedebug = shift; # optional
my $fileoffset = shift; # optional
my $subparse = shift;
my $definename = shift;
my $inputCounter = shift;
my $lang = shift;
my $sublang = shift;
my $fullpath = $parserState->{FULLPATH};
my $nameObjDumpDebug = 0;
# $forcedebug = 1;
if ($forcedebug) { $parserState->dbprint(); }
if ($forcedebug) { $treeTop->dbprint(); }
$forcedebug = $forcedebug || $HeaderDoc::fileDebug;
my $subparseDebug = 0;
my $localDebug = 0 || $forcedebug;
my $sodDebug = 0 || $forcedebug;
my $parseDebug = 0 || $forcedebug;
my $listDebug = 0 || $forcedebug;
my $parmDebug = 0 || $forcedebug;
my $retDebug = 0 || $forcedebug;
if (!length($declaration)) {
$declaration = $treeTop->textTree();
}
my $perlClassPrefix = "";
if ($parserState->{perlClassName}) {
$perlClassPrefix = $parserState->{perlClassName};
}
cluck("PARSERSTATE IS $parserState\n") if ($localDebug);
if ($forcedebug) { $parserState->print(); }
if ($forcedebug) { print STDERR "FD\n"; }
# my $lang = $parserState->{lang};
# my $sublang = $parserState->{sublang};
# print STDERR "SL: $sublang STATE: $parserState\n";
my $pascal = 0;
if ($lang eq "pascal") { $pascal = 1; }
my $perl_or_shell = 0;
if ($lang eq "perl" || $lang eq "shell") {
# IMPORTANT: TCL is NOT a shell for these purposes because it has
# tokens of the form foo::bar.
$perl_or_shell = 1;
}
if ($parserState->{seenElse} && $parserState->{functionContents} && !$parserState->{elseContents}) {
$parserState->{elseContents} = $parserState->{functionContents};
$parserState->{functionContents} = "";
} elsif ($parserState->{seenIf} && $parserState->{functionContents} && !$parserState->{ifContents}) {
$parserState->{ifContents} = $parserState->{functionContents};
$parserState->{functionContents} = "";
}
my $returntype = $parserState->{returntype};
my $sodtype = $parserState->{sodtype};
my $sodname = $perlClassPrefix.$parserState->{sodname};
my $basetype = $parserState->{basetype};
my $callbackName = $parserState->{callbackName};
my $psName = $parserState->{name};
my $posstypes = $parserState->{posstypes};
my $sodclass = $parserState->{sodclass};
my $value = $parserState->{value};
my $simpleTDcontents = $parserState->{simpleTDcontents};
my $availability = $parserState->{availability};
if ($parserState->{variabletype}) {
$returntype = $parserState->{variabletype};
$sodtype = $parserState->{variabletype};
}
# TCL is a little odd.
if ($lang eq "tcl" && $parserState->{inClass}) {
$sodclass = "class";
$parserState->{sodclass} = "class";
$sodtype = join(",", @{$parserState->{pplStack}});
$parserState->{classtype} = "class";
print "SETTING sodtype TO $sodtype\n" if ($forcedebug);
}
if ($lang eq "applescript" && $parserState->{sodclass} eq "class") {
$sodclass = "script";
$parserState->{sodclass} = "script";
}
# AppleScript supports multi-word names, but does not support
# types.
if ($lang eq "applescript") {
if (length($sodtype)) {
$sodname = "$sodtype $sodname";
$sodname =~ s/^\s*//sg;
$sodtype = "";
$parserState->{frozensodname} = $sodname;
}
}
# if ($localDebug || 1) {
# print STDERR "Preliminary parsed parameters:\n";
# my $count = 1;
# foreach my $ppl (@{$parserState->{parsedParamList}}) {
# print STDERR "Parameter $count:\n";
# print STDERR $ppl."\n";
# }
# print STDERR "End preliminary parsed parameters:\n";
# }
if ($pascal && $parserState->{nameList}) {
$sodtype = $sodtype . $sodname;
$sodname = "";
# $sodname = $parserState->{nameList};
}
# if ($sodclass eq "variable") {
# if ($parserState->{constKeywordFound}) {
# $sodclass = "constant";
# }
# }
if ($subparse) {
$inputCounter = $parserState->{inputCounter};
}
my $extendsClass = cppsupers($parserState->{extendsClass}, $lang, $sublang);
my $implementsClass = cppsupers($parserState->{implementsClass}, $lang, $sublang);
print STDERR "PS: $parserState\n" if ($localDebug);
my @parsedParamList = @{$parserState->{parsedParamList}};
my @pplStack = @{$parserState->{pplStack}};
my @freezeStack = @{$parserState->{freezeStack}};
if ($parserState->{prekeywordsodname}) {
print STDERR "RESTORING PRE-KEYWORD SODNAME: $sodname -> $parserState->{prekeywordsodname}\n" if ($localDebug);
$sodname = $parserState->{prekeywordsodname};
$sodtype = $parserState->{prekeywordsodtype};
}
if ($parserState->{stackFrozen}) {
print STDERR "RESTORING SODNAME: $sodname -> $parserState->{frozensodname}\n" if ($localDebug);
$sodname = $parserState->{frozensodname};
}
# if ($parserState->{simpleTypedef}) { $psName = ""; }
my $conformsToList = $parserState->{conformsToList};
# From here down is a bunch of code for determining which names
# for a given type/function/whatever are legit and which aren't.
# It is mostly a priority scheme. The data type names are first,
# and thus lowest priority.
my @nameObjects = ();
my $typelist = "";
my $namelist = "";
my $rawnamelist = $parserState->{lastsymbol};
if ($pascal) {
$rawnamelist = $parserState->{nameList};
}
# print STDERR "RNL: \"".$parserState->{nameList}."\"\n";
my @variableAltNameObjects = ();
my @names = split(/[,\s;]/, $rawnamelist);
if ($parserState->{variablenames}) {
my %temp = %{$parserState->{variablenames}};
@names = keys %temp;
my $stars = "";
# print STDERR "RT: ".$parserState->{returntype}."\n";
my $temprt = $parserState->{returntype};
if ($temprt =~ s/(\**)\s*$//s) {
$stars = $1;
}
if ($parserState->{variablestars}) {
my %stars = %{$parserState->{variablestars}};
$stars{$sodname} = $stars;
$parserState->{variablestars} = \%stars;
# print STDERR "SODNAME STARS: $stars (sodname is \"$sodname\")\n";
}
}
foreach my $insname (@names) {
my $origname = $insname;
# print "NAME: $insname\n";
if ($insname =~ /\S/) {
$insname =~ s/\s//so;
$insname =~ s/^[*^]//sgo;
my $newtype = $parserState->{typestring};
if ($pascal && ($parserState->{waitingForTypeInformation})) {
$newtype = $sodclass;
}
if (length($insname)) {
$typelist .= " $newtype";
$namelist .= ",$insname";
}
# print STDERR "INSNAME: $insname\n";
my $nameobj = HeaderDoc::TypeHelper->new();
$nameobj->{NAME} = $insname;
$nameobj->{TYPE} = $newtype;
# print STDERR "HERE\n";
if ($parserState->{variablestars}) {
# print STDERR "HEREB ($origname)\n";
my %stars = %{$parserState->{variablestars}};
# print STDERR "STARSB: ".$stars{$origname}."\n";
$nameobj->{STARS} = $stars{$origname};
# print STDERR "STARS: ".$nameobj->{STARS}."\n";
}
$nameobj->{POSSTYPES} = $posstypes;
$nameobj->{EXTENDSCLASS} = $extendsClass;
$nameobj->{IMPLEMENTSCLASS} = $implementsClass;
$nameobj->{INSERTEDAT} = "names";
push(@nameObjects, $nameobj);
if ($parserState->{variablenames}) {
push(@variableAltNameObjects, $nameobj);
}
}
}
$typelist =~ s/^ //o;
$namelist =~ s/^,//o;
# print STDERR "TLPOINT: \"$typelist\"\n";
if ($pascal) {
# Pascal only has one name for a type, and it follows the word "type"
if (!length($typelist)) {
$typelist .= "$parserState->{typestring}";
$namelist .= "$psName";
my $nameobj = HeaderDoc::TypeHelper->new();
$nameobj->{NAME} = $psName;
$nameobj->{TYPE} = $parserState->{typestring};
$nameobj->{POSSTYPES} = $posstypes;
$nameobj->{EXTENDSCLASS} = $extendsClass;
$nameobj->{IMPLEMENTSCLASS} = $implementsClass;
$nameobj->{INSERTEDAT} = "Pascal type";
push(@nameObjects, $nameobj);
}
}
print STDERR "TL (PRE): $typelist\n" if ($localDebug);
if (!length($basetype)) { $basetype = $parserState->{typestring}; }
print STDERR "BT: $basetype\n" if ($localDebug);
print STDERR "NAME is $psName\n" if ($localDebug || $listDebug);
# print STDERR $HeaderDoc::outerNamesOnly . " or " . length($namelist) . ".\n";
# If the name field contains a value, and if we've seen at least one brace or parenthesis
# (to avoid "typedef struct foo bar;" giving us an empty declaration for struct foo), and
# if either we want tag names (foo in "struct foo { blah } foo_t") or there is no name
# other than a tag name (foo in "struct foo {blah}"), then we give the tag name. Scary
# little bit of logic. Sorry for the migraine.
# Note: at least for argparse == 2 (used when handling nested headerdoc
# markup), we don't want to return more than one name/type EVER.
# if (($psName && length($psName) && !$parserState->{simpleTypedef} && (!($HeaderDoc::outerNamesOnly || $argparse == 2) || !length($namelist))) || ($namelist !~ /\w/))
if (($psName && length($psName) && !$parserState->{simpleTypedef} && (!($HeaderDoc::outerNamesOnly || $argparse == 2) || !scalar(@nameObjects))) || !scalar(@nameObjects)) { # || ($namelist !~ /\w/))
print STDERR "NAME BLOCK BEGIN\nNM: \"$psName\"\nSTD: $parserState->{simpleTypedef}\nONO: ".$HeaderDoc::outerNamesOnly."\nAP: $argparse\nLNL: \"".$namelist."\" (".length($namelist).")\nNAME BLOCK END\n" if ($localDebug);
if ((!length($psName)) || $namelist !~ /\Q$psName\E/) {
print STDERR "NAME AND TYPE APPENDED\n" if ($localDebug);
if (length($namelist)) {
$namelist .= ",";
$typelist .= " ";
}
$namelist .= "$psName";
$typelist .= "$basetype";
my $nameobj = HeaderDoc::TypeHelper->new();
$nameobj->{NAME} = $psName;
$nameobj->{TYPE} = $basetype;
if (!scalar(@nameObjects)) {
# If this is the only name, set possible types.
$nameobj->{POSSTYPES} = $posstypes;
} else {
# Otherwise, it's a tag name for a typedef struct,
# eg. iname in "typedef struct iname {...} foo_t;"
# and it is really just a struct, not a typedef.
$nameobj->{POSSTYPES} = $basetype;
}
# @@@ FOR NOW
$nameobj->{POSSTYPES} = $posstypes;
$nameobj->{EXTENDSCLASS} = $extendsClass;
$nameobj->{IMPLEMENTSCLASS} = $implementsClass;
$nameobj->{INSERTEDAT} = "Variable, enum, etc.";
push(@nameObjects, $nameobj);
}
} else {
# if we never found the name, it might be an anonymous enum,
# struct, union, etc.
print STDERR "Poss Anon Case\n" if ($localDebug);
if (!scalar(@names)) {
print STDERR "Empty output ($basetype, $parserState->{typestring}).\n" if ($localDebug || $listDebug);
$namelist = " ";
$typelist = "$basetype";
my $nameobj = HeaderDoc::TypeHelper->new();
$nameobj->{NAME} = "";
$nameobj->{TYPE} = $basetype;
$nameobj->{POSSTYPES} = $posstypes;
$nameobj->{EXTENDSCLASS} = $extendsClass;
$nameobj->{IMPLEMENTSCLASS} = $implementsClass;
$nameobj->{INSERTEDAT} = "Anonymous enum";
push(@nameObjects, $nameobj);
}
print STDERR "NUMNAMES: ".scalar(@names)."\n" if ($localDebug || $listDebug);
}
print STDERR "NL: \"$namelist\".\n" if ($localDebug || $listDebug);
print STDERR "TL: \"$typelist\".\n" if ($localDebug || $listDebug);
print STDERR "PT: \"$posstypes\"\n" if ($localDebug || $listDebug);
print STDERR "SN: \"$sodname\"\nST: \"$sodtype\"\nSC: \"$sodclass\"\n" if ($localDebug || $sodDebug);
my $destructor = 0;
if ($sodtype =~ s/\~$//s) {
$sodname = "~" . $sodname;
$destructor = 1;
}
# If it's a callback, the other names and types are bogus. Throw them away.
$callbackName =~ s/^.*:://o;
$callbackName =~ s/^[*^]+//o;
print STDERR "CBN: \"$callbackName\"\n" if ($localDebug || $listDebug);
print STDERR "CBNP: \"$parserState->{callbackNamePending}\"\n" if ($localDebug || $listDebug);
print STDERR "CBSN: \"$parserState->{cbsodname}\"\n" if ($localDebug || $listDebug);
if (length($callbackName)) {
if (length($parserState->{cbsodname})) {
$callbackName = $parserState->{cbsodname};
}
$psName = $callbackName;
print STDERR "DEC: \"$declaration\"\n" if ($localDebug || $listDebug);
my $cbtype = "";
$namelist = $psName;
if ($parserState->{callbackIsTypedef}) {
$cbtype = "typedef";
$typelist = "typedef";
$posstypes = "function";
} else {
$cbtype = "callback";
$typelist = "callback";
$posstypes = "function typedef";
}
@nameObjects = ();
my $nameobj = HeaderDoc::TypeHelper->new();
$nameobj->{NAME} = $psName;
$nameobj->{TYPE} = $cbtype;
$nameobj->{POSSTYPES} = $posstypes;
$nameobj->{EXTENDSCLASS} = $extendsClass;
$nameobj->{IMPLEMENTSCLASS} = $implementsClass;
$nameobj->{INSERTEDAT} = "callback";
if ($parserState->{callbackIsTypedef}) {
$nameobj->{ISCALLBACK} = 1;
}
push(@nameObjects, $nameobj);
print STDERR "NL: \"$namelist\".\n" if ($localDebug || $listDebug);
print STDERR "TL: \"$typelist\".\n" if ($localDebug || $listDebug);
print STDERR "PT: \"$posstypes\"\n" if ($localDebug || $listDebug);
# my $newdec = "";
# my $firstpart = 2;
# foreach my $decpart (split(/\n/, $declaration)) {
# if ($firstpart == 2) {
# $newdec .= "$decpart ";
# $firstpart--;
# } elsif ($firstpart) {
# $decpart =~ s/^\s*//o;
# $newdec .= "$decpart\n";
# $firstpart--;
# } else {
# $newdec .= "$decpart\n";
# }
# }
# $declaration = $newdec;
}
if (length($parserState->{preTemplateSymbol}) && ($sodclass eq "function")) {
print STDERR "Template function detected. Changing sodname from ".$sodname." to ".$parserState->{preTemplateSymbol}."\n" if ($localDebug || $sodDebug);
$sodname = $parserState->{preTemplateSymbol};
$sodclass = "ftmplt";
print STDERR "sodclass -> ftmplt (return state)[13]\n" if ($sodDebug);
$posstypes = "ftmplt function method"; # can it really be a method?
changeAll(\@nameObjects, "POSSTYPES", "ftmplt function method", 0); # may be no-op.
}
# If it isn't a constant, the value is something else. Otherwise,
# the variable name is whatever came before the equals sign.
print STDERR "TVALUE: $value\n" if ($localDebug);
print STDERR "SC: \"".$sodclass."\"\n" if ($localDebug);
my $holdtypelist = 0;
if ($sodclass ne "variable") {
$value = "";
} elsif (length($value) || ($sodclass eq "variable")) {
my $varDebug = 0;
my $reset_name = 0;
if (length($value)) {
$reset_name = 1;
}
# If we have a variable whose type starts with "class" or similar, restore that token here.
if ($parserState->{sodtypeclasstoken} && !$parserState->{ISFORWARDDECLARATION}) {
$sodtype =~ s/^\s*//s;
$sodtype = $parserState->{sodtypeclasstoken}." ".$sodtype;
}
# print STDERR "TYPELIST: $typelist\n";
# print STDERR "PRE VALUE: ".$value."\n";
# print STDERR "PT: ".$posstypes."\n";
$value =~ s/^\s*//so;
$value =~ s/\s*$//so;
if ($parserState->{constKeywordFound}) {
print STDERR "const keyword found\n" if ($localDebug || $sodDebug || $varDebug);
$sodclass = "constant";
print STDERR "sodclass -> constant (return state)[14]\n" if ($sodDebug);
$typelist = "constant";
$posstypes = "variable";
changeAll(\@nameObjects, "TYPE", "constant", 0);
changeAll(\@nameObjects, "POSSTYPES", "variable", 0);
} else {
print STDERR "const keyword NOT found\n" if ($localDebug || $sodDebug || $varDebug);
$sodclass = "variable";
print STDERR "sodclass -> variable (return state)[15]\n" if ($sodDebug);
$typelist = "variable";
$posstypes = "constant";
changeAll(\@nameObjects, "TYPE", "variable", 0);
changeAll(\@nameObjects, "POSSTYPES", "constant", 0);
}
$holdtypelist = 1;
print STDERR "Variable detected. Changing sodname from ".$sodname." to ".$parserState->{preEqualsSymbol}."\n" if ($localDebug || $sodDebug || $varDebug);
print STDERR "Changing sodclass to ".$sodclass."\nChanging posstypes to ".$posstypes."\n" if ($localDebug || $sodDebug || $varDebug);
print STDERR "TYPELIST IS ".$typelist."\n" if ($localDebug || $sodDebug || $varDebug);
if ($reset_name) {
$sodname = $parserState->{preEqualsSymbol};
}
}
# We lock in the name prior to walking through parameter names for
# K&R C-style declarations. Restore that name first.
if (length($parserState->{kr_c_name})) {
print STDERR "K&R C declaration detected. Changing sodname from ".$sodname." to ".$parserState->{kr_c_name}."\n" if ($localDebug || $sodDebug);
$sodname = $parserState->{kr_c_name};
$sodclass = "function";
print STDERR "sodclass -> function (return state)[16]\n" if ($sodDebug);
}
# Okay, so now if we're not an objective C method and the sod code decided
# to specify a name for this function, it takes precendence over other naming.
if (length($sodname) && !$parserState->{occmethod}) {
if (!length($callbackName)) { # && $parserState->{callbackIsTypedef}
if ((!$perl_or_shell) || (!length($psName))) {
$psName = $sodname;
$namelist = $psName;
@nameObjects = @variableAltNameObjects;
my $nameobj = HeaderDoc::TypeHelper->new();
$nameobj->{NAME} = $psName;
$nameobj->{TYPE} = $sodclass;
if ($parserState->{variablestars}) {
# print STDERR "HEREC ($psName)\n";
my %stars = %{$parserState->{variablestars}};
# print STDERR "STARSC: ".$stars{$psName}."\n";
$nameobj->{STARS} = $stars{$psName};
# print STDERR "STARS: ".$nameobj->{STARS}."\n";
}
$nameobj->{POSSTYPES} = $posstypes;
$nameobj->{EXTENDSCLASS} = $extendsClass;
$nameobj->{IMPLEMENTSCLASS} = $implementsClass;
$nameobj->{INSERTEDAT} = "sodname (functions, mostly)";
push(@nameObjects, $nameobj);
} else {
changeAll(\@nameObjects, "TYPE", $sodclass, 0);
}
$typelist = "$sodclass";
if (!length($parserState->{preTemplateSymbol}) && !$holdtypelist) {
$posstypes = "$sodclass";
changeAll(\@nameObjects, "POSSTYPES", $sodclass, 0);
}
print STDERR "SETTING NAME/TYPE TO $sodname, $sodclass\n" if ($sodDebug);
if ($sodclass eq "function") {
$posstypes .= " method";
changeAll(\@nameObjects, "POSSTYPES", "method", 1);
}
}
}
# If we're an objective C method, obliterate everything and just
# shove in the right values.
print STDERR "DEC: $declaration\n" if ($sodDebug || $localDebug);
if ($parserState->{occmethod}) {
$typelist = "method";
changeAll(\@nameObjects, "TYPE", "method", 0);
$posstypes = "method function";
changeAll(\@nameObjects, "POSSTYPES", "method function", 0);
if ($parserState->{occmethod} == 2) {
$namelist = "$parserState->{occmethodname}";
@nameObjects = ();
my $nameobj = HeaderDoc::TypeHelper->new();
$nameobj->{NAME} = $parserState->{occmethodname};
$nameobj->{TYPE} = "method";
$nameobj->{POSSTYPES} = "method function";
$nameobj->{EXTENDSCLASS} = $extendsClass;
$nameobj->{IMPLEMENTSCLASS} = $implementsClass;
$nameobj->{INSERTEDAT} = "occmethod";
push(@nameObjects, $nameobj);
}
}
# If we're a macro... well, this gets ugly. We rebuild the parsed
# parameter list from the declaration and otherwise use the name grabbed
# by the sod code.
if ($parserState->{inMacro} == 3) {
$typelist = "#define";
$posstypes = "function method";
$namelist = $sodname;
@nameObjects = ();
my $nameobj = HeaderDoc::TypeHelper->new();
$nameobj->{NAME} = $sodname;
$nameobj->{TYPE} = "#define";
$nameobj->{POSSTYPES} = "function* method*";
$nameobj->{EXTENDSCLASS} = $extendsClass;
$nameobj->{IMPLEMENTSCLASS} = $implementsClass;
$nameobj->{INSERTEDAT} = "CPP define";
push(@nameObjects, $nameobj);
$value = "";
@parsedParamList = ();
my $declaration = $treeTop->textTree();
# cluck("DEFINENAME IS \"$definename\"\n");
# @@@ Do this right?
if ($definename && $declaration =~ /$definename\s+\w+\(/) {
if (!$parserState->{cppMacroHasArgs}) {
warn("Dec match but not args match. Please file a bug and\ninclude a copy of this header.\n".$declaration);
}
}
if ($parserState->{cppMacroHasArgs}) {
if ($definename && $declaration !~ /$definename\s+\w+\(/) {
warn("Args match but not dec match. Please file a bug and\ninclude a copy of this header.\n".$declaration);
}
}
# print STDERR "PS $parserState HAS ARGS: ".$parserState->{cppMacroHasArgs}."\n";
if ($parserState->{cppMacroHasArgs}) {
# if ($definename && $declaration =~ /$definename\s+\w+\(/) { }
my $pplref = defParmParse($declaration, $inputCounter, $definename, $forcedebug, $fullpath);
print STDERR "parsedParamList replaced\n" if ($parmDebug);
@parsedParamList = @{$pplref};
} else {
# It can't be a function-like macro, but it could be
# a constant.
$posstypes = "constant";
changeAll(\@nameObjects, "POSSTYPES", "constant", 0);
}
} elsif ($parserState->{inMacro} == 4) {
$typelist = "MACRO";
$posstypes = "MACRO";
$value = "";
@parsedParamList = ();
changeAll(\@nameObjects, "TYPE", "MACRO", 0);
changeAll(\@nameObjects, "POSSTYPES", "MACRO", 0);
}
# If we're an operator, our type is 'operator', not 'function'. Our fallback
# name is 'function'.
if ($parserState->{inOperator}) {
$typelist = "operator";
$posstypes = "function";
changeAll(\@nameObjects, "TYPE", "operator", 0);
changeAll(\@nameObjects, "POSSTYPES", "function", 0);
}
# if we saw private parameter types, restore the first declaration (the
# public part) and store the rest for later. Note that the parse tree
# code makes this deprecated.
my $privateDeclaration = "";
if ($inPrivateParamTypes) {
$privateDeclaration = $declaration;
$declaration = $publicDeclaration;
}
print STDERR "TYPELIST WAS \"$typelist\"\n" if ($localDebug);;
# warn("left blockParse (macro)\n");
print STDERR "NumPPs: ".scalar(@parsedParamList)."\n" if ($localDebug);
# $treeTop->printTree();
# If we have parsed parameters that haven't been pushed onto
# the stack of parsed parameters, push them now.
if (scalar(@parsedParamList)) {
foreach my $stackitem (@parsedParamList) {
$stackitem =~ s/^\s*//so;
$stackitem =~ s/\s*$//so;
if (length($stackitem)) {
push(@pplStack, $stackitem);
}
}
}
# Restore the frozen stack (to avoid bogus parameters after
# the curly brace for inline functions/methods)
if ($parserState->{stackFrozen}) {
@pplStack = @freezeStack;
}
if ($localDebug) {
foreach my $stackitem (@pplStack) {
print STDERR "stack contained $stackitem\n";
}
}
# If we have a C++ struct that looks like a class (struct foo : bar {...})
# then we need to pick off the class name.
if ($parserState->{structClassName}) {
print STDERR "CHANGING NAME FROM $namelist to $parserState->{structClassName}.\n" if ($localDebug);
$namelist = $parserState->{structClassName};
@nameObjects = ();
my $nameobj = HeaderDoc::TypeHelper->new();
$nameobj->{NAME} = $parserState->{structClassName};
$nameobj->{TYPE} = "struct"; # @@@ CHECK ME DAG
$nameobj->{POSSTYPES} = "";
$nameobj->{EXTENDSCLASS} = $extendsClass;
$nameobj->{IMPLEMENTSCLASS} = $implementsClass;
$nameobj->{INSERTEDAT} = "Struct Class";
push(@nameObjects, $nameobj);
}
# If we have a simple typedef, do some formatting on the contents.
# This is used by the upper layers so that if you have
# "typedef struct myStruct;", you can associate the fields from
# "struct myStruct" with the typedef, thus allowing more
# flexibility in tagged/parsed parameter comparison.
#
$simpleTDcontents =~ s/^\s*//so;
$simpleTDcontents =~ s/\s*;\s*$//so;
if ($simpleTDcontents =~ s/\s*\w+$//so) {
my $continue = 1;
while ($simpleTDcontents =~ s/\s*,\s*$//so) {
$simpleTDcontents =~ s/\s*\w+$//so;
}
}
if (length($simpleTDcontents)) {
my $psc = @pplStack;
print STDERR "SIMPLETYPEDEF: $inputCounter, $declaration, $typelist, $namelist, $posstypes, $value, OMITTED $psc, $returntype, $privateDeclaration, $treeTop, $simpleTDcontents, $availability\n" if ($parseDebug || $sodDebug || $localDebug);
$typelist = "typedef";
if (length($sodname)) {
# typedefs w/o struct/enum/union, e.g. "typedef uint32_t foo;"
# don't have a sodname, so we'd better return something....
$namelist = $sodname;
@nameObjects = ();
my $nameobj = HeaderDoc::TypeHelper->new();
$nameobj->{NAME} = $sodname;
$nameobj->{TYPE} = "typedef";
$nameobj->{POSSTYPES} = "";
$nameobj->{EXTENDSCLASS} = $extendsClass;
$nameobj->{IMPLEMENTSCLASS} = $implementsClass;
$nameobj->{INSERTEDAT} = "Simple typedef";
push(@nameObjects, $nameobj);
} else {
changeAll(\@nameObjects, "TYPE", "typedef", 0);
changeAll(\@nameObjects, "POSSTYPES", "", 0);
}
$posstypes = "";
}
# If we have a class, do some funky stuff.
if ($parserState->{inClass} || $parserState->{inProtocol}) {
# if ($parserState->{inProtocol}) {
# print STDERR "PROTOCOL\n";
# $localDebug = 1;
# }
print STDERR "INCLASS!\n" if ($localDebug);
print STDERR "SODNAME WAS $sodname\n" if ($localDebug);
print STDERR "PTS: $parserState->{preTemplateSymbol}\n" if ($localDebug);
$declaration = $treeTop->textTree();
$sodtype =~ s/^\s*//s;
my @classparts = split(/\s/, $sodtype, 2);
my $classname = "";
my $superclass = "";
# print STDERR "RETURNING CLASS: SODTYPE IS $sodtype\n";
if (scalar(@classparts)) {
print STDERR "CLASSPARTS FOUND.\n" if ($localDebug);
$classname = $classparts[0];
$superclass = $sodname;
# $classparts[0]." : $sodname";
} else {
print STDERR "NO CLASSPARTS FOUND.\n" if ($localDebug);
$classname = $sodname;
$superclass = "";
}
if ($parserState->{inProtocol}) {
# Get the class name a different way.
$superclass = $parserState->{extendsProtocol};
$superclass =~ s/\s+//sg;
$superclass =~ s/,,/,/sg;
$superclass =~ s/^,//sg;
$superclass =~ s/,$//sg;
$superclass =~ s/,/\cA/sg;
print STDERR "PROTOCOLSUPER: $superclass\n" if ($localDebug);
}
$namelist = $classname;
@nameObjects = ();
my $nameobj = HeaderDoc::TypeHelper->new();
$nameobj->{NAME} = $classname;
$nameobj->{TYPE} =$parserState->{classtype};
$nameobj->{POSSTYPES} = "$superclass"; # @@@ IS THIS RIGHT?
$nameobj->{EXTENDSCLASS} = $extendsClass;
$nameobj->{IMPLEMENTSCLASS} = $implementsClass;
$nameobj->{INSERTEDAT} = "class[1]";
push(@nameObjects, $nameobj);
# print STDERR "RETURNING CLASS: NAMELIST IS $classname\n";
$typelist = "$parserState->{classtype}";
$posstypes = "$superclass";
print STDERR "SET posstypes to \"$superclass\"\n" if ($localDebug);
changeAll(\@nameObjects, "TYPE", $parserState->{classtype}, 0);
changeAll(\@nameObjects, "POSSTYPES", $superclass, 0);
print STDERR "SUPER WAS \"$superclass\"\n" if ($localDebug);
print STDERR "categoryClass is $parserState->{categoryClass}\n" if ($localDebug || $parseDebug);
if (length($parserState->{categoryClass})) {
$posstypes = $namelist;
$posstypes =~ s/\s*//sg;
$namelist .= $parserState->{categoryClass};
$namelist =~ s/\s*//sg;
print STDERR "NL: $namelist\n" if ($localDebug || $parseDebug);
changeAll(\@nameObjects, "POSSTYPES", $posstypes, 0);
$nameObjects[0]->{NAME} .= $parserState->{categoryClass};
$nameObjects[0]->{NAME} =~ s/\s*//sg;
$nameObjects[0]->{TYPE} = $parserState->{classtype};
$nameObjects[0]->{POSSTYPES} = $posstypes; # @@@ IS THIS RIGHT?
$nameobj->{EXTENDSCLASS} = $extendsClass;
$nameobj->{IMPLEMENTSCLASS} = $implementsClass;
$nameObjects[0]->{INSERTEDAT} = "class[2cat]";
my $nameobj = $nameObjects[0];
@nameObjects = ();
push(@nameObjects, $nameobj);
}
}
if ($parserState->{forceClassName}) {
$namelist = $parserState->{forceClassName};
$posstypes = cppsupers($parserState->{forceClassSuper}, $lang, $sublang);
print STDERR "CPPSUPERS: $posstypes\n" if ($localDebug);
@nameObjects = ();
my $nameobj = HeaderDoc::TypeHelper->new();
$nameobj->{NAME} = $parserState->{forceClassName};
$nameobj->{TYPE} = $parserState->{classtype};
$nameobj->{POSSTYPES} = cppsupers($parserState->{forceClassSuper}, $lang, $sublang); # @@@ IS THIS RIGHT?
$nameobj->{EXTENDSCLASS} = $extendsClass;
$nameobj->{IMPLEMENTSCLASS} = $implementsClass;
$nameobj->{INSERTEDAT} = "class[3force]";
push(@nameObjects, $nameobj);
}
if ($parserState->{occSuper}) {
$posstypes = $parserState->{occSuper};
changeAll(\@nameObjects, "POSSTYPES", $parserState->{occSuper}, 0);
}
$returntype = decomment($returntype);
# print STDERR "Return type was: $returntype\n" if ($argparse || $sodclass eq "function" || $parserState->{occmethod});
if (($lang eq "pascal" && length($sodtype)) ||
($lang ne "pascal" && (length($sodname) && !$parserState->{occmethod}))) {
# print "SODTYPE IS ".$sodtype."\n";
$sodtype =~ s/\* \*/**/g;
# If you consider trailing brackets to be part of the type, enable these lines:
# if ($parserState->{sodbrackets}) {
# $sodtype .= $parserState->{sodbrackets};
# }
# Note: the following code was added while tracking down a bug. Do not reenable this. This warning
# will flag a lot of valid changes as warnings.
# $b = $returntype;
# $a = $sodtype;
# $a =~ s/^\s*//sg; $a =~ s/\s*$//sg;
# $b =~ s/^\s*//sg; $b =~ s/\s*$//sg;
# if ($a ne $b) {
# print STDERR "WARNING: CHANGED RETURN TYPE FROM ".$returntype." TO ".$sodtype."\n";
# $treeTop->dbprint();
# }
if (!$pascal) {
$returntype = $sodtype;
print STDERR "REPLACING RETURNTYPE[4]: NOW \"$returntype\".\n" if ($retDebug);
} elsif ($parserState->{waitingForTypeInformation}) {
$returntype =~ s/^\s*:\s*//s;
$returntype =~ s/\s*;\s*$//s;
}
# print STDERR "NEW RT: $returntype\n";
}
if (length($parserState->{occmethodreturntype})) {
$returntype = decomment($parserState->{occmethodreturntype});
}
# print STDERR "Return type: $returntype\n" if ($argparse || $sodclass eq "function" || $parserState->{occmethod});
# print STDERR "DEC: $declaration\n" if ($argparse || $sodclass eq "function" || $parserState->{occmethod});
print STDERR "PTDEC: ".$treeTop->textTree()."\n" if ($localDebug || $retDebug);
if ($parserState->{INMODULE}) {
print STDERR "MODULE DETECTED\n" if ($localDebug);
$sodclass = "module";
print STDERR "sodclass -> module (return state)\n[17]" if ($sodDebug);
}
cluck("Backtrace\n") if ($localDebug);
print STDERR "RETURNING NAMELIST: \"$namelist\"\nRETURNING TYPELIST: \"$typelist\"\n" if ($localDebug || $retDebug);
if (length($lastACS)) {
$HeaderDoc::AccessControlState = $lastACS;
}
print STDERR "LEFTBP\n" if ($localDebug);
if ($parserState->{isProperty}) {
print STDERR "isProperty Set.\n" if ($localDebug || $listDebug);
$typelist = "property";
$posstypes="property variable* function* method*";
$sodclass="";
print STDERR "sodclass -> \"\" (return state)[18]\n" if ($sodDebug);
changeAll(\@nameObjects, "TYPE", "property", 0);
changeAll(\@nameObjects, "POSSTYPES", "property variable* function* method*", 0);
# Eliminate bogus parameter tag warnings about (copy), etc.
@parsedParamList = ();
@pplStack = ();
}
if ($pascal && ($sodclass eq "enum")) {
$posstypes = "constant variable";
changeAll(\@nameObjects, "POSSTYPES", "constant variable", 0);
}
print STDERR "UPDATED:\n" if ($localDebug || $listDebug);
print STDERR "NL: \"$namelist\".\n" if ($localDebug || $listDebug);
print STDERR "TL: \"$typelist\".\n" if ($localDebug || $listDebug);
print STDERR "PT: \"$posstypes\"\n" if ($localDebug || $listDebug);
print STDERR "SN: \"$sodname\"\nST: \"$sodtype\"\nSC: \"$sodclass\"\n" if ($localDebug || $sodDebug);
if ($typelist !~ /\#define/) {
# Availability is meaningless for a macro, and worse, macros can be used to define new
# availability macros, which would cause this to just plain misbehave.
$availability = mergeComplexAvailability($availability, $parserState->{availabilityNodesArray});
}
print STDERR "SUBPARSE: $subparse NAME: $namelist TTIC: ".$treeTop->{INPUTCOUNTER}." TTBO: ".$treeTop->{BLOCKOFFSET}."\n" if ($subparseDebug);
if ($subparse && defined($treeTop->{INPUTCOUNTER})) { $inputCounter = $treeTop->{INPUTCOUNTER}; } elsif ($subparse) { warn("Line numbers may be wrong [1].\n"); }
if ($subparse && defined($treeTop->{BLOCKOFFSET})) { $fileoffset = $treeTop->{BLOCKOFFSET}; } elsif ($subparse) { warn("Line numbers may be wrong [2].\n"); }
if ($parserState->{ISFORWARDDECLARATION}) {
$typelist = "forwarddeclaration-$typelist";
# print STDERR "FORWARD DECLARATION NAMELIST: $namelist\n";
}
# print STDERR "TREE TOP GOING OUT IS $treeTop\n" if ($localDebug);
my $tempnl = "";
my $temptl = "";
my $temppt = "";
# nameObjDump(\@nameObjects);
foreach my $nameobj (@nameObjects) {
$tempnl .= ",$nameobj->{NAME}";
$temptl .= " $nameobj->{TYPE}";
$temppt = "$nameobj->{POSSTYPES}";
}
$tempnl =~ s/^,//s;
$temptl =~ s/^ //s;
# This can be enabled for testing purposes, but may warn about legitimate differences on occasion.
# if ($tempnl ne $namelist || $temptl ne $typelist || $temppt ne $posstypes) {
# warn "NEW STYLE TYPES DO NOT MATCH.\n";
# warn "NL: $namelist\n";
# warn "NLN: $tempnl\n";
# warn "TL: $typelist\n";
# warn "TLN: $temptl\n";
# warn "PT: $posstypes\n";
# warn "PTN: $temppt\n";
# foreach my $nameobj (@nameObjects) {
# warn "\tIA: ".$nameobj->{INSERTEDAT}."\n";
# }
# }
my $lastparm = pop(@pplStack);
print STDERR "LP: $lastparm\n" if ($localDebug || $parmDebug);
$lastparm =~ s/\s*;\s*$//s;
if ($lastparm ne "") {
push(@pplStack, $lastparm);
}
print STDERR "POSTLP: $lastparm\n" if ($localDebug || $parmDebug);
# Merge in the extra parameters from new-style AppleScript handlers
if ($lang eq "applescript") {
print STDERR "OFIN: ".$parserState->{OfIn}." ASLABEL: ".$parserState->{ASlabel}."\n" if ($parseDebug);;
if (length($parserState->{OfIn})) {
print STDERR "PUSHED ".$parserState->{OfIn}." into parsedParamList\n" if ($parseDebug || $forcedebug);
push(@pplStack, $parserState->{OfIn});
}
if (length($parserState->{ASlabel})) {
print STDERR "PUSHED ".$parserState->{ASlabel}." into parsedParamList\n" if ($parseDebug || $forcedebug);
push(@pplStack, $parserState->{ASlabel});
}
}
if ($parmDebug) {
print STDERR "PARSED PARAMETERS:";
my $count = 1;
foreach my $ppl (@pplStack) {
print "#".$count++."\n";
print $ppl."\n";
}
print STDERR "END OF PARSED PARAMETERS\n";
}
# $returntype =~ s/^\s*//s;
# $returntype =~ s/\s*$//s;
# print STDERR "SUBLANG: $sublang GLOBAL: ".$HeaderDoc::sublang."\n";
if ($sublang eq "MIG" && $parserState->{simpleTypedef}) {
# $parserState->dbprint();
$returntype = $value;
$value = "";
}
my $propertyAttributes = "";
if ($parserState->{isProperty}) {
# Objective-C properties in the form "@property(readOnly)" end up with
# the @property and property type info in the returntype field.
# Remove it and store it elsewhere (though this is somewhat superfluous
# since it also shows up in the parsed parameters list).
if ($returntype =~ s/^\s*\@property\s*\((.*?)\)\s*//s) {
$propertyAttributes = $1;
}
}
# print STDERR "SODCLASS: $sodclass SODNAME: $sodname SODTYPE: $sodtype LANG: $sublang\n";
my $memberOfClass = "";
my $origsodname = $sodname;
if ($sodclass eq "function" && $parserState->{isConstructor} && $lang eq "tcl") {
$memberOfClass = $sodname;
print STDERR "MEMBER OF CLASS: $memberOfClass\n" if ($localDebug || $forcedebug);
} elsif ($sublang eq "javascript" && $sodclass eq "variable" && $sodname =~ s/^(\w+(?:\.\w+)*)\s*\.\s*prototype\s*\.\s*//s) {
my $headerobj = $HeaderDoc::headerObject;
my $possible_class = $1;
my $temp = $headerobj->findClass($possible_class);
print STDERR "Checking for class \"$possible_class\"\n" if ($localDebug || $forcedebug);
# Don't throw away the class part unless we've actually seen this class.
if ($temp) {
$memberOfClass = $possible_class;
print STDERR "MEMBER OF CLASS: $memberOfClass\n" if ($localDebug || $forcedebug);
changeAllMatching(\@nameObjects, "NAME", "$origsodname", "NAME", "$sodname", 0);
changeAllMatching(\@nameObjects, "TYPE", "variable", "TYPE", "function", 0);
changeAllMatching(\@nameObjects, "TYPE", "variable", "POSSTYPES", "function constant variable", 0);
} else {
$sodname = $origsodname;
}
} elsif ($sodclass eq "function" && $sodtype =~ /(\w+)\s*::\s*$/) {
$memberOfClass = $1;
print STDERR "MEMBER OF CLASS: $memberOfClass\n" if ($localDebug || $forcedebug);
}
if ($localDebug || $nameObjDumpDebug) {
print STDERR "DUMPING NAME OBJECTS ON RETURN:\n";
nameObjDump(\@nameObjects);
print STDERR "RETURN TYPE: $returntype\n";
}
if ($lang eq "perl") {
# These are bogus anyway.
@pplStack = ();
}
changeAllMatching(\@nameObjects, "TYPE", "constant", "POSSTYPES", "constant variable", 0);
changeAllMatching(\@nameObjects, "TYPE", "variable", "POSSTYPES", "constant variable", 0);
if ($sublang eq "javascript" && $sodclass eq "function") {
$posstypes = "function method class";
changeAll(\@nameObjects, "POSSTYPES", $posstypes, 0); # may be no-op.
} elsif ($lang eq "applescript" && $sodclass eq "function") {
$posstypes = "function method ".$parserState->{classtype};
changeAll(\@nameObjects, "POSSTYPES", $posstypes, 0); # may be no-op.
}
# print STDERR "ATEND PS $parserState HAS ARGS: ".$parserState->{cppMacroHasArgs}."\n";
# We're outta here.
return ($inputCounter, $declaration, $typelist, $namelist, $posstypes, $value, \@pplStack, $returntype, $privateDeclaration, $treeTop, $simpleTDcontents, $availability, $fileoffset, $conformsToList, $parserState->{functionContents}, $parserState, \@nameObjects, $extendsClass, $implementsClass, $propertyAttributes, $memberOfClass, $lang, $sublang);
}
# /*!
# @abstract
# Dumps an array of {@link //apple_ref/perl/cl/HeaderDoc::TypeHelper TypeHelper} objects for debugging purposes.
# @param arrayRef
# A reference to the array to dump.
# */
sub nameObjDump($)
{
my $arrayRef = shift;
my @objarr = @{$arrayRef};
print STDERR "DUMPING LIST\n";
foreach my $obj (@objarr) {
print STDERR "OBJECT $obj:\n";
print STDERR "\tNAME: ".$obj->{NAME}."\n";
print STDERR "\tTYPE: ".$obj->{TYPE}."\n";
print STDERR "\tPOSSTYPES: ".$obj->{POSSTYPES}."\n";
print STDERR "\tINSERTEDAT: ".$obj->{INSERTEDAT}."\n";
}
print STDERR "END DUMP\n";
}
# /*!
# @abstract
# Searches an array of {@link //apple_ref/perl/cl/HeaderDoc::TypeHelper TypeHelper} objects for a matching name.
# @param arrayRef
# A reference to the array to search.
# @param element
# The key in each object to search.
# @param value
# The expected value of that key.
# */
sub findMatch($$$)
{
my $arrayRef = shift;
my $element = shift;
my $value = shift;
my @array = @{$arrayRef};
my $localDebug = 0;
foreach my $item (@array) {
print STDERR "CHECKING ELEMENT $element (".$item->{$element}.") against /$value/\n" if ($localDebug);
if ($item->{$element} =~ /$value/) {
print STDERR "MATCH\n" if ($localDebug);
return $item;
}
print STDERR "NOT MATCH\n" if ($localDebug);
}
print STDERR "NO MATCHES FOUND\n" if ($localDebug);
return undef;
}
# /*!
# @abstract
# Changes an array of {@link //apple_ref/perl/cl/HeaderDoc::TypeHelper TypeHelper} objects.
# @param arrayRef
# The array to dump.
# @param element
# The key in each object to modify.
# @param value
# The desired value for the specified key.
# @param append
# If 0, replace the existing value with $value.
#
# If 1, append $value to the existing
# value (space-delimited).
# */
sub changeAll($$$$)
{
my $arrayRef = shift;
my $element = shift;
my $value = shift;
my $append = shift;
my @array = @{$arrayRef};
my $localDebug = 0;
foreach my $item (@array) {
print STDERR "CHANGED $element from $item->{$element} to " if ($localDebug);
if ($append) {
$item->{$element} = $item->{$element}." ".$value;
} else {
$item->{$element} = $value;
}
print STDERR "$item->{$element}\n" if ($localDebug);
print STDERR "APPEND: $append\n" if ($localDebug);
}
}
# /*!
# @abstract
# Changes matching members of an array of {@link //apple_ref/perl/cl/HeaderDoc::TypeHelper TypeHelper} objects.
# @param arrayRef
# The array to dump.
# @param matchingElement
# The key in each object to match.
# @param matchingValue
# The value for that key that, if matching, indicates the object should be modified.
# @param element
# The key in each object to modify.
# @param value
# The desired value for the specified key.
# @param append
# If 0, replace the existing value with $value.
#
# If 1, append $value to the existing
# value (space-delimited).
# */
sub changeAllMatching($$$$$$)
{
my $arrayRef = shift;
my $matchingElement = shift;
my $matchingValue = shift;
my $element = shift;
my $value = shift;
my $append = shift;
my @array = @{$arrayRef};
my $localDebug = 0;
foreach my $item (@array) {
if ($item->{$matchingElement} eq $matchingValue) {
print STDERR "CHANGED $element from $item->{$element} to " if ($localDebug);
if ($append) {
$item->{$element} = $item->{$element}." ".$value;
} else {
$item->{$element} = $value;
}
print STDERR "$item->{$element}\n" if ($localDebug);
print STDERR "APPEND: $append\n" if ($localDebug);
}
}
}
# /*!
# @abstract
# Merges availability from multiple sources.
# @param orig_avail
# The original availability derived from comments.
# @param nodearrayref
# The array of availability nodes generated from parse
# tokens parsed by the parser.
# */
sub mergeComplexAvailability($$)
{
my $orig_avail = shift;
my $nodearrayref = shift;
if (!$nodearrayref) { return $orig_avail; }
my @nodearray = @{$nodearrayref};
foreach my $noderef (@nodearray) {
my $node = $noderef;
# print STDERR "NODE IS $node\n";
my @availabilitylist = @{$node->parseComplexAvailability()};
foreach my $entry (@availabilitylist) {
if (index($orig_avail, $entry) == -1) {
$orig_avail .= " ".$entry;
}
}
}
return $orig_avail;
}
# /*!
# @abstract
# A legacy piece of code that adjusts spacing in the raw
# declaration.
# @deprecated
# This is going away eventually.
# */
sub spacefix
{
my $curline = shift;
my $part = shift;
my $lastchar = shift;
my $soc = shift;
my $eoc = shift;
my $ilc = shift;
my $ilc_b = shift;
my $localDebug = 0;
if ($HeaderDoc::use_styles) { return $curline; }
print STDERR "SF: \"$curline\" \"$part\" \"$lastchar\"\n" if ($localDebug);
if (($part !~ /[;,]/o)
&& length($curline)) {
# space before most tokens, but not [;,]
if ($part eq $ilc || $part eq $ilc_b) {
if ($lastchar ne " ") {
$curline .= " ";
}
}
elsif ($part eq $soc) {
if ($lastchar ne " ") {
$curline .= " ";
}
}
elsif ($part eq $eoc) {
if ($lastchar ne " ") {
$curline .= " ";
}
}
elsif ($part =~ /\(/o) {
print STDERR "PAREN\n" if ($localDebug);
if ($curline !~ /[\)\w\*]\s*$/o) {
print STDERR "CASEA\n" if ($localDebug);
if ($lastchar ne " ") {
print STDERR "CASEB\n" if ($localDebug);
$curline .= " ";
}
} else {
print STDERR "CASEC\n" if ($localDebug);
$curline =~ s/\s*$//o;
}
} elsif ($part =~ /^\w/o) {
if ($lastchar eq "\$") {
$curline =~ s/\s*$//o;
} elsif ($part =~ /^\d/o && $curline =~ /-$/o) {
$curline =~ s/\s*$//o;
} elsif ($curline !~ /[\*\(]\s*$/o) {
if ($lastchar ne " ") {
$curline .= " ";
}
} else {
$curline =~ s/\s*$//o;
}
} elsif ($lastchar =~ /\w/o) {
#($part =~ /[=!+-\/\|\&\@\*/ etc.)
$curline .= " ";
}
}
if ($curline =~ /\/\*$/o) { $curline .= " "; }
return $curline;
}
# /*!
# @abstract
# A legacy piece of code that generates spaces for the raw
# declaration.
# @deprecated
# This is going away eventually.
# */
sub nspaces
{
my $n = shift;
my $string = "";
while ($n-- > 0) { $string .= " "; }
return $string;
}
# /*!
# @abstract
# A piece of debug code that prints the brace stack.
# @discussion
# This does nothing unless localDebug is set to 1 below.
# This should probably be revisited to key off something
# in the calling function.
# */
sub pbs
{
my @braceStack = shift;
my $localDebug = 0;
if ($localDebug) {
print STDERR "BS: ";
foreach my $p (@braceStack) { print STDERR "$p "; }
print STDERR "ENDBS\n";
}
}
# parse #define arguments
# /*!
# @abstract
# Parses #define arguments.
# @param declaration
# The text of the declaration to parse.
# @param inputCounter
# The line number (for debugging purposes).
# @param definename
# The name of the #define.
# @param braceDebug
# Set to 1 to print debug info.
# @param fullpath
# The header file path (for debugging purposes).
# */
sub defParmParse
{
my $declaration = shift;
my $inputCounter = shift;
my $definename = shift;
my $braceDebug = shift;
my $fullpath = shift;
my @myargs = ();
my $localDebug = 0;
my $curname = "";
# print STDERR "IN DEFPARMPARSE. DECLARATION: $declaration\nDEFINENAME $definename\n";
$declaration =~ s/.*?$definename\s+\w+\s*\(//so;
# print STDERR "IN DEFPARMPARSE. PARM GUTS: $declaration\n";
my @braceStack = ( "(" );
my @tokens = split(/(\W)/, $declaration);
foreach my $token (@tokens) {
print STDERR "TOKEN: $token\n" if ($localDebug);
if (!scalar(@braceStack)) { last; }
if ($token =~ /[\(\[]/o) {
print STDERR "open paren/bracket - $token\n" if ($localDebug);
push(@braceStack, $token);
print STDERR "PUSHED $token ONTO BRACESTACK [8]\n" if ($braceDebug);
} elsif ($token =~ /\)/o) {
print STDERR "close paren\n" if ($localDebug);
my $top = pop(@braceStack);
print STDERR "POPPED $top FROM BRACESTACK [7]\n" if ($braceDebug);
if ($top !~ /\(/o) {
warn("$fullpath:$inputCounter: warning: Parentheses do not match (macro).\nWe may have a problem.\n");
}
} elsif ($token =~ /\]/o) {
print STDERR "close bracket\n" if ($localDebug);
my $top = pop(@braceStack);
print STDERR "POPPED $top FROM BRACESTACK [8]\n" if ($braceDebug);
if ($top !~ /\[/o) {
warn("$fullpath:$inputCounter: warning: Braces do not match (macro).\nWe may have a problem.\n");
}
} elsif ($token =~ /,/o && (scalar(@braceStack) == 1)) {
$curname =~ s/^\s*//sgo;
$curname =~ s/\s*$//sgo;
push(@myargs, $curname);
print STDERR "pushed \"$curname\"\n" if ($localDebug);
$curname = "";
} else {
$curname .= $token;
}
}
$curname =~ s/^\s*//sgo;
$curname =~ s/\s*$//sgo;
if (length($curname)) {
print STDERR "pushed \"$curname\"\n" if ($localDebug);
push(@myargs, $curname);
}
return \@myargs;
}
# /*!
# @abstract
# Returns whether a token should be ignored.
# @discussion
# Checks the ignore list and availability macros.
# @return
# Returns the availability string if one is available.
# Otherwise, returns 0 if the token is a normal token,
# 1 if the token is in the ignore list and should be
# dropped during parsing, or 3 if the token represents
# an availability macro that has arguments and thus
# needs special handling.
# */
sub ignore
{
my $part = shift;
my $ignorelistref = shift;
my %ignorelist = %{$ignorelistref};
my $phignorelistref = shift;
my %perheaderignorelist = %{$phignorelistref};
my $localDebug = 0;
# if ($part =~ /AVAILABLE/o) {
# $localDebug = 1;
# }
print STDERR "CHECKING TOKEN: \"$part\"\n" if ($localDebug);
my $def = $HeaderDoc::availability_defs{$part};
if ($def && length($def)) {
print STDERR "AVAILABILITY DEF FOUND: $def\n" if ($localDebug);
if ($HeaderDoc::availability_has_args{$part}) {
return 3;
}
return $def;
}
my $isa = isStandardAvailability($part);
if ($isa) { return $isa; }
if ($ignorelist{$part}) {
print STDERR "IGNORING $part\n" if ($localDebug);
return 1;
}
if ($perheaderignorelist{$part}) {
print STDERR "IGNORING $part\n" if ($localDebug);
return 1;
}
print STDERR "NO MATCH FOUND\n" if ($localDebug);
if ($localDebug) {
print STDERR "Ignore list:\n";
foreach my $key (keys %ignorelist) {
print STDERR " ".$key." -> ".$ignorelist{$key}."\n";
}
print STDERR "\nPer-header ignore list:\n";
foreach my $key (keys %perheaderignorelist) {
print STDERR " ".$key." -> ".$perheaderignorelist{$key}."\n";
}
print STDERR "\nAvailability macros:\n";
foreach my $key (keys %HeaderDoc::availability_defs) {
print STDERR " ".$key." -> ".$HeaderDoc::availability_defs{$key}."\n";
}
}
return 0;
}
# /*!
# @abstract
# The outer block parser
#
# @param apiOwner
# The API owner object (class, header, etc.)
# into which new declarations should be inserted.
#
# @param fullpath
# The path to the file being parsed.
#
# @param inFunction
# Set to 1 if an \@function comment
# preceded this declaration.
#
# @param inUnknown
# Set to 1 if a new-style comment (with no
# top-level HeaderDoc tag) preceded this declaration.
#
# @param inTypedef
# Set to 1 if an \@typedef comment
# preceded this declaration.
#
# @param inStruct
# Set to 1 if an \@struct comment
# preceded this declaration.
#
# @param inEnum
# Set to 1 if an \@enum comment
# preceded this declaration.
#
# @param inUnion
# Set to 1 if an \@union comment
# preceded this declaration.
#
# @param inConstant
# Set to 1 if an \@constant or
# \@const comment preceded this
# declaration.
#
# @param inVar
# Set to 1 if an \@var comment
# preceded this declaration.
#
# @param inMethod
# Set to 1 if an \@method comment
# preceded this declaration.
#
# @param inPDefine
# Set to 1 if an \@define comment
# preceded this declaration.
#
# Set to 2 if an \@defineblock or
# \@definedblock comment preceded
# this declaration.
#
# @param inClass
# Set to 1 if an \@class comment
# preceded this declaration.
#
# @param inInterface
# Set to 1 if an \@interface comment
# preceded this declaration.
#
# @param blockOffset
# The line number where the current block begins. The
# line number printed is (blockOffset + inputCounter).
#
# @param categoryObjectsref
# A reference to the initial array of category
# (HeaderDoc::ObjCCategory) objects.
# New category objects are added to this array.
#
# @param classObjectsref
# A reference to the initial array of class
# (HeaderDoc::CPPClass and
# HeaderDoc::ObjCClss) objects.
# New category objects are added to this array.
#
# @param classType
# The class type, based on what class was
# last parsed. Used when parsing fragments
# within a class. Legal values are
# intf, occ,
# occCat, or any value that
# is valid for sublang.
#
# This is used to determine whether to treat the
# \@method tag as an Objective-C method
# (HeaderDoc::Method) or as a normal
# method (HeaderDoc::Function).
#
# @param cppAccessControlState
# The new access control state (public, private, etc.).
# It is named cpp because at the time it was naed, the
# only langauge that required it was C++ (where
# sublang = "cpp").
#
# @param fieldsref
# An array of fields returned from a call to
# {@link //apple_ref/perl/instm/HeaderDoc::Utilities/stringToFields//() stringToFields} on a HeaderDoc comment.
#
# @param fullpath
# The full (possibly relative) path to the current
# input file.
#
# @param functionGroup
# The function group currently in effect.
#
# @param headerObject
# The header object that will eventually contain any
# objects produced.
#
# @param inputCounter
# The offset within the array. This is added to
# blockOffset when printing the line number.
#
# @param inputlinesref
# A reference to an array of code lines.
#
# @param lang
# The language family to use in parsing. Overrides
# HeaderDoc::lang.
#
# @param nlines
# The number of lines in inputlinesref.
#
# @param preAtPart
# Text before the initial \@ in the
# preceding HeaderDoc comment. Contains the
# discussion in a new-style comment. Otherwise,
# contains whitespace.
#
# @param xml_output
# Set to 1 if output should be in XML format, else 0.
# This sets the outputformat value on new
# objects.
#
# @param localDebug
# Set to 1 to enable lots of general debug spew.
#
# @param hangDebug
# Set to 1 to enable lots of debug spew specific to
# tracking down infinite loops.
#
# @param parmDebug
# Set to 1 to enable lots of debug spew specific to
# parameter handling.
#
# @param blockDebug
# Set to 1 to debug block handling (both define blocks
# and blocks wrapped in C preprocessor macros).
#
# @param subparse
# Set to 1 to use subparse mode (handling a declaration
# extracted out of an existing parse tree).
#
# @param subparseTree
# The source parse tree in subparse mode. Ignored
# otherwise.
#
# @param nodec
# No longer used. Always pass zero.
#
# @param allow_multi
# Pass 1 to allow blocks to be created when a
# #if statement is found immediately
# after a HeaderDoc comment. Pass 0 to disable this
# feature.
#
# @param subparseCommentTree
# Used in block mode because subparseTree is empty by
# definition when the comment precedes the declaration.
#
# @param sublang
# The language variant to use in parsing. Overrides
# HeaderDoc::sublang used in previous
# versions of this function. Optional FOR NOW.
#
# @param hashtreecur
# A {@link //apple_ref/perl/cl/HeaderDoc::HashObject HashObject} instance
# that reflects the current position in the CPP hash tree.
# This is used by the parser to manage the C preprocessor
# hash tables in the presence of #if directives.
#
# For a detailed explanation, see the documentation for the
# {@link //apple_ref/perl/cl/HeaderDoc::HashObject HashObject} class.
#
# Although this is optional, if you don't pass these correctly,
# you won't get support for #if/#else/#endif blocks.
#
# @param hashtreeroot
# A {@link //apple_ref/perl/cl/HeaderDoc::HashObject HashObject} instance
# that represents the root of the CPP hash tree.
# This is used by the parser to manage the C preprocessor
# hash tables in the presence of #if directives.
#
# For a detailed explanation, see the documentation for the
# {@link //apple_ref/perl/cl/HeaderDoc::HashObject HashObject} class.
#
# Although this is optional, if you don't pass these correctly,
# you won't get support for #if/#else/#endif blocks.
#
# @result
# Returns the array ($inputCounter, $cppAccessControlState, $classType, \@classObjects, \@categoryObjects, $blockOffset, $numcurlybraces, $foundMatch, $lang, $sublang).
#
# inputCountercppAccessControlStateclassTypeclassObjectsCPPClass or ObjCClass).categoryObjectsObjCCategory).blockOffsetnumcurlybracesfoundMatch\@function
# comment matched a function or function-like macro).langsublang\@defineblock comment,
# but have not yet seen any #define macros.
# \@defineblock comment,
# and have seen at least one #define macro.
# #if macro before the first
# declaration. Treat the following declarations as
# a group until the corresponding #endif macro
# Var, Enum, Typedef, CPPClass, etc.)
# for a given set of type information.
# @discussion
# This logic got so large that it was too much of a pain to maintain
# in two places in {@link blockParseOutside}, hence the separate function.
# @param curObj
# IN: The current master object from {@link blockParseOutside}. This master object
# is generated based on the top-level tag in the HeaderDoc comment,
# if present. (If the comment has no top-level tag, this is a generic
# {@link //apple_ref/perl/cl/HeaderDoc::HeaderElement HeaderElement}
# object.)
# @param typedefname
# IN: The typedefname parse token (obtained from a call to
# {@link //apple_ref/perl/instm/HeaderDoc::Utilities/parseTokens//() parseTokens}.
# @param typestring
# IN: The typestring field out of the parser state object.
# See the parserState class for more information.
# @param posstypes
# IN: The posstypes field out of the parser state object.
# See the parserState class for more information.
# @param outertype
# IN: The primary type returned by the parser. For example, in the case of a
# typedef struct declaration, the outer type would be
# typedef.
# @param curtype
# IN: The type that we are searching for (as defined by the HeaderDoc comment).
# @param classType
# IN: The class type of the enclosing context.
#
# OUT: The class type of the class just parsed; unchanged if the current
# declaration is not a class.
# @param classKeyword
# IN: The class keyword from the HeaderDoc comment (e.g. for
# an \@class comment, the value is class). If
# unspecified, the value is auto.
# @param declaration
# IN: The raw declaration. For classes, passed to
# {@link //apple_ref/perl/instm/HeaderDoc::Utilities/classTypeFromFieldAndBPinfo//() classTypeFromFieldAndBPinfo}. Otherwise unused.
# @param fieldref
# IN: A reference to the array of fields from the HeaderDoc comment.
# @param functionGroup
# IN: The name of the current function group.
# @param varIsConstant
# IN: Probably doesn't matter.
#
# OUT: Returns 1 if the variable declaration is a constant, else 0.
# @param blockmode
# IN: Nonzero if the parser is in a #define block. (For details, see
# {@link blockParseOutside}.
# @param inClass
# IN: Nonzero if the HeaderDoc comment began with \@class.
# @param inInterface
# IN: Nonzero if the HeaderDoc comment began with \@interface.
# @param inTypedef
# IN: Nonzero if the HeaderDoc comment began with \@typedef.
# @param inStruct
# IN: Nonzero if the HeaderDoc comment began with \@struct.
# @param fullpath
# IN: The filename with leading path parts (for debugging purposes/warnings).
# @param inputCounter
# IN: The position within the current text block (for debugging purposes/warnings).
# @param blockOffset
# IN: The offset of the current text block from the start of the file (for debugging purposes/warnings).
# @param lang
# IN: The programming language of the file being parsed. Used to determine whether certain
# Pascal-specific keywords are active.
# @param outerLocalDebug
# IN: The value of localDebug in {@link blockParseOutside}. Set high for debugging.
# @param functionContents
# IN: The function body. Used to populate the object (if it's a function).
# @param apiOwner
# IN: The object into which this object will eventually be inserted. (Used to set the
# appropriate field in the object; this function does NOT add the object to the
# apiOwner object in any way.)
# @param subparseInputCounter
# IN: An override for the inputCounter field used when doing a subparse (handling a
# parse tree that has already been parsed once). Leave unset normally.
# @param subparseBlockOffset
# IN: An override for the blockOffset field used when doing a subparse (handling a
# parse tree that has already been parsed once). Leave unset normally.
# @param extendsClass
# IN: The superclass name (obtained from the block parser).
# @param implementsClass
# IN: The name of the class that this class implements (Java-specific, obtained from
# the block parser).
# @param alwaysProcessComment
# IN: Indicates that the processComment() call should me made on the resulting object
# even if curtype is UNKNOWN (meaning that the comment would normally get processed
# later in {@link blockParseOutside}). Used only in the case of a conversion request in
# blockParseOutisde.
# @result
# Returns the array ($extra, $classType, $varIsConstant).
# */
sub objForType
{
my $curObj = shift; # IN
my $typedefname = shift; # IN
my $typestring = shift; # IN
my $posstypes = shift; # IN
my $outertype = shift; # IN
my $curtype = shift; # IN
my $classType = shift; # INOUT
my $classKeyword = shift; # IN
my $declaration = shift; # IN
my $fieldref = shift; # IN
my $functionGroup = shift; # IN
my $varIsConstant = shift; # INOUT
my $blockmode = shift; # IN
my $inClass = shift; # IN
my $inInterface = shift; # IN
my $inTypedef = shift; # IN
my $inStruct = shift; # IN
my $fullpath = shift; # IN
my $inputCounter = shift; # IN
my $blockOffset = shift; # IN
my $lang = shift; # IN
my $sublang = shift; # IN
my $outerLocalDebug = shift; # IN
my $functionContents = shift; # IN
my $apiOwner = shift; # IN
my $subparseInputCounter = shift; # IN
my $subparseBlockOffset = shift; # IN
my $extendsClass = shift; # IN
my $implementsClass = shift; # IN
my $alwaysProcessComment = shift; # IN
my $parseTokensRef = shift; # IN
my $parserState = shift; # IN
my $extra = undef; # OUT
my $localDebug = 0;
my %parseTokens = %{$parseTokensRef};
my $filename = basename($fullpath);
print STDERR "FOR DECLARATION $declaration\n" if ($localDebug);
# printFields($fieldref);
my $classregexp = $parseTokens{classregexp};
my $moduleregexp = $parseTokens{moduleregexp};
# print STDERR "CHECK: $classregexp\n";
# print STDERR "CO: $curObj HASPC: ".$curObj->{HASPROCESSEDCOMMENT}." CURTYPE: $curtype\n";
# print "TYPESTRING \"$typestring\" OUTERTYPE: \"$outertype\"\n";
if ($typestring eq $outertype || !$HeaderDoc::outerNamesOnly) {
# $typestring =~ /^(class|\@class|\@interface|\@implementation|\@protocol|interface|module|namespace|package)/
if (((length($classregexp) && $typestring =~ /$classregexp/) ||
(length($moduleregexp) && $typestring =~ /$moduleregexp/) || $inClass) && !$inTypedef && !$inStruct) {
print STDERR "blockParse returned class\n" if ($localDebug);
print STDERR "RAWDEC: $declaration\n" if ($localDebug && $outerLocalDebug);
$classType = classTypeFromFieldAndBPinfo($classKeyword, $typestring." ".$posstypes, $declaration, $fullpath, $inputCounter+$blockOffset, $sublang);
print STDERR "classtype: $classType\n" if ($localDebug);
if ($classType eq "intf") {
$extra = HeaderDoc::ObjCProtocol->new("LANG" => $lang, "SUBLANG" => $sublang);
$extra->apiOwner($apiOwner);
} elsif ($classType eq "occCat") {
$extra = HeaderDoc::ObjCCategory->new("LANG" => $lang, "SUBLANG" => $sublang);
$extra->apiOwner($apiOwner);
} elsif ($classType eq "occ") {
$extra = HeaderDoc::ObjCClass->new("LANG" => $lang, "SUBLANG" => $sublang);
$extra->apiOwner($apiOwner);
} else {
$extra = HeaderDoc::CPPClass->new("LANG" => $lang, "SUBLANG" => $sublang);
$extra->apiOwner($apiOwner);
if ($inInterface || $typestring =~ /typedef/ || $typestring =~ /struct/) {
# cluck "Setting isCOMInterface -> 1 ($inInterface, $typestring)\n";
$inInterface = 0;
$extra->isCOMInterface(1);
$extra->tocTitlePrefix('COM Interface:');
}
if ($classType eq "IDL") {
if ($typestring =~ /(module|namespace)/) {
$extra->isModule(1);
}
}
}
if ($typestring =~ /typedef/ || $outertype =~ /typedef/) {
$extra->CClass(1);
}
print STDERR "TYPESTRING IS $typestring. CCLASS IS ".$extra->CClass."\n" if ($localDebug);
$extra->group($HeaderDoc::globalGroup);
# if ($HeaderDoc::module)
if ($parserState->{MODULE}) {
$extra->indexgroup($parserState->{MODULE}); # $HeaderDoc::module
print STDERR "MODULE: ".$parserState->{MODULE}."\n"; # @@@
}
$extra->filename($filename);
$extra->fullpath($fullpath);
if (defined($subparseInputCounter)) {
$extra->linenuminblock($subparseInputCounter);
$extra->blockoffset($subparseBlockOffset);
} else {
$extra->linenuminblock($inputCounter);
$extra->blockoffset($blockOffset);
}
# $extra->linenum($inputCounter+$blockOffset);
$extra->headerObject($HeaderDoc::headerObject);
# my $superclass = &get_super($classType, $declaration);
my $class = ref($extra) || $extra;
my $superclass = $posstypes;
my $superclassfieldname = "Superclass";
if ($extra->CClass()) {
$superclassfieldname = "";
} elsif ($class =~ /HeaderDoc::ObjCCategory/) {
$superclassfieldname = "Extends Class";
} elsif ($class =~ /HeaderDoc::ObjCProtocol/) {
$superclassfieldname = "Extends Protocol";
}
# print STDERR "SUPER: $superclass\n";
if (length($superclass) && length($superclassfieldname) && (!($extra->checkShortLongAttributes($superclassfieldname))) && !$extra->CClass()) {
$extra->attribute($superclassfieldname, $superclass, 0, 1);
}
$superclassfieldname = "Extends Class";
if (length($extendsClass) && length($superclassfieldname) && (!($extra->checkShortLongAttributes($superclassfieldname))) && !$extra->CClass()) {
$extra->attribute($superclassfieldname, $extendsClass, 0, 1);
}
$superclassfieldname = "Implements Class";
if (length($implementsClass) && length($superclassfieldname) && (!($extra->checkShortLongAttributes($superclassfieldname))) && !$extra->CClass()) {
$extra->attribute($superclassfieldname, $implementsClass, 0, 1);
}
# $extra->declaration($declaration);
# $extra->declarationInHTML($declaration);
# if ($curtype eq "UNKNOWN" || $alwaysProcessComment) {
$extra->processComment($fieldref);
# }
# if ($typestring eq "\@protocol") {
# push (@classObjects, $extra);
# $headerObject->addToProtocols($extra);
# } elsif ($typestring eq "\@interface") {
# push (@categoryObjects, $extra);
# headerObject->addToCategories($extra);
# } elsif ($typestring eq "\@class") {
# push (@classObjects, $extra);
# $headerObject->addToClasses($extra);
# } else {
# # class or typedef struct
# push (@classObjects, $extra);
# $headerObject->addToClasses($extra);
# }
} elsif (($typestring =~ /^$typedefname/ && length($typedefname)) || ($typestring =~ /$classregexp/ && length($classregexp))) {
print STDERR "blockParse returned $typedefname\n" if ($localDebug);
if ($localDebug) {
foreach my $field (@{$fieldref}) {
print STDERR "FIELD $field\n";
}
}
$extra = HeaderDoc::Typedef->new("LANG" => $lang, "SUBLANG" => $sublang);
$extra->apiOwner($apiOwner);
$extra->group($HeaderDoc::globalGroup);
$extra->filename($filename);
$extra->fullpath($fullpath);
if (defined($subparseInputCounter)) {
$extra->linenuminblock($subparseInputCounter);
$extra->blockoffset($subparseBlockOffset);
} else {
$extra->linenuminblock($inputCounter);
$extra->blockoffset($blockOffset);
}
# $extra->linenum($inputCounter+$blockOffset);
$curObj->masterEnum(1);
if ($curtype eq "UNKNOWN" || $alwaysProcessComment) {
$extra->processComment($fieldref);
}
} elsif ($typestring =~ /^struct/o || $typestring =~ /^union/o || ($lang eq "pascal" && $typestring =~ /^record/o)) {
print STDERR "blockParse returned struct or union ($typestring)\n" if ($localDebug);
$extra = HeaderDoc::Struct->new("LANG" => $lang, "SUBLANG" => $sublang);
$extra->apiOwner($apiOwner);
$extra->group($HeaderDoc::globalGroup);
$extra->filename($filename);
$extra->fullpath($fullpath);
if (defined($subparseInputCounter)) {
$extra->linenuminblock($subparseInputCounter);
$extra->blockoffset($subparseBlockOffset);
} else {
$extra->linenuminblock($inputCounter);
$extra->blockoffset($blockOffset);
}
# $extra->linenum($inputCounter+$blockOffset);
if ($typestring =~ /union/o) {
$extra->isUnion(1);
}
if ($curtype eq "UNKNOWN" || $alwaysProcessComment) {
$extra->processComment($fieldref);
}
} elsif ($typestring =~ /^enum/o) {
print STDERR "blockParse returned enum\n" if ($localDebug);
$extra = HeaderDoc::Enum->new("LANG" => $lang, "SUBLANG" => $sublang);
$extra->apiOwner($apiOwner);
$extra->group($HeaderDoc::globalGroup);
$extra->filename($filename);
$extra->fullpath($fullpath);
if (defined($subparseInputCounter)) {
$extra->linenuminblock($subparseInputCounter);
$extra->blockoffset($subparseBlockOffset);
} else {
$extra->linenuminblock($inputCounter);
$extra->blockoffset($blockOffset);
}
# $extra->linenum($inputCounter+$blockOffset);
if ($curtype eq "UNKNOWN" || $alwaysProcessComment) {
$extra->processComment($fieldref);
}
if ($curtype eq "enum" || $curtype eq "typedef") {
$extra->masterEnum(0);
} else {
$extra->masterEnum(1);
}
} elsif ($typestring =~ /^MACRO/o) {
print STDERR "blockParse returned MACRO\n" if ($localDebug);
# silently ignore this noise.
} elsif ($typestring =~ /^\#define/o) {
print STDERR "blockParse returned #define\n" if ($localDebug);
$extra = HeaderDoc::PDefine->new("LANG" => $lang, "SUBLANG" => $sublang);
$extra->apiOwner($apiOwner);
$extra->inDefineBlock($blockmode);
$extra->group($HeaderDoc::globalGroup);
$extra->filename($filename);
$extra->fullpath($fullpath);
if (defined($subparseInputCounter)) {
$extra->linenuminblock($subparseInputCounter);
$extra->blockoffset($subparseBlockOffset);
} else {
$extra->linenuminblock($inputCounter);
$extra->blockoffset($blockOffset);
}
# $extra->linenum($inputCounter+$blockOffset);
if ($curtype eq "UNKNOWN" || $alwaysProcessComment) {
$extra->processComment($fieldref);
}
} elsif ($typestring =~ /^property/o) {
$varIsConstant = 0;
print STDERR "blockParse returned property\n" if ($localDebug);
$extra = HeaderDoc::Var->new("LANG" => $lang, "SUBLANG" => $sublang);
$extra->apiOwner($apiOwner);
$extra->group($HeaderDoc::globalGroup);
$extra->filename($filename);
$extra->fullpath($fullpath);
if (defined($subparseInputCounter)) {
$extra->linenuminblock($subparseInputCounter);
$extra->blockoffset($subparseBlockOffset);
} else {
$extra->linenuminblock($inputCounter);
$extra->blockoffset($blockOffset);
}
# $extra->linenum($inputCounter+$blockOffset);
$extra->isProperty(1);
if ($curtype eq "UNKNOWN" || $alwaysProcessComment) {
$extra->processComment($fieldref);
}
} elsif ($typestring =~ /^constant/o) {
# if ($declaration =~ /\s+const\s+/o) {
$varIsConstant = 1;
print STDERR "blockParse returned constant\n" if ($localDebug);
$extra = HeaderDoc::Constant->new("LANG" => $lang, "SUBLANG" => $sublang);
$extra->apiOwner($apiOwner);
$extra->group($HeaderDoc::globalGroup);
$extra->filename($filename);
$extra->fullpath($fullpath);
if (defined($subparseInputCounter)) {
$extra->linenuminblock($subparseInputCounter);
$extra->blockoffset($subparseBlockOffset);
} else {
$extra->linenuminblock($inputCounter);
$extra->blockoffset($blockOffset);
}
# $extra->linenum($inputCounter+$blockOffset);
if ($curtype eq "UNKNOWN" || $alwaysProcessComment) {
$extra->processComment($fieldref);
}
} elsif ($typestring =~ /^variable/o) {
$varIsConstant = 0;
print STDERR "blockParse returned variable\n" if ($localDebug);
$extra = HeaderDoc::Var->new("LANG" => $lang, "SUBLANG" => $sublang);
$extra->apiOwner($apiOwner);
$extra->group($HeaderDoc::globalGroup);
$extra->filename($filename);
$extra->fullpath($fullpath);
if (defined($subparseInputCounter)) {
$extra->linenuminblock($subparseInputCounter);
$extra->blockoffset($subparseBlockOffset);
} else {
$extra->linenuminblock($inputCounter);
$extra->blockoffset($blockOffset);
}
# $extra->linenum($inputCounter+$blockOffset);
if ($curtype eq "UNKNOWN" || $alwaysProcessComment) {
$extra->processComment($fieldref);
}
} elsif ($typestring =~ /^(function|method|operator|ftmplt|callback)/o) {
print STDERR "blockParse returned function or method\n" if ($localDebug);
if ($typestring =~ /method/) {
$extra = HeaderDoc::Method->new("LANG" => $lang, "SUBLANG" => $sublang);
$extra->apiOwner($apiOwner);
$extra->functionContents($functionContents);
if (length($functionGroup)) {
$extra->group($functionGroup);
} else {
$extra->group($HeaderDoc::globalGroup);
}
$extra->filename($filename);
$extra->fullpath($fullpath);
if (defined($subparseInputCounter)) {
$extra->linenuminblock($subparseInputCounter);
$extra->blockoffset($subparseBlockOffset);
} else {
$extra->linenuminblock($inputCounter);
$extra->blockoffset($blockOffset);
}
# $extra->linenum($inputCounter+$blockOffset);
if ($curtype eq "UNKNOWN" || $alwaysProcessComment) {
$extra->processComment($fieldref);
}
} else {
$extra = HeaderDoc::Function->new("LANG" => $lang, "SUBLANG" => $sublang);
$extra->apiOwner($apiOwner);
$extra->functionContents($functionContents);
if (length($functionGroup)) {
$extra->group($functionGroup);
} else {
$extra->group($HeaderDoc::globalGroup);
}
$extra->filename($filename);
$extra->fullpath($fullpath);
if (defined($subparseInputCounter)) {
$extra->linenuminblock($subparseInputCounter);
$extra->blockoffset($subparseBlockOffset);
} else {
$extra->linenuminblock($inputCounter);
$extra->blockoffset($blockOffset);
}
# $extra->linenum($inputCounter+$blockOffset);
if ($curtype eq "UNKNOWN" || $alwaysProcessComment) {
$extra->processComment($fieldref);
}
}
if ($typestring eq "callback") {
$extra->isCallback(1);
}
if ($typestring eq "ftmplt") {
$extra->isTemplate(1);
}
} else {
my $linenum = $inputCounter + $blockOffset;
warn("$fullpath:$linenum: warning: Unknown keyword $typestring in block-parsed declaration.\n".
"This usually means that your code requires C preprocessing in order to be\n".
"valid C syntax and either C preprocessing is not enabled (-p) or the required\n".
"macros lack HeaderDoc comments. Use of the \@parseOnly tag is recommended\n".
"for these special symbols.\n");
}
} else {
print STDERR "Dropping alternate name\n" if ($localDebug);
}
return ($extra, $classType, $varIsConstant);
}
# /*!
# @abstract
# Creates "see also" references between related APIs.
# @param listref
# A reference to an array of objects to be cross-linked.
# @discussion
# When the parser sees, for example, an \@typedef
# comment, followed by a struct, followed by a
# typedef, it treats these as related APIs and
# automatically associates the comment with both of these
# two declarations. This function links those together at
# the end.
# */
sub objlink
{
my $listref = shift;
my @list = @{$listref};
my @reflist = ();
my @masterreflist = ();
my $localDebug = 0;
my $masterobj = undef;
foreach my $objref (@list) {
my $obj = ${$objref};
bless($obj, "HeaderDoc::HeaderElement");
bless($obj, $obj->{CLASS});
if ($obj =~ /HeaderDoc::PDefine/) {
if ($obj->isBlock) {
$masterobj = $obj;
}
}
print STDERR "Obj: $obj\n" if ($localDebug);
}
print STDERR "MO: $masterobj\n" if ($localDebug);
foreach my $objref (@list) {
my $obj = ${$objref};
# change whitespace to ctrl-d to
# allow multi-word names.
my $ern = $obj->name();
# print STDERR "RN: $ern\n";
if ($ern =~ /\s/o && $localDebug) {
print STDERR "changed space to ctrl-d\n";
print STDERR "ref is ".$obj->apiuid()."\n";
}
$ern =~ s/\s/\cD/sgo;
if ($obj != $masterobj) {
push(@reflist, $ern." ".$obj->apiuid());
}
}
if ($masterobj) {
my $ern = $masterobj->name();
if ($ern =~ /\s/o && $localDebug) {
print STDERR "changed space to ctrl-d\n";
print STDERR "ref is ".$masterobj->apiuid()."\n";
}
$ern =~ s/\s/\cD/sgo;
@masterreflist = @reflist;
@reflist = ();
push(@reflist, $ern." ".$masterobj->apiuid());
foreach my $apiref (@masterreflist) {
# Don't try this.
# $masterobj->see("seealso\n$apiref");
if (!$masterobj->seeDupCheck($apiref) && !$masterobj->{HIDESINGLETONS}) {
$masterobj->attributelist("See Also", $apiref);
$masterobj->seeDupCheck($apiref, 1);
$masterobj->autoRelate($apiref);
}
}
}
foreach my $objref (@list) {
my $obj = ${$objref};
if ($obj != $masterobj) {
my $uid = $obj->apiuid();
if ($masterobj->{HIDESINGLETONS}) {
$obj->{HIDEDOC} = 1;
}
foreach my $apiref (@reflist) {
my $rawref = $apiref;
$rawref =~ s/.* //s;
if ($rawref ne $uid) {
# Don't try this.
# $obj->see("seealso\n$apiref");
if (!$obj->seeDupCheck($apiref)) {
$obj->attributelist("See Also", $apiref);
$obj->seeDupCheck($apiref, 1);
$obj->autoRelate($apiref);
}
}
}
}
}
}
# /*! @abstract
# Removes a token from the C preprocessor macros list.
# @discussion
# Used with availability macros so that C preprocessor doesn't
# strip out the availability macro tokens out before the parser sees
# them.
# */
sub cpp_remove($)
{
my $name = shift;
my $localDebug = 0;
print STDERR "Removing token \"$name\" from C preprocessor macros list.\n" if ($localDebug);
delete $CPP_HASH{$name};
delete $CPP_ARG_HASH{$name};
}
# /*! @abstract
# Adds a C preprocessor macro to the parser.
# @param parseTree
# The parse tree for the macro in question.
# @param dropdeclaration
# True if the declaration's contents should be omitted entirely.
# */
sub cpp_add($$)
{
my $parseTree = shift;
my $dropdeclaration = shift;
my $lang = shift;
my $sublang = shift;
# Don't use textTreeNC here because we need to be able to handle
# #define comments that contain HeaderDoc markup.
my $string = $parseTree->textTree($lang, $sublang);
$string =~ s/^\/\*.*?\*\///s;
print STDERR "IN cpp_add: ADDING \"$string\"\n" if ($cppDebug || $cppAddDebug);
return cpp_add_string($string, $dropdeclaration);
}
# /*! @abstract
# Adds a C preprocessor macro to the parser.
# @param string
# The string form of the macro in question.
# @param dropdeclaration
# True if the declaration's contents should be omitted entirely.
# */
sub cpp_add_string($$)
{
my $string = shift;
my $dropdeclaration = shift;
my $localDebug = 0;
$string =~ s/\n$//s;
my $slstring = $string;
$slstring =~ s/\\\n/ /sg;
print STDERR "cpp_add: STRING WAS $string\n" if ($cppDebug || $localDebug || $cppDebugFromToken || $cppAddDebug);
print STDERR "SLSTRING: $slstring\n" if ($localDebug || $cppDebug || $cppAddDebug);
# if ($slstring =~ s/^\s*#define\s+(\w+)\(//s) {
if ($dropdeclaration && $slstring =~ s/^\s*#define\s+(\w+)(\s|$)//s) {
my $name = $1;
print STDERR "Dropping declaration \"$name\"." if ($localDebug || $cppDebug);
# Deleting token by force.
if (exists $CPP_HASH{$name}) {
warn "Multiple definitions for $name. Using first.\n" if ($cppDebug || $warnAllMultipleDefinitions);
} else {
$CPP_HASH{$name} = "";
}
} elsif ($slstring =~ s/^(?:\/\*.*?\*\/)?\s*#define\s+((?:\w|::|->)+)(\s|\(|\{)//s) {
my $name = $1;
# my $firsttoken = $2;
print STDERR "CPP ADDING FUNC-LIKE MACRO\n" if ($localDebug || $cppDebug);
print STDERR "GOT NAME $name\n" if ($localDebug || $cppDebug);
$string =~ s/^.*?\Q$name\E//s;
print STDERR "POST-STRIP: STRING IS \"$string\"\n" if ($localDebug || $cppDebug);
my @tokens = split(/(\/\/|\/\*|\*\/|\W)/, $string);
my $firstpart = "";
my $lastpart = "";
my $fpdone = 0;
my $lasttoken = "";
my $inChar = 0; my $inString = 0; my $inComment = 0; my $inSLC = 0;
my $inParen = 0;
foreach my $token (@tokens) {
if (!$token) { next; };
print STDERR "TOK: $token LAS: $lasttoken ICH: $inChar ICO: $inComment ISL: $inSLC IST: $inString\n" if ($localDebug || $cppDebug);
if (!$fpdone) {
if (!$inParen && $token =~ /\w/) {
$lastpart .= $token;
$fpdone = 1;
next;
} elsif ($token eq "//" && !$inComment) {
# Since we don't strip single-line comments, we have to avoid breaking the parse
# when a macro is included. (Note that this makes us consistent which GNU cpp,
# but other C preprocessors will choke on any code that trips this case.)
$inSLC = 1;
$token = "/*";
$lastpart .= $token;
$fpdone = 1;
next;
} elsif ($token eq "/*" && !$inChar && !$inString && !$inSLC) {
$inComment = 1;
} elsif ($token eq "*/" && !$inChar && !$inString && !$inSLC) {
$inComment = 0;
} elsif ($token eq '\\') {
if ($lasttoken eq '\\') { $lasttoken = ""; }
else { $lasttoken = $token; }
} elsif ($token eq '"') {
if ($lasttoken ne '\\') {
if (!$inChar && !$inComment && !$inSLC) {
$inString = !$inString;
}
}
$lasttoken = $token;
} elsif ($token eq "'") {
if ($lasttoken ne '\\') {
if (!$inString && !$inComment && !$inSLC) {
$inChar = !$inChar;
}
}
$lasttoken = $token;
} elsif (!$inChar && !$inString && !$inComment && !$inSLC) {
if ($token eq "(") {
$inParen++;
} elsif ($token eq ")") {
$inParen--;
} elsif ($token =~ /\s/) {
if (!$inParen) {
$fpdone = 1;
}
}
$lasttoken = $token;
}
$firstpart .= $token;
} else {
print STDERR "TAILTOKEN: \"$token\"\n" if ($cppDebug);
if ($token eq "//" && !$inComment) {
$inSLC = 1;
$token = "/*";
} elsif ($token eq "/*" && !$inChar && !$inString && !$inSLC) {
$inComment = 1;
} elsif ($token eq "*/" && !$inChar && !$inString && !$inSLC) {
$inComment = 0;
}
$lastpart .= $token;
}
}
$firstpart =~ s/^\(//s;
$firstpart =~ s/\s*$//s;
$firstpart =~ s/\)$//s;
if ($inSLC) {
# See comment about single-line comments above.
$lastpart .= "*/";
}
print STDERR "FP: \"$firstpart\"\nLP: \"$lastpart\"\nFPLPEND\n" if ($cppDebug || $localDebug);
if ($lastpart) {
my @lines = split(/[\r\n]/, $lastpart);
my $lastline = pop(@lines);
my $definition = "";
foreach my $line (@lines) {
if ($line) {
$line =~ s/\\\s*$//s;
$line .= "\n";
$definition .= $line;
}
}
# $lastline .= "\n";
print STDERR "LL: \"$lastline\"\n" if ($cppDebug);
push(@lines, $lastline);
$definition .= "$lastline";
print STDERR "ADDING NAME=\"$name\" ARGS=\"$firstpart\" DEFINITION=\"$definition\"\n" if ($cppDebug);
if (exists $CPP_HASH{$name}) {
warn "Multiple definitions for $name. Using first.\n" if (($cppDebug || $warnAllMultipleDefinitions) && $HeaderDoc::enable_cpp);
} else {
$CPP_HASH{$name} = $definition;
if (length($firstpart)) {
$CPP_ARG_HASH{$name} = $firstpart;
}
}
} else {
# This is defining a function-like macro to wipe.
# warn("Unable to process #define macro \"$name\".\n");
if (exists $CPP_HASH{$name}) {
warn "Multiple definitions for $name. Using first.\n" if ($cppDebug || $warnAllMultipleDefinitions);
} else {
$CPP_HASH{$name} = "";
if (length($firstpart)) {
$CPP_ARG_HASH{$name} = $firstpart;
}
}
}
} elsif ($slstring =~ s/^\s*#define\s+(\w+)\s*$//s) {
my $name = $1;
# This is defining a single token to delete.
if (exists $CPP_HASH{$name}) {
warn "Multiple definitions for $name. Using first.\n" if ($cppDebug || $warnAllMultipleDefinitions);
} else {
$CPP_HASH{$name} = "";
}
} else {
warn "COWARDLY REFUSING TO HANDLE \"$string\".\n" if ($HeaderDoc::enable_cpp);
}
}
# /*!
# @abstract
# Adds C preprocessor macro passed in with the -D flag
# on the command line.
# */
sub cpp_add_cl
{
my $name = shift;
my $value = shift;
$CPP_HASH{$name} = $value;
}
# /*!
# @abstract
# Performs C preprocessing on a single token.
# @discussion
# Much of the actual processing happens in the caller. For simple substitutions, this
# returns the updated part. For function-like macros, this returns true for the
# hasargs value and also returns an array of argument names for use when processing
# the contents of the macros. In practice, that third value is never used.
# @param part
# The part to process.
# @param linenum
# The line number where the part appears. Used for determining which #define directives
# apply at that point in time.
# @result
# Returns the array ($newtoken, $hasargs, \@arguments)
# */
sub cpp_preprocess
{
my $part = shift;
my $linenum = shift;
# my $hashlistref = shift;
# my $arghashlistref = shift;
my $hasargs = 0;
# my @hashlist = ();
# my @arghashlist = ();
# if ($hashlistref) { @hashlist = @{$hashlistref}; }
# if ($arghashlistref) { @arghashlist = @{$arghashlistref}; }
my $count = 0;
if ($HeaderDoc::enable_cpp > 0) {
print STDERR "CPP ENABLE\n" if ($cppDebug > 1);
foreach my $hashhashref (@HeaderDoc::cppHashList) {
print STDERR "HASHREFCHECK\n" if ($cppDebug > 1);
my $hashref = $hashhashref->{HASHREF};
print STDERR "HASHREF: $hashref\n" if ($cppDebug);
if (!$hashref) {
warn "Empty hashref object!\n";
next;
}
my %hash = %{$hashhashref->{HASHREF}};
if ($linenum <= $hashhashref->{LINENUM}) {
print STDERR "Skiping hash $hashhashref->{FILENAME}. Line not reached.\n" if ($cppDebug);
next;
}
print STDERR "COUNT: $count\nNARGHASHES: ".scalar(@HeaderDoc::cppArgHashList)."\n" if ($cppDebug);
print STDERR "NHASHES: ".scalar(@HeaderDoc::cppHashList)."\n" if ($cppDebug);
my $arghashref = $HeaderDoc::cppArgHashList[$count++];
my %arghash = %{$arghashref};
my $altpart = $hash{$part};
my $exists = defined $hash{$part};
if ($exists) {
print STDERR "EXTHASH FOUND NAME=\"$part\" REPLACEMENT=\"$altpart\"\n" if ($cppDebug);
if ($arghash{$part}) { $hasargs = 1; }
print STDERR "HASARGS: $hasargs\n" if ($cppDebug);
return ($altpart, $hasargs, $arghash{$part});
}
}
my $altpart = $CPP_HASH{$part};
my $exists = exists $CPP_HASH{$part};
if ($exists) {
print STDERR "FOUND NAME=\"$part\" REPLACEMENT=\"$altpart\"\n" if ($cppDebug);
if (exists($CPP_ARG_HASH{$part})) { $hasargs = 1; }
print STDERR "HASARGS: $hasargs\n" if ($cppDebug);
return ($altpart, $hasargs, $CPP_ARG_HASH{$part});
}
} else {
print STDERR "C preprocessing is disabled.\n" if ($cppDebug);
}
# If we got here, either CPP is disabled or we didn't find anything.
if ($HeaderDoc::enable_cpp != -1) {
print STDERR "Checking token \"$part\" for ignored macros\n" if ($cppDebug);
my $altpart = $HeaderDoc::perHeaderIgnoreFuncMacros{$part};
if ($altpart && length($altpart)) {
print STDERR "Found token \"$part\" among ignored macros\n" if ($cppDebug);
$hasargs = 2;
$part = "";
}
}
return ($part, $hasargs, "");
}
# /*!
# @abstract
# Returns the current C preprocessor hash tables and
# wipes them clean for the next header.
# */
sub getAndClearCPPHash
{
my %newhash = %CPP_HASH;
my %newarghash = %CPP_ARG_HASH;
%CPP_HASH = ();
%CPP_ARG_HASH = ();
return (\%newhash, \%newarghash);
}
# /*!
# @abstract
# Sets a new CPP hash and CPP argument hash in place of the existing one.
# @param cpphashref
# A reference to the new CPP symbol hash.
# @param cpparghashref
# A reference to the new CPP argument hash.
# */
sub setCPPHashes
{
my $cpphashref = shift;
my $cpparghashref = shift;
# cluck("setCPPHashes called. HASH: $cpphashref ARGHASH: $cpparghashref\n");
### print STDERR "setCPPHashes called. HASH: $cpphashref ARGHASH: $cpparghashref\n";
### print STDERR "\nDUMPING NEW HASH:\n\n";
### printHash(%{$cpphashref});
### print STDERR "\nDONE\n\n";
### print STDERR "\nDUMPING NEW ARGUMENT HASH:\n\n";
### printHash(%{$cpparghashref});
### print STDERR "\nDONE\n\n";
%CPP_HASH = %{$cpphashref};
%CPP_ARG_HASH = %{$cpparghashref};
}
# /*!
# @abstract
# Parses C preprocessor arguments.
# @param name
# The name of the C preprocessor macro for which these arguments are the parameters.
# @param linenum
# The line number where this line appears. Used for determining which #define directives
# apply at that point in time.
# @param arglistref
# An array containing a parse tree for each actual parameters to this instance of the C
# preprocessor macro (in order of occurrence).
# */
sub cpp_argparse
{
my $name = shift;
my $linenum = shift;
my $arglistref = shift;
# my $cpphashref = shift;
# my $cpparghashref = shift;
my @arglist = ();
if ($arglistref) { @arglist = @{$arglistref}; }
my %arghash = ();
if ($cppDebug) {
print STDERR "CPP_ARGPARSE: NM $name ARGS:\n";
foreach my $arg (@arglist) {
print STDERR "$arg\n";
$arg->printTree();
}
print STDERR "ENDARGS\n";
}
print STDERR "SEARCHING FOR NAME \"$name\"\n" if ($cppDebug);
my ($newtoken, $has_args, $pattern) = cpp_preprocess($name, $linenum); # , $cpphashref, $cpparghashref);
print STDERR "PATTERN WAS \"$pattern\"\n" if ($cppDebug);
my @parts = split(/,/, $pattern);
my $count = 0;
while ($count < scalar(@parts)) {
my $part = $parts[$count];
print STDERR "ORIGPART WAS $part\n" if ($cppDebug);
$part =~ s/\s//sg;
if (!$arglist[$count]) {
warn "Not enough arguments to macro $name\n";
} else {
print STDERR "CALLING ON ".$arglist[$count]."\n" if ($cppDebug);
$arghash{$part} = cpp_subparse($arglist[$count]); #, $cpphashref, $cpparghashref);
print STDERR "PART \"$part\" VALUE: \"".$arghash{$part}."\"\n" if ($cppDebug)
}
print STDERR "POINTS TO $arghash{$part}\n" if ($cppDebug);
$count++;
}
my $retstring = "";
my @ntparts = split(/(\W)/, $newtoken);
my $lastpart = "";
my $poundcount = 0;
foreach my $part (@ntparts) {
if (length($part)) {
print STDERR "PART WAS $part\n" if ($cppDebug);
if ($part eq "#") {
$poundcount++;
} else {
my $curpart = "";
if (defined($arghash{$part})) {
# 1 pound means stringify the next argument
print STDERR "Inserting argument (".$arghash{$part}.") for $part\n" if ($cppDebug);
$curpart = (($poundcount == 1) ? "\"" : "").$arghash{$part}.(($poundcount == 1) ? "\"" : "");
} else {
# 1 pound means stringify the next argument
print STDERR "No arguments found for $part\n" if ($cppDebug);
$curpart = (($poundcount == 1) ? "\"" : "").$part.(($poundcount == 1) ? "\"" : "");
}
if ($poundcount < 2) {
# poundcount of 1 means just stringify, 0 means just insert the token.
# Either way, commit the previous token and set the new last token value
# to the current token.
$retstring .= $lastpart;
$lastpart = $curpart;
} else {
# 2 means concatenate with the last token
# Concatenate this token onto the last token for further processing.
$lastpart .= $curpart;
}
$poundcount = 0;
}
}
}
$retstring .= $lastpart;
return $retstring;
}
# /*!
# @abstract
# Used by cpp_argparse to recursively perform preprocessing on tokens within the
# actual arguments to a macro.
# @param tree
# A parse tree for the actual argument in question.
# */
sub cpp_subparse($)
{
my $tree = shift;
# my $hashlistref = shift;
# my $arghashlistref = shift;
my ($newtoken, $has_args, $tempstring) = cpp_preprocess($tree->token(), $tree->linenum()); #, $hashlistref, $arghashlistref);
if ($cppDebug) {
print STDERR "SUBPARSE: ARGS: $has_args\n";
$tree->dbprint();
print STDERR "END SUBPARSE DUMP\n";
}
if ($has_args) {
my $name = $tree->token();
my $paren = $tree->next();
if (!$paren) { return; }
if ($paren->token() =~ /\(/) {
# Recurse.
my @parts = ();
my $fc = $paren->firstchild();
my $subparsetop = HeaderDoc::ParseTree->new();
my $subparsecur = $subparsetop;
while ($fc) { # drop closing ')'
my $fct = $fc->token();
print STDERR "FCT: $fct\n" if ($cppDebug);
if ($fct eq ',') {
print STDERR "PUSH\n" if ($cppDebug);
push(@parts, $subparsetop);
$subparsetop = $subparsecur = HeaderDoc::ParseTree->new();
} else {
print STDERR "NEXT\n" if ($cppDebug);
$subparsecur = $subparsecur->next(HeaderDoc::ParseTree->new());
$subparsecur->token($fct);
}
$fc = $fc->next();
}
push(@parts, $subparsetop);
print STDERR "CALLING ARGPARSE FROM cpp_subparse().\n" if ($cppDebug);
my $ap = cpp_argparse($name, $tree->linenum(), \@parts); #, $hashlistref, $arghashlistref);
print STDERR "Changed token from $tree (\"".$tree->token."\") to \"$ap\"\n" if ($cppDebug);
$tree->token($ap);
$paren->token("");
$paren->firstchild(undef);
if ($paren->next->token ne ")") {
warn("Tree structure problem (cpp_subparse point 1). Please file a bug.\n");
} else {
$paren->next->token("");
}
} else {
warn("Tree structure problem (cpp_subparse point 2). Please file a bug.\n");
}
} else {
$tree->token($newtoken);
}
my $fc = $tree->firstchild();
if ($fc) {
cpp_subparse($fc);
}
my $n = $tree->next();
if ($n) {
cpp_subparse($n);
}
return $tree->textTree();
}
# /*!
# @abstract
# Scrapes the C++ superclass information from a declaration.
# @discussion
# This function is also used for the Java implements information.
# */
sub cppsupers
{
my $string = shift;
my $lang = shift;
my $sublang = shift;
my $localDebug = 0;
my @parts = split(/(\W)/, $string);
my $superlist = "";
my $cursuper = "";
# my ($parseTokens{sotemplate}, $parseTokens{eotemplate}, $parseTokens{operator}, $parseTokens{soc}, $parseTokens{eoc}, $parseTokens{ilc}, $parseTokens{ilc_b}, $parseTokens{sofunction},
# $parseTokens{soprocedure}, $parseTokens{sopreproc}, $parseTokens{lbrace}, $parseTokens{rbrace}, $parseTokens{unionname}, $parseTokens{structname},
# $parseTokens{enumname},
# $parseTokens{typedefname}, $parseTokens{varname}, $parseTokens{constname}, $parseTokens{structisbrace}, $parseTokens{macronames},
# $classregexp, $classbraceregexp, $classclosebraceregexp, $accessregexp,
# $requiredregexp, $parseTokens{propname}, $parseTokens{objcdynamicname}, $parseTokens{objcsynthesizename}, $moduleregexp, $parseTokens{definename},
# $parseTokens{functionisbrace}, $parseTokens{classisbrace}, $parseTokens{lbraceconditionalre}, $parseTokens{lbraceunconditionalre}, $parseTokens{assignmentwithcolon},
# $labelregexp, $parseTokens{parmswithcurlybraces}, $parseTokens{superclasseswithcurlybraces}, $parseTokens{soconstructor}) = parseTokens($lang, $sublang);
my %parseTokens = %{parseTokens($lang, $sublang)};
# print STDERR "PROPNAME4: $parseTokens{propname}\n";
my $accessregexp = $parseTokens{accessregexp};
my $inTemplate = 0;
foreach my $part (@parts) {
if ($part eq "<") {
$inTemplate = 1;
$cursuper .= $part;
} elsif ($part eq ">") {
$inTemplate = 0;
$cursuper .= $part;
} elsif (!$inTemplate && $part eq ",") {
$superlist .= "\cA".$cursuper;
$cursuper = "";
} elsif ($part =~ /\cA/) {
# drop
} elsif (!length($accessregexp) || $part !~ /$accessregexp/) {
$cursuper .= $part;
}
}
$superlist .= "\cA".$cursuper;
$superlist =~ s/^\cA//s;
# print STDERR "CPPSUPERS LANG IS $lang\n";
if ($lang eq "tcl" || $sublang eq "tcl") {
$superlist =~ s/^\s*{//s;
$superlist =~ s/}\s*$//s;
}
print STDERR "SUPERLIST IS $superlist\n" if ($localDebug);
return $superlist;
}
# /*!
# @abstract
# Strips comments out of a return type declaration.
# @discussion
# This should only be used when handling return types. It does not handle
# strings or anything requiring actual parsing. It strictly rips out
# C comments (both single-line and standard).
# */
sub decomment
{
my $string = shift;
my $newstring = "";
my @lines = split(/\n/, $string);
foreach my $line (@lines) {
$line =~ s/\/\/.*$//g;
if (length($line)) {
$newstring .= $line;
}
}
$newstring =~ s/\/\*.*?\*\///sg;
return $newstring;
}
# /*!
# @abstract
# Reconstructs a HeaderDoc comment from a field list.
# @param fields
# An array of fields.
# @param preAtPart
# The part before the first \@ sign (the declaration of a
# new-style HeaderDoc comment, or empty for an old-style
# HeaderDoc comment).
# @param message
# Content to use if the field set is empty.
# */
sub buildCommentFromFields
{
my @fields = shift;
my $preAtPart = shift;
my $message = shift;
my $string = "";
my $first = 1;
my $at = "";
foreach my $field (@fields) {
# print STDERR "FIELD: $field\n";
$string .= $at.$field."\n";
if ($first && length($preAtPart)) {
$string .= " ".$preAtPart."\n";
$first = 0;
}
$at = "\@";
}
if ($string =~ /\S/) {
if ($string =~ /^\s*\/\*/s) {
$string .= " */\n";
}
$string = "$message\n".$string;
}
return $string;
}
# /*!
# @abstract
# Returns a regular expression for searching for macro tokens
# derived from a hash table.
# @param nameref
# A reference to a hash in which the names of the macro tokens
# (e.g. #define, #if, #ifdef) are the hash keys.
# @param onlywithpound
# If 0, includes all tokens as-is.
#
# If 1, includes only tokens that begin with a # sign and
# strips off the leading #, e.g. define instead of
# #define.
#
# If 2, includes only tokens that do not begin with a # sign.
# */
sub macroRegexpFromList
{
# cluck("here");
my $nameref = shift;
my $onlywithpound = shift;
my %names = %{$nameref};
my $regexpstring = "";
my $pipe = "";
my $lparen = "(";
foreach my $name (keys %names) {
# print "MACRONAME $name\n";
if (!$onlywithpound) {
$regexpstring .= $lparen.$pipe.$name;
$pipe = "|"; $lparen = "";
} elsif ($onlywithpound == 1) {
# Stuff starting with "#"
if ($name =~ /^#/) {
my $temp = $name;
$temp =~ s/^#//;
$regexpstring .= $lparen.$pipe.$temp;
$pipe = "|"; $lparen = "";
}
} elsif ($onlywithpound == 2) {
# Stuff that does NOT start with "#"
if ($name !~ /^#/) {
$regexpstring .= $lparen.$pipe.$name;
$pipe = "|"; $lparen = "";
}
}
}
if ($regexpstring ne "") { $regexpstring .= ")"; }
return $regexpstring;
}
# /*!
# @abstract
# Returns true if a field set is effectively empty.
# */
sub empty_comment
{
my @fields = shift;
if (!scalar(@fields)) { return 1; }
if (scalar(@fields) == 1 && $fields[0] =~ /^\s*\/\*\!\s*$/) { return 1; }
return 0;
}
# /*!
# @abstract
# Merges CPP hashes and CPP argument hashes based on interpreting
# a stack of #if ... #else ... #elif ... #endif
# directives.
# @discussion
# Used when processing blocks that might corrupt each other.
#
# For example, if you have a #if ... #else ... #endif
# block in which the #if side is a #define
# that defines the name of a nonexistent function to an existing
# function and the #else side or #elif
# side is a real function definition for that same symbol name,
# the C preprocessor would dutifully turn that function declaration
# into a declaration for the other function. Oops.
#
# Instead, upon entering such a block, the parser makes a backup of
# the C preprocessor's working hashes (which contain C preprocessing
# tokens and argument lists). This gives the preprocessor a
# base state for the block. Whenever a #else or
# #elif directive appears, the parser makes an
# intermediate copy of the hash coming out of that block, then
# resets the working hashes to the base state (prior to the initial
# #if). When the closing #endif
# directive appears, the parser merges all of the intermediate
# (per-block) hashes together and sets the working hashes to
# that value.
#
# For detailed explanation, see the documentation for
# {@link //apple_ref/perl/cl/HeaderDoc::HashObject HashObject}.
# */
sub cppHashMerge
{
my $root = shift;
my $curhashobj = shift;
my $cpphashref = shift;
my $cpparghashref = shift;
my $token = shift;
my $localDebug = 0;
print STDERR "IN cppHashMerge WITH TOKEN: $token\n" if ($localDebug);
if (!$root) {
$root = HeaderDoc::HashObject->new();
}
if (!$curhashobj) {
$curhashobj = $root;
}
print STDERR "GOING IN:\n" if ($localDebug);
$root->dbprint() if ($localDebug);
my $hashret = ();
my $arghashret = ();
SWITCH: {
($token =~ /#if/) && do {
print STDERR "IF CASE\n" if ($localDebug);
($hashret, $arghashret) = $curhashobj->cppHashNodeSetHashes($cpphashref, $cpparghashref);
# print STDERR "CHECK: ".$curhashobj->{CPPHASH}.", ".$curhashobj->{CPPARGHASH}."\n";
$curhashobj = $curhashobj->cppHashNodeNewChild($token);
last;
};
($token =~ /#else/) && do {
print STDERR "ELSE CASE\n" if ($localDebug);
# Throw away values from previous if/elif clause for now.
$curhashobj-> cppHashNodeSetHashes($cpphashref, $cpparghashref);
$curhashobj = $curhashobj->cppHashNodeNewSibling($token);
# Return the parent node's hashes.
($hashret, $arghashret) = $curhashobj->cppHashNodeResetToParent();
last;
};
($token =~ /#elif/) && do {
print STDERR "ELIF CASE\n" if ($localDebug);
# Throw away values from previous if/elif clause for now.
$curhashobj->cppHashNodeSetHashes($cpphashref, $cpparghashref);
$curhashobj = $curhashobj->cppHashNodeNewSibling($token);
# Return the parent node's hashes.
($hashret, $arghashret) = $curhashobj->cppHashNodeResetToParent();
last;
};
($token =~ /#endif/) && do {
print STDERR "ENDIF CASE\n" if ($localDebug);
# Throw away values from previous if/else/elif clause for now.
$curhashobj->cppHashNodeSetHashes($cpphashref, $cpparghashref);
# Return the union of all this node's siblings' hashes.
($curhashobj, $hashret, $arghashret) = $curhashobj->cppHashNodePop();
last;
};
{
# die("Unknown CPP macro type \"$token\" in cppHashMerge\n");
# Other macros make it in here, so return what was passed in.
print STDERR "COMING OUT:\n" if ($localDebug);
$root->dbprint() if ($localDebug);
return ($cpphashref, $cpparghashref, $root, $curhashobj);
};
}
# warn("HR: $hashret, AHR: $arghashret\n");
# print STDERR "CPP HASH DUMP:\n";
# printHash(%{$hashret});
# print STDERR "DONE\n";
print STDERR "COMING OUT:\n" if ($localDebug);
$root->dbprint() if ($localDebug);
return ($hashret, $arghashret, $root, $curhashobj);
}
# /*!
# @abstract
# Configures the access control state and optional/required
# state for methods and variables within a class based on
# the current language and class type.
# */
sub configureAccessControlStateForClass
{
my $parserState = shift;
my $lang = $parserState->{lang};
if ($lang eq "php") {
$HeaderDoc::AccessControlState = "public";
} elsif ($lang eq "java") {
$HeaderDoc::AccessControlState = "package-private";
} elsif ($lang eq "C") {
if ($parserState->{classIsObjC} || ($parserState->{sublang} eq "IDL" && $HeaderDoc::idl_language eq "occ")) {
$HeaderDoc::AccessControlState = "private";
if ($parserState->{inProtocol}) {
$HeaderDoc::OptionalOrRequired = "\@required"; # The default in Objective C
}
} elsif ($parserState->{sublang} eq "IDL" && ($HeaderDoc::idl_language eq "idl" || $HeaderDoc::idl_language eq "javascript" || $HeaderDoc::idl_language eq "js")) {
$HeaderDoc::AccessControlState = "public";
} else {
$HeaderDoc::AccessControlState = "protected";
}
}
}
1;