#! /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: # # # @param ignoreref # A reference to a hash of tokens to ignore on all headers. # @param perheaderignoreref # A reference to a hash of tokens, generated from \@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: # # # # @vargroup External variables # # @var HeaderDoc::parseIfElse # Enables parsing of 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: # # @var inRegexpFirstPart # When parsing regular expressions, the contents of the right side are # largely unparsed (no parenthesis or bracket interpolation, for example). # Thus, it is important to know whether you are in the left side or the # right side during parsing. Unfortunately, the 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: # # # # The value is 2 up to and including the leading symbol (e.g. /). # It goes to zero upon reaching the symbol that terminates the first # part of the regular expression (e.g. /). # @var inRegexpCharClass # # In a regular expression character class, the first character # behaves differently; a closing bracket as the first character # in a character class is treated as a literal. (For example, # []] is a character class containing only a close bracket.) # To support this, the inRegexpCharClass has # several values: # # # @var regexpNoInterpolate # Certain regular expression commands don't result in any parsing # within them (e.g. the tr command). If set, this is equivalent to # setting 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. # # # @var treeSkip # This gets set to 1 if the current part should not be inserted into the parse tree # (generally because it has already been inserted in some form during parsing). # @var treePopOnNewLine # This indicates that the current position in the parse tree should be popped from # the 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 =~ /{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 =~ /{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). # #
#
inputCounter
#
The new value for inputCounter, adjusted for the lines # that have were parsed.
#
cppAccessControlState
#
The new access control state (public, private, etc.)
#
classType
#
The new value for class type, based on what class was # last parsed. Used when parsing fragments within a class.
#
classObjects
#
A reference to an array of class objects (either # CPPClass or ObjCClass).
#
categoryObjects
#
A reference to an array of category objects # (ObjCCategory).
#
blockOffset
#
The new block offset (relative to inputCounter), # adjusted for the lines already parsed.
#
numcurlybraces
#
The number of curly braces parsed. Not # particularly useful anymore.
#
foundMatch
#
True if this pass found an object that matches # the requested type (e.g. an \@function # comment matched a function or function-like macro).
#
lang
#
The programming language.
#
sublang
#
The sublanguage (which may change as new # classes are parsed).
#
# # @discussion # This is the block parser API you should generally be calling if you are # reusing this code for other purposes. It parses a declaration and # returns an appropriate set of HeaderDoc objects. It includes all of # the HeaderDoc name processing voodoo. More explanation of this code # is probably in order, but there's no time right now. # # Common mistakes: # # Unlike {@link blockParse}, you must increment the input # counter or you risk an infinite loop. (When looping # with {@link blockParse}, you must not increment # the input counter or you will skip lines.) # # @var blockmode # Possible values: # # # */ sub blockParseOutside { my $apiOwner = shift; my $inFunction = shift; my $inUnknown = shift; my $inTypedef = shift; my $inStruct = shift; my $inEnum = shift; my $inUnion = shift; my $inConstant = shift; my $inVar = shift; my $inMethod = shift; my $inPDefine = shift; my $inClass = shift; my $inInterface = shift; # my $blockDec = shift; # my $blockmode = shift; my $blockOffset = shift; # my $case_sensitive = shift; my $categoryObjectsref = shift; my $classObjectsref = shift; my $classType = shift; my $cppAccessControlState = shift; # my $curtype = shift; # my $declaration = shift; my $fieldsref = shift; my $fullpath = shift; my $functionGroup = shift; my $headerObject = shift; # my $inClass = shift; # my $innertype = shift; my $inputCounter = shift; my $inputlinesref = shift; # my $keywordhashref = shift; my $lang = shift; # my $namelist = shift; # my $newcount = shift; my $nlines = shift; # my $outertype = shift; # my $posstypes = shift; my $preAtPart = shift; # my $parseTokens{typedefname} = shift; # my $typelist = shift; # my $varIsConstant = shift; my $xml_output = shift; # cluck("BPO: FP: $fullpath\n"); my $filename = basename($fullpath); # print STDERR "PREATPART: $preAtPart\n"; my $localDebug = shift; my $hangDebug = shift; my $parmDebug = shift; my $blockDebug = shift; my $subparse = shift; my $subparseTree = shift; # my $outputdir = shift; my $nodec = shift; my $allow_multi = shift; my $subparseCommentTree = shift; # Used in block mode because # subparseTree is empty by # definition when the comment # precedes the declaration. my $sublang = shift; # optional FOR NOW. if (!$sublang) { print STDERR "WARNING: Old API use detected. Please update your\ncode to call blockParseOutside with a sublang argument.\nThis will break in a future version of HeaderDoc.\n"; cluck("Backtrace:\n"); $sublang = $HeaderDoc::sublang; } my $hashtreecur = shift; # If you don't pass these correctly, you won't get the my $hashtreeroot = shift; # support for #if/#else/#endif blocks. # print STDERR "IN BLOCKPARSEOUTSIDE HTC: $hashtreecur HTR: $hashtreeroot\n"; # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 001: SUBLANG NOMATCH\n"; } print STDERR "ALLOW_MULTI: $allow_multi\n" if ($localDebug); # $localDebug = 1; $blockDebug = 1; my $subparseDebug = 0; my $nameDebug = 0; my $nameObjDebug = 0; my $nestClassDebug = 0; my $missingParseTreeDebug = 0; my $mustLockDiscussion = 0; # cluck('BPO') if (!$subparse); # cluck('BPO SUBPARSE') if ($subparse); if ($subparse && ($localDebug || $subparseDebug)) { print "SUBPARSE COMMENT TREE: $subparseCommentTree\n"; $subparseCommentTree->dbprint(); } if ($inClass && $nestClassDebug) { $localDebug = 1; $blockDebug = 1; $hangDebug = 1; # turn on the kitchen sink. } # The number of curly braces at the top level---aids in skipping # declarations at the outer levels my $numcurlybraces = 0; if ($localDebug) { if ($subparse) { print STDERR "SUBPARSE\n"; } else { print STDERR "PARSE\n"; } } my $lastParseTree = undef; my $slowokay = ($subparse == 2) ? 1 : 0; my @linkobjs = (); my $old_enable_cpp = $HeaderDoc::enable_cpp; if ($subparse) { # We don't want to remove #define macros just because they appeared # within a class declaration.... :-) $HeaderDoc::enable_cpp = -1; } print STDERR "IN BLOCKPARSEOUTSIDE, INPUTCOUNTER: $inputCounter BLOCKOFFSET: $blockOffset\n" if ($localDebug || $HeaderDoc::inputCounterDebug); # Args here my @classObjects = @{$classObjectsref}; my @categoryObjects = (); if ($categoryObjectsref) { # print STDERR "GOT categoryObjectsRef!\n"; @categoryObjects = @{$categoryObjectsref}; } my @fields = @{$fieldsref}; my @inputLines = @{$inputlinesref}; my @parseTrees = (); my $methods_with_new_parser = 1; my $curObj = undef; my $classKeyword = "auto"; my $functionContents = ""; my $subparseInputCounter = undef; my $subparseBlockOffset = undef; if ($subparse && $subparseTree) { $subparseInputCounter = $subparseTree->{LINENUM}; $subparseBlockOffset = 0; } # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 002: SUBLANG NOMATCH\n"; } # 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, $HeaderDoc::sublang); my %parseTokens = %{parseTokens($lang, $sublang)}; # print STDERR "BPO: FIELDS: \n"; # foreach my $field (@fields) { # print STDERR "FIELD: $field\n"; # } # print STDERR "END FIELDS\n"; # printFields(\@fields); my $foundMatch = 0; print STDERR "blockParseOutside: APIOWNER IS $apiOwner\n" if ($localDebug); if ($inUnknown || $inTypedef || $inStruct || $inEnum || $inUnion || $inConstant || $inVar || $inFunction || ($inMethod && $methods_with_new_parser) || $inPDefine || $inClass) { # print STDERR "PROPNAME3: $parseTokens{propname}\n"; my $varIsConstant = 0; my $blockmode = 0; my $blocklevel = 0; my $curtype = ""; my $warntype = ""; my $blockDebug = 0 || $localDebug; my $parmDebug = 0 || $localDebug; # my $localDebug = 1; # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 003: SUBLANG NOMATCH\n"; } if ($inPDefine == 2) { print STDERR "BLOCKMODE[1] -> 1\n" if ($localDebug || $blockDebug); $blockmode = 1; $mustLockDiscussion = 1; if ($subparse) { $subparseTree = $subparseCommentTree->next(); print "LINE NUMBER NOW: ".$subparseTree->{LINENUM}."\n" if ($subparseDebug); print "INPUT COUNTER OF TOKEN: ".$subparseTree->{INPUTCOUNTER}."\n" if ($subparseDebug); print "BLOCK OFFSET OF TOKEN: ".$subparseTree->{BLOCKOFFSET}."\n" if ($subparseDebug); # Because this was set previously, # reset it here. $subparseInputCounter = $subparseTree->{LINENUM}; # Because the first comment in a block # does not have input counter information # associated with it (no declaration there), # we have to add it from the LINENUM value. $subparseTree->{INPUTCOUNTER} = $subparseInputCounter; $subparseTree->{BLOCKOFFSET} = 0; } } if ($inFunction || $inMethod) { if ($localDebug) { if ($inMethod) { print STDERR "inMethod\n"; } else { print STDERR "inFunction\n"; } } my $method = 0; if ($classType eq "occ" || $classType eq "intf" || $classType eq "occCat") { if ($apiOwner !~ /^HeaderDoc::Header/) { $method = 1; } } if ($method) { $curObj = HeaderDoc::Method->new("LANG" => $lang, "SUBLANG" => $sublang); $curtype = "method"; } else { $curObj = HeaderDoc::Function->new("LANG" => $lang, "SUBLANG" => $sublang); $curtype = "function"; } $curObj->apiOwner($apiOwner); if ($xml_output) { $curObj->outputformat("hdxml"); } else { $curObj->outputformat("html"); } if (length($functionGroup)) { $curObj->group($functionGroup); } else { $curObj->group($HeaderDoc::globalGroup); } $curObj->filename($filename); $curObj->fullpath($fullpath); if (defined($subparseInputCounter)) { $curObj->linenuminblock($subparseInputCounter); $curObj->blockoffset($subparseBlockOffset); } else { $curObj->linenuminblock($inputCounter); $curObj->blockoffset($blockOffset); } # $curObj->linenum($inputCounter+$blockOffset); # print STDERR "LINE NUMBER IS $inputCounter + $blockOffset\n"; # printFields(\@fields); if ($method) { $curObj->processComment(\@fields); } else { $curObj->processComment(\@fields); } } elsif ($inPDefine) { print STDERR "inPDefine\n" if ($localDebug); $curtype = "#define"; if ($blockmode) { $warntype = "defineblock"; } $curObj = HeaderDoc::PDefine->new("LANG" => $lang, "SUBLANG" => $sublang); $curObj->apiOwner($apiOwner); $curObj->group($HeaderDoc::globalGroup); if ($xml_output) { $curObj->outputformat("hdxml"); } else { $curObj->outputformat("html"); } $curObj->inDefineBlock($blockmode); $curObj->filename($filename); $curObj->fullpath($fullpath); if (defined($subparseInputCounter)) { $curObj->linenuminblock($subparseInputCounter); $curObj->blockoffset($subparseBlockOffset); } else { $curObj->linenuminblock($inputCounter); $curObj->blockoffset($blockOffset); } # $curObj->linenum($inputCounter+$blockOffset); $curObj->processComment(\@fields); if ($mustLockDiscussion) { $curObj->discussionLocked(1); } } elsif ($inVar) { # print STDERR "inVar!!\n"; print STDERR "inVar\n" if ($localDebug); $curtype = "variable"; $varIsConstant = 0; $curObj = HeaderDoc::Var->new("LANG" => $lang, "SUBLANG" => $sublang); $curObj->apiOwner($apiOwner); $curObj->group($HeaderDoc::globalGroup); if ($xml_output) { $curObj->outputformat("hdxml"); } else { $curObj->outputformat("html"); } $curObj->filename($filename); $curObj->fullpath($fullpath); if (defined($subparseInputCounter)) { $curObj->linenuminblock($subparseInputCounter); $curObj->blockoffset($subparseBlockOffset); } else { $curObj->linenuminblock($inputCounter); $curObj->blockoffset($blockOffset); } # $curObj->linenum($inputCounter+$blockOffset); $curObj->processComment(\@fields); } elsif ($inConstant) { print STDERR "inConstant\n" if ($localDebug); $curtype = "constant"; $varIsConstant = 1; $curObj = HeaderDoc::Constant->new("LANG" => $lang, "SUBLANG" => $sublang); $curObj->apiOwner($apiOwner); $curObj->group($HeaderDoc::globalGroup); if ($xml_output) { $curObj->outputformat("hdxml"); } else { $curObj->outputformat("html"); } $curObj->filename($filename); $curObj->fullpath($fullpath); if (defined($subparseInputCounter)) { $curObj->linenuminblock($subparseInputCounter); $curObj->blockoffset($subparseBlockOffset); } else { $curObj->linenuminblock($inputCounter); $curObj->blockoffset($blockOffset); } # $curObj->linenum($inputCounter+$blockOffset); $curObj->processComment(\@fields); } elsif ($inUnknown || $inClass) { if ($localDebug) { if ($inUnknown) { print STDERR "inUnknown\n"; } else { print STDERR "inClass\n"; } } $curtype = "UNKNOWN"; if ($inUnknown) { $curObj = HeaderDoc::HeaderElement->new("LANG" => $lang, "SUBLANG" => $sublang); $curObj->apiOwner($apiOwner); $classKeyword = "auto"; } else { $curObj = HeaderDoc::APIOwner->new("LANG" => $lang, "SUBLANG" => $sublang); $curObj->apiOwner($apiOwner); $classKeyword = $fields[0]; $classKeyword =~ s/^\s*\/\*\!\s*//s; if (!length($classKeyword)) { $classKeyword = $fields[1]; } } $curObj->filename($filename); $curObj->fullpath($fullpath); $curObj->apiOwner($apiOwner); $curObj->group($HeaderDoc::globalGroup); if ($xml_output) { $curObj->outputformat("hdxml"); } else { $curObj->outputformat("html"); } warnHDComment(\@inputLines, $inputCounter, $blockOffset, $lang, "unknown", "11", \%parseTokens); } elsif ($inTypedef) { # print STDERR "inTypedef\n"; $localDebug = 1; print STDERR "inTypedef\n" if ($localDebug); $curtype = $parseTokens{typedefname}; # if ($lang eq "pascal") { # $curtype = "type"; # } else { # $curtype = "typedef"; # } $curObj = HeaderDoc::Typedef->new("LANG" => $lang, "SUBLANG" => $sublang); $curObj->apiOwner($apiOwner); $curObj->group($HeaderDoc::globalGroup); if ($xml_output) { $curObj->outputformat("hdxml"); } else { $curObj->outputformat("html"); } $curObj->filename($filename); $curObj->fullpath($fullpath); if (defined($subparseInputCounter)) { $curObj->linenuminblock($subparseInputCounter); $curObj->blockoffset($subparseBlockOffset); } else { $curObj->linenuminblock($inputCounter); $curObj->blockoffset($blockOffset); } # $curObj->linenum($inputCounter+$blockOffset); $curObj->processComment(\@fields); $curObj->masterEnum(0); warnHDComment(\@inputLines, $inputCounter, $blockOffset, $lang, "enum", "11a", \%parseTokens); # if a struct declaration precedes the typedef, suck it up } elsif ($inStruct || $inUnion) { if ($localDebug) { if ($inUnion) { print STDERR "inUnion\n"; } else { print STDERR "inStruct\n"; } } if ($inUnion) { $curtype = "union"; } else { $curtype = "struct"; } $curObj = HeaderDoc::Struct->new("LANG" => $lang, "SUBLANG" => $sublang); $curObj->apiOwner($apiOwner); $curObj->group($HeaderDoc::globalGroup); if ($inUnion) { $curObj->isUnion(1); } else { $curObj->isUnion(0); } if ($xml_output) { $curObj->outputformat("hdxml"); } else { $curObj->outputformat("html"); } $curObj->filename($filename); $curObj->fullpath($fullpath); if (defined($subparseInputCounter)) { $curObj->linenuminblock($subparseInputCounter); $curObj->blockoffset($subparseBlockOffset); } else { $curObj->linenuminblock($inputCounter); $curObj->blockoffset($blockOffset); } # $curObj->linenum($inputCounter+$blockOffset); $curObj->processComment(\@fields); warnHDComment(\@inputLines, $inputCounter, $blockOffset, $lang, "$curtype", "11b", \%parseTokens); } elsif ($inEnum) { print STDERR "inEnum\n" if ($localDebug); $curtype = "enum"; $curObj = HeaderDoc::Enum->new("LANG" => $lang, "SUBLANG" => $sublang); $curObj->apiOwner($apiOwner); $curObj->masterEnum(1); $curObj->group($HeaderDoc::globalGroup); if ($xml_output) { $curObj->outputformat("hdxml"); } else { $curObj->outputformat("html"); } $curObj->filename($filename); $curObj->fullpath($fullpath); if (defined($subparseInputCounter)) { $curObj->linenuminblock($subparseInputCounter); $curObj->blockoffset($subparseBlockOffset); } else { $curObj->linenuminblock($inputCounter); $curObj->blockoffset($blockOffset); } # $curObj->linenum($inputCounter+$blockOffset); $curObj->processComment(\@fields); warnHDComment(\@inputLines, $inputCounter, $blockOffset, $lang, "$curtype", "11c", \%parseTokens); } my $origcurtype = $curtype; my $firstBlockObjType = ""; my $firstBlockCurType = ""; # if ($nameDebug) { $curObj->dbprint(); } if (!length($warntype)) { $warntype = $curtype; } while (($inputLines[$inputCounter] !~ /\S/o) && ($inputCounter <= $nlines)){ # print STDERR "BLANKLINE IS $inputLines[$inputCounter]\n"; $inputCounter++; print STDERR "INCREMENTED INPUTCOUNTER [3]\n" if ($HeaderDoc::inputCounterDebug); # print STDERR "warntype is $warntype\n"; warnHDComment(\@inputLines, $inputCounter, $blockOffset, $lang, "$warntype", "12", \%parseTokens); print STDERR "Input line number[7]: $inputCounter\n" if ($localDebug); }; # my $declaration = $inputLines[$inputCounter]; print STDERR "NEXT LINE is ".$inputLines[$inputCounter].".\n" if ($localDebug); my $outertype = ""; my $newcount = 0; my $declaration = ""; my $namelist = ""; my $extendsClass = ""; my $implementsClass = ""; my $returnedParserState = undef; my $nameObjectsRef = undef; # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 004: SUBLANG NOMATCH\n"; } my ($case_sensitive, $keywordhashref) = $curObj->keywords(); my $typelist = ""; my $innertype = ""; my $posstypes = ""; print STDERR "PTCT: $posstypes =? $curtype\n" if ($localDebug || $blockDebug); my $blockDec = ""; $localDebug = 0 || $nestClassDebug; my $hangDebug = 0 || $localDebug; $subparseDebug = 0 || $localDebug || $subparseDebug; print STDERR "ENTERING IC: $inputCounter\n" if ($localDebug); my $lastParserState = undef; print STDERR "LOOPTEST: (($blockmode || ($outertype ne $curtype && $innertype ne $curtype && $posstypes !~ /$curtype/ && !($inTypedef && $outertype =~ /^(class|\@class|\@interface|\@implementation|\@protocol)/))) && ($inputCounter <= $nlines))\n" if ($localDebug || $hangDebug || $nameDebug || $nameObjDebug || $subparseDebug); my $previousInputCounter = $inputCounter; my $bail = 0; my $checkLineNumbers = 0; my $blockCurNameAutoGenerated = 0; my $firstDeclaration = 1; my $realApiOwner = $apiOwner; my $leading_linenum = $inputCounter+$blockOffset; while (($blockmode || ($outertype ne $curtype && $innertype ne $curtype && $posstypes !~ /$curtype/ && !($inTypedef && $outertype =~ /^(class|\@class|\@interface|\@implementation|\@protocol)/))) && (($inputCounter <= $nlines) || ($subparse && !$checkLineNumbers))) { # ($typestring !~ /$parseTokens{typedefname}/) $apiOwner = $realApiOwner; # print "APIO AT TOP OF BLOCK: $apiOwner\n"; # print "HEADER AT TOP OF BLOCK: $headerObject\n"; print STDERR "TOP OF LOOP: BLOCKMODE IS $blockmode\n" if ($blockDebug || $localDebug || $subparseDebug || $hangDebug); if ($HeaderDoc::parsing_man_pages) { while ($inputLines[$inputCounter] =~ /^\s*(or|and)\s*$/i) { $inputCounter++; } } # print STDERR "DEC: $declaration\n"; if ($firstDeclaration) { $firstDeclaration = 0; } else { if ($HeaderDoc::enableParanoidWarnings && $posstypes !~ "MACRO" && !$blockmode) { my ($tagname, $tag_re, $superclassFieldName) = $curObj->tagNameRegexpAndSuperclassFieldNameForType(); warn("$fullpath:$leading_linenum: ".$tagname." \"".$curObj->name()."\" declaration not\nfound immediately after HeaderDoc comment. Declarations after this will\nbe treated as part of the same declaration.\n"); # warn("Last declaration was $declaration\n"); # warn("CURTYPE $curtype INNERTYPE $innertype OUTERTYPE $outertype POSSTYPES $posstypes\n"); } } if ($hangDebug) { print STDERR "In Block Loop\n"; } if ($HeaderDoc::inputCounterDebug) { print STDERR "In block loop with blockmode: $blockmode, blocklevel = $blocklevel\n"; } # while ($inputLines[$inputCounter] !~ /\S/o && ($inputCounter <= $nlines)) { $inputCounter++; } # if (warnHDComment(\@inputLines, $inputCounter, 0, $lang, "blockParse:$outertype", "18b", \%parseTokens)) { # last; # } else { print STDERR "OK\n"; } print STDERR "DOING SOMETHING\n" if ($localDebug); print STDERR "CURRENT LINE: ".$inputLines[$inputCounter]."\n" if ($localDebug); # $HeaderDoc::ignore_apiuid_errors = 1; # my $oldisdoc = $curObj->appleRefIsDoc(); # $curObj->appleRefIsDoc(1); # my $junk = $curObj->apirefSetup(); # $curObj->appleRefIsDoc($oldisdoc); # $HeaderDoc::ignore_apiuid_errors = 0; # the value of a constant my $value = ""; my $pplref = undef; my $returntype = undef; my $propertyAttributes = undef; my $memberOfClass = ""; my $pridec = ""; my $parseTree = undef; my $simpleTDcontents = ""; my $bpavail = ""; my $conformsToList; # Suddenly feeling nonconformist. print STDERR "Entering blockParse\n" if ($hangDebug); # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 005: SUBLANG NOMATCH\n"; } print STDERR "ENTERING BP WITH IC: $inputCounter\n" if ($HeaderDoc::inputCounterDebug); if ($subparse) { print STDERR "subparse\n" if ($localDebug || $blockDebug || $hangDebug); if ($lastParseTree) { # second parse tree encountered (i.e. last one didn't match) if ($subparseDebug) { print STDERR "GOING FOR ANOTHER PARSE TREE.\n"; $lastParseTree->printTree(); } if ($lastParserState) { my $lastend = $lastParserState->{lastTreeNode}; $parseTree = $lastend->nextTokenNoComments($parseTokens{soc}, $parseTokens{ilc}, $parseTokens{ilc_b}); } else { $parseTree = $lastParseTree->nextTokenNoComments($parseTokens{soc}, $parseTokens{ilc}, $parseTokens{ilc_b}); } if ($subparseDebug) { print STDERR "FOUND:\n"; $parseTree->printTree(); } if (!$parseTree) { my $curname = $curObj->name(); if (!empty_comment(@fields)) { # Don't warn if there wasn't # really a HeaderDoc comment # involved. warn("End of parse tree reached while searching for matching declaration[1].\n"); warn "No matching declaration found. Last name was $curname\n"; warn buildCommentFromFields(@fields, $preAtPart, "The HeaderDoc comment that caused this was:\n")."\n"; warn "$outertype ne $curtype && $innertype ne $curtype && $posstypes !~ $curtype\n"; } $HeaderDoc::enable_cpp = $old_enable_cpp; objlink(\@linkobjs); my $classobjref = undef; my $catobjref = undef; $classType = undef; $blockOffset = 0; $numcurlybraces = 0; $foundMatch = 0; if (!$curObj->{INSERTED}) { $curObj->free(0, 1, undef); } print STDERR "EARLY RETURN" if ($hangDebug || $localDebug || $subparseDebug); if ($curObj->discussionLocked()) { $curObj->unlockDiscussion(); } return ($inputCounter, $cppAccessControlState, $classType, $classobjref, $catobjref, $blockOffset, $numcurlybraces, $foundMatch, $lang, $sublang, $hashtreecur, $hashtreeroot); } $lastParseTree = $parseTree; } else { # first parse tree encountered print STDERR "FIRST PARSE TREE.\n" if ($subparseDebug); $parseTree = $subparseTree;; if ($subparseDebug && $parseTree) { print STDERR "PARSETREE FOLLOWS:\n"; $parseTree->printTree(); } elsif ($subparseDebug) { print STDERR "NO PARSE TREE\n"; } print STDERR "HERE\n" if ($localDebug); $lastParseTree = $parseTree; if (!$parseTree) { my $curname = $curObj->name(); if (!empty_comment(@fields)) { # Don't warn if there wasn't # really a HeaderDoc comment # involved. warn("End of parse tree reached while searching for matching declaration[2].\n"); warn "No matching declaration found. Last name was $curname\n"; warn buildCommentFromFields(@fields, $preAtPart, "The HeaderDoc comment that caused this was:\n")."\n"; warn "$outertype ne $curtype && $innertype ne $curtype && $posstypes !~ $curtype\n"; } $HeaderDoc::enable_cpp = $old_enable_cpp; objlink(\@linkobjs); my $classobjref = undef; my $catobjref = undef; $classType = undef; $blockOffset = 0; $numcurlybraces = 0; $foundMatch = 0; if (!$curObj->{INSERTED}) { $curObj->free(0, 1, undef); } if ($curObj->discussionLocked()) { $curObj->unlockDiscussion(); } return ($inputCounter, $cppAccessControlState, $classType, $classobjref, $catobjref, $blockOffset, $numcurlybraces, $foundMatch, $lang, $sublang, $hashtreecur, $hashtreeroot); } } # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 005a: SUBLANG NOMATCH\n"; } # From here down happens for every parse tree. print STDERR "THERE\n" if ($localDebug); # print STDERR "Dumping parse tree (debug)\n"; # print STDERR $parseTree->textTree(); # print STDERR "Done dumping parse tree (debug)\n"; my @ppl = (); @ppl = $parseTree->parsedParams($lang, $sublang); $pplref = \@ppl; print STDERR "PPLREF is $pplref\n" if ($localDebug); my $treestring = $parseTree->textTree(); if ($treestring !~ /\w/) { my $curname = $curObj->name(); if (!empty_comment(@fields)) { # Don't warn if there wasn't # really a HeaderDoc comment # involved. warn("End of parse tree reached while searching for matching declaration[3].\n"); warn "No matching declaration found. Last name was $curname\n"; warn buildCommentFromFields(@fields, $preAtPart, "The HeaderDoc comment that caused this was:\n")."\n"; warn "$outertype ne $curtype && $innertype ne $curtype && $posstypes !~ $curtype\n"; } $HeaderDoc::enable_cpp = $old_enable_cpp; objlink(\@linkobjs); my $classobjref = undef; my $catobjref = undef; $classType = undef; $blockOffset = 0; $numcurlybraces = 0; $foundMatch = 0; if (!$curObj->{INSERTED}) { $curObj->free(0, 1, undef); } if ($curObj->discussionLocked()) { $curObj->unlockDiscussion(); } return ($inputCounter, $cppAccessControlState, $classType, $classobjref, $catobjref, $blockOffset, $numcurlybraces, $foundMatch, $lang, $sublang, $hashtreecur, $hashtreeroot); } @inputLines = (); foreach my $line (split(/\n/, $treestring)) { push(@inputLines, "$line\n"); } $nlines = scalar(@inputLines) + 1000; $inputCounter = 0; $HeaderDoc::AccessControlState = $parseTree->acs(); $cppAccessControlState = $parseTree->acs(); my $parserState = $parseTree->parserState(); my $findstate = $parseTree; while (!defined($parserState) && $findstate) { print STDERR "POS IS $findstate\n" if ($localDebug); print STDERR "POSTOKE IS ".$findstate->token()."\n" if ($localDebug); $parserState = $findstate->parserState; $findstate = $findstate->next(); } # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 005b: SUBLANG NOMATCH\n"; } if (!$parserState || $inClass) { # Failure case. Something is broken in the block parser. print STDERR "NOPARSERSTATE\n" if ($localDebug); if (!$slowokay && !$inClass) { $checkLineNumbers = 1; warn("Couldn't find parser state. Using slow method.\n"); warn buildCommentFromFields(@fields, $preAtPart, "The HeaderDoc comment that caused this was:\n")."\n"; $localDebug = 1; $hangDebug = 1; if (0) { warn "APIO: PT: ".$apiOwner->parseTree()."\n"; my $tree = ${$apiOwner->parseTree()}; bless($tree, "HeaderDoc::ParseTree"); print STDERR "TREE is $tree\n"; $tree->dbprint(); } } ($newcount, $declaration, $typelist, $namelist, $posstypes, $value, $pplref, $returntype, $pridec, $parseTree, $simpleTDcontents, $bpavail, $blockOffset, $conformsToList, $functionContents, $returnedParserState, $nameObjectsRef, $extendsClass, $implementsClass, $propertyAttributes, $memberOfClass, $lang, $sublang) = &blockParse($fullpath, $blockOffset, \@inputLines, $inputCounter, 0, \%HeaderDoc::ignorePrefixes, \%HeaderDoc::perHeaderIgnorePrefixes, \%HeaderDoc::perHeaderIgnoreFuncMacros, $keywordhashref, $case_sensitive, $lang, $sublang); # @@@ CHECKME DAG if ($curObj->isAPIOwner) { $parseTree->apiOwner($curObj); } else { $parseTree->addAPIOwner($curObj); } print STDERR "API OWNER FOR $parseTree is ".$parseTree->apiOwner()."\n" if ($localDebug); print STDERR "NC: $newcount\n" if ($localDebug); $numcurlybraces += $parseTree->curlycount($parseTokens{lbrace}); if ($inClass && $nestClassDebug) { print STDERR "NESTCLASS TEST:\n"; $parseTree->dbprint(); print STDERR "END NESTCLASS TEST:\n"; print STDERR "(\$newcount, \$declaration, \$typelist, \$namelist, \$posstypes, \$value, \$pplref, \$returntype, \$pridec, \$parseTree, \$simpleTDcontents, \$bpavail, \$blockOffset) = "; print STDERR "($newcount, DECLARATION OMITTED, $typelist, $namelist, $posstypes, $value, $pplref, $returntype, $pridec, $parseTree, $simpleTDcontents, $bpavail, $blockOffset)\n"; } print STDERR "newcount IS $newcount\n" if ($localDebug); print STDERR "dec is $declaration\n" if ($localDebug); print STDERR "TYPELIST IS \"$typelist\"\n" if ($localDebug); print STDERR "NAMELIST IS \"$namelist\"\n" if ($localDebug); print STDERR "POSSTYPES IS \"$posstypes\"\n" if ($localDebug); print STDERR "PPLREF IS $pplref\n" if ($localDebug); print STDERR "RETURNTYPE IS \"$returntype\"\n" if ($localDebug); print STDERR "parseTree IS \"$parseTree\"\n" if ($localDebug); $lastParserState = undef; # prevent infinite loop. # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 005c: SUBLANG NOMATCH\n"; } if ($typelist eq "MACRO" && ($returntype !~ /\#define/)) { if ($blockmode != 2) { if ($inClass) { # Classes are special. They can't be combined with #if # statements, so don't even try. warn("$fullpath:".($inputCounter + $blockOffset).": warning: Macros found between comments and declaration. Ignoring.\n") if (!$HeaderDoc::running_test); print STDERR "DEC: $declaration\n" if (!$HeaderDoc::running_test); } else { if ($returntype =~ /#if/ && $allow_multi) { $blockmode = 3; $blocklevel++; $curObj->isBlock(1); print STDERR "BLOCKMODE[2] -> $blockmode\n" if ($localDebug || $blockDebug); $curObj->addParseTree(\$parseTree); } elsif ($returntype =~ /#endif/ && $allow_multi) { $blocklevel--; my $prev_blockmode = $blockmode; if (!$blocklevel) { $blockmode = 0; } print STDERR "BLOCKMODE[3] -> $blockmode\n" if ($localDebug || $blockDebug); $curObj->addParseTree(\$parseTree); if ($prev_blockmode) { my ($cpphashref, $cpparghashref) = getAndClearCPPHash(); ($cpphashref, $cpparghashref, $hashtreeroot, $hashtreecur) = cppHashMerge($hashtreeroot, $hashtreecur, $cpphashref, $cpparghashref, $returntype); $hashtreeroot = $hashtreeroot; $hashtreecur = $hashtreecur; setCPPHashes($cpphashref, $cpparghashref); } $inputCounter = $newcount; last; } elsif ($returntype =~ /#elif/ && $allow_multi) { $curObj->addParseTree(\$parseTree); } elsif ($returntype =~ /#else/ && $allow_multi) { $curObj->addParseTree(\$parseTree); } elsif ($returntype !~ /#(if|endif|else)/ || $allow_multi) { if (@fields != ()) { warn("$fullpath:".($inputCounter + $blockOffset).": warning: Macros found between comments and declaration. Ignoring.\n") if (!$HeaderDoc::running_test); print STDERR "DEC: $declaration\n" if (!$HeaderDoc::running_test); } } my ($cpphashref, $cpparghashref) = getAndClearCPPHash(); ($cpphashref, $cpparghashref, $hashtreeroot, $hashtreecur) = cppHashMerge($hashtreeroot, $hashtreecur, $cpphashref, $cpparghashref, $returntype); $hashtreeroot = $hashtreeroot; $hashtreecur = $hashtreecur; setCPPHashes($cpphashref, $cpparghashref); } } $inputCounter = $newcount; next; } # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 005d: SUBLANG NOMATCH\n"; } } else { $parserState->{APIODONE} = 1; # Normal case. my $subParseDebugPoint = (0 || $localDebug || $subparseDebug); my $newblockoffset; ($newcount, $declaration, $typelist, $namelist, $posstypes, $value, $pplref, $returntype, $pridec, $parseTree, $simpleTDcontents, $bpavail, $newblockoffset, $conformsToList, $functionContents, $returnedParserState, $nameObjectsRef, $extendsClass, $implementsClass, $propertyAttributes, $memberOfClass, $lang, $sublang) = &blockParseReturnState($parserState, $parseTree, 0, "", 0, "", "", ($localDebug || $blockDebug), 0, $subparse, $parseTokens{definename}, $inputCounter, $lang, $sublang); # $newcount = 1; # @@@ CHECKME DAG if ($curObj->isAPIOwner) { $parseTree->apiOwner($curObj); } else { $parseTree->addAPIOwner($curObj); } print STDERR "API OWNER FOR $parseTree is ".$parseTree->apiOwner()."\n" if ($localDebug); $numcurlybraces += $parseTree->curlycount($parseTokens{lbrace}, $parserState->{lastTreeNode}); print STDERR "newcount IS $newcount\n" if ($subParseDebugPoint); print STDERR "dec is $declaration\n" if ($subParseDebugPoint); print STDERR "TYPELIST IS \"$typelist\"\n" if ($subParseDebugPoint); print STDERR "NAMELIST IS \"$namelist\"\n" if ($subParseDebugPoint); print STDERR "POSSTYPES IS \"$posstypes\"\n" if ($subParseDebugPoint); print STDERR "PPLREF IS $pplref\n" if ($subParseDebugPoint); print STDERR "RETURNTYPE IS \"$returntype\"\n" if ($subParseDebugPoint); print STDERR "parseTree IS \"$parseTree\"\n" if ($subParseDebugPoint); print STDERR "allow_multi IS $allow_multi\n" if ($subParseDebugPoint); $lastParserState = $parserState; # Do this up front because blockParseReturnState is pulling more precise line numbers that we tuck away in the parse tree. $blockOffset = $newblockoffset; $inputCounter = $newcount; # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 005e: SUBLANG NOMATCH\n"; } if ($typelist eq "MACRO" && ($returntype !~ /\#define/)) { if ($inClass) { # Classes are special. They can't be combined with #if # statements, so don't even try. warn("$fullpath:".($inputCounter + $blockOffset).": warning: Macros found between comments and declaration. Ignoring.\n") if (!$HeaderDoc::running_test); print STDERR "DEC: $declaration\n" if (!$HeaderDoc::running_test); } else { if ($blockmode != 2) { if ($returntype =~ /#if/ && $allow_multi) { $blockmode = 3; $blocklevel++; $curObj->isBlock(1); print STDERR "BLOCKMODE[4] -> $blockmode\n" if ($localDebug || $blockDebug); # print STDERR "RETURN TYPE IS $returntype\n"; # print STDERR "DECLARATION IS $declaration\n"; $curObj->addParseTree(\$parseTree); } elsif ($returntype =~ /#endif/ && $allow_multi) { $blocklevel--; my $prev_blockmode = $blockmode; if (!$blocklevel) { $blockmode = 0; } print STDERR "BLOCKMODE[5] -> $blockmode\n" if ($localDebug || $blockDebug); $curObj->addParseTree(\$parseTree); print STDERR "CUROBJ: $curObj\n" if ($missingParseTreeDebug); my $temp = $curObj->parseTreeList(); if ($prev_blockmode) { my ($cpphashref, $cpparghashref) = getAndClearCPPHash(); ($cpphashref, $cpparghashref, $hashtreeroot, $hashtreecur) = cppHashMerge($hashtreeroot, $hashtreecur, $cpphashref, $cpparghashref, $returntype); $hashtreeroot = $hashtreeroot; $hashtreecur = $hashtreecur; setCPPHashes($cpphashref, $cpparghashref); } # This is going to get decremented later, and we # skip the assignment down below, so do it here. $inputCounter = $newcount; print STDERR "ENDIF LAST[1]: AT END IC: $inputCounter\n" if ($HeaderDoc::inputCounterDebug); last; } elsif ($returntype =~ /#else/ && $allow_multi) { $curObj->addParseTree(\$parseTree); } elsif ($returntype !~ /#(if|endif|else)/ || $allow_multi) { if (@fields != ()) { warn("$fullpath:".($inputCounter + $blockOffset).": warning: Macros found between comments and declaration. Ignoring.\n") if (!$HeaderDoc::running_test); print STDERR "DEC: $declaration\n" if (!$HeaderDoc::running_test); } } } my ($cpphashref, $cpparghashref) = getAndClearCPPHash(); ($cpphashref, $cpparghashref, $hashtreeroot, $hashtreecur) = cppHashMerge($hashtreeroot, $hashtreecur, $cpphashref, $cpparghashref, $returntype); $hashtreeroot = $hashtreeroot; $hashtreecur = $hashtreecur; setCPPHashes($cpphashref, $cpparghashref); } $subparseInputCounter = $parseTree->{LINENUM}; $subparseBlockOffset = 0; $curObj->linenuminblock($subparseInputCounter); $curObj->blockoffset($subparseBlockOffset); next; } # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 005f: SUBLANG NOMATCH\n"; } $subparseInputCounter = $parseTree->{LINENUM}; $subparseBlockOffset = 0; # print STDERR "RUNNING TEXTTREE\n" if ($nameDebug); $declaration = $parseTree->textTree(); # $parseTree->dbprint(); $curObj->linenuminblock($subparseInputCounter); $curObj->blockoffset($subparseBlockOffset); print STDERR "NEW INFO: LNIB: $inputCounter BO: $blockOffset\n" if ($subParseDebugPoint); } } else { # NOT subparse print STDERR "Parsing\n" if ($localDebug); if ($nodec) { print STDERR "NODEC\n" if ($localDebug); $declaration = ""; $parseTree = HeaderDoc::ParseTree->new(); my @ppl = (); $pplref = \@ppl; $newcount = $inputCounter; # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 005g: SUBLANG NOMATCH\n"; } } else { print STDERR "PREIC: $inputCounter\n" if ($localDebug); # print STDERR "PRELANG: $lang SUB: $sublang\n"; ($newcount, $declaration, $typelist, $namelist, $posstypes, $value, $pplref, $returntype, $pridec, $parseTree, $simpleTDcontents, $bpavail, $blockOffset, $conformsToList, $functionContents, $returnedParserState, $nameObjectsRef, $extendsClass, $implementsClass, $propertyAttributes, $memberOfClass, $lang, $sublang) = &blockParse($fullpath, $blockOffset, \@inputLines, $inputCounter, 0, \%HeaderDoc::ignorePrefixes, \%HeaderDoc::perHeaderIgnorePrefixes, \%HeaderDoc::perHeaderIgnoreFuncMacros, $keywordhashref, $case_sensitive, $lang, $sublang); # @@@ CHECKME DAG if ($curObj->isAPIOwner) { $parseTree->apiOwner($curObj); } else { $parseTree->addAPIOwner($curObj); } # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 005h: SUBLANG NOMATCH\n"; } $curObj->addToCleanup(\$parseTree); print STDERR "PT HERE IS $parseTree\n" if ($HeaderDoc::debugAllocations); print STDERR "API OWNER FOR $parseTree is ".$parseTree->apiOwner()."\n" if ($localDebug); # print STDERR "DECLARATION:\n"; $parseTree->printTree(); print STDERR "END DECLARATION\n"; if ($localDebug) { print STDERR "IL0: ".$inputLines[0]."\n"; print STDERR "STARTDEC\n$declaration\nENDDEC\n"; print STDERR "STARTTREE\n"; $parseTree->printTree(); print STDERR "ENDTREE\n"; } if ($inClass) { # If they explicitly tagged it, it must be important. if ($typelist =~ "forwarddeclaration-") { $typelist =~ s/^forwarddeclaration-//; } if ($typelist eq "MACRO" && ($returntype !~ /\#define/)) { # print STDERR "INCLASS: returned $typelist\n"; if ($inClass) { # Classes are special. They can't be combined with #if # statements, so don't even try. warn("$fullpath:".($inputCounter + $blockOffset).": warning: Macros found between comments and declaration. Ignoring.\n") if (!$HeaderDoc::running_test); print STDERR "DEC: $declaration\n" if (!$HeaderDoc::running_test); } else { if ($returntype =~ /#if/ && $allow_multi) { $blockmode = 3; $blocklevel++; $curObj->isBlock(1); print STDERR "BLOCKMODE[6] -> $blockmode\n" if ($localDebug || $blockDebug); $curObj->addParseTree(\$parseTree); } elsif ($returntype =~ /#endif/ && $allow_multi) { $blocklevel--; my $prev_blockmode = $blockmode; if (!$blocklevel) { $blockmode = 0; } print STDERR "BLOCKMODE[7] -> $blockmode\n" if ($localDebug || $blockDebug); $curObj->addParseTree(\$parseTree); if ($prev_blockmode) { my ($cpphashref, $cpparghashref) = getAndClearCPPHash(); ($cpphashref, $cpparghashref, $hashtreeroot, $hashtreecur) = cppHashMerge($hashtreeroot, $hashtreecur, $cpphashref, $cpparghashref, $returntype); $hashtreeroot = $hashtreeroot; $hashtreecur = $hashtreecur; setCPPHashes($cpphashref, $cpparghashref); } # This is going to get decremented later, and we # skip the assignment down below, so do it here. $inputCounter = $newcount; print STDERR "ENDIF LAST[2]: AT END IC: $inputCounter\n" if ($HeaderDoc::inputCounterDebug); last; } elsif ($returntype =~ /#else/ && $allow_multi) { $curObj->addParseTree(\$parseTree); } elsif ($returntype !~ /#(if|endif|else)/ || $allow_multi) { if (@fields != ()) { warn("$fullpath:".($inputCounter + $blockOffset).": warning: Macros found between class comments and class. Ignoring.\n") if (!$HeaderDoc::running_test); print STDERR "DEC: $declaration\n" if (!$HeaderDoc::running_test); } } my ($cpphashref, $cpparghashref) = getAndClearCPPHash(); ($cpphashref, $cpparghashref, $hashtreeroot, $hashtreecur) = cppHashMerge($hashtreeroot, $hashtreecur, $cpphashref, $cpparghashref, $returntype); $hashtreeroot = $hashtreeroot; $hashtreecur = $hashtreecur; setCPPHashes($cpphashref, $cpparghashref); } $inputCounter = $newcount; next; } # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 005i: SUBLANG NOMATCH\n"; } } else { print STDERR "HERE TL: $typelist RT: $returntype\n" if ($HeaderDoc::inputCounterDebug); if ($typelist eq "MACRO" && ($returntype !~ /\#define/)) { if ($inClass) { # Classes are special. They can't be combined with #if # statements, so don't even try. warn("$fullpath:".($inputCounter + $blockOffset).": warning: Macros found between comments and declaration. Ignoring.\n") if (!$HeaderDoc::running_test); print STDERR "DEC: $declaration\n" if (!$HeaderDoc::running_test); } else { if ($returntype =~ /#if/ && $allow_multi) { $blockmode = 3; $blocklevel++; $curObj->isBlock(1); print STDERR "BLOCKMODE[8] -> $blockmode\n" if ($localDebug || $blockDebug); $curObj->addParseTree(\$parseTree); } elsif ($returntype =~ /#endif/ && $allow_multi) { $blocklevel--; my $prev_blockmode = $blockmode; if (!$blocklevel) { $blockmode = 0; } print STDERR "BLOCKMODE[9] -> $blockmode\n" if ($localDebug || $blockDebug); $curObj->addParseTree(\$parseTree); if ($prev_blockmode) { my ($cpphashref, $cpparghashref) = getAndClearCPPHash(); ($cpphashref, $cpparghashref, $hashtreeroot, $hashtreecur) = cppHashMerge($hashtreeroot, $hashtreecur, $cpphashref, $cpparghashref, $returntype); $hashtreeroot = $hashtreeroot; $hashtreecur = $hashtreecur; setCPPHashes($cpphashref, $cpparghashref); } # This is going to get decremented later, and we # skip the assignment down below, so do it here. $inputCounter = $newcount; print STDERR "ENDIF LAST[3]: AT END IC: $inputCounter\n" if ($HeaderDoc::inputCounterDebug); if ($blocklevel) { next; } last; } elsif ($returntype =~ /#else/ && $allow_multi) { $curObj->addParseTree(\$parseTree); } elsif ($returntype !~ /#(if|endif|else)/ || $allow_multi) { if (@fields != ()) { warn("$fullpath:".($inputCounter + $blockOffset).": warning: Macros found between comments and declaration. Ignoring.\n") if (!$HeaderDoc::running_test); print STDERR "DEC: $declaration\n" if (!$HeaderDoc::running_test); } } my ($cpphashref, $cpparghashref) = getAndClearCPPHash(); # print STDERR "GOING INTO $returntype: CPP HASH DUMP:\n"; # printHash(%{$cpphashref}); # print STDERR "DONE\n"; # print STDERR "\nARGUMENT HASH:\n\n"; # printHash(%{$cpparghashref}); # print STDERR "\nDONE\n\n"; ($cpphashref, $cpparghashref, $hashtreeroot, $hashtreecur) = cppHashMerge($hashtreeroot, $hashtreecur, $cpphashref, $cpparghashref, $returntype); $hashtreeroot = $hashtreeroot; $hashtreecur = $hashtreecur; # print STDERR "COMING OUT OF $returntype: CPP HASH DUMP:\n"; # printHash(%{$cpphashref}); # print STDERR "DONE\n"; # print STDERR "\nARGUMENT HASH:\n\n"; # printHash(%{$cpparghashref}); # print STDERR "\nDONE\n\n"; setCPPHashes($cpphashref, $cpparghashref); } # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 005j: SUBLANG NOMATCH\n"; } $inputCounter = $newcount; next; } } } } # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 005k: SUBLANG NOMATCH\n"; } if ($memberOfClass ne "") { # my $prefix = $apiOwner->apiUIDPrefix(); # my $classuid = "//$prefix/$lang/cl/$memberOfClass"; my $temp = $realApiOwner->findClass($memberOfClass); # objectForUID($classuid); if ($temp) { print STDERR "CLASSSEARCH FOUND CLASS. Will insert into class object $temp instead.\n" if ($localDebug || $nameDebug); $apiOwner = $temp; } else { print STDERR "CLASSSEARCH COULD NOT FIND CLASS $memberOfClass. Will insert into header object $apiOwner.\n" if ($localDebug || $nameDebug); } } print STDERR "HAVE DECLARATION NOW\n" if ($nameObjDebug); # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 006: SUBLANG NOMATCH\n"; } # print STDERR "TYPELIST: $typelist\n"; # print STDERR "POSSTYPES: $posstypes\n"; # print STDERR "NAMELIST: $namelist\n"; if ($declaration !~ /\S/) { warn("Empty declaration. Skipping to end of loop.\n") if ($localDebug || $hangDebug || $nameObjDebug || $nameDebug); print STDERR "EMPTY: AT END IC: $inputCounter\n" if ($HeaderDoc::inputCounterDebug); $inputCounter = $newcount; last; } $foundMatch = 1; if ($hangDebug) { print STDERR "DUMPING PARSE TREE:\n";$parseTree->dbprint();print STDERR "PARSETREEDONE\n"; } if ($bpavail && length($bpavail)) { $curObj->availability($bpavail); } # print STDERR "BPAVAIL ($namelist): $bpavail\n"; print STDERR "Left blockParse\n" if ($hangDebug); $curObj->privateDeclaration($pridec); $curObj->parseTree(\$parseTree); # print STDERR "PT: $parseTree\n"; # print STDERR "PT IS A $parseTree\n"; # $parseTree->htmlTree(); # $parseTree->processEmbeddedTags(); my @parsedParamList = @{$pplref}; print STDERR "VALUE IS $value\n" if ($localDebug); # warn("nc: $newcount. ts: $typestring. nl: $namelist\nBEGIN:\n$declaration\nEND.\n"); $declaration =~ s/^\s*//so; # if (!length($declaration)) { next; } print STDERR "obtained declaration\n" if ($localDebug); if ($localDebug || $nameDebug) { print STDERR "IC: $inputCounter\n"; print STDERR "DC: \"$declaration\"\n"; # if ($localDebug); print STDERR "TL: \"$typelist\"\n"; print STDERR "NL: \"$namelist\"\n"; print STDERR "PT: \"$posstypes\"\n"; } $inputCounter = $newcount; # FIX UP TYPES HERE my @oldnames = split(/[,;]/, $namelist); my @oldtypes = split(/ /, $typelist); my @nameObjects = @{$nameObjectsRef}; my $i=0; if ($nameObjDebug) { print STDERR "\n"; while ($i < scalar(@oldnames)) { print STDERR "EXPECTED NAME: ".$oldnames[$i]."\n"; print STDERR "EXPECTED TYPE: ".$oldtypes[$i]."\n\n"; $i++; } foreach my $tempobj (@nameObjects) { print STDERR "GOT NAME: ".$tempobj->{NAME}."\n"; } foreach my $tempobj (@nameObjects) { print STDERR "GOT TYPE: ".$tempobj->{TYPE}."\n"; } } my $curname = $curObj->rawname(); my $curname_extended = $curObj->rawname_extended(); # print "CN1: $curname CN2: ".$curObj->name()."\n"; # my $curname = $curObj->name(); # print STDERR "NN: $#oldnames CN: \"$curname\"\n"; # $outertype = $oldtypes[0]; # my $outername = $oldnames[0]; $outertype = $nameObjects[0]->{TYPE}; my $outername = $nameObjects[0]->{NAME}; # print STDERR "ON: \"$outername\"\n"; if ($outertype eq "") { $outertype = $curtype; my $linenum = $inputCounter + $blockOffset; if ((!$nodec) && (!$HeaderDoc::running_test)) { warn("$fullpath:$linenum: WARNING: anonymous type.\n"); warn("IC: $inputCounter\n"); warn("DC: \"$declaration\"\n"); warn("TL: \"$typelist\"\n"); warn("NL: \"$namelist\"\n"); warn("PT: \"$posstypes\"\n"); } } elsif ($HeaderDoc::ignore_apiowner_names == 2 && length($outername) && !$curObj->isBlock) { if ($localDebug || $nameDebug) { print STDERR "CURNAME CHANGED FROM $curname -> $outername\n"; print STDERR "CURNAME_EXTENDED CHANGED FROM $curname_extended -> $outername\n"; } $curname = $outername; $curname_extended = $outername; } if ($localDebug || $nameDebug) { print STDERR "CURNAME: $curname\n"; print STDERR "OUTERNAME: $outername\n"; print STDERR "IGNORE: ".$HeaderDoc::ignore_apiowner_names."\n"; } if ($outername eq "") { if ($HeaderDoc::enableParanoidWarnings || $curname eq "") { my $linenum = $inputCounter + $blockOffset; my $withno = ""; if ($curname eq "") { $withno = " with no name provided in comment"; } if (!$HeaderDoc::running_test) { warn("$fullpath:$linenum: WARNING: anonymous type$withno.\n"); warn("IC: $inputCounter\n"); warn("DC: \"$declaration\"\n"); warn("TL: \"$typelist\"\n"); warn("NL: \"$namelist\"\n"); warn("PT: \"$posstypes\"\n"); } if ($curname eq "") { # Try first parsed parameter name. my $ppstring = $parsedParamList[0]; { $ppstring .= ";"; my @array = ( $ppstring ); my $parseTree = undef; my $simpleTDcontents = ""; my $bpavail = ""; my $bogusblockoffset; my $conformsToList; # throw this away here. my ($bogusIC, $dec, $type, $name, $pt, $value, $pplref, $returntype, $pridec, $tempParseTree, $tempSimpleTDcontents, $tempbpavail, $tempbogusblockoffset, $tempConformsToList, $tempfunctionContents, $tempParserState, $tempNameObjectsRef, $ec, $ic, $propertyAttributes, $memberOfClass, $pplang, $ppsublang) = &blockParse($fullpath, ($inputCounter + $blockOffset), \@array, 0, 1, \%HeaderDoc::ignorePrefixes, \%HeaderDoc::perHeaderIgnorePrefixes, \%HeaderDoc::perHeaderIgnoreFuncMacros, $keywordhashref, $case_sensitive, $lang, $sublang); $tempParseTree->dispose(); $curname = $name; } # Try first tagged parameter name. if ($curname eq "") { $curname = $curObj->firstconstname(); } if ($curname ne "" && (!$HeaderDoc::running_test)) { warn("Using first constant name: $curname\n"); } $curname_extended = $curname; } } } $nodec = 0; # $innertype = $oldtypes[scalar(@oldtypes)-1]; $innertype = $nameObjects[scalar(@nameObjects)-1]->{TYPE}; # print STDERR "IT: $innertype\nEXPECTED: ". $oldtypes[scalar(@oldtypes)-1]."\n"; if ($localDebug) { foreach my $obj (@nameObjects) { my $ot = $obj->{TYPE}; print STDERR "TYPE: \"$ot\"\n"; } } # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 007: SUBLANG NOMATCH\n"; } # my $nameDebug = 1; # Uncomment to enable debugging. if ($nameDebug) { print STDERR "GOT DECLARATION.\n"; warn("IC: $inputCounter\n"); warn("DC: \"$declaration\"\n"); warn("TL: \"$typelist\"\n"); warn("NL: \"$namelist\"\n"); warn("PT: \"$posstypes\"\n"); } my $explicit_name_differs = 1; my $explicit_name_canonical = 0; $curname =~ s/^\s*//o; $curname =~ s/\s*$//o; $curname_extended =~ s/^\s*//o; $curname_extended =~ s/\s*$//o; # my @names = ( ); #$curname # my @types = ( ); #$outertype my $dropped = 0; print STDERR "names:\n" if ($nameDebug); # Fix up user-specified names that should end in a colon but don't. if ($curname !~ /:$/o) { # foreach my $name (@oldnames) { } foreach my $obj (@nameObjects) { my $name = $obj->{NAME}; my $NCname = $name; my $NCcurname = $curname; $NCname =~ s/:$//so; $NCcurname =~ s/:$//so; print STDERR "NM \"$name\" CN: \"$curname\" [1]\n" if ($nameDebug); if ($NCname eq $NCcurname && $name ne $curname) { $curname .= ":"; $curObj->name($curname); $curObj->rawname($curname); # } elsif ($name eq $curname) { # $dropped = 1; # print STDERR "dropped ($name = $curname)\n" if ($nameDebug); } } } # Fix up user-specified names that should not end in a colon but do. # Also check for a type conversion request. Just a bit of explanation. # A conversion request occurs when the main object is not of the correct # type to accept the declaration that follows it, where the following # declaration is of a type that ostensibly should be allowed to silently # match against that type, but where the declaration cannot be safely # assigned to a curObj of that type for technical reasons (missing # functions in the object, for example). my $conversion_requested = 0; my $newcurtype = "UNKNOWN"; my $isCallback = 0; print STDERR "Initial name object count: ".scalar(@nameObjects)."\n" if ($nameDebug); # foreach my $name (@oldnames) foreach my $obj (@nameObjects) { my $pt = $obj->{POSSTYPES}; if ($obj->{ISCALLBACK}) { $isCallback = 1; } if ($curname =~ /:$/o) { my $name = $obj->{NAME}; my $NCname = $name; my $NCcurname = $curname; $NCname =~ s/:$//so; $NCcurname =~ s/:$//so; print STDERR "NM \"$name\" CN: \"$curname\" [2]\n" if ($nameDebug); if ($NCname eq $NCcurname && $name ne $curname) { $curname = $NCcurname; $curObj->name($curname); $curObj->rawname($curname); # } elsif ($name eq $curname) { # $dropped = 1; # print STDERR "dropped ($name = $curname)\n" if ($nameDebug); $curname_extended = $curObj->rawname_extended(); } } print STDERR "\nLOOKING FOR $curtype*\n" if ($nameDebug); print STDERR "POSS $pt\n" if ($nameDebug); print STDERR "NAME OBJ TYPE IS ".$obj->{TYPE}."\n" if ($nameDebug); print STDERR "CUROBJ IS $curObj\n" if ($nameDebug); if ((!$conversion_requested) && ($pt =~ /\Q$curtype\E\*/) && (!$curObj->{INSERTED})) { print STDERR "MATCH: CONVERSION REQUESTED => 1\n" if ($nameDebug); $conversion_requested = 1; $newcurtype = $obj->{TYPE}; } elsif ($pt =~ /\Q$curtype\E/) { print STDERR "EXACT MATCH: CONVERSION REQUESTED => -1\n" if ($nameDebug); $conversion_requested = -1; $newcurtype = $obj->{TYPE}; } else { print STDERR "NO CONVERSION MATCH.\nPT: $pt\nCT: $curtype\nOT: $obj->{TYPE}\n" if ($nameDebug); } } print STDERR "CR is $conversion_requested\n" if ($nameDebug); $curname =~ s/^\s*//o; $curname =~ s/\s*$//o; $curname_extended =~ s/^\s*//o; $curname_extended =~ s/\s*$//o; print STDERR "endnames\n" if ($nameDebug); # print STDERR "DROPPED: $dropped\n"; if ((!length($curname) && $blockmode) || ($conversion_requested == 1)) { print STDERR "CONVERSION PATH\n" if ($nameDebug); my $allmatch = 1; if ($conversion_requested == 1) { # $nameDebug = 1; print STDERR "CONVERSION REQUESTED\n" if ($nameDebug); print STDERR "NAMES:\n" if ($nameDebug); } else { print STDERR "HAS NO CURNAME IN BLOCK MODE\n" if ($nameDebug); print STDERR "NAMES:\n" if ($nameDebug); } my $count = 0; print STDERR "CURTYPE: $curtype\n" if ($nameDebug); # foreach my $name (@oldnames) { foreach my $obj (@nameObjects) { my $name = $obj->{NAME}; if (!length($curname)) { $curname = $name; print STDERR "CHANGING CURTYPE FROM $curtype to ".$obj->{TYPE}."\n" if ($nameDebug); print STDERR "CURTYPE CHANGE[1]\n" if ($nameDebug); $curtype = $obj->{TYPE}; # $oldtypes[$count]; if (($curtype ne $origcurtype) && ($origcurtype ne "UNKNOWN")) { my $possfound = 0; my $pt = $obj->{POSSTYPES}; # $pt; my @ptlist = split(/\s/, $posstypes); foreach my $pt (@ptlist) { my $pttrim = $pt; $pttrim =~ s/\W//sg; if ($pttrim eq $curtype) { $possfound = 1; } if ($pttrim eq $curtype."*") { $possfound = 2; } print STDERR "CMP_P $pttrim $curtype\n" if ($nameDebug); } if (!$possfound) { warn "WARNING: Not all types in block match ($curtype != $origcurtype).\n"; } } } elsif ($name ne $curname) { print STDERR "NAMEMATCH: $name NE $curname\n" if ($nameDebug); $allmatch = 0; } print STDERR "NAME: $name\n" if ($nameDebug); $count++; } $curname =~ s/^\s*//o; $curname =~ s/\s*$//o; if ($conversion_requested == 1) { print STDERR "CURTYPE CHANGE[2]\n" if ($nameDebug); $curObj->origType($curtype); $curtype = $newcurtype; } print STDERR "CURTYPE NOW: $curtype\n" if ($nameDebug); print STDERR "ENDNAMES:\n" if ($nameDebug); if (!$allmatch && !$conversion_requested) { warn "WARNING: No name found in block mode and names do not match. Using first.\n" if (!$HeaderDoc::running_test); # $curname =~ s/^_//; # $curname .= "_multideclaration_block"; } # push(@names, $curname); # push(@types, $outertype); # $curname_inserted = 1; my $newcurObj; my $typestring = $curtype; my $ncdeclaration = $parseTree->textTreeNC($lang, $sublang, 1); ($newcurObj, $classType, $varIsConstant) = objForType( $curObj, $parseTokens{typedefname}, $typestring, $posstypes, $outertype, $curtype, $classType, $classKeyword, $ncdeclaration, \@fields, $functionGroup, $varIsConstant, $blockmode, $inClass, $inInterface, $inTypedef, $inStruct, $fullpath, $inputCounter, $blockOffset, $lang, $sublang, 0, $functionContents, $apiOwner, $subparseInputCounter, $subparseBlockOffset, $extendsClass, $implementsClass, 1, \%parseTokens); if ($mustLockDiscussion) { $curObj->prepareDiscussionForTemporary(); } # print "PARSER STATE: $returnedParserState\n"; print STDERR "CUROBJ ON RETURN: $curObj\n" if ($nameDebug); print STDERR "NEWCUROBJ ON RETURN: $newcurObj\n" if ($nameDebug); my @keys = keys %{$curObj}; print STDERR "Cloning object $curObj to $newcurObj...\n" if ($nameDebug); foreach my $key (@keys) { # print STDERR "$key => ".$curObj->{$key}."\n"; if ($key ne "CLASS") { $newcurObj->{$key} = $curObj->{$key}; } } print STDERR "NEWCUROBJ AFTER CLONE: $newcurObj\n" if ($nameDebug); print STDERR "NEWCUROBJ CLASS AFTER CLONE: ".$newcurObj->{CLASS}."\n" if ($nameDebug); # if ($curObj->can("masterEnum") && $curObj->masterEnum()) # $newcurObj->masterEnum($curObj->masterEnum()); # } my $group = $curObj->group(); $newcurObj->group($group); $curObj->apiOwner()->removeFromGroup($group, $curObj); $parseTree->apiOwnerSub($curObj, $newcurObj); # @@@ $curObj->dbprint() if ($HeaderDoc::debugAllocations); if (!$curObj->{INSERTED}) { $curObj->free(0, 1, $newcurObj); } print STDERR "Replacing $curObj with $newcurObj\n" if ($HeaderDoc::debugAllocations); $curObj = $newcurObj; $curObj->apiOwner($apiOwner); $blockCurNameAutoGenerated = 1; } elsif ($blockCurNameAutoGenerated == 1) { my $count = 0; print STDERR "CURNAME AUTO PATH (BLOCKMODE $blockmode)\n" if ($nameDebug); my $allmatch = 1; my $typematch = 1; # foreach my $name (@oldnames) { } foreach my $obj (@nameObjects) { my $name = $obj->{NAME}; if (!length($curname)) { $curname = $name; if (!length($curtype)) { print STDERR "CURTYPE CHANGE[3]\n" if ($nameDebug); $curtype = $obj->{TYPE}; # $oldtypes[$count]; } elsif ($curtype ne $obj->{TYPE}) { $typematch = 0; } } elsif ($name ne $curname) { $allmatch = 0; } print STDERR "NAME: $name\n" if ($nameDebug); $count++; } if (!$allmatch || !$typematch) { if (!$allmatch) { warn "WARNING: No name found in block mode and names do not match. Using first.\n" if (!$HeaderDoc::running_test); } if (!$typematch) { warn "WARNING: No name found in block mode and types do not match. Using first.\n" if (!$HeaderDoc::running_test); } # $curname =~ s/^_//; $curname .= "_multideclaration_block"; $blockCurNameAutoGenerated = 2; } } # print STDERR "SETTING curObj $curObj PARSER STATE TO $returnedParserState\n"; # print STDERR " DECLARATION: $declaration\n\n"; $curObj->parserState($returnedParserState); if (!$firstBlockObjType) { $firstBlockObjType = $newcurtype; $firstBlockCurType = $curtype; } # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 008: SUBLANG NOMATCH\n"; } print STDERR "ORIG CURTYPE $origcurtype FIRST CURTYPE WAS $firstBlockCurType\n". "CURTYPE $curtype INFUNCTION: $inFunction\n" if ($nameObjDebug || $nameDebug); # Normally, initialize to 0, but initialize to 1 if # we're in an @defineblock block. The parsed type # of a block define doesn't match the type generated # by the presence of an @defineblock directive # (intentionally to avoid an early exit). Thus, # the type comparison code fails for that case. # Fortunately, in that case, we always want to add # the name, so we just initialize this to the value # stored in $blockmode.... :-) # The curname (user-specified name) should be inserted # only if: # 1. The type matches. # 2. The name does not match. # See if the type matches. my $docname = ""; my $found = $blockmode; print STDERR "Current APIOwner is ".$apiOwner->name()."\n" if ($localDebug || $nameDebug); # foreach my $ot (@oldtypes) { } foreach my $obj (@nameObjects) { my $ottrim = $obj->{TYPE}; $ottrim =~ s/\W//sg; # DAG - Not sure why, but in some cases, the types # from $typelist are simply listed as 'define' # instead of '#define'. Fix those up. if ($ottrim eq "define") { $ottrim = "#define"; } # Now do the comparison.... if ($ottrim eq $curtype) { $found = 1; } print STDERR "CMP_O $ottrim $curtype\n" if ($nameDebug); # print "CUROBJ IS $curObj\n" if ($nameDebug); } my @ptlist = split(/\s/, $posstypes); # foreach my $pt (@ptlist) { } foreach my $obj (@nameObjects) { my $pt = $obj->{POSSTYPES}; # $pt; my @ptlist = split(/\s/, $posstypes); foreach my $pt (@ptlist) { my $pttrim = $pt; $pttrim =~ s/\W//sg; if ($pttrim eq $curtype) { $found = 1; } if ($pttrim eq $curtype."*") { $found = 2; } print STDERR "CMP_P $pttrim $curtype\n" if ($nameDebug); } } my $curname_inserted = 0; my $curObjIsTainted = 0; # Insert curname into list if it matches the current type # or if there is no other name. # print STDERR "TEST POINT\n"; if (length($curname) && length($curtype)) { print STDERR "HAS CURNAME\n" if ($nameDebug); my $foundName = findMatch(\@nameObjects, "NAME", '\S'); if ($found || !$foundName) { if (!$foundName) { print STDERR "Explicit name is canonical name\n" if ($nameDebug); $explicit_name_canonical = 1; } else { print STDERR "Found matching name\n" if ($nameDebug); } my $nameobj = HeaderDoc::TypeHelper->new(); $nameobj->{NAME} = $curname; $nameobj->{TYPE} = $outertype; $nameobj->{POSSTYPES} = $nameObjects[0]->{POSSTYPES}; $nameobj->{INSERTEDAT} = "OUTER 1"; $nameobj->{ACTIVE} = 1; print STDERR "CREATING AS ACTIVE: $curname\n" if ($nameObjDebug); if (($curtype ne $outertype) && !$explicit_name_canonical && !$blockmode) { print STDERR "TYPE MISMATCH for $nameobj" if ($nameDebug); $curObj->unregister(); $curObjIsTainted = $nameobj; } else { @nameObjects = ( ($nameobj), (@nameObjects)); # push(@names, $curname); # push(@types, $outertype); # (( $obj->{TYPE} eq $curtype && ($cmpname eq $cmpcurname || !length($curname))) && ((!$curObj->{INSERTED}) || $typestring eq $firstBlockCurType)) # $obj->{TYPE}; $curname_inserted = 1; } } else { print STDERR "NOT FOUND AND NAME COUNT NONZERO\n" if ($nameDebug); } } else { print STDERR "HAS NO CURNAME NOT IN BLOCK MODE\n" if ($nameDebug); } my $on = scalar(@nameObjects); print STDERR "NUMNAMES: ".scalar(@nameObjects).", FOUND: $found CURNAME: $curname, ".$curObj->name."\n" if ($nameDebug); if ($localDebug || $nameDebug) { foreach my $nameObj (@nameObjects) { my $name = $nameObj->{NAME}; my $type = $nameObj->{TYPE}; print STDERR "NAME $name TYPE $type\n"; } } # print STDERR "COAPIO: ".$curObj->apiOwner()." APIO: $apiOwner\n"; my $count = 0; my $operator = 0; # if ($typelist eq "operator") { # $operator = 1; # } # foreach my $name (@oldnames) {} # We don't want to insert an object that could potentially cause a tainted # curObj to appear in the output, so if its name matches the name and # type of an actual object (e.g. "@struct _foo" for # "typedef struct _foo { ...} foo") because that would cause a crash. # However, if there is no name/type match, we need to insert the object or # the alternate "doc" naming won't work. The following code checks for this # condition and inserts the object if needed. if ($curObjIsTainted) { my $foundMatchWithTaintedObject = 0; foreach my $obj (@nameObjects) { if ($obj == $curObjIsTainted) { next; } if ($obj->{NAME} eq $curObjIsTainted->{NAME}) { $foundMatchWithTaintedObject = 1; } } if (!$foundMatchWithTaintedObject) { @nameObjects = ( ($curObjIsTainted), (@nameObjects)); $curname_inserted = 1; } } foreach my $obj (@nameObjects) { if ($obj->{ACTIVE}) { # Skip the main name that we just added. next; } # my $name = $obj->{NAME}; # my $objtype = $obj->{TYPE}; my $operator = 0; if ($obj->{TYPE} eq "operator") { $operator = 1; } print STDERR "OPERATOR: $operator\n" if ($nameDebug || $nameObjDebug); if (!length($obj->{NAME})) { # Anonymous enum next; } if ($operator) { $obj->{NAME} =~ s/^\s*operator\s*//so; $obj->{NAME} = "operator ".$obj->{NAME}; $curname =~ s/^operator(\s*)(\S+)/operator $2/so; } print STDERR "NAME \"$obj->{NAME}\"\nCURNAME \"$curname\"\nOUTERTYPE \"$outertype\"\nOBJTYPE \"".$obj->{TYPE}."\"\n" if ($nameDebug); # If we have a valid tag name, we normally don't insert it if it is the same as the # parsed name to avoid duplication. If we didn't insert it before, though, we had # better insert it here. It will be inserted either above or here, depending on # whether we have a type match. If we have an anonymous type, it will always be # inserted above. # if ((($obj->{NAME} eq $curname) && ($oldtypes[$count] eq $outertype)) && $curname_inserted) if ((($obj->{NAME} eq $curname) && ($obj->{TYPE} eq $outertype)) && $curname_inserted) { print STDERR "Explicit name matches parsed.\n" if ($nameDebug); # We've already inserted this name. $explicit_name_differs = 0; $count++; } else { # print STDERR "Explicit name ($curname) does NOT match parsed ($obj->{NAME}) or type ($outertype) does not match (".$oldtypes[$count].") or not curname_inserted ($curname_inserted). Adding to list.\n" if ($nameDebug); print STDERR "Explicit name ($curname) does NOT match parsed ($obj->{NAME}) or type ($outertype) does not match (".$obj->{TYPE}.") or not curname_inserted ($curname_inserted). Adding to list.\n" if ($nameDebug); if (($obj->{NAME} eq $curname)) { $curname_inserted = 1; } print STDERR "DOCNAME: $curname\n" if ($nameDebug); $docname = $curname; # push(@names, $obj->{NAME}); # push(@types, $oldtypes[$count++]); print STDERR "ACTIVATING: $obj->{NAME}\n" if ($nameObjDebug); $obj->{ACTIVE} = 1; } } # if (!$curname_inserted && $found) { # push(@names, $curname); # push(@types, $outertype); # } # foreach my $xname (@names) { print STDERR "XNAME: $xname\n"; } if ($hangDebug) { print STDERR "Point A\n"; } # $explicit_name_differs = 0; print STDERR "END: $explicit_name_differs; ENC: $explicit_name_canonical\n" if ($nameDebug); # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 009: SUBLANG NOMATCH\n"; } # If we are the only name for an object, the user-entered (tagged/explicit) name is # treated as canonical for apple_ref purposes. Otherwise, the user- # entered name is just a special doc name. if ($explicit_name_differs && !$explicit_name_canonical && ($curname_inserted || $curname =~ /\W/) && $found) { # The tagged name is different and is not the only name for this object print STDERR "Setting APPLEREFISDOC for $curObj : \"".$curObj->name()."\" [1]\n" if ($nameDebug); $curObj->appleRefIsDoc(1); my $prevignore = $HeaderDoc::ignore_apiuid_errors; $HeaderDoc::ignore_apiuid_errors = 1; my $junk = $curObj->apirefSetup(1); print STDERR "APIREF: ".$curObj->apiref()."\n" if ($nameDebug); $HeaderDoc::ignore_apiuid_errors = $prevignore; } else { # Either the tagged name is different or there is no parsed name. if ($curname_extended =~ /[^\w\:]/) { # The tagged name contains illegal characters. This cannot be treated as a code symbol name. print STDERR "Setting APPLEREFISDOC for $curObj : \"".$curObj->name()."\" [2]\n" if ($nameDebug); if ($explicit_name_canonical) { # If there is no parsed namem, embedded constants and similar should be treated # as code symbols because this is the only place they are documented. $curObj->appleRefIsDoc(2); } else { $curObj->appleRefIsDoc(1); } if ($curObj->{INSERTED}) { my $prevignore = $HeaderDoc::ignore_apiuid_errors; $HeaderDoc::ignore_apiuid_errors = 1; my $junk = $curObj->apirefSetup(1); print STDERR "APIREF: ".$curObj->apiref()."\n" if ($nameDebug); $HeaderDoc::ignore_apiuid_errors = $prevignore; } } else { print STDERR "Clearing APPLEREFISDOC for $curObj : ".$curObj->name()."\n" if ($nameDebug); $curObj->appleRefIsDoc(0); # print "INSERTED: ".$curObj->{INSERTED}."\n"; if ($curObj->{INSERTED}) { my $prevignore = $HeaderDoc::ignore_apiuid_errors; $HeaderDoc::ignore_apiuid_errors = 1; # $curObj->dbprint(); my $junk = $curObj->apirefSetup(1); print STDERR "APIREF: ".$curObj->apiref()."\n" if ($nameDebug); $HeaderDoc::ignore_apiuid_errors = $prevignore; } } } print STDERR "CUROBJ IS $curObj\n" if ($nameDebug); my $matching_declaration = 0; if ($outertype eq $curtype || $innertype eq $curtype || findMatch(\@nameObjects, "POSSTYPES", $curtype)) { if (findMatch(\@nameObjects, "POSSTYPES", $curtype.'\*')) { $matching_declaration = 2; } else { $matching_declaration = 1; } # Make sure we have the right UID for methods $curObj->declaration($declaration); # $HeaderDoc::ignore_apiuid_errors = 1; # my $oldisdoc = $curObj->appleRefIsDoc(); # $curObj->appleRefIsDoc(1); # my $junk = $curObj->apirefSetup(); # $curObj->appleRefIsDoc($oldisdoc); # $HeaderDoc::ignore_apiuid_errors = 0; } elsif ($curtype eq "UNKNOWN") { $matching_declaration = 1; } else { print STDERR "NOMATCH: OUTER: $outertype CUR: $curtype INNER: $innertype\n" if ($nameDebug); } $count = 0; # foreach my $name (@names) {} print STDERR "ENTERING NAMEOBJECT LOOP. CURTYPE IS $curtype CUROBJ is $curObj\n" if ($nameObjDebug || $nameDebug); foreach my $obj (@nameObjects) { print STDERR "IN NAMEOBJECT LOOP. CURTYPE IS $curtype CUROBJ is $curObj\n" if ($nameObjDebug || $nameDebug); # print STDERR "NAMEOBJECT: NAME: ".$obj->{NAME}." TYPE: ".$obj->{TYPE}."\n"; if (!$obj->{ACTIVE}) { print STDERR "SKIPPING OBJECT $obj (NAME ".$obj->{NAME}.") because it is inactive\n" if ($nameDebug || $nameObjDebug); # This one wasn't marked for inclusion. next; } else { print STDERR "ADDING OBJECT $obj (NAME ".$obj->{NAME}.") because it is active\n" if ($nameDebug || $nameObjDebug); } my $name = $obj->{NAME}; my $typestring = $obj->{TYPE}; my $posstypes = $obj->{POSSTYPES}; my $outerLocalDebug = $localDebug; my $localDebug = 0 || $nameDebug || $nestClassDebug; # my $typestring = $types[$count++]; my $rawname = $name; print STDERR "NAME IS \"$name\"\n" if ($localDebug); print STDERR "CURNAME IS \"$curname\"\n" if ($localDebug); print STDERR "TYPESTRING IS $typestring\n" if ($localDebug); print STDERR "CURTYPE IS $curtype\n" if ($localDebug); print STDERR "MATCH: $name IS A $typestring.\n" if ($localDebug); print STDERR "DEC ($name / $typestring): $declaration\n" if ($localDebug && $outerLocalDebug); $name =~ s/\s*$//go; $name =~ s/^\s*//go; my $cmpname = $name; my $cmpcurname = $curname; $cmpname =~ s/:$//so; $cmpcurname =~ s/:$//so; if (!length($name)) { next; } my $extra_needs_setup = 0; print STDERR "Got $name ($curname)\n" if ($localDebug); print STDERR "POSSTYPES: $posstypes\n" if ($nameDebug || $nameObjDebug); print "CUROBJ CHECKPOINT: $curObj\n" if ($nameObjDebug); my $extra = undef; if ($blockmode && ($typestring ne $firstBlockObjType) && ($typestring ne $firstBlockCurType)) { warn "WARNING: Block declaration contains multiple types\n ($typestring != $firstBlockObjType)\n"; } # print STDERR "$typestring eq $curtype && ($cmpname eq $cmpcurname || !length($curname))\n"; print "CUROBJ: $curObj INSERTED: $curObj->{INSERTED}\n" if ($nameDebug); # print STDERR "(($typestring eq $curtype && ($cmpname eq $cmpcurname || !length($curname))) && ((!$curObj->{INSERTED}) || $typestring eq $firstBlockCurType))" if ($nameDebug); if ((!$curObjIsTainted) && (($typestring eq $curtype && ($cmpname eq $cmpcurname || !length($curname))) && ((!$curObj->{INSERTED}) || $typestring eq $firstBlockCurType))) { print STDERR "$curtype = $typestring\n" if ($localDebug); # $HeaderDoc::ignore_apiuid_errors = 1; # my $junk = $curObj->apirefSetup(); # $HeaderDoc::ignore_apiuid_errors = 0; $extra = $curObj; print STDERR "EXTRA IS CUROBJ ($extra) FROM NAME OBJECT $obj\n" if ($nameObjDebug); if ($curObj->{INSERTED}) { $curObj->{INSERTED} = 2; } else { $curObj->{INSERTED} = 1; } # print STDERR "E=C\n$extra\n$curObj\n"; push(@linkobjs, \$extra); if ($blockmode) { $blockDec .= $declaration; print STDERR "SPDF[1]\n" if ($hangDebug); $curObj->isBlock(1); # $curObj->setDeclaration($blockDec); print STDERR "END SPDF[1]\n" if ($hangDebug); # $declaration = $curObj->declaration() . $declaration; } } else { $extra_needs_setup = 1; print STDERR "NAME IS $name\n" if ($localDebug); if ($curtype eq "function" && $posstypes =~ /function/o) { $curtype = "UNKNOWN"; print STDERR "setting curtype to UNKNOWN\n" if ($localDebug); } if ($typestring =~ /forwarddeclaration-/) { $bail = 1; ## $inputCounter--; ## @@@ DAG CHECKME @@@ ## print STDERR "DECREMENTED INPUTCOUNTER [4]\n" if ($HeaderDoc::inputCounterDebug); print STDERR "BAILFAST[1]: AT END IC: $inputCounter\n" if ($HeaderDoc::inputCounterDebug); last; } my $ncdeclaration = $parseTree->textTreeNC($lang, $sublang, 1); ($extra, $classType, $varIsConstant) = objForType( $curObj, $parseTokens{typedefname}, $typestring, $posstypes, $outertype, $curtype, $classType, $classKeyword, $ncdeclaration, \@fields, $functionGroup, $varIsConstant, $blockmode, $inClass, $inInterface, $inTypedef, $inStruct, $fullpath, $inputCounter, $blockOffset, $lang, $sublang, $outerLocalDebug, $functionContents, $apiOwner, $subparseInputCounter, $subparseBlockOffset, $extendsClass, $implementsClass, 0, \%parseTokens); print "EXTRA ON RETURN IS $extra\n" if ($nameDebug || $nameObjDebug); } my $class = ref($extra) || $extra; if ($class =~ /HeaderDoc::HeaderElement/) { next; } # print STDERR "CHECKING TYPE: "; if ($extra) { # print STDERR "SETTING extra $extra PARSER STATE TO $returnedParserState\n"; # print STDERR " DECLARATION: $declaration\n\n"; $extra->parserState($returnedParserState); if ($matching_declaration) { # print STDERR "NOT SUPPRESSING $name: YES ($extra)\n"; $extra->suppressChildren(0); } else { # print STDERR "SUPPRESSING $name: NO ($extra)\n"; $extra->suppressChildren(1); } } # print STDERR "CHECKING NAME: "; # if ($extra && ($rawname eq $docname) && (!$explicit_name_canonical || !$matching_declaration )) { # print STDERR "NAME: $rawname DOCNAME: $docname EXPLICIT: $explicit_name_canonical CURTYPE: $curtype TYPESTRING: $typestring MATCHING: $matching_declaration\n"; # # $extra->appleRefIsDoc(1); # print STDERR "YES\n"; # } else { # if ($extra) { # # $extra->appleRefIsDoc(0); # # $extra->wipeUIDCache(); # # $extra->apirefSetup(1); # print STDERR "NO: $docname != $rawname \n"; # } # } # print STDERR "HERE\n"; if ($hangDebug) { print STDERR "Point NEWB\n"; } if ($curtype eq "UNKNOWN" && $extra && !$blockmode) { my $orig_parsetree_ref = $curObj->parseTree(); bless($orig_parsetree_ref, "HeaderDoc::ParseTree"); my $pt = ${$orig_parsetree_ref}; # $pt->apiOwnerSub($curObj, $extra); if ((!$curObj->{INSERTED}) && ($curObj != $extra)) { $curObj->free(0, 1, $extra); } $curObj = $extra; $curObj->apiOwner($apiOwner); my $prevignore = $HeaderDoc::ignore_apiuid_errors; $HeaderDoc::ignore_apiuid_errors = 2; # my $oldisdoc = $curObj->appleRefIsDoc(); # $curObj->appleRefIsDoc(1); # my $junk = $curObj->apirefSetup(); # $curObj->appleRefIsDoc($oldisdoc); $HeaderDoc::ignore_apiuid_errors = $prevignore; # @@@ CHECKME DAG if ($extra->isAPIOwner) { $pt->apiOwner($extra); } else { $pt->addAPIOwner($extra); } $curObj->parseTree($orig_parsetree_ref); } else { print STDERR "NOT SETTING PARSETREE. Current type is $curtype\n"."\n" if ($missingParseTreeDebug); print STDERR "CUROBJ IS $curObj\n" if ($missingParseTreeDebug); print STDERR "CUROBJ PT IS".$curObj->parseTree()."\n" if ($missingParseTreeDebug); } if ($extra) { print STDERR "Processing \"extra\" ($extra).\n" if ($localDebug); print STDERR "EXTRANAME: \"".$name."\"\n" if ($localDebug); if ($isCallback) { if ($extra->can("isFunctionPointer")) { $extra->isFunctionPointer($isCallback); } } if ($bpavail && length($bpavail)) { $extra->availability($bpavail); } my $cleantypename = "$typestring $name"; $cleantypename =~ s/\s+/ /sgo; $cleantypename =~ s/^\s*//so; $cleantypename =~ s/\s*$//so; if (length($cleantypename)) { $HeaderDoc::namerefs{$cleantypename} = $extra; $extra->addToNameRefs($cleantypename); } my $extraclass = ref($extra) || $extra; my $abstract = $curObj->abstract(); my $discussion_set = $curObj->discussion_set(); my $discussion = $curObj->raw_discussion(); my $override_discussion = undef; my $nameline_discussion = $curObj->raw_nameline_discussion(); print STDERR "OLD DISCUSSION: $discussion\n" if ($nameDebug); print STDERR "OLD NAMELINE DISCUSSION: $nameline_discussion\n" if ($nameDebug); my $pridec = $curObj->privateDeclaration(); $extra->privateDeclaration($pridec); if ($curObj != $extra) { my $orig_parsetree_ref = $curObj->parseTree(); print STDERR "CO != EX. PTREF is $orig_parsetree_ref\n"."\n" if ($missingParseTreeDebug); # my $orig_parsetree = ${$orig_parsetree_ref}; bless($orig_parsetree_ref, "HeaderDoc::ParseTree"); # @@@ CHECKME DAG if ($extra->isAPIOwner) { $$orig_parsetree_ref->apiOwner($extra); } else { $$orig_parsetree_ref->addAPIOwner($extra); } $extra->parseTree($orig_parsetree_ref); # ->clone()); # my $new_parsetree = $extra->parseTree(); # bless($new_parsetree, "HeaderDoc::ParseTree"); # $new_parsetree->addAPIOwner($extra); # $new_parsetree->processEmbeddedTags(); } else { print STDERR "CO == EX.\n"."\n" if ($missingParseTreeDebug); } # print STDERR "PROCESSING CO $curObj EX $extra\n"; # print STDERR "PT: ".$curObj->parseTree()."\n"; if ($blockmode) { my $parmDescDebug = $parmDebug || 0; # my $altDiscussionRef = $curObj->checkAttributeLists("Included Defines"); print STDERR "Looking for discussion for \"$name\"\n" if ($parmDescDebug); my $discussionParam = $curObj->taggedParamMatching($name); print STDERR "GOT OBJECT $discussionParam\n" if ($parmDescDebug); print STDERR "SELF: $curObj DP: $discussionParam\n" if ($parmDescDebug); # ADP: $altDiscussionRef if ($discussionParam) { my $altdiscussion = $discussionParam->halfbaked_discussion(); print "AD IS: $altdiscussion\n" if ($parmDescDebug); if ($altdiscussion =~ /\S/) { $override_discussion = $altdiscussion; } $discussionParam->{MAINOBJECT} = \$extra; # print "MAINOBJECT: ".$discussionParam->{MAINOBJECT}."\n"; # print "EXTRA: $extra\n"; # print STDERR "SET DISCUSSION TO $override_discussion\n" if ($parmDescDebug); # } elsif ($altDiscussionRef) { # my @altDiscEntries = @{$altDiscussionRef}; # foreach my $field (@altDiscEntries) { # my ($dname, $ddisc, $is_on_nameline) = &getAPINameAndDisc($field, $lang); # if ($name eq $dname) { # if (!$is_on_nameline) { # $discussion = $ddisc; # $discussion_set = 1; # $nameline_discussion = ""; # } else { # $nameline_discussion = $ddisc; # $discussion = ""; # } # } # } } if ($curObj != $extra) { # we use the parsed parms to # hold subdefines. $curObj->addParsedParameter($extra); } } print STDERR "Point B1\n" if ($hangDebug); if ($extraclass ne "HeaderDoc::Method" && !$extra->isAPIOwner()) { print STDERR "Point B2\n" if ($hangDebug); my $paramName = ""; my $position = 0; my $type = ""; if ($extraclass eq "HeaderDoc::Function") { $extra->returntype($returntype); } my @tempPPL = @parsedParamList; foreach my $parsedParam (@tempPPL) { # the real code my $ppDebug = 0 || $parmDebug; print STDERR "PARSED PARAM: \"$parsedParam\"\n" if ($ppDebug); my $ppstring = $parsedParam; $ppstring =~ s/^\s*//sgo; $ppstring =~ s/\s*$//sgo; my $foo; my $dec; my $pridec; my $type; my $name; my $pt; my $value; my $pplref; my $returntype; my @nameObjects = (); my $pplang = $lang; my $ppsublang = $sublang; if ($ppstring eq "...") { # $name = $ppstring; # $type = ""; # $pt = ""; my $nameobj = HeaderDoc::TypeHelper->new(); $nameobj->{NAME} = $ppstring; $nameobj->{TYPE} = ""; $nameobj->{POSSTYPES} = ""; $nameobj->{INSERTEDAT} = "varargs"; push(@nameObjects, $nameobj); } else { $ppstring .= ";"; my @array = ( $ppstring ); my $parseTree = undef; my $simpleTDcontents = ""; my $bpavail = ""; my $bogusblockoffset; my $conformsToList; # throw this away here. my $ec = ""; my $ic = ""; my $argreturnedParserState; # Don't stop on this! ($foo, $dec, $type, $name, $pt, $value, $pplref, $returntype, $pridec, $parseTree, $simpleTDcontents, $bpavail, $bogusblockoffset, $conformsToList, $functionContents, $argreturnedParserState, $nameObjectsRef, $ec, $ic, $propertyAttributes, $memberOfClass, $pplang, $ppsublang) = &blockParse($fullpath, $extra->linenum(), \@array, 0, 1, \%HeaderDoc::ignorePrefixes, \%HeaderDoc::perHeaderIgnorePrefixes, \%HeaderDoc::perHeaderIgnoreFuncMacros, $keywordhashref, $case_sensitive, $lang, $sublang); $parseTree->dispose(); @nameObjects = @{$nameObjectsRef}; } if ($ppDebug) { print STDERR "NAME: $name\n"; print STDERR "TYPE: $type\n"; print STDERR "PT: $pt\n"; print STDERR "RT: $returntype\n"; } foreach my $obj (@nameObjects) { my $name = $obj->{NAME}; my $stars = $obj->{STARS}; print STDERR "NAME: $name TYPE: $returntype\n" if ($ppDebug); my $param = HeaderDoc::MinorAPIElement->new("LANG" => $pplang, "SUBLANG" => $ppsublang); $param->apiOwner($apiOwner); if (defined($subparseInputCounter)) { $param->linenuminblock($subparseInputCounter); $param->blockoffset($subparseBlockOffset); } else { $param->linenuminblock($inputCounter); $param->blockoffset($blockOffset); } # $param->linenum($inputCounter+$blockOffset); $param->outputformat($extra->outputformat); $returntype =~ s/^\s*//s; $returntype =~ s/\s*$//s; if ($obj->{NAME} eq "") { warn("Anonymous data structure inside struct or union.\n"); warn("LISTING:\n$parsedParam\nEND LISTING\n"); warn("OWNER IS: $rawname\n"); next; } print STDERR "BLOCKPARSE PARAMETER PARSE RETURNED NAME $obj->{NAME}\n" if ($ppDebug); print STDERR "RETURNTYPE IS $returntype\n" if ($ppDebug); # ($returntype =~ /(^|\s)(struct|union|enum|record|typedef)$/) # print STDERR "SL: $ppsublang\n"; if ($extraclass =~ /HeaderDoc::Function/ && $ppsublang ne "php") { # Handle cases where a function is given with no actual # parameter name. my $enumname = $parseTokens{enumname}; my $typedefname = $parseTokens{typedefname}; my $structname = $parseTokens{structname}; my $unionname = $parseTokens{unionname}; if ($pplang ne "pascal" && $ppsublang ne "MIG" && (($structname && $returntype =~ /(^|\s)\Q$structname\E$/) || ($unionname && $returntype =~ /(^|\s)\Q$unionname\E$/) || ($enumname && $returntype =~ /(^|\s)\Q$enumname\E$/) || ($typedefname && $returntype =~ /(^|\s)\Q$typedefname\E$/))) { print STDERR "OOPS\n"; $returntype .= " ".$obj->{NAME}; $name = ""; } elsif (!length($returntype)) { $returntype .= " $name"; if ($name !~ /\.\.\./) { $name = ""; # WAS anonymous$name, which broke parameter checking } } } print STDERR "NM: $name RT $returntype\n" if ($ppDebug); $param->name($name); $param->position($position++); my $typeval = $returntype; if ($stars) { $typeval .= " ".$stars; } $param->type($typeval); $extra->addParsedParameter($param); } } } elsif ($extraclass eq "HeaderDoc::Method") { # we're a method $extra->returntype($returntype); my @newpps = $parseTree->objCparsedParams($lang, $sublang); # print STDERR "PPLIST for $name:\n"; foreach my $newpp (@newpps) { # print STDERR "Parsed param: ".$newpp->{NAME}."\n"; $extra->addParsedParameter($newpp); } # print STDERR "END PPLIST:\n"; # $extra->dbprint(); } if ($extra->{CLASS} ne "HeaderDoc::PDefine" && $blockmode == 2) { # Bail out of block mode if something other than a #define appears. my $linenum = $inputCounter + $blockOffset; warn("$fullpath:$linenum: warning: Unterminated \@defineblock detected.\n"); $blockmode = 0; print STDERR "\$extra->{CLASS}=\"".$extra->{CLASS}."\"\n" if ($localDebug); # Now try to back off a bit so that we can get the previous HeaderDoc # block, if any. If we're just reprocessing existing parse trees, # this isn't needed. if (!$subparse) { my $poplines = 0; print STDERR "Previous line number was ".($previousInputCounter + $blockOffset).".\n" if ($localDebug); $inputCounter = $previousInputCounter; while ($inputCounter >= 1) { my $checkline = $inputLines[$inputCounter]; print STDERR "IC: $inputCounter CL: $checkline\n" if ($localDebug); if ($checkline =~ /\/\*\!/) { last; } if ($checkline =~ /\#\s*define/) { while ($checkline =~ /\\\s*$/) { $inputCounter++; print STDERR "INCREMENTED INPUTCOUNTER [5]\n" if ($HeaderDoc::inputCounterDebug); $checkline = $inputLines[$inputCounter]; } # pointing at the last line of the declaration. Bump it # forward one more to undo the inputCounter-- after the loop. $inputCounter++; print STDERR "INCREMENTED INPUTCOUNTER [6]\n" if ($HeaderDoc::inputCounterDebug); last; } $inputCounter--; print STDERR "DECREMENTED INPUTCOUNTER [7]\n" if ($HeaderDoc::inputCounterDebug); $poplines++; } # point to the line before the comment marker. $inputCounter--; print STDERR "DECREMENTED INPUTCOUNTER [8]\n" if ($HeaderDoc::inputCounterDebug); $curObj->dropParsedParameter(); # $curObj->dbprint(); $bail = 1; print STDERR "BAILFAST[2]: AT END IC: $inputCounter\n" if ($HeaderDoc::inputCounterDebug); last; } } if (length($simpleTDcontents)) { $extra->typedefContents($simpleTDcontents); } print STDERR "Point B3\n" if ($hangDebug || $nameDebug); print STDERR "AT BOTTOM: DISCUSSION IS: ".($override_discussion ? $override_discussion : $discussion)."\n" if ($parmDebug); if ($preAtPart =~ /\S/) { print STDERR "preAtPart: $preAtPart\n" if ($localDebug); if (($blockmode == 2) && $extra->can("blockDiscussion")) { $extra->blockDiscussion($preAtPart); if ($override_discussion) { $extra->discussion($override_discussion); } } else { $extra->discussion(($override_discussion ? $override_discussion : $preAtPart)); } } elsif ($extra != $curObj) { # Otherwise this would be bad.... print STDERR "SETTING DISCUSSION: extra != CurObj\n" if ($parmDebug); # print STDERR "BLOCKMODE: $blockmode\n"; # print STDERR "NOT EQUAL CASE\n NL DISC: $nameline_discussion\n DISC: $discussion\n OD: $override_discussion\n"; if ($blockmode == 1 || $blockmode == 2) { if (!$discussion) { # Only do this if no discussion. Otherwise, this is # part of the block name. print STDERR "SETTING DISCUSSION: blockmode == 2 and NO discussion\n" if ($parmDebug); $extra->blockDiscussion($nameline_discussion); } else { print STDERR "SETTING DISCUSSION: blockmode == 2 and discussion\n" if ($parmDebug); $extra->blockDiscussion($discussion); } if ($override_discussion) { # print STDERR "OVERRIDE DISCUSSION $override_discussion\n"; $extra->discussion($override_discussion); } } else { if ($discussion_set || $override_discussion) { print STDERR "SETTING DISCUSSION: blockmode NOT 2 and discussion_set\n" if ($parmDebug); $extra->discussion(($override_discussion ? $override_discussion : $discussion)); print STDERR "NEW DISC IS $discussion\n" if ($parmDebug); } else { print STDERR "SETTING DISCUSSION: blockmode NOT 2 and NOT discussion_set\n" if ($parmDebug); $extra->nameline_discussion($nameline_discussion); } } } print STDERR "Point B4\n" if ($hangDebug || $nameDebug); $extra->abstract($abstract); if (length($value)) { $extra->value($value); } if ($extra != $curObj || !length($curObj->name())) { $name =~ s/^(\s|\*)*//sgo; } print STDERR "NAME IS \"$name\"\n" if ($localDebug || $nameDebug); $extra->rawname($name); print STDERR "RN: \"".$extra->rawname()."\"\n" if ($localDebug || $nameDebug); print STDERR "NM: \"".$extra->name()."\"\n" if ($localDebug || $nameDebug); # my $namestring = $curObj->name(); # if ($explicit_name_differs && 0) { # $extra->name("$name ($namestring)"); # } else { # $extra->name($name); # } print STDERR "Point B5\n" if ($hangDebug); # $HeaderDoc::ignore_apiuid_errors = 1; $extra->name($name); # my $junk = $extra->apirefSetup(); # $HeaderDoc::ignore_apiuid_errors = 0; # Set up Objective-C "Conforming To" list. if ($extra =~ /HeaderDoc::ObjC/) { $extra->conformsToList($conformsToList) } # print STDERR "NAMES: \"".$curObj->name()."\" & \"".$extra->name()."\"\n"; # print STDERR "ADDYS: ".$curObj." & ".$extra."\n"; if ($extra != $curObj) { my @params = $curObj->taggedParameters(); foreach my $param (@params) { print STDERR "CONSTANT $param\n" if ($parmDebug); if (!$param->{ISDEFINE}) { my $newparam = $param->clone(); $newparam->apiOwner($extra); $extra->addTaggedParameter($newparam); } elsif ($param->name() eq $extra->rawname() || $param->name() eq $extra->name()) { my @subparams = $param->userDictArray(); print "SP: ".@subparams."\n" if ($parmDebug); foreach my $hashRef (@subparams) { while (my ($param, $disc) = each %{$hashRef}) { print STDERR "PARAM IS $param\n" if ($parmDebug); my $paramobj = HeaderDoc::MinorAPIElement->new("LANG" => $lang, "SUBLANG" => $sublang); $paramobj->name($param); $paramobj->discussion($disc); $extra->addTaggedParameter($paramobj); } } } else { print STDERR "NOMATCH: PARAM NAME IS ".$param->name()." EXTRA IS ".$extra->rawname()." OR ".$extra->name()."\n" if ($parmDebug); } } my @constants = $curObj->constants(); foreach my $constant (@constants) { # print STDERR "CONSTANT $constant\n"; if ($extra->can("addToConstants")) { my $newconstant = $constant->clone(); $newconstant->apiOwner($extra); $extra->addToConstants($newconstant); # print STDERR "ATC\n"; } elsif ($extra->can("addConstant")) { my $newconstant = $constant->clone(); $newconstant->apiOwner($extra); $extra->addConstant($newconstant); # print STDERR "AC\n"; } } my @local_variables = $curObj->variables(); foreach my $variable (@local_variables) { # print STDERR "LOCAL VARIABLE $variable\n"; my $newvariable = $variable->clone(); $newvariable->apiOwner($extra); $extra->addVariable($newvariable); # print STDERR "AV\n"; } print STDERR "Point B6\n" if ($hangDebug); if (length($curObj->name())) { # my $a = $extra->rawname(); my $b = $curObj->rawname(); my $c = $curObj->name(); # print STDERR "EXTRA RAWNAME: $a\nCUROBJ RAWNAME: $b\nCUROBJ NAME: $c\n"; push(@linkobjs, \$extra); # $curObj->attributelist("See Also", $ern." ".$extra->apiuid()); # $extra->attributelist("See Also", $crn." ".$curObj->apiuid()); } } print STDERR "Point B7 TS = $typestring\n" if ($hangDebug); if (ref($apiOwner) ne "HeaderDoc::Header") { if (!$apiOwner->isCOMInterface()) { $extra->accessControl($cppAccessControlState); # @@@ FIXME DAG CHECK FOR OBJC } } if ($extra != $curObj && $curtype ne "UNKNOWN" && $curObj->can("fields") && $extra->can("fields")) { my @fields = $curObj->fields(); print STDERR "B7COPY\n" if ($localDebug); foreach my $field (@fields) { bless($field, "HeaderDoc::MinorAPIElement"); my $newfield = $field->clone(); $newfield->apiOwner($extra); $extra->addToFields($newfield); # print STDERR "Added field ".$newfield->name()." to $extra ".$extra->name()."\n"; } } $extra->apiOwner($apiOwner); if ($xml_output) { $extra->outputformat("hdxml"); } else { $extra->outputformat("html"); } $extra->filename($filename); $extra->fullpath($fullpath); # warn("Added ".$extra->name()." ".$extra->apiuid().".\n"); # print STDERR "ITD: $inTypedef\n"; print STDERR "B8X blockmode=$blockmode ts=$typestring\n" if ($localDebug || $hangDebug); my $typedefname = $parseTokens{typedefname}; my $classregexp = $parseTokens{classregexp}; my $moduleregexp = $parseTokens{moduleregexp}; # if (($typestring =~ /^(class|\@class|\@interface|\@implementation|\@protocol|interface|module|namespace|package)/ || $inClass) && !$inTypedef) if (((length($classregexp) && $typestring =~ /$classregexp/) || (length($moduleregexp) && $typestring =~ /$moduleregexp/) || $inClass) && !$inTypedef) { print STDERR "ITSACLASS! ($extra->name)\n" if ($localDebug); $extra->declaration($declaration); $extra->declarationInHTML($declaration); # if (!$subparse || ($extra != $curObj)) { # my $localDebug = 1; print STDERR "ADDING \"".$extra->name."\" TO CLASSES/PROTOCOLS/*\n" if ($localDebug); print STDERR "RAWDEC: $declaration\n" if ($localDebug); my $ncdeclaration = $parseTree->textTreeNC($lang, $sublang, 1); $classType = classTypeFromFieldAndBPinfo($classKeyword, $typestring." ".$posstypes, $ncdeclaration, $fullpath, $inputCounter+$blockOffset, $sublang); # print STDERR "CLASSTYPE: $classType\n"; if ($classType eq "intf") { push (@classObjects, $extra); print STDERR "intf\n" if ($localDebug); $apiOwner->addToProtocols($extra) if ($extra->{INSERTED} != 2); } elsif ($classType eq "occCat") { push (@categoryObjects, $extra); print STDERR "occCat\n" if ($localDebug); $apiOwner->addToCategories($extra) if ($extra->{INSERTED} != 2); } elsif ($classType eq "occ") { push (@classObjects, $extra); print STDERR "occ\n" if ($localDebug); $apiOwner->addToClasses($extra) if ($extra->{INSERTED} != 2); } elsif ($classType eq "C" || $classType eq "cpp" || $extra->isCOMInterface() || $classType eq $lang || $classType eq $sublang) { # print STDERR "CT: $classType\n"; # class or typedef struct # (java, C, cpp, etc.) push (@classObjects, $extra); print STDERR "other ($classType)\n" if ($localDebug); $apiOwner->addToClasses($extra) if ($extra->{INSERTED} != 2); # print STDERR "ADDING CLASS\n"; } else { print STDERR "Unknown class type $classType\n"; } # } if ($lang eq "perl") { # print STDERR "Perl Class\n"; $HeaderDoc::perlClassChange = $extra; } } elsif (($typestring =~ /$typedefname/ && length($typedefname)) || ($typestring =~ /^(class|\@class|\@interface|\@implementation|\@protocol)/)) { if (length($declaration)) { $extra->setDeclaration($declaration); } if (length($extra->name())) { if (($blockmode != 2) || ($extra != $curObj)) { $apiOwner->addToTypedefs($extra) if ($extra->{INSERTED} != 2); } } } elsif ($typestring =~ /MACRO/o) { # throw these away. # $extra->setDeclaration($declaration); # $apiOwner->addToPDefines($extra); if ($localDebug || $subparseDebug) { print STDERR "Skipping insertion of MACRO in block mode.\n"; } } elsif ($typestring =~ /#define/o) { print STDERR "SPDF[2]\n" if ($hangDebug); $extra->setDeclaration($declaration); # print STDERR "DEC:$declaration\n" if ($hangDebug); print STDERR "END SPDF[2]\n" if ($hangDebug); print STDERR "EXTRA IS $extra\n" if ($nameDebug); print STDERR "PDEF DECL: $declaration\n" if ($nameDebug); if ($extra !~ /HeaderDoc::PDefine/) { die("Unexpected type $extra"); } if (($blockmode != 2) || ($extra != $curObj)) { $apiOwner->addToPDefines($extra) if ($extra->{INSERTED} != 2); print STDERR "Adding #define to $apiOwner in block mode. $extra == $curObj\n" if ($localDebug || $subparseDebug); } elsif ($localDebug || $subparseDebug) { print STDERR "Skipping insertion of #define in block mode. $extra != $curObj\n"; } if ($extra->can('isAvailabilityMacro') && $extra->isAvailabilityMacro()) { addAvailabilityMacro($extra->name, $extra->discussion); } } elsif ($typestring =~ /struct/o || $typestring =~ /union/o || ($lang eq "pascal" && $typestring =~ /record/o)) { if ($typestring =~ /union/o) { $extra->isUnion(1); } else { $extra->isUnion(0); } # $extra->declaration($declaration); # print STDERR "PRE (DEC IS $declaration)\n"; $extra->setDeclaration($declaration); # print STDERR "POST\n"; if (($blockmode != 2) || ($extra != $curObj)) { $apiOwner->addToStructs($extra) if ($extra->{INSERTED} != 2); } } elsif ($typestring =~ /enum/o) { # print STDERR "TYPESTRING MATCH: \"$typestring\" = \"enum\"\n"; $extra->declaration($declaration); $extra->declarationInHTML($extra->getEnumDeclaration($declaration)); print STDERR "B8ENUM\n" if ($localDebug || $hangDebug); if (($blockmode != 2) || ($extra != $curObj)) { print STDERR "B8ENUMINSERT apio=$apiOwner\n" if ($localDebug || $hangDebug); $apiOwner->addToEnums($extra) if ($extra->{INSERTED} != 2); } } elsif ($typestring =~ /\#define/o) { print STDERR "SPDF[3]\n" if ($hangDebug); $extra->setDeclaration($declaration); print STDERR "END SPDF[3]\n" if ($hangDebug); if (($blockmode != 2) || ($extra != $curObj)) { $headerObject->addToPDefines($extra); print STDERR "Adding #define to $headerObject in block mode. $extra == $curObj\n" if ($localDebug || $subparseDebug); } elsif ($localDebug || $subparseDebug) { print STDERR "Skipping insertion of #define in block mode. $extra != $curObj\n"; } if ($extra->can('isAvailabilityMacro') && $extra->isAvailabilityMacro()) { addAvailabilityMacro($extra->name, $extra->discussion); } } elsif ($typestring =~ /(function|method|operator|ftmplt|callback)/o) { if ($typestring =~ /method/) { $extra->setDeclaration($declaration); # $HeaderDoc::ignore_apiuid_errors = 1; # my $junk = $extra->apirefSetup(1); # $HeaderDoc::ignore_apiuid_errors = 0; if (($blockmode != 2) || ($extra != $curObj)) { $apiOwner->addToMethods($extra) if ($extra->{INSERTED} != 2); } } else { print STDERR "SFD\n" if ($hangDebug); # print STDERR "EXTRA IS $extra\n"; if (ref($extra) ne "HeaderDoc::HeaderElement") { $extra->setDeclaration($declaration); } print STDERR "END SFD\n" if ($hangDebug); # $HeaderDoc::ignore_apiuid_errors = 1; # my $junk = $extra->apirefSetup(1); # $HeaderDoc::ignore_apiuid_errors = 0; if (($blockmode != 2) || ($extra != $curObj)) { $apiOwner->addToFunctions($extra) if ($extra->{INSERTED} != 2); } } if ($typestring eq "callback") { # For future expansion $extra->isCallback(1); } if ($typestring eq "ftmplt") { $extra->isTemplate(1); } } elsif ($typestring =~ /^property/o) { $varIsConstant = 0; $extra->isProperty(1); $extra->declaration($declaration); $extra->setDeclaration($declaration); $returntype =~ s/^\s*//s; $returntype =~ s/\s*$//s; $extra->returntype($returntype); # ("\@property $returntype"); if (ref($apiOwner) ne "HeaderDoc::Header") { $extra->accessControl($cppAccessControlState); } if (($blockmode != 2) || ($extra != $curObj)) { $apiOwner->addToProps($extra) if ($extra->{INSERTED} != 2); } } elsif ($typestring =~ /constant/o) { # print STDERR "TS CONSTANT (RET: $returntype)\n"; $extra->declaration($declaration); $extra->setDeclaration($declaration); $returntype =~ s/^\s*//s; $returntype =~ s/\s*$//s; $extra->returntype($returntype); if (length($extra->name())) { # if (ref($apiOwner) ne "HeaderDoc::Header") { # $extra->accessControl($cppAccessControlState); # if (($blockmode != 2) || ($extra != $curObj)) { $apiOwner->addToVars($extra) if ($extra->{INSERTED} != 2); } # } else { # headers group by type if (($blockmode != 2) || ($extra != $curObj)) { $apiOwner->addToConstants($extra) if ($extra->{INSERTED} != 2); } # } } } elsif ($typestring =~ /variable/o) { $extra->declaration($declaration); $extra->setDeclaration($declaration); $returntype =~ s/^\s*//s; $returntype =~ s/\s*$//s; $extra->returntype($returntype); if (ref($apiOwner) ne "HeaderDoc::Header") { $extra->accessControl($cppAccessControlState); } if (($blockmode != 2) || ($extra != $curObj)) { $apiOwner->addToVars($extra) if ($extra->{INSERTED} != 2); } } else { my $linenum = $inputCounter + $blockOffset; warn("$fullpath:$linenum: warning: Unknown typestring $typestring returned by blockParse\n"); } print STDERR "B9 blockmode=$blockmode ts=$typestring\n" if ($localDebug || $hangDebug); print STDERR "DOC REF: ".$extra->appleRefIsDoc()."\n" if ($nameDebug); # $extra->checkDeclaration(); my $prevignore = $HeaderDoc::ignore_apiuid_errors; $HeaderDoc::ignore_apiuid_errors = 1; my $junk = $extra->apirefSetup(1); print STDERR "APIREF (".$extra->name()."): ".$extra->apiref()."\n" if ($nameDebug); $HeaderDoc::ignore_apiuid_errors = $prevignore; print "ADDED $extra to APIOWNER $apiOwner (curObj is $curObj)\n" if ($nameDebug); } } if ($hangDebug) { print STDERR "Point C\n"; print STDERR "inputCounter is $inputCounter, #inputLines is $nlines\n"; } # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 010: SUBLANG NOMATCH\n"; } print STDERR "READ DECLARATION \"$declaration\"\n" if ($HeaderDoc::inputCounterDebug); if (!$bail) { while ($inputLines[$inputCounter] !~ /\S/o && ($inputCounter <= $nlines)) { $inputCounter++; print STDERR "INCREMENTED INPUTCOUNTER [9]\n" if ($HeaderDoc::inputCounterDebug); } # $inputCounter--; # print STDERR "DECREMENTED INPUTCOUNTER [10]: LINE ".$inputLines[$inputCounter]."\n" if ($HeaderDoc::inputCounterDebug); if ($hangDebug) { print STDERR "Point D\n"; } if ($curtype eq "UNKNOWN") { $curtype = $outertype; } if ((($outertype ne $curtype && $innertype ne $curtype && $posstypes !~ /$curtype/ && !($inTypedef && $outertype =~ /^(class|\@class|\@interface|\@implementation|\@protocol)/))) && (($inputCounter > $nlines) || warnHDComment(\@inputLines, $inputCounter, $blockOffset, $lang, "blockParse:$outertype", "18a", \%parseTokens))) { if (!$HeaderDoc::running_test) { warn "No matching declaration found. Last name was $curname\n"; warn buildCommentFromFields(@fields, $preAtPart, "The HeaderDoc comment that caused this was:\n")."\n"; warn "$outertype ne $curtype && $innertype ne $curtype && $posstypes !~ $curtype\n"; } $foundMatch = 0; print STDERR "NOMATCH: AT END IC: $inputCounter\n" if ($HeaderDoc::inputCounterDebug); last; } if ($hangDebug) { print STDERR "Point E\n"; } # print STDERR "IC: $inputCounter\nLINE: ".$inputLines[$inputCounter]."\nSUBPARSE: $subparse\n"; if ($blockmode && (!$subparse)) { while (($inputLines[$inputCounter] =~ /^\s*\/[\/*][^!]/ || $inputLines[$inputCounter] !~ /\S/s) && ($inputCounter <= $nlines)){ $inputCounter++; } } # print STDERR "POSTIC: $inputCounter\nPOSTLINE: ".$inputLines[$inputCounter]."\nPOSTSUBPARSE: $subparse\n"; if ($blockmode == 1) { warn "next line: ".$inputLines[$inputCounter]."\n" if ($hangDebug); print STDERR "BLOCKMODE[10] -> 2\n" if ($localDebug || $blockDebug); $blockmode = 2; } if ($blockmode == 2) { my $prevignore = $HeaderDoc::ignore_apiuid_errors; $HeaderDoc::ignore_apiuid_errors = 1; if (warnHDComment(\@inputLines, $inputCounter, $blockOffset, $lang, "blockMode:$outertype", "18a", \%parseTokens) == 1) { # print STDERR "OT: $outertype\n"; $blockmode = 0; print STDERR "BLOCKMODE[11] -> 0\n" if ($localDebug || $blockDebug); warn "Block Mode Ending\n" if ($hangDebug); } $HeaderDoc::ignore_apiuid_errors = $prevignore; } print STDERR "PTCT: $posstypes =? $curtype\n" if ($localDebug || $blockDebug); $previousInputCounter = $inputCounter; } else { print STDERR "BAIL: AT END IC: $inputCounter\n" if ($HeaderDoc::inputCounterDebug); last; } print STDERR "AT END LOOPTEST: (($blockmode || ($outertype ne $curtype && $innertype ne $curtype && $posstypes !~ /$curtype/ && !($inTypedef && $outertype =~ /^(class|\@class|\@interface|\@implementation|\@protocol)/))) && ($inputCounter <= $nlines)) || ($subparse && !$checkLineNumbers)\n" if ($localDebug || $hangDebug || $nameDebug || $nameObjDebug || $subparseDebug || $blockDebug); print STDERR "AT END IC: $inputCounter\n" if ($HeaderDoc::inputCounterDebug); } print STDERR "OUT OF LOOP. Exited with blockmode = $blockmode\n" if ($localDebug || $blockDebug || $subparseDebug || $hangDebug); if (length($blockDec)) { $curObj->declaration($blockDec); $curObj->declarationInHTML($blockDec); } if ($hangDebug) { print STDERR "Point F\n"; } if ($curObj->can('isAvailabilityMacro') && $curObj->isAvailabilityMacro()) { addAvailabilityMacro($curObj->name, $curObj->discussion); } print STDERR "Out of Block\n" if ($localDebug || $blockDebug || $hangDebug); # the end of this block assumes that inputCounter points # to the last line grabbed, but right now it points to the # next line available. Back it up by one. $inputCounter--; print STDERR "DECREMENTED INPUTCOUNTER TO $inputCounter [11]: LINE ".$inputLines[$inputCounter]."\n" if ($HeaderDoc::inputCounterDebug); # warn("NEWDEC:\n$declaration\nEND NEWDEC\n"); } ## end blockParse handler if ($subparse) { $HeaderDoc::enable_cpp = $old_enable_cpp; } objlink(\@linkobjs); if ($curObj) { print "CO AT END: $curObj\n" if ($HeaderDoc::debugAllocations); if (!$curObj->{INSERTED}) { $curObj->free(0, 1, undef); } } if ($curObj && $curObj->discussionLocked()) { $curObj->unlockDiscussion(); } # if ($sublang ne $HeaderDoc::sublang) { print STDERR "CHECKPOINT 011: SUBLANG NOMATCH\n"; } return ($inputCounter, $cppAccessControlState, $classType, \@classObjects, \@categoryObjects, $blockOffset, $numcurlybraces, $foundMatch, $lang, $sublang, $hashtreecur, $hashtreeroot); } # /*! # @abstract # Returns a HeaderDoc object (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;