FrT;@1|>>0|$15|HeaderDoc::Test%22|$4|CODE$7|COMMENT$7|CPPCODE$15|EXPECTED_RESULT$23|EXPECTED_RESULT_ALLDECS$7|FAILMSG$8|FILENAME$4|LANG$4|NAME$7|SUBLANG$4|TYPE$155247|sub blockParse { my $filename = 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 $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 $cbnDebug = 0; my $macroDebug = 0; my $apDebug = 0; my $tsDebug = 0; my $treeDebug = 0; my $ilcDebug = 0; my $regexpDebug = 0; my $parserStackDebug = 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 $liteDebug = 0 || $HeaderDoc::fileDebug; # Just prints the tokens. my $parserStateInsertDebug = 0; $cppDebug = $cppDebugDefault || $HeaderDoc::fileDebug; # State variables (part 1 of 3) # my $typestring = ""; my $continue = 1; # set low when we're done. my $parsedParamParse = 0; # set high when current token is part of param. # 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 $perl_or_shell = 0; 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; 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" || $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(); # $parserState->{hollow} = $treeTop; setHollowWithLineNumbers(\$parserState, $treeTop, $fileoffset, $inputCounter); $parserState->{lang} = $lang; $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 $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 perl regexp. 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 ($sotemplate, $eotemplate, $operator, $soc, $eoc, $ilc, $ilc_b, $sofunction, $soprocedure, $sopreproc, $lbrace, $rbrace, $unionname, $structname, $enumname, $typedefname, $varname, $constname, $structisbrace, $macronameref, $classregexp, $classbraceregexp, $classclosebraceregexp, $accessregexp, $requiredregexp, $propname, $objcdynamicname, $objcsynthesizename, $moduleregexp, $definename) = parseTokens($lang, $sublang); my $macrore_pound = macroRegexpFromList($macronameref, 1); my $macrore_nopound = macroRegexpFromList($macronameref, 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 $propname\n"; if ($parseDebug) { print STDERR "SOT: $sotemplate EOF: $eotemplate OP: $operator SOC: $soc EOC: $eoc ILC: $ilc ILC_B: $ilc_b\n"; print STDERR "SOFUNC: $sofunction SOPROC: $soprocedure SOPREPROC: $sopreproc LBRACE: $lbrace RBRACE: $rbrace\n"; print STDERR "UNION: $unionname STRUCT: $structname TYPEDEF: $typedefname VAR: $varname CONST: $constname\n"; print STDERR "STRUCTISBRACE: $structisbrace MACRONAMEREF: $macronameref 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") { $perl_or_shell = 1; if ($lang eq "perl") { $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; if ($lang eq "pascal") { $pascal = 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 $categoryClass = ""; # my $classtype = ""; # my $inClass = 0; my $pushParserStateAfterToken = 0; my $pushParserStateAfterWordToken = 0; my $pushParserStateAtBrace = 0; my $occPushParserStateOnWordTokenAfterNext = 0; $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 "INCOMING INPUTCOUNTER: $inputCounter\n" if ($HeaderDoc::inputCounterDebug); while ($continue && ($inputCounter <= $nlines)) { $HeaderDoc::CurLine = $inputCounter + $fileoffset; my $line = $inputLines[$inputCounter++]; print STDERR "GOT LINE: $line\n" if (($localDebug && $apDebug) || $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 "CHANGED LINE FROM \"$line\" to \"$1\"\n" if ($localDebug || $liteDebug); $line = $1."\n"; } } print STDERR "LINE[$inputCounter] : $line\n" if ($offsetDebug); # The tokenizer if ($lang eq "perl" || $lang eq "shell") { @parts = split(/("|'|\#|\{|\}|\(|\)|\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) {foreach my $partlist (@parts) {print STDERR "PARTLIST: \"$partlist\"\n"; }} # 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; # print STDERR "CHECK LINE $line\n"; if ($line =~ /^\s*#include (.*)$/) { my $rest = $1; $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 "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; while ($pos < scalar(@parts)) { my $part = $parts[$pos]; my $noCPPThisToken = 0; if (length($part)) { if (!$inChar && !$inString && !$inComment && !$inSLC) { if ($parserState->{NEXTTOKENNOCPP} == 1) { # We're in an "if" block. if ($part eq "defined") { $parserState->{NEXTTOKENNOCPP} = 3; } } elsif ($parserState->{NEXTTOKENNOCPP} == 2) { # 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) { # 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)/) { $parserState->{NEXTTOKENNOCPP} = 2; } elsif ($inCPPSpecial && $part =~ /if/) { $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 $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 $soc) { print STDERR "SOC\n"if ($cppleaddebug); $inComment = 1; } elsif (!$inComment && ($part eq $ilc || $part eq $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) { ($newpart, $hasargs) = 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) { $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 \"$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; } } 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) { print STDERR "CPPS: \"$cppstring\"\n"; warn "Non-terminated macro.\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 "CHANGED LINE FROM \"$line\" to \"$1\"\n" if ($localDebug || $liteDebug); $line = $1."\n"; } } print STDERR "INCREMENTED INPUTCOUNTER [2]\n" if ($HeaderDoc::inputCounterDebug); # @parts = split(/(\W)/, $line); if ($lang eq "perl" || $lang eq "shell") { @parts = split(/("|'|\#|\{|\}|\(|\)|\s|;|\\|\W)/, $line); } else { @parts = split(/("|'|\/\/|\/\*|\*\/|::|==|<=|>=|!=|\<\<|\>\>|\{|\}|\(|\)|\s|;|\\|\W)/, $line); } } } until (!$incppargs && !$inComment); # The tokenizer if ($lang eq "perl" || $lang eq "shell") { @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); # 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; $treeSkip = 0; # $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); $forcenobreak = 0; if ($nextpart eq "\r") { $nextpart = "\n"; } if ($localDebug && $nextpart eq "\n") { print STDERR "NEXTPART IS NEWLINE!\n"; } if ($localDebug && $part eq "\n") { 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); print STDERR "CURLINE IS \"$curline\"\n" if ($localDebug || $hangDebug); 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); } } elsif ($occPushParserStateOnWordTokenAfterNext) { # if ($part !~ /(\s|<)/) if ($part =~ /(\/\/|\/\*|\-|\+|\w|\@)/) { $parserState->{lastTreeNode} = $treeCur; print STDERR "parserState pushed onto stack[occPushParserStateOnWordTokenAfterNext]\n" if ($parserStackDebug); $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 0; $parserState->{lang} = $lang; $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++; } 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} inRegexp: $inRegexp\n"; print STDERR "PART: regexpNoInterpolate: $regexpNoInterpolate\n"; 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 ($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); printf("PART: $part TEMPAVAIL: $tempavail\n") if ($localDebug || $gccAttributeDebug); if ($tempavail && ($tempavail ne "1") && ($tempavail ne "2")) { $parserState->{availability} = $tempavail; } elsif ($tempavail eq "2") { # Reusing the GCC attribute handling code because that does exactly what we need. print STDERR "Function-like availability macro detected. Collecting.\n" if ($localDebug || $gccAttributeDebug); $parserState->{attributeState} = 1; $parserState->{attributeParts} = (); # Add __attribute__ as the next token. $treeCur = $treeCur->addSibling($part, 0); 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; } # Handle the GCC "__attribute__" extension outside the context of # the parser because it isn't part of the language and massively # breaks the syntax. if ($lang eq "C" && isKeyword($part, $keywordhashref, $case_sensitive) == 2) { print STDERR "GCC attribute detected. Collecting.\n" if ($localDebug || $gccAttributeDebug); $parserState->{attributeState} = 1; $parserState->{attributeParts} = (); # Add __attribute__ as the next token. $treeCur = $treeCur->addSibling($part, 0); push(@treeStack, $treeCur); # Nest all contents one level lower. $treeCur = $treeCur->addChild("", 0); $part = $nextpart; next; } elsif ($parserState->{attributeState} == 1) { if ($part eq "(") { print STDERR "GCC attribute open paren\n" if ($localDebug || $gccAttributeDebug); $parserState->{attributeState} = -1; } $treeCur = $treeCur->addSibling($part, 0); $part = $nextpart; next; } elsif ($parserState->{attributeState} < 0) { if ($part eq "(") { $parserState->{attributeState}--; print STDERR "GCC attribute open paren, count=".(0-$parserState->{attributeState})."\n" if ($localDebug || $gccAttributeDebug); } elsif ($part eq ")") { $parserState->{attributeState}++; print STDERR "GCC attribute close paren, count=".(0-$parserState->{attributeState})."\n" if ($localDebug || $gccAttributeDebug); } $treeCur = $treeCur->addSibling($part, 0); if (($localDebug || $gccAttributeDebug) && !$parserState->{attributeState}) { print STDERR "GCC attribute: done collecting.\n"; # Get back to where we started. $treeCur = pop(@treeStack); } $part = $nextpart; next; } # Here be the parser. Abandon all hope, ye who enter here. $treepart = ""; 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 print STDERR "parserState pushed onto stack[PROTOCOL]\n" if ($parserStackDebug); $parserState->{inProtocol} = -1; $parserState->{lastTreeNode} = $treeCur; $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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); # $parserState->{lastTreeNode} = $treeCur; # push(@parserStack, $parserState); # $parserState = HeaderDoc::ParserState->new(); # $parserState->{lang} = $lang; # $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); $parserState->{lastTreeNode} = $treeCur; print STDERR "parserState pushed onto stack[cparen2]\n" if ($parserStackDebug); $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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"; if ($part eq ":") { print STDERR "INCLASS COLON\n" if ($parseDebug || $classDebug); $parserState->{forceClassName} = $parserState->{sodname}; $parserState->{forceClassSuper} = ""; # print STDERR "XSUPER: $parserState->{forceClassSuper}\n"; } elsif ($part eq "{" || $part eq ";") { print STDERR "INCLASS BRCSEMI\n" if ($parseDebug || $classDebug); $parserState->{forceClassDone} = 1; if ($parserState->{classIsObjC} && $part eq "{") { $parserState->{ISFORWARDDECLARATION} = 0; $parserState->{lastTreeNode} = $treeCur; print STDERR "parserState pushed onto stack[OCC-BRCSEMI]\n" if ($parserStackDebug); $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 0; $parserState->{lang} = $lang; $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}) { 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->{classIsObjC}) { print STDERR "INCLASS NOTOBJC (OTHER)\n" if ($parseDebug || $classDebug); 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}; } # } 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 $ilc || $part eq $ilc_b) && ($lang ne "perl" || $lasttoken ne "\$")) { # print STDERR "should be ILC?\n"; # } else { # print STDERR "NO CHANEC: PART \"$part\" ILC \"$ilc\" ILC_B: \"ilc_b\" LANG: \"$lang\" LASTTOKEN: \"$lasttoken\"\n"; # } SWITCH: { # Blank declaration handlers (mostly for misuse of # OSMetaClassDeclareReservedUsed and similar) (($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; }; # 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 "$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|pragma|import|include)/ && ($part ne $definename)) || ($parserState->{inMacro} == 0 && $macrore_nopound ne "" && $part =~ /$macrore_nopound/)) # (($parserState->{inMacro} == 1 && $part =~ /(if|ifdef|ifndef|endif|else|undef|elif|pragma|import|include)/ )) && do (!$parserState->{inComment} && (($parserState->{inMacro} == 1 && $macrore_pound ne "" && $part =~ /^$macrore_pound$/ && ($part ne $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|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 "$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|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 "$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 $soc) && ($part ne $eoc) && $part =~ /\s/) && do { $treepart = $part; $part = ""; last SWITCH; }; ($parserState->{inMacro} == 1 && ($part ne $soc) && ($part ne $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 $soc) && ($part ne $eoc)) && do { print STDERR "INMACRO OTHERTOKEN: CASE 06\n" if ($liteDebug); print STDERR "INMACRO > 1, PART NE //" if ($parseDebug || $localDebug); if ($part eq "\\") { $parserState->addBackslash(); } elsif ($part !~ /[ \t]/) { $parserState->addBackslash(); } print STDERR "PART: $part\n" if ($macroDebug); if ($parserState->{seenMacroPart} && $HeaderDoc::truncate_inline) { 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; } elsif ($part =~ /[\{\(]/o) { print STDERR "MACRO: BRACE\n" if ($macroDebug); if (!$parserState->{macroNoTrunc}) { # $parserState->{seenBraces} = 1; $HeaderDoc::hidetokens = 3; } } else { print STDERR "MACRO: OTHERTOKEN\n" if ($macroDebug); $parserState->{macroNoTrunc} = 2; } } } if ($part =~ /[\{\(]/o) { push(@braceStack, $part); print STDERR "PUSH\n" if ($macroDebug); } elsif ($part =~ /[\}\)]/o) { if ($part ne peekmatch(\@braceStack, $filename, $inputCounter)) { if ($parserState->{macroNoTrunc} == 1) { # We haven't reached the end of the first part of the declaration, so this is an error. warn("$filename:$inputCounter: warning: Initial braces in macro name do not match.\nWe may have a problem.\n"); } } pop(@braceStack); print STDERR "POP\n" if ($macroDebug); } 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 # print STDERR "IRE: $inRegexp IRT: $inRegexpTrailer IS: $parserState->{inString} ICo $parserState->{inComment} ILC: $parserState->{inInlineComment} ICh $parserState->{inChar}\n"; (length($regexppattern) && $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? $inRegexp = 2; } else { $inRegexp = 4; # print STDERR "REGEXP PART IS \"$part\"\n"; if ($part eq "tr") { $regexpNoInterpolate = 1; } # if ($part =~ /tr/) { $regexpNoInterpolate = 1; } } last SWITCH; }; # end regexppattern (($inRegexp || $parserState->{lastsymbol} eq "~") && (length($regexpcharpattern) && $part =~ /^($regexpcharpattern)$/ && (!scalar(@regexpStack) || $part eq peekmatch(\@regexpStack, $filename, $inputCounter)))) && do { print STDERR "REGEXP CHARACTER: CASE 08\n" if ($liteDebug); print STDERR "REGEXP?\n" if ($regexpDebug); if (!$inRegexp) { $inRegexp = 2; } # if ($lasttoken eq "\\") if ($parserState->isQuoted($lang. $sublang)) { # jump to next match. $lasttoken = $part; $parserState->{lastsymbol} = $part; next SWITCH; } print STDERR "REGEXP POINT A\n" if ($regexpDebug); $lasttoken = $part; $parserState->{lastsymbol} = $part; if ($part eq "#" && ((scalar(@regexpStack) != 1) || (peekmatch(\@regexpStack, $filename, $inputCounter) ne "#"))) { if ($nextpart =~ /^\s/o) { # it's a comment. jump to next match. next SWITCH; } } print STDERR "REGEXP POINT B\n" if ($regexpDebug); if (!scalar(@regexpStack)) { push(@regexpStack, $part); $inRegexp--; } else { my $match = peekmatch(\@regexpStack, $filename, $inputCounter); my $tos = pop(@regexpStack); if (!scalar(@regexpStack) && ($match eq $part)) { $inRegexp--; if ($inRegexp == 2 && $tos eq "/") { # we don't double the slash in the # middle of a s/foo/bar/g style # expression. $inRegexp--; } if ($inRegexp) { push(@regexpStack, $tos); } } elsif (scalar(@regexpStack) == 1) { push(@regexpStack, $tos); if ($tos =~ /['"`]/o || $regexpNoInterpolate) { # these don't interpolate. next SWITCH; } } else { push(@regexpStack, $tos); if ($tos =~ /['"`]/o || $regexpNoInterpolate) { # these don't interpolate. next SWITCH; } push(@regexpStack, $part); } } print STDERR "REGEXP POINT C\n" if ($regexpDebug); if (!$inRegexp) { $inRegexpTrailer = 2; } last SWITCH; }; # end regexpcharpattern # Start of preprocessor macros ($part eq "$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); } 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 "$sofunction" || $part eq "$soprocedure") && do { print STDERR "SOFUNC: CASE 10\n" if ($liteDebug); $parserState->{sodclass} = "function"; print STDERR "K&R C FUNCTION FOUND [1].\n" if ($localDebug); $parserState->{kr_c_function} = 1; $parserState->{typestring} = "function"; $parserState->{startOfDec} = 2; $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); last SWITCH; }; # C++ destructor handler. ($part =~ /\~/o && $lang eq "C" && $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 && $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; $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) && do { print STDERR "NEWLINE: CASE 13\n" if ($liteDebug); # NEWLINE FOUND $treepart = $part; if ($inRegexp) { warn "$filename:$inputCounter: warning: multi-line regular expression\n"; } print STDERR "NLCR\n" if ($tsDebug || $treeDebug || $localDebug); 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; } else { $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); print STDERR "skipped pushing CPP directive $parsedParam into parsedParamList [1]\n" if ($parmDebug || $cppDebug || $localDebug); $parsedParam = ""; } } } if ($treePopOnNewLine < 0) { # pop once for //, possibly again for macro $treePopOnNewLine = 0 - $treePopOnNewLine; $treeCur = $treeCur->addSibling($treepart, 0); bless($treeCur, "HeaderDoc::ParseTree"); # push(@treeStack, $treeCur); $treeSkip = 1; $treeCur = pop(@treeStack); if (!$treeCur) { $treeCur = $treeTop; warn "$filename:$inputCounter: warning: Attempted to pop off top of tree\n"; } $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [1]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if ($treePopOnNewLine == 1 || ($treePopOnNewLine && !$parserState->isQuoted())) { # $parserState->{lastsymbol} ne "\\" $treeCur = $treeCur->addSibling($treepart, 0); bless($treeCur, "HeaderDoc::ParseTree"); # push(@treeStack, $treeCur); $treeSkip = 1; $treeCur = pop(@treeStack); if (!$treeCur) { $treeCur = $treeTop; warn "$filename:$inputCounter: warning: Attempted to pop off top of tree\n"; } $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->addSibling("", 0); # empty token print STDERR "TSPOP [1a]\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 $sotemplate && !$parserState->{seenBraces} && ($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(@braceStack, $part); pbs(@braceStack); if (!$parserState->{seenBraces}) { # TREEDONE $treeNest = 1; 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 $eotemplate && !$parserState->{seenBraces} && ($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); if (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [2]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if ($top ne "$sotemplate") { warn("$filename:$inputCounter: warning: Template (angle) brackets do not match.\nWe may have a problem.\n"); } } last SWITCH; }; # # Handles C++ access control state, e.g. "public:" # ($part eq ":") && 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 (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) { 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); $parserState->{hollow} = undef; $parserState->{onlyComments} = 1; print STDERR "hollowskip -> 1 (ACS)\n" if ($parserStateInsertDebug); $hollowskip = 1; $HeaderDoc::AccessControlState = $1; $lastACS = $1; last SWITCH; } elsif ($parserState->{typestring} eq "struct") { if (!(scalar(@braceStack) - $parserState->{initbsCount})) { if (!$parserState->{structClassName}) { $parserState->{structClassName} = $parserState->{lastsymbol}; $parserState->{bracePending} = 2; } } } } }; (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 MATCH: \"$part\"\n" if ($localDebug || $parseDebug); $hollowskip = 1; print STDERR "hollowskip -> 1 (requiredregexp)\n" if ($parserStateInsertDebug); last SWITCH; }; # # C++ copy constructor handler. For example: # # char *class(void *a, void *b) : # class(pri_type, pri_type); # ($part eq ":") && 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" && $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\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 (!$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 { next SWITCH; } }; # Non-newline, non-carriage-return whitespace handler. ($part =~ /\s/o) && do { print STDERR "Whitespace: CASE 19\n" if ($liteDebug); # 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 "\"") && 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})) { $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 (!$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 (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [3]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } } $parserState->{inString} = (1-$parserState->{inString}); } } $lastchar = $part; $parserState->{lastsymbol} = ""; last SWITCH; }; ($part eq "[") && do { print STDERR "LEFT BRACKET: CASE 22\n" if ($liteDebug); # left square bracket (square brace) if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate)) { 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(@braceStack, $part); pbs(@braceStack); if (!$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; } $lastchar = $part; last SWITCH; }; ($part eq "]") && do { print STDERR "CLOSE BRACKET: CASE 23\n" if ($liteDebug); # right square bracket (square brace) if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate)) { print STDERR "rbracket\n" if ($localDebug); if (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inString})) { $parserState->{onlyComments} = 0; print STDERR "[g]onlyComments -> 0\n" if ($macroDebug); } my $top = pop(@braceStack); if (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [4]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if ($top ne "[") { warn("$filename:$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; } $lastchar = $part; last SWITCH; }; ($part eq "'") && do { print STDERR "SINGLE QUOTE: CASE 24\n" if ($liteDebug); print STDERR "squo\n" if ($localDebug); if (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inString})) { # 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 (!$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 (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [5]\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 $ilc || $part eq $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} = 4; print STDERR "inInlineComment -> 1\n" if ($ilcDebug); $curline = spacefix($curline, $part, $lastchar, $soc, $eoc, $ilc, $ilc_b); if (!$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("$filename:$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 $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 (!$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("$filename:$linenum: warning: Nested comment found [2]. Ignoring.\n"); } } $parserState->{lastsymbol} = ""; $lastchar = $part; last SWITCH; }; ($part eq $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; $curline = spacefix($curline, $part, $lastchar); $ppSkipOneToken = 1; if (!$parserState->{seenBraces}) { $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [6]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } } elsif (!$parserState->{inComment} && !$parserState->{inInlineComment} && !$parserState->{inString} && !$parserState->{inChar} && !$inRegexp) { my $linenum = $inputCounter + $fileoffset; warn("$filename:$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::test_mode)) { warn("$filename:$linenum: warning: Nested comment found [3]. Ignoring.\n"); } } $parserState->{lastsymbol} = ""; $lastchar = $part; last SWITCH; }; # Parenthesis and brace handlers. ($part eq "(") && do { print STDERR "OPEN PAREN: CASE 28\n" if ($liteDebug); my @tempppl = undef; if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate)) { if (!(scalar(@braceStack)-$parserState->{initbsCount})) { # start parameter parsing after this token print STDERR "parsedParamParse -> 2\n" if ($parmDebug); $parsedParamParse = 2; 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"; # 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->{returntype} = "$declaration$curline"; } elsif (!$parserState->{freezereturn} && !$parserState->{hollow}) { $parserState->{returntype} = "$curline"; $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); 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"; # $parserState->{callbackName} = ""; $parserState->{functionReturnsCallback}++; print "Function returning callback. NAME: $parserState->{cbsodname}\n" if ($parmDebug || $localDebug || $parseDebug); print STDERR "parsedParamParse -> 2\n" if ($parmDebug); $parsedParamParse = 2; print STDERR "parsedParamList wiped\n" if ($parmDebug); @tempppl = @{$parserState->{parsedParamList}}; @{$parserState->{parsedParamList}} = (); $parsedParam = ""; } } if ($parserState->{inOperator} == 1) { $parserState->{inOperator} = 2; } push(@braceStack, $part); pbs(@braceStack); if (!$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) { $parserState->{sodclass} = "function"; $parserState->{freezereturn} = 1; $parserState->{returntype} =~ s/^\s*//so; $parserState->{returntype} =~ s/\s*$//so; } $parserState->{startOfDec} = 0; 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 "OUTGOING CURLINE: \"$curline\"\n" if ($localDebug); last SWITCH; }; ($part eq ")") && do { print STDERR "CLOSE PAREN: CASE 29\n" if ($liteDebug); if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate && (peek(\@regexpStack) ne "("))) { if ((scalar(@braceStack)-$parserState->{initbsCount} - $parserState->{functionReturnsCallback}) == 1) { # stop parameter parsing $parsedParamParse = 0; print STDERR "parsedParamParse -> 0\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 = pop(@braceStack); pbs(@braceStack); if (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [6a]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if (!($test eq "(")) { # ) brace hack for vi warn("$filename:$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; 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; }; (casecmp($part, $lbrace, $case_sensitive)) && do { print STDERR "LEFT BRACE: CASE 30\n" if ($liteDebug); if ($parserState->{onlyComments} && !$parserState->{inComment} && !$parserState->{inInlineComment} && !$parserState->{inChar} && !($inRegexp && $regexpNoInterpolate) && scalar(@parserStack)) { # 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 && $regexpNoInterpolate)) { $parserState->{bracePending} = 0; print STDERR "bracePending -> 0 [brace]\n" if ($localDebug); $parserState->{onlyComments} = 0; print STDERR "[k]onlyComments -> 0\n" if ($macroDebug); 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\n" if ($parmDebug); } # start parameter parsing after this token print STDERR "parsedParamParse -> 2\n" if ($parmDebug); $parsedParamParse = 2; # 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 "seenBraces -> 1\n" if ($parseDebug); $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(@braceStack, $part); pbs(@braceStack); if (!$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; 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; }; (casecmp($part, $rbrace, $case_sensitive)) && do { print STDERR "RIGHT BRACE: CASE 31\n" if ($liteDebug); if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate && (peek(\@regexpStack) ne "$lbrace"))) { 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); my $bsCount = scalar(@braceStack); if (scalar(@parserStack) && !($bsCount - $parserState->{initbsCount})) { print STDERR "parserState: ENDOFSTATE\n" if ($parserStackDebug); if ($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}; $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; $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 [1a]\n" if ($localDebug || $liteDebug); $parserState->{noInsert} = 0; $continue = 0; print STDERR "AT END: REALPS IS ".$parserState->{REALPS}."\n" if ($parserStackDebug || $localDebug); print STDERR "STACK COUNT: ".scalar(@parserStack)."\n" if ($parserStackDebug || $localDebug); } if ($lang eq "php" || ($lang eq "C" && $sublang eq "IDL")) { # print STDERR "PHP OUT OF BRACES?: ".scalar(@braceStack)."\n"; if (scalar(@braceStack) == 1) { # PHP and IDL classes end at # the brace. print STDERR "continue -> 0 [1a]\n" if ($localDebug || $liteDebug); $continue = 0; } } 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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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); } if ((scalar(@braceStack)-$parserState->{initbsCount}) == 1) { # stop parameter parsing $parsedParamParse = 0; print STDERR "parsedParamParse -> 0\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 = ""; } else { # start parameter parsing after this token print STDERR "parsedParamParse -> 2\n" if ($parmDebug); $parsedParamParse = 2; } 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\n" if ($parmDebug); } print STDERR "rbrace\n" if ($localDebug); my $test = pop(@braceStack); pbs(@braceStack); if (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [7]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if (!($test eq "$lbrace") && (!length($structname) || (!($test eq $structname) && $structisbrace))) { warn("$filename:$inputCounter: warning: Braces do not match.\nWe may have a problem.\n"); warn("Declaration to date: $declaration$curline\n"); } $curline = spacefix($curline, $part, $lastchar); $parserState->{lastsymbol} = ""; $lastchar = $part; $parserState->{startOfDec} = 0; 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($propname) && $propname =~ /\@/) || length($objcdynamicname) || length($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 $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 $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 $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 $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, $filename, $inputCounter)) { warn("$filename:inputCounter: warning: Class braces do not match.\nWe may have a problem.\n"); } $parserState->{seenBraces} = 1; pop(@braceStack); $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [6]\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; $HeaderDoc::module = $parserState->{MODULE}; $continue = 0; print STDERR "continue -> 0 [occend]\n" if ($localDebug); } 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}; $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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $parserState->{inputCounter} = $inputCounter; $parserState->{initbsCount} = scalar(@braceStack); } print STDERR "parserState popped from parserStack[\@end]\n" if ($parserStackDebug); $parserState = pop(@parserStack) || $parserState; $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. ### ($sotemplate, $eotemplate, $operator, $soc, $eoc, $ilc, $ilc_b, $sofunction, ### $soprocedure, $sopreproc, $lbrace, $rbrace, $unionname, $structname, ### $enumname, ### $typedefname, $varname, $constname, $structisbrace, $macronameref, ### $classregexp, $classbraceregexp, $classclosebraceregexp, $accessregexp, ### $requiredregexp, $propname, $objcdynamicname, $objcsynthesizename, $moduleregexp, $definename) = parseTokens($lang, $sublang); ### print STDERR "PROPNAME NOW $propname\n" if ($localDebug || $parseDebug || $classDebug); my $localclasstype = $1; if ($part =~ /^\@/) { $part =~ s/^\@//s; } if (!(scalar(@braceStack)-$parserState->{initbsCount})) { if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) { print STDERR "ITISACLASS\n" if ($localDebug); if (!length($parserState->{sodclass})) { 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"; $parserState->{classtype} = $localclasstype; $parserState->{preclasssodtype} = $parserState->{sodtype} . $part; $parserState->{sodtype} = ""; $parserState->{startOfDec} = 1; $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(@braceStack, $localclasstype); pbs(@braceStack); $treeNest = 1; if ($treeDebug) { print STDERR "TS TREENEST -> 1 [17]\n"; } # } else { # print STDERR "CBRE: \"$classbraceregexp\"\n"; } ($lang, $sublang) = getLangAndSublangFromClassType($localclasstype); $HeaderDoc::lang = $lang; $HeaderDoc::sublang = $sublang; ($sotemplate, $eotemplate, $operator, $soc, $eoc, $ilc, $ilc_b, $sofunction, $soprocedure, $sopreproc, $lbrace, $rbrace, $unionname, $structname, $enumname, $typedefname, $varname, $constname, $structisbrace, $macronameref, $classregexp, $classbraceregexp, $classclosebraceregexp, $accessregexp, $requiredregexp, $propname, $objcdynamicname, $objcsynthesizename, $moduleregexp, $definename) = parseTokens($lang, $sublang); my $macrore = macroRegexpFromList($macronameref); # print STDERR "PROPNAME2: $propname\n"; print STDERR "ARP: $accessregexp\n" if ($localDebug); last SWITCH; } } } }; ($part eq $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 $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 $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 $structname || $part eq $enumname || $part eq $unionname) && do { print STDERR "STRUCT/ENUM/UNION: CASE 36\n" if ($liteDebug); if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) { if ($structisbrace) { if ($parserState->{sodclass} eq "function") { $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(@braceStack, $part); pbs(@braceStack); if (!$parserState->{seenBraces}) { # 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; 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 (!$parserState->{seenBraces}) { # TREEDONE # $treePopTwo++; # $treeNest = 1; # push(@treeStack, $treeCur); # $treeCur = $treeCur->addChild($part, 0); $treeSkip = 1; # bless($treeCur, "HeaderDoc::ParseTree"); # } } $parserState->{onlyComments} = 0; print STDERR "[n]onlyComments -> 0\n" if ($macroDebug); $continuation = 1; # $parserState->{simpleTypedef} = 0; if ($parserState->{basetype} eq "") { $parserState->{basetype} = $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 "sodname cleared (seu)\n" if ($sodDebug); } $lastchar = $part; }; # end if }; # end do ($part =~ /^$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; $parserState->{simpleTypedef} = 1; print STDERR "simpleTypedef -> 1\n" if ($localDebug); # previous case falls through, so be explicit. if ($part =~ /^$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 "sodname cleared ($typedefname)\n" if ($sodDebug); } $lastchar = $part; }; # end if }; # end do # C++ operator keyword handler ($part eq "$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->{lastsymbol} = $part; $lastchar = $part; last SWITCH; # next; }; # Punctuation handlers ($part =~ /;/o) && do { print STDERR "SEMICOLON: CASE 39\n" if ($liteDebug); if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) { if ($parsedParamParse) { $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 $parsedParamParse = 2; $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; $continuation = 1; if ($parserState->{occmethod}) { $prespaceadjust = -$prespace; } # previous case falls through, so be explicit. if ($part =~ /;/o && !$parserState->{inMacroLine} && !$parserState->{inMacro}) { my $bsCount = scalar(@braceStack)-$parserState->{initbsCount}; if (!$bsCount && !$parserState->{kr_c_function}) { if ($parserState->{startOfDec} == 2) { $parserState->{sodclass} = "constant"; $parserState->{startOfDec} = 1; } elsif (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar} || $parserState->{inString})) { $parserState->{startOfDec} = 1; } # $parserState->{lastsymbol} .= $part; } if (!$bsCount) { $treeCur = $treeCur->addSibling(";"); $treepart = " "; # $treeSkip = 1; if (0) { $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [8]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } # $parserState->{lastTreeNode} = $treeCur; # print STDERR "LASTTREENODE -> $treeCur (".$treeCur->token().")\n"; while ($parserState->{treePopTwo}--) { $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [9]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } $parserState->{treePopTwo} = 0; } } $lastchar = $part; }; # end if }; # end do ($part eq "=" && ($parserState->{lastsymbol} ne "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 "[q]onlyComments -> 0\n" if ($macroDebug); if ($part =~ /=/o && !(scalar(@braceStack)-$parserState->{initbsCount}) && $nextpart !~ /=/o && $lastchar !~ /=/o && $parserState->{sodclass} ne "function" && !$inPType) { print STDERR "valuepending -> 1\n" if ($valueDebug); $parserState->{valuepending} = 1; $parserState->{preEqualsSymbol} = $parserState->{lastsymbol}; $parserState->{sodclass} = "constant"; $parserState->{startOfDec} = 0; }; # 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); } if ($part =~ /,/o && $parsedParamParse && !($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && ((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 $parsedParamParse = 2; print STDERR "parsedParamParse -> 2\n" if ($parmDebug); }; # end if }; # end do ($part =~ /[*^]/) && do { if ($lastnspart eq "(" && # ")" !($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !$parserState->{callbackNamePending} && ((scalar(@braceStack)-$parserState->{initbsCount}) == 1)) { # print "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})) { if (!ignore($part, $ignoreref, $perheaderignoreref)) { 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 (!$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}; $parsedParamParse = 1; print STDERR "parsedParamParse -> 1\n" if ($parmDebug); } } } } $lastchar = $part; if ($part =~ /\w/o || $part eq "::") { if ($parserState->{callbackNamePending} == 1) { if (!($part eq $structname || $part eq $enumname || $part eq $unionname || $part eq $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} = ""; $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"; $parserState->{sodclass} = "constant"; $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 !~ /[,;\[\]]/o && !$parserState->{inBrackets}) { my $opttilde = ""; if ($parserState->{seenTilde}) { $opttilde = "~"; } 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}) { print STDERR "Setting sodname (maybe type) to \"$part\"\n" if ($sodDebug); $parserState->{sodname} = $opttilde.$part; if ($part =~ /\w/o) { $parserState->{startOfDec}++; } } 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}) { if ($parserState->{inOperator} == 1) { $parserState->{sodname} .= $part; } else { if (length($parserState->{sodname})) { $parserState->{sodtype} .= " $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; } } elsif ($part eq "[") { # if ($part !~ /[;\[\]]/o) $parserState->{inBrackets} += 1; print STDERR "inBrackets -> $parserState->{inBrackets}\n" if ($sodDebug); } elsif ($part eq "]") { $parserState->{inBrackets} -= 1; print STDERR "inBrackets -> $parserState->{inBrackets}\n" if ($sodDebug); } # end if ($part !~ /[;\[\]]/o) if (!($part eq $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 $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 ($parserState->{seenBraces}) { # print "SEENBRACES. TP: $treepart PT: $part\n"; if ($treepart) { $parserState->{functionContents} .= $treepart; } else { $parserState->{functionContents} .= $part; } # print "SEENBRACES. FC: ".$parserState->{functionContents}."\n"; } 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 $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); 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 (!$parserState->{seenBraces}) { # 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); } $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); } } 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; setHollowWithLineNumbers(\$parserState, $treeCur, $fileoffset, $inputCounter); $sethollow = 0; } print STDERR "TSPUSH\n" if ($tsDebug || $treeDebug); push(@treeStack, $treeCur); $treeCur = $treeCur->addChild("", 0); bless($treeCur, "HeaderDoc::ParseTree"); } } } 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}) { # print STDERR "WARNING: RETURN TYPE CHANGE[A]".$parserState->{returntype}." CHANGED TO $declaration$curline.\n"; $parserState->{returntype} = "$declaration$curline"; } elsif (!$parserState->{freezereturn} && !$parserState->{hollow}) { # print STDERR "WARNING: RETURN TYPE CHANGE[B]".$parserState->{returntype}." CHANGED TO $curline.\n"; $parserState->{returntype} = "$curline"; $declaration = ""; # } else { # print STDERR "WARNING: LEAVING RETURN TYPE ALONE: ".$parserState->{returntype}." NOT CHANGED TO $curline.\n"; } # 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. if (($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) || !$ignoretoken) { if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !$ppSkipOneToken) { if ($parsedParamParse == 1) { $parsedParam .= $part; } elsif ($parsedParamParse == 2) { $parsedParamParse = 1; print STDERR "parsedParamParse -> 1\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 (!$parserState->{seenBraces}) { # 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); print STDERR "KRC: $parserState->{kr_c_function} SB: $parserState->{seenBraces}\n" if ($localDebug); if (!($bsCount - $parserState->{initbsCount}) && $parserState->{lastsymbol} =~ /;\s*$/o) { # print STDERR "DPA\n"; if ((!$parserState->{kr_c_function} || $parserState->{seenBraces}) && !$parserState->{inMacro}) { # print STDERR "DPB\n"; if (!scalar(@parserStack)) { $continue = 0; print STDERR "continue -> 0 [3]\n" if ($localDebug); } elsif (!$parserState->{onlyComments}) { # Process entry here if ($parserState->{noInsert}) { print STDERR "parserState insertion skipped[SEMI-1]\n" if ($parserStackDebug); } elsif ($parserState->{hollow}) { my $treeRef = $parserState->{hollow}; $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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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 "bsCount: $bsCount - $parserState->{initbsCount}, ls: $parserState->{lastsymbol}\n" if ($localDebug); pbs(@braceStack); } if (!($bsCount - $parserState->{initbsCount}) && $parserState->{seenBraces} && ($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}) { # Fix nesting. # print STDERR "LASTTREENODE -> $treeCur (".$treeCur->token().")\n"; while ($parserState->{treePopTwo}--) { $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [13]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } $treeCur = $treeCur->addSibling(";", 0); $parserState->{lastTreeNode} = $treeCur; $parserState->{treePopTwo} = 0; } if (!scalar(@parserStack)) { $continue = 0; print STDERR "continue -> 0 [4]\n" if ($localDebug); } elsif (!$parserState->{onlyComments}) { # Process entry here if ($parserState->{noInsert}) { print STDERR "parserState insertion skipped[SEMI-2]\n" if ($parserStackDebug); } elsif ($parserState->{hollow}) { my $treeRef = $parserState->{hollow}; $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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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 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 ($localDebug || $liteDebug); } 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}); } else { cpp_add($parserState->{hollow}, 1); $HeaderDoc::skipNextPDefine = 0; } } if ($parserState->{noInsert}) { print STDERR "parserState insertion skipped\n" if ($parserStackDebug); } elsif ($parserState->{hollow}) { my $treeRef = $parserState->{hollow}; $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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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 "$filename:$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) { print STDERR "parserState pushed onto stack[token]\n" if ($parserStackDebug); $parserState->{lastTreeNode} = $treeCur; $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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); $parserState->{lastTreeNode} = $treeCur; $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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, $lbrace, $case_sensitive)) { $parserState->{ISFORWARDDECLARATION} = 0; 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; # } $parserState->{lastTreeNode} = $treeCur; $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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 (!casecmp($tok, $rbrace, $case_sensitive) && $part !~ /\)/) { # $parserState->{hollow} = $treeCur; setHollowWithLineNumbers(\$parserState, $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 (!casecmp($tok, $rbrace, $case_sensitive) && $part !~ /\)/) { setHollowWithLineNumbers(\$parserState, $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; } # end foreach (parts of the current line) } # end while (continue && ...) 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); $parserState->{lastTreeNode} = $treeCur; $parserState->{inputCounter} = $inputCounter; print STDERR "PARSERSTATE: $parserState\n" if ($localDebug); if ($parserState->{inMacro} == 3) { if (!$HeaderDoc::skipNextPDefine) { cpp_add($treeTop); } else { cpp_add($treeTop, 1); $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); while ($tempParserState) { $parserState = $tempParserState; $tempParserState = pop(@parserStack); } $HeaderDoc::module = $parserState->{MODULE}; if ($localDebug || $apDebug || $liteDebug || $parseDebug) { 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 "FC: ".$parserState->{functionContents}."\n"; return blockParseReturnState($parserState, $treeTop, $argparse, $declaration, $inPrivateParamTypes, $publicDeclaration, $lastACS, $retDebug, $fileoffset, 0, $definename, $inputCounter); } $1202|# /*! The blockParse function is the core of HeaderDoc's parse engine. # @param filename the filename being parser. # @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 disable warnings when parsing arguments to avoid seeing them twice. # @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: controls whether keywords should be processed in a case-sensitive fashion. # @result Returns ($inputCounter, $declaration, $typelist, $namelist, $posstypes, $value, \@pplStack, $returntype, $privateDeclaration, $treeTop, $simpleTDcontents, $availability). # */ $0|$496862|-=: TOP LEVEL COMMENT PARSE VALUES :=- inHeader: 0 inClass: 0 inInterface: 0 inCPPHeader: 0 inOCCHeader: 0 inPerlScript: 0 inShellScript: 0 inPHPScript: 0 inJavaSource: 0 inFunctionGroup: 0 inGroup: 0 inFunction: 0 inPDefine: 0 inTypedef: 0 inUnion: 0 inStruct: 0 inConstant: 0 inVar: 0 inEnum: 0 inMethod: 0 inAvailabilityMacro: 0 inUnknown: 1 classType: unknown inputCounter: 0 blockOffset: 0 fullpath: /test_suite_bogus_path/Perl_function_2.test -=: BLOCKPARSE PARSER STATE KEYS :=- $parserState->{FULLPATH} => /test_suite_bogus_path/Perl_function_2.test $parserState->{NEXTTOKENNOCPP} => 0 $parserState->{availability} => $parserState->{backslashcount} => 0 $parserState->{basetype} => $parserState->{bracePending} => 0 $parserState->{callbackIsTypedef} => 0 $parserState->{callbackName} => $parserState->{callbackNamePending} => -1 $parserState->{categoryClass} => $parserState->{classtype} => $parserState->{curvarstars} => ********************************************************************************* $parserState->{freezeStack} => ARRAY(OBJID) $parserState->{freezereturn} => 1 $parserState->{frozensodname} => blockParse $parserState->{functionContents} => { my $filename = 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 $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 $cbnDebug = 0; my $macroDebug = 0; my $apDebug = 0; my $tsDebug = 0; my $treeDebug = 0; my $ilcDebug = 0; my $regexpDebug = 0; my $parserStackDebug = 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 $liteDebug = 0 || $HeaderDoc::fileDebug; # Just prints the tokens. my $parserStateInsertDebug = 0; $cppDebug = $cppDebugDefault || $HeaderDoc::fileDebug; # State variables (part 1 of 3) # my $typestring = ""; my $continue = 1; # set low when we're done. my $parsedParamParse = 0; # set high when current token is part of param. # 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 $perl_or_shell = 0; 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; 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" || $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(); # $parserState->{hollow} = $treeTop; setHollowWithLineNumbers(\$parserState, $treeTop, $fileoffset, $inputCounter); $parserState->{lang} = $lang; $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 $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 perl regexp. 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 ($sotemplate, $eotemplate, $operator, $soc, $eoc, $ilc, $ilc_b, $sofunction, $soprocedure, $sopreproc, $lbrace, $rbrace, $unionname, $structname, $enumname, $typedefname, $varname, $constname, $structisbrace, $macronameref, $classregexp, $classbraceregexp, $classclosebraceregexp, $accessregexp, $requiredregexp, $propname, $objcdynamicname, $objcsynthesizename, $moduleregexp, $definename) = parseTokens($lang, $sublang); my $macrore_pound = macroRegexpFromList($macronameref, 1); my $macrore_nopound = macroRegexpFromList($macronameref, 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 $propname\n"; if ($parseDebug) { print STDERR "SOT: $sotemplate EOF: $eotemplate OP: $operator SOC: $soc EOC: $eoc ILC: $ilc ILC_B: $ilc_b\n"; print STDERR "SOFUNC: $sofunction SOPROC: $soprocedure SOPREPROC: $sopreproc LBRACE: $lbrace RBRACE: $rbrace\n"; print STDERR "UNION: $unionname STRUCT: $structname TYPEDEF: $typedefname VAR: $varname CONST: $constname\n"; print STDERR "STRUCTISBRACE: $structisbrace MACRONAMEREF: $macronameref 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") { $perl_or_shell = 1; if ($lang eq "perl") { $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; if ($lang eq "pascal") { $pascal = 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 $categoryClass = ""; # my $classtype = ""; # my $inClass = 0; my $pushParserStateAfterToken = 0; my $pushParserStateAfterWordToken = 0; my $pushParserStateAtBrace = 0; my $occPushParserStateOnWordTokenAfterNext = 0; $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 "INCOMING INPUTCOUNTER: $inputCounter\n" if ($HeaderDoc::inputCounterDebug); while ($continue && ($inputCounter <= $nlines)) { $HeaderDoc::CurLine = $inputCounter + $fileoffset; my $line = $inputLines[$inputCounter++]; print STDERR "GOT LINE: $line\n" if (($localDebug && $apDebug) || $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 "CHANGED LINE FROM \"$line\" to \"$1\"\n" if ($localDebug || $liteDebug); $line = $1."\n"; } } print STDERR "LINE[$inputCounter] : $line\n" if ($offsetDebug); # The tokenizer if ($lang eq "perl" || $lang eq "shell") { @parts = split(/("|'|\#|\{|\}|\(|\)|\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) {foreach my $partlist (@parts) {print STDERR "PARTLIST: \"$partlist\"\n"; }} # 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; # print STDERR "CHECK LINE $line\n"; if ($line =~ /^\s*#include (.*)$/) { my $rest = $1; $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 "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; while ($pos < scalar(@parts)) { my $part = $parts[$pos]; my $noCPPThisToken = 0; if (length($part)) { if (!$inChar && !$inString && !$inComment && !$inSLC) { if ($parserState->{NEXTTOKENNOCPP} == 1) { # We're in an "if" block. if ($part eq "defined") { $parserState->{NEXTTOKENNOCPP} = 3; } } elsif ($parserState->{NEXTTOKENNOCPP} == 2) { # 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) { # 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)/) { $parserState->{NEXTTOKENNOCPP} = 2; } elsif ($inCPPSpecial && $part =~ /if/) { $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 $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 $soc) { print STDERR "SOC\n"if ($cppleaddebug); $inComment = 1; } elsif (!$inComment && ($part eq $ilc || $part eq $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) { ($newpart, $hasargs) = 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) { $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 \"$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; } } 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) { print STDERR "CPPS: \"$cppstring\"\n"; warn "Non-terminated macro.\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 "CHANGED LINE FROM \"$line\" to \"$1\"\n" if ($localDebug || $liteDebug); $line = $1."\n"; } } print STDERR "INCREMENTED INPUTCOUNTER [2]\n" if ($HeaderDoc::inputCounterDebug); # @parts = split(/(\W)/, $line); if ($lang eq "perl" || $lang eq "shell") { @parts = split(/("|'|\#|\{|\}|\(|\)|\s|;|\\|\W)/, $line); } else { @parts = split(/("|'|\/\/|\/\*|\*\/|::|==|<=|>=|!=|\<\<|\>\>|\{|\}|\(|\)|\s|;|\\|\W)/, $line); } } } until (!$incppargs && !$inComment); # The tokenizer if ($lang eq "perl" || $lang eq "shell") { @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); # 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; $treeSkip = 0; # $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); $forcenobreak = 0; if ($nextpart eq "\r") { $nextpart = "\n"; } if ($localDebug && $nextpart eq "\n") { print STDERR "NEXTPART IS NEWLINE!\n"; } if ($localDebug && $part eq "\n") { 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); print STDERR "CURLINE IS \"$curline\"\n" if ($localDebug || $hangDebug); 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); } } elsif ($occPushParserStateOnWordTokenAfterNext) { # if ($part !~ /(\s|<)/) if ($part =~ /(\/\/|\/\*|\-|\+|\w|\@)/) { $parserState->{lastTreeNode} = $treeCur; print STDERR "parserState pushed onto stack[occPushParserStateOnWordTokenAfterNext]\n" if ($parserStackDebug); $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 0; $parserState->{lang} = $lang; $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++; } 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} inRegexp: $inRegexp\n"; print STDERR "PART: regexpNoInterpolate: $regexpNoInterpolate\n"; 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 ($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); printf("PART: $part TEMPAVAIL: $tempavail\n") if ($localDebug || $gccAttributeDebug); if ($tempavail && ($tempavail ne "1") && ($tempavail ne "2")) { $parserState->{availability} = $tempavail; } elsif ($tempavail eq "2") { # Reusing the GCC attribute handling code because that does exactly what we need. print STDERR "Function-like availability macro detected. Collecting.\n" if ($localDebug || $gccAttributeDebug); $parserState->{attributeState} = 1; $parserState->{attributeParts} = (); # Add __attribute__ as the next token. $treeCur = $treeCur->addSibling($part, 0); 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; } # Handle the GCC "__attribute__" extension outside the context of # the parser because it isn't part of the language and massively # breaks the syntax. if ($lang eq "C" && isKeyword($part, $keywordhashref, $case_sensitive) == 2) { print STDERR "GCC attribute detected. Collecting.\n" if ($localDebug || $gccAttributeDebug); $parserState->{attributeState} = 1; $parserState->{attributeParts} = (); # Add __attribute__ as the next token. $treeCur = $treeCur->addSibling($part, 0); push(@treeStack, $treeCur); # Nest all contents one level lower. $treeCur = $treeCur->addChild("", 0); $part = $nextpart; next; } elsif ($parserState->{attributeState} == 1) { if ($part eq "(") { print STDERR "GCC attribute open paren\n" if ($localDebug || $gccAttributeDebug); $parserState->{attributeState} = -1; } $treeCur = $treeCur->addSibling($part, 0); $part = $nextpart; next; } elsif ($parserState->{attributeState} < 0) { if ($part eq "(") { $parserState->{attributeState}--; print STDERR "GCC attribute open paren, count=".(0-$parserState->{attributeState})."\n" if ($localDebug || $gccAttributeDebug); } elsif ($part eq ")") { $parserState->{attributeState}++; print STDERR "GCC attribute close paren, count=".(0-$parserState->{attributeState})."\n" if ($localDebug || $gccAttributeDebug); } $treeCur = $treeCur->addSibling($part, 0); if (($localDebug || $gccAttributeDebug) && !$parserState->{attributeState}) { print STDERR "GCC attribute: done collecting.\n"; # Get back to where we started. $treeCur = pop(@treeStack); } $part = $nextpart; next; } # Here be the parser. Abandon all hope, ye who enter here. $treepart = ""; 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 print STDERR "parserState pushed onto stack[PROTOCOL]\n" if ($parserStackDebug); $parserState->{inProtocol} = -1; $parserState->{lastTreeNode} = $treeCur; $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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); # $parserState->{lastTreeNode} = $treeCur; # push(@parserStack, $parserState); # $parserState = HeaderDoc::ParserState->new(); # $parserState->{lang} = $lang; # $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); $parserState->{lastTreeNode} = $treeCur; print STDERR "parserState pushed onto stack[cparen2]\n" if ($parserStackDebug); $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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"; if ($part eq ":") { print STDERR "INCLASS COLON\n" if ($parseDebug || $classDebug); $parserState->{forceClassName} = $parserState->{sodname}; $parserState->{forceClassSuper} = ""; # print STDERR "XSUPER: $parserState->{forceClassSuper}\n"; } elsif ($part eq "{" || $part eq ";") { print STDERR "INCLASS BRCSEMI\n" if ($parseDebug || $classDebug); $parserState->{forceClassDone} = 1; if ($parserState->{classIsObjC} && $part eq "{") { $parserState->{ISFORWARDDECLARATION} = 0; $parserState->{lastTreeNode} = $treeCur; print STDERR "parserState pushed onto stack[OCC-BRCSEMI]\n" if ($parserStackDebug); $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 0; $parserState->{lang} = $lang; $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}) { 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->{classIsObjC}) { print STDERR "INCLASS NOTOBJC (OTHER)\n" if ($parseDebug || $classDebug); 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}; } # } 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 $ilc || $part eq $ilc_b) && ($lang ne "perl" || $lasttoken ne "\$")) { # print STDERR "should be ILC?\n"; # } else { # print STDERR "NO CHANEC: PART \"$part\" ILC \"$ilc\" ILC_B: \"ilc_b\" LANG: \"$lang\" LASTTOKEN: \"$lasttoken\"\n"; # } SWITCH: { # Blank declaration handlers (mostly for misuse of # OSMetaClassDeclareReservedUsed and similar) (($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; }; # 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 "$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|pragma|import|include)/ && ($part ne $definename)) || ($parserState->{inMacro} == 0 && $macrore_nopound ne "" && $part =~ /$macrore_nopound/)) # (($parserState->{inMacro} == 1 && $part =~ /(if|ifdef|ifndef|endif|else|undef|elif|pragma|import|include)/ )) && do (!$parserState->{inComment} && (($parserState->{inMacro} == 1 && $macrore_pound ne "" && $part =~ /^$macrore_pound$/ && ($part ne $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|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 "$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|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 "$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 $soc) && ($part ne $eoc) && $part =~ /\s/) && do { $treepart = $part; $part = ""; last SWITCH; }; ($parserState->{inMacro} == 1 && ($part ne $soc) && ($part ne $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 $soc) && ($part ne $eoc)) && do { print STDERR "INMACRO OTHERTOKEN: CASE 06\n" if ($liteDebug); print STDERR "INMACRO > 1, PART NE //" if ($parseDebug || $localDebug); if ($part eq "\\") { $parserState->addBackslash(); } elsif ($part !~ /[ \t]/) { $parserState->addBackslash(); } print STDERR "PART: $part\n" if ($macroDebug); if ($parserState->{seenMacroPart} && $HeaderDoc::truncate_inline) { 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; } elsif ($part =~ /[\{\(]/o) { print STDERR "MACRO: BRACE\n" if ($macroDebug); if (!$parserState->{macroNoTrunc}) { # $parserState->{seenBraces} = 1; $HeaderDoc::hidetokens = 3; } } else { print STDERR "MACRO: OTHERTOKEN\n" if ($macroDebug); $parserState->{macroNoTrunc} = 2; } } } if ($part =~ /[\{\(]/o) { push(@braceStack, $part); print STDERR "PUSH\n" if ($macroDebug); } elsif ($part =~ /[\}\)]/o) { if ($part ne peekmatch(\@braceStack, $filename, $inputCounter)) { if ($parserState->{macroNoTrunc} == 1) { # We haven't reached the end of the first part of the declaration, so this is an error. warn("$filename:$inputCounter: warning: Initial braces in macro name do not match.\nWe may have a problem.\n"); } } pop(@braceStack); print STDERR "POP\n" if ($macroDebug); } 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 # print STDERR "IRE: $inRegexp IRT: $inRegexpTrailer IS: $parserState->{inString} ICo $parserState->{inComment} ILC: $parserState->{inInlineComment} ICh $parserState->{inChar}\n"; (length($regexppattern) && $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? $inRegexp = 2; } else { $inRegexp = 4; # print STDERR "REGEXP PART IS \"$part\"\n"; if ($part eq "tr") { $regexpNoInterpolate = 1; } # if ($part =~ /tr/) { $regexpNoInterpolate = 1; } } last SWITCH; }; # end regexppattern (($inRegexp || $parserState->{lastsymbol} eq "~") && (length($regexpcharpattern) && $part =~ /^($regexpcharpattern)$/ && (!scalar(@regexpStack) || $part eq peekmatch(\@regexpStack, $filename, $inputCounter)))) && do { print STDERR "REGEXP CHARACTER: CASE 08\n" if ($liteDebug); print STDERR "REGEXP?\n" if ($regexpDebug); if (!$inRegexp) { $inRegexp = 2; } # if ($lasttoken eq "\\") if ($parserState->isQuoted($lang. $sublang)) { # jump to next match. $lasttoken = $part; $parserState->{lastsymbol} = $part; next SWITCH; } print STDERR "REGEXP POINT A\n" if ($regexpDebug); $lasttoken = $part; $parserState->{lastsymbol} = $part; if ($part eq "#" && ((scalar(@regexpStack) != 1) || (peekmatch(\@regexpStack, $filename, $inputCounter) ne "#"))) { if ($nextpart =~ /^\s/o) { # it's a comment. jump to next match. next SWITCH; } } print STDERR "REGEXP POINT B\n" if ($regexpDebug); if (!scalar(@regexpStack)) { push(@regexpStack, $part); $inRegexp--; } else { my $match = peekmatch(\@regexpStack, $filename, $inputCounter); my $tos = pop(@regexpStack); if (!scalar(@regexpStack) && ($match eq $part)) { $inRegexp--; if ($inRegexp == 2 && $tos eq "/") { # we don't double the slash in the # middle of a s/foo/bar/g style # expression. $inRegexp--; } if ($inRegexp) { push(@regexpStack, $tos); } } elsif (scalar(@regexpStack) == 1) { push(@regexpStack, $tos); if ($tos =~ /['"`]/o || $regexpNoInterpolate) { # these don't interpolate. next SWITCH; } } else { push(@regexpStack, $tos); if ($tos =~ /['"`]/o || $regexpNoInterpolate) { # these don't interpolate. next SWITCH; } push(@regexpStack, $part); } } print STDERR "REGEXP POINT C\n" if ($regexpDebug); if (!$inRegexp) { $inRegexpTrailer = 2; } last SWITCH; }; # end regexpcharpattern # Start of preprocessor macros ($part eq "$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); } 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 "$sofunction" || $part eq "$soprocedure") && do { print STDERR "SOFUNC: CASE 10\n" if ($liteDebug); $parserState->{sodclass} = "function"; print STDERR "K&R C FUNCTION FOUND [1].\n" if ($localDebug); $parserState->{kr_c_function} = 1; $parserState->{typestring} = "function"; $parserState->{startOfDec} = 2; $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); last SWITCH; }; # C++ destructor handler. ($part =~ /\~/o && $lang eq "C" && $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 && $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; $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) && do { print STDERR "NEWLINE: CASE 13\n" if ($liteDebug); # NEWLINE FOUND $treepart = $part; if ($inRegexp) { warn "$filename:$inputCounter: warning: multi-line regular expression\n"; } print STDERR "NLCR\n" if ($tsDebug || $treeDebug || $localDebug); 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; } else { $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); print STDERR "skipped pushing CPP directive $parsedParam into parsedParamList [1]\n" if ($parmDebug || $cppDebug || $localDebug); $parsedParam = ""; } } } if ($treePopOnNewLine < 0) { # pop once for //, possibly again for macro $treePopOnNewLine = 0 - $treePopOnNewLine; $treeCur = $treeCur->addSibling($treepart, 0); bless($treeCur, "HeaderDoc::ParseTree"); # push(@treeStack, $treeCur); $treeSkip = 1; $treeCur = pop(@treeStack); if (!$treeCur) { $treeCur = $treeTop; warn "$filename:$inputCounter: warning: Attempted to pop off top of tree\n"; } $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [1]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if ($treePopOnNewLine == 1 || ($treePopOnNewLine && !$parserState->isQuoted())) { # $parserState->{lastsymbol} ne "\\" $treeCur = $treeCur->addSibling($treepart, 0); bless($treeCur, "HeaderDoc::ParseTree"); # push(@treeStack, $treeCur); $treeSkip = 1; $treeCur = pop(@treeStack); if (!$treeCur) { $treeCur = $treeTop; warn "$filename:$inputCounter: warning: Attempted to pop off top of tree\n"; } $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->addSibling("", 0); # empty token print STDERR "TSPOP [1a]\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 $sotemplate && !$parserState->{seenBraces} && ($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(@braceStack, $part); pbs(@braceStack); if (!$parserState->{seenBraces}) { # TREEDONE $treeNest = 1; 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 $eotemplate && !$parserState->{seenBraces} && ($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); if (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [2]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if ($top ne "$sotemplate") { warn("$filename:$inputCounter: warning: Template (angle) brackets do not match.\nWe may have a problem.\n"); } } last SWITCH; }; # # Handles C++ access control state, e.g. "public:" # ($part eq ":") && 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 (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) { 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); $parserState->{hollow} = undef; $parserState->{onlyComments} = 1; print STDERR "hollowskip -> 1 (ACS)\n" if ($parserStateInsertDebug); $hollowskip = 1; $HeaderDoc::AccessControlState = $1; $lastACS = $1; last SWITCH; } elsif ($parserState->{typestring} eq "struct") { if (!(scalar(@braceStack) - $parserState->{initbsCount})) { if (!$parserState->{structClassName}) { $parserState->{structClassName} = $parserState->{lastsymbol}; $parserState->{bracePending} = 2; } } } } }; (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 MATCH: \"$part\"\n" if ($localDebug || $parseDebug); $hollowskip = 1; print STDERR "hollowskip -> 1 (requiredregexp)\n" if ($parserStateInsertDebug); last SWITCH; }; # # C++ copy constructor handler. For example: # # char *class(void *a, void *b) : # class(pri_type, pri_type); # ($part eq ":") && 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" && $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\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 (!$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 { next SWITCH; } }; # Non-newline, non-carriage-return whitespace handler. ($part =~ /\s/o) && do { print STDERR "Whitespace: CASE 19\n" if ($liteDebug); # 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 "\"") && 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})) { $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 (!$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 (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [3]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } } $parserState->{inString} = (1-$parserState->{inString}); } } $lastchar = $part; $parserState->{lastsymbol} = ""; last SWITCH; }; ($part eq "[") && do { print STDERR "LEFT BRACKET: CASE 22\n" if ($liteDebug); # left square bracket (square brace) if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate)) { 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(@braceStack, $part); pbs(@braceStack); if (!$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; } $lastchar = $part; last SWITCH; }; ($part eq "]") && do { print STDERR "CLOSE BRACKET: CASE 23\n" if ($liteDebug); # right square bracket (square brace) if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate)) { print STDERR "rbracket\n" if ($localDebug); if (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inString})) { $parserState->{onlyComments} = 0; print STDERR "[g]onlyComments -> 0\n" if ($macroDebug); } my $top = pop(@braceStack); if (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [4]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if ($top ne "[") { warn("$filename:$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; } $lastchar = $part; last SWITCH; }; ($part eq "'") && do { print STDERR "SINGLE QUOTE: CASE 24\n" if ($liteDebug); print STDERR "squo\n" if ($localDebug); if (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inString})) { # 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 (!$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 (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [5]\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 $ilc || $part eq $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} = 4; print STDERR "inInlineComment -> 1\n" if ($ilcDebug); $curline = spacefix($curline, $part, $lastchar, $soc, $eoc, $ilc, $ilc_b); if (!$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("$filename:$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 $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 (!$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("$filename:$linenum: warning: Nested comment found [2]. Ignoring.\n"); } } $parserState->{lastsymbol} = ""; $lastchar = $part; last SWITCH; }; ($part eq $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; $curline = spacefix($curline, $part, $lastchar); $ppSkipOneToken = 1; if (!$parserState->{seenBraces}) { $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [6]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } } elsif (!$parserState->{inComment} && !$parserState->{inInlineComment} && !$parserState->{inString} && !$parserState->{inChar} && !$inRegexp) { my $linenum = $inputCounter + $fileoffset; warn("$filename:$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::test_mode)) { warn("$filename:$linenum: warning: Nested comment found [3]. Ignoring.\n"); } } $parserState->{lastsymbol} = ""; $lastchar = $part; last SWITCH; }; # Parenthesis and brace handlers. ($part eq "(") && do { print STDERR "OPEN PAREN: CASE 28\n" if ($liteDebug); my @tempppl = undef; if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate)) { if (!(scalar(@braceStack)-$parserState->{initbsCount})) { # start parameter parsing after this token print STDERR "parsedParamParse -> 2\n" if ($parmDebug); $parsedParamParse = 2; 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"; # 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->{returntype} = "$declaration$curline"; } elsif (!$parserState->{freezereturn} && !$parserState->{hollow}) { $parserState->{returntype} = "$curline"; $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); 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"; # $parserState->{callbackName} = ""; $parserState->{functionReturnsCallback}++; print "Function returning callback. NAME: $parserState->{cbsodname}\n" if ($parmDebug || $localDebug || $parseDebug); print STDERR "parsedParamParse -> 2\n" if ($parmDebug); $parsedParamParse = 2; print STDERR "parsedParamList wiped\n" if ($parmDebug); @tempppl = @{$parserState->{parsedParamList}}; @{$parserState->{parsedParamList}} = (); $parsedParam = ""; } } if ($parserState->{inOperator} == 1) { $parserState->{inOperator} = 2; } push(@braceStack, $part); pbs(@braceStack); if (!$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) { $parserState->{sodclass} = "function"; $parserState->{freezereturn} = 1; $parserState->{returntype} =~ s/^\s*//so; $parserState->{returntype} =~ s/\s*$//so; } $parserState->{startOfDec} = 0; 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 "OUTGOING CURLINE: \"$curline\"\n" if ($localDebug); last SWITCH; }; ($part eq ")") && do { print STDERR "CLOSE PAREN: CASE 29\n" if ($liteDebug); if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate && (peek(\@regexpStack) ne "("))) { if ((scalar(@braceStack)-$parserState->{initbsCount} - $parserState->{functionReturnsCallback}) == 1) { # stop parameter parsing $parsedParamParse = 0; print STDERR "parsedParamParse -> 0\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 = pop(@braceStack); pbs(@braceStack); if (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [6a]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if (!($test eq "(")) { # ) brace hack for vi warn("$filename:$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; 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; }; (casecmp($part, $lbrace, $case_sensitive)) && do { print STDERR "LEFT BRACE: CASE 30\n" if ($liteDebug); if ($parserState->{onlyComments} && !$parserState->{inComment} && !$parserState->{inInlineComment} && !$parserState->{inChar} && !($inRegexp && $regexpNoInterpolate) && scalar(@parserStack)) { # 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 && $regexpNoInterpolate)) { $parserState->{bracePending} = 0; print STDERR "bracePending -> 0 [brace]\n" if ($localDebug); $parserState->{onlyComments} = 0; print STDERR "[k]onlyComments -> 0\n" if ($macroDebug); 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\n" if ($parmDebug); } # start parameter parsing after this token print STDERR "parsedParamParse -> 2\n" if ($parmDebug); $parsedParamParse = 2; # 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 "seenBraces -> 1\n" if ($parseDebug); $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(@braceStack, $part); pbs(@braceStack); if (!$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; 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; }; (casecmp($part, $rbrace, $case_sensitive)) && do { print STDERR "RIGHT BRACE: CASE 31\n" if ($liteDebug); if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate && (peek(\@regexpStack) ne "$lbrace"))) { 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); my $bsCount = scalar(@braceStack); if (scalar(@parserStack) && !($bsCount - $parserState->{initbsCount})) { print STDERR "parserState: ENDOFSTATE\n" if ($parserStackDebug); if ($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}; $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; $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 [1a]\n" if ($localDebug || $liteDebug); $parserState->{noInsert} = 0; $continue = 0; print STDERR "AT END: REALPS IS ".$parserState->{REALPS}."\n" if ($parserStackDebug || $localDebug); print STDERR "STACK COUNT: ".scalar(@parserStack)."\n" if ($parserStackDebug || $localDebug); } if ($lang eq "php" || ($lang eq "C" && $sublang eq "IDL")) { # print STDERR "PHP OUT OF BRACES?: ".scalar(@braceStack)."\n"; if (scalar(@braceStack) == 1) { # PHP and IDL classes end at # the brace. print STDERR "continue -> 0 [1a]\n" if ($localDebug || $liteDebug); $continue = 0; } } 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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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); } if ((scalar(@braceStack)-$parserState->{initbsCount}) == 1) { # stop parameter parsing $parsedParamParse = 0; print STDERR "parsedParamParse -> 0\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 = ""; } else { # start parameter parsing after this token print STDERR "parsedParamParse -> 2\n" if ($parmDebug); $parsedParamParse = 2; } 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\n" if ($parmDebug); } print STDERR "rbrace\n" if ($localDebug); my $test = pop(@braceStack); pbs(@braceStack); if (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [7]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if (!($test eq "$lbrace") && (!length($structname) || (!($test eq $structname) && $structisbrace))) { warn("$filename:$inputCounter: warning: Braces do not match.\nWe may have a problem.\n"); warn("Declaration to date: $declaration$curline\n"); } $curline = spacefix($curline, $part, $lastchar); $parserState->{lastsymbol} = ""; $lastchar = $part; $parserState->{startOfDec} = 0; 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($propname) && $propname =~ /\@/) || length($objcdynamicname) || length($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 $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 $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 $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 $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, $filename, $inputCounter)) { warn("$filename:inputCounter: warning: Class braces do not match.\nWe may have a problem.\n"); } $parserState->{seenBraces} = 1; pop(@braceStack); $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [6]\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; $HeaderDoc::module = $parserState->{MODULE}; $continue = 0; print STDERR "continue -> 0 [occend]\n" if ($localDebug); } 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}; $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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $parserState->{inputCounter} = $inputCounter; $parserState->{initbsCount} = scalar(@braceStack); } print STDERR "parserState popped from parserStack[\@end]\n" if ($parserStackDebug); $parserState = pop(@parserStack) || $parserState; $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. ### ($sotemplate, $eotemplate, $operator, $soc, $eoc, $ilc, $ilc_b, $sofunction, ### $soprocedure, $sopreproc, $lbrace, $rbrace, $unionname, $structname, ### $enumname, ### $typedefname, $varname, $constname, $structisbrace, $macronameref, ### $classregexp, $classbraceregexp, $classclosebraceregexp, $accessregexp, ### $requiredregexp, $propname, $objcdynamicname, $objcsynthesizename, $moduleregexp, $definename) = parseTokens($lang, $sublang); ### print STDERR "PROPNAME NOW $propname\n" if ($localDebug || $parseDebug || $classDebug); my $localclasstype = $1; if ($part =~ /^\@/) { $part =~ s/^\@//s; } if (!(scalar(@braceStack)-$parserState->{initbsCount})) { if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) { print STDERR "ITISACLASS\n" if ($localDebug); if (!length($parserState->{sodclass})) { 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"; $parserState->{classtype} = $localclasstype; $parserState->{preclasssodtype} = $parserState->{sodtype} . $part; $parserState->{sodtype} = ""; $parserState->{startOfDec} = 1; $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(@braceStack, $localclasstype); pbs(@braceStack); $treeNest = 1; if ($treeDebug) { print STDERR "TS TREENEST -> 1 [17]\n"; } # } else { # print STDERR "CBRE: \"$classbraceregexp\"\n"; } ($lang, $sublang) = getLangAndSublangFromClassType($localclasstype); $HeaderDoc::lang = $lang; $HeaderDoc::sublang = $sublang; ($sotemplate, $eotemplate, $operator, $soc, $eoc, $ilc, $ilc_b, $sofunction, $soprocedure, $sopreproc, $lbrace, $rbrace, $unionname, $structname, $enumname, $typedefname, $varname, $constname, $structisbrace, $macronameref, $classregexp, $classbraceregexp, $classclosebraceregexp, $accessregexp, $requiredregexp, $propname, $objcdynamicname, $objcsynthesizename, $moduleregexp, $definename) = parseTokens($lang, $sublang); my $macrore = macroRegexpFromList($macronameref); # print STDERR "PROPNAME2: $propname\n"; print STDERR "ARP: $accessregexp\n" if ($localDebug); last SWITCH; } } } }; ($part eq $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 $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 $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 $structname || $part eq $enumname || $part eq $unionname) && do { print STDERR "STRUCT/ENUM/UNION: CASE 36\n" if ($liteDebug); if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) { if ($structisbrace) { if ($parserState->{sodclass} eq "function") { $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(@braceStack, $part); pbs(@braceStack); if (!$parserState->{seenBraces}) { # 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; 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 (!$parserState->{seenBraces}) { # TREEDONE # $treePopTwo++; # $treeNest = 1; # push(@treeStack, $treeCur); # $treeCur = $treeCur->addChild($part, 0); $treeSkip = 1; # bless($treeCur, "HeaderDoc::ParseTree"); # } } $parserState->{onlyComments} = 0; print STDERR "[n]onlyComments -> 0\n" if ($macroDebug); $continuation = 1; # $parserState->{simpleTypedef} = 0; if ($parserState->{basetype} eq "") { $parserState->{basetype} = $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 "sodname cleared (seu)\n" if ($sodDebug); } $lastchar = $part; }; # end if }; # end do ($part =~ /^$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; $parserState->{simpleTypedef} = 1; print STDERR "simpleTypedef -> 1\n" if ($localDebug); # previous case falls through, so be explicit. if ($part =~ /^$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 "sodname cleared ($typedefname)\n" if ($sodDebug); } $lastchar = $part; }; # end if }; # end do # C++ operator keyword handler ($part eq "$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->{lastsymbol} = $part; $lastchar = $part; last SWITCH; # next; }; # Punctuation handlers ($part =~ /;/o) && do { print STDERR "SEMICOLON: CASE 39\n" if ($liteDebug); if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) { if ($parsedParamParse) { $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 $parsedParamParse = 2; $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; $continuation = 1; if ($parserState->{occmethod}) { $prespaceadjust = -$prespace; } # previous case falls through, so be explicit. if ($part =~ /;/o && !$parserState->{inMacroLine} && !$parserState->{inMacro}) { my $bsCount = scalar(@braceStack)-$parserState->{initbsCount}; if (!$bsCount && !$parserState->{kr_c_function}) { if ($parserState->{startOfDec} == 2) { $parserState->{sodclass} = "constant"; $parserState->{startOfDec} = 1; } elsif (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar} || $parserState->{inString})) { $parserState->{startOfDec} = 1; } # $parserState->{lastsymbol} .= $part; } if (!$bsCount) { $treeCur = $treeCur->addSibling(";"); $treepart = " "; # $treeSkip = 1; if (0) { $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [8]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } # $parserState->{lastTreeNode} = $treeCur; # print STDERR "LASTTREENODE -> $treeCur (".$treeCur->token().")\n"; while ($parserState->{treePopTwo}--) { $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [9]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } $parserState->{treePopTwo} = 0; } } $lastchar = $part; }; # end if }; # end do ($part eq "=" && ($parserState->{lastsymbol} ne "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 "[q]onlyComments -> 0\n" if ($macroDebug); if ($part =~ /=/o && !(scalar(@braceStack)-$parserState->{initbsCount}) && $nextpart !~ /=/o && $lastchar !~ /=/o && $parserState->{sodclass} ne "function" && !$inPType) { print STDERR "valuepending -> 1\n" if ($valueDebug); $parserState->{valuepending} = 1; $parserState->{preEqualsSymbol} = $parserState->{lastsymbol}; $parserState->{sodclass} = "constant"; $parserState->{startOfDec} = 0; }; # 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); } if ($part =~ /,/o && $parsedParamParse && !($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && ((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 $parsedParamParse = 2; print STDERR "parsedParamParse -> 2\n" if ($parmDebug); }; # end if }; # end do ($part =~ /[*^]/) && do { if ($lastnspart eq "(" && # ")" !($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !$parserState->{callbackNamePending} && ((scalar(@braceStack)-$parserState->{initbsCount}) == 1)) { # print "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})) { if (!ignore($part, $ignoreref, $perheaderignoreref)) { 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 (!$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}; $parsedParamParse = 1; print STDERR "parsedParamParse -> 1\n" if ($parmDebug); } } } } $lastchar = $part; if ($part =~ /\w/o || $part eq "::") { if ($parserState->{callbackNamePending} == 1) { if (!($part eq $structname || $part eq $enumname || $part eq $unionname || $part eq $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} = ""; $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"; $parserState->{sodclass} = "constant"; $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 !~ /[,;\[\]]/o && !$parserState->{inBrackets}) { my $opttilde = ""; if ($parserState->{seenTilde}) { $opttilde = "~"; } 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}) { print STDERR "Setting sodname (maybe type) to \"$part\"\n" if ($sodDebug); $parserState->{sodname} = $opttilde.$part; if ($part =~ /\w/o) { $parserState->{startOfDec}++; } } 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}) { if ($parserState->{inOperator} == 1) { $parserState->{sodname} .= $part; } else { if (length($parserState->{sodname})) { $parserState->{sodtype} .= " $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; } } elsif ($part eq "[") { # if ($part !~ /[;\[\]]/o) $parserState->{inBrackets} += 1; print STDERR "inBrackets -> $parserState->{inBrackets}\n" if ($sodDebug); } elsif ($part eq "]") { $parserState->{inBrackets} -= 1; print STDERR "inBrackets -> $parserState->{inBrackets}\n" if ($sodDebug); } # end if ($part !~ /[;\[\]]/o) if (!($part eq $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 $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 ($parserState->{seenBraces}) { # print "SEENBRACES. TP: $treepart PT: $part\n"; if ($treepart) { $parserState->{functionContents} .= $treepart; } else { $parserState->{functionContents} .= $part; } # print "SEENBRACES. FC: ".$parserState->{functionContents}."\n"; } 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 $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); 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 (!$parserState->{seenBraces}) { # 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); } $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); } } 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; setHollowWithLineNumbers(\$parserState, $treeCur, $fileoffset, $inputCounter); $sethollow = 0; } print STDERR "TSPUSH\n" if ($tsDebug || $treeDebug); push(@treeStack, $treeCur); $treeCur = $treeCur->addChild("", 0); bless($treeCur, "HeaderDoc::ParseTree"); } } } 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}) { # print STDERR "WARNING: RETURN TYPE CHANGE[A]".$parserState->{returntype}." CHANGED TO $declaration$curline.\n"; $parserState->{returntype} = "$declaration$curline"; } elsif (!$parserState->{freezereturn} && !$parserState->{hollow}) { # print STDERR "WARNING: RETURN TYPE CHANGE[B]".$parserState->{returntype}." CHANGED TO $curline.\n"; $parserState->{returntype} = "$curline"; $declaration = ""; # } else { # print STDERR "WARNING: LEAVING RETURN TYPE ALONE: ".$parserState->{returntype}." NOT CHANGED TO $curline.\n"; } # 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. if (($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) || !$ignoretoken) { if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !$ppSkipOneToken) { if ($parsedParamParse == 1) { $parsedParam .= $part; } elsif ($parsedParamParse == 2) { $parsedParamParse = 1; print STDERR "parsedParamParse -> 1\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 (!$parserState->{seenBraces}) { # 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); print STDERR "KRC: $parserState->{kr_c_function} SB: $parserState->{seenBraces}\n" if ($localDebug); if (!($bsCount - $parserState->{initbsCount}) && $parserState->{lastsymbol} =~ /;\s*$/o) { # print STDERR "DPA\n"; if ((!$parserState->{kr_c_function} || $parserState->{seenBraces}) && !$parserState->{inMacro}) { # print STDERR "DPB\n"; if (!scalar(@parserStack)) { $continue = 0; print STDERR "continue -> 0 [3]\n" if ($localDebug); } elsif (!$parserState->{onlyComments}) { # Process entry here if ($parserState->{noInsert}) { print STDERR "parserState insertion skipped[SEMI-1]\n" if ($parserStackDebug); } elsif ($parserState->{hollow}) { my $treeRef = $parserState->{hollow}; $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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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 "bsCount: $bsCount - $parserState->{initbsCount}, ls: $parserState->{lastsymbol}\n" if ($localDebug); pbs(@braceStack); } if (!($bsCount - $parserState->{initbsCount}) && $parserState->{seenBraces} && ($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}) { # Fix nesting. # print STDERR "LASTTREENODE -> $treeCur (".$treeCur->token().")\n"; while ($parserState->{treePopTwo}--) { $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [13]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } $treeCur = $treeCur->addSibling(";", 0); $parserState->{lastTreeNode} = $treeCur; $parserState->{treePopTwo} = 0; } if (!scalar(@parserStack)) { $continue = 0; print STDERR "continue -> 0 [4]\n" if ($localDebug); } elsif (!$parserState->{onlyComments}) { # Process entry here if ($parserState->{noInsert}) { print STDERR "parserState insertion skipped[SEMI-2]\n" if ($parserStackDebug); } elsif ($parserState->{hollow}) { my $treeRef = $parserState->{hollow}; $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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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 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 ($localDebug || $liteDebug); } 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}); } else { cpp_add($parserState->{hollow}, 1); $HeaderDoc::skipNextPDefine = 0; } } if ($parserState->{noInsert}) { print STDERR "parserState insertion skipped\n" if ($parserStackDebug); } elsif ($parserState->{hollow}) { my $treeRef = $parserState->{hollow}; $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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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 "$filename:$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) { print STDERR "parserState pushed onto stack[token]\n" if ($parserStackDebug); $parserState->{lastTreeNode} = $treeCur; $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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); $parserState->{lastTreeNode} = $treeCur; $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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, $lbrace, $case_sensitive)) { $parserState->{ISFORWARDDECLARATION} = 0; 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; # } $parserState->{lastTreeNode} = $treeCur; $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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 (!casecmp($tok, $rbrace, $case_sensitive) && $part !~ /\)/) { # $parserState->{hollow} = $treeCur; setHollowWithLineNumbers(\$parserState, $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 (!casecmp($tok, $rbrace, $case_sensitive) && $part !~ /\)/) { setHollowWithLineNumbers(\$parserState, $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; } # end foreach (parts of the current line) } # end while (continue && ...) 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); $parserState->{lastTreeNode} = $treeCur; $parserState->{inputCounter} = $inputCounter; print STDERR "PARSERSTATE: $parserState\n" if ($localDebug); if ($parserState->{inMacro} == 3) { if (!$HeaderDoc::skipNextPDefine) { cpp_add($treeTop); } else { cpp_add($treeTop, 1); $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); while ($tempParserState) { $parserState = $tempParserState; $tempParserState = pop(@parserStack); } $HeaderDoc::module = $parserState->{MODULE}; if ($localDebug || $apDebug || $liteDebug || $parseDebug) { 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 "FC: ".$parserState->{functionContents}."\n"; return blockParseReturnState($parserState, $treeTop, $argparse, $declaration, $inPrivateParamTypes, $publicDeclaration, $lastACS, $retDebug, $fileoffset, 0, $definename, $inputCounter); } $parserState->{functionReturnsCallback} => 0 $parserState->{hollow} => HeaderDoc::ParseTree=HASH(OBJID) $parserState->{inBrackets} => 0 $parserState->{inChar} => $parserState->{inClass} => 0 $parserState->{inComment} => 0 $parserState->{inInlineComment} => 0 $parserState->{inMacro} => 0 $parserState->{inMacroLine} => 0 $parserState->{inOperator} => 0 $parserState->{inPrivateParamTypes} => 0 $parserState->{inString} => 0 $parserState->{inTemplate} => 0 $parserState->{initbsCount} => 0 $parserState->{inputCounter} => 3647 $parserState->{kr_c_function} => 0 $parserState->{kr_c_name} => $parserState->{lang} => perl $parserState->{lastTreeNode} => HeaderDoc::ParseTree=HASH(OBJID) $parserState->{lastsymbol} => $parserState->{macroNoTrunc} => 1 $parserState->{name} => blockParse $parserState->{namePending} => 0 $parserState->{noInsert} => 0 $parserState->{occmethod} => 0 $parserState->{occmethodname} => $parserState->{occparmlabelfound} => 2 $parserState->{onlyComments} => 0 $parserState->{parsedParamList} => ARRAY(OBJID) $parserState->{parsedParamParse} => 0 $parserState->{posstypes} => $parserState->{posstypesPending} => 0 $parserState->{pplStack} => ARRAY(OBJID) $parserState->{preEqualsSymbol} => $parserState->{preTemplateSymbol} => $parserState->{prekeywordsodname} => $parserState->{prekeywordsodtype} => $parserState->{returntype} => sub blockParse $parserState->{seenBraces} => 1 $parserState->{seenMacroPart} => 0 $parserState->{seenTilde} => 0 $parserState->{simpleTDcontents} => $parserState->{simpleTypedef} => 0 $parserState->{sodclass} => function $parserState->{sodname} => blockParse $parserState->{sodtype} => $parserState->{stackFrozen} => 1 $parserState->{startOfDec} => 0 $parserState->{sublang} => perl $parserState->{temponlyComments} => 0 $parserState->{typestring} => function $parserState->{value} => $parserState->{valuepending} => 0 -=: BLOCKPARSE RETURN VALUES :=- newcount: 3647 typelist: function namelist: blockParse posstypes: function method value: returntype: pridec: simpleTDcontents: bpavail: blockOffset: 0 conformsToList: functionContents: { my $filename = 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 $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 $cbnDebug = 0; my $macroDebug = 0; my $apDebug = 0; my $tsDebug = 0; my $treeDebug = 0; my $ilcDebug = 0; my $regexpDebug = 0; my $parserStackDebug = 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 $liteDebug = 0 || $HeaderDoc::fileDebug; # Just prints the tokens. my $parserStateInsertDebug = 0; $cppDebug = $cppDebugDefault || $HeaderDoc::fileDebug; # State variables (part 1 of 3) # my $typestring = ""; my $continue = 1; # set low when we're done. my $parsedParamParse = 0; # set high when current token is part of param. # 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 $perl_or_shell = 0; 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; 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" || $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(); # $parserState->{hollow} = $treeTop; setHollowWithLineNumbers(\$parserState, $treeTop, $fileoffset, $inputCounter); $parserState->{lang} = $lang; $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 $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 perl regexp. 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 ($sotemplate, $eotemplate, $operator, $soc, $eoc, $ilc, $ilc_b, $sofunction, $soprocedure, $sopreproc, $lbrace, $rbrace, $unionname, $structname, $enumname, $typedefname, $varname, $constname, $structisbrace, $macronameref, $classregexp, $classbraceregexp, $classclosebraceregexp, $accessregexp, $requiredregexp, $propname, $objcdynamicname, $objcsynthesizename, $moduleregexp, $definename) = parseTokens($lang, $sublang); my $macrore_pound = macroRegexpFromList($macronameref, 1); my $macrore_nopound = macroRegexpFromList($macronameref, 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 $propname\n"; if ($parseDebug) { print STDERR "SOT: $sotemplate EOF: $eotemplate OP: $operator SOC: $soc EOC: $eoc ILC: $ilc ILC_B: $ilc_b\n"; print STDERR "SOFUNC: $sofunction SOPROC: $soprocedure SOPREPROC: $sopreproc LBRACE: $lbrace RBRACE: $rbrace\n"; print STDERR "UNION: $unionname STRUCT: $structname TYPEDEF: $typedefname VAR: $varname CONST: $constname\n"; print STDERR "STRUCTISBRACE: $structisbrace MACRONAMEREF: $macronameref 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") { $perl_or_shell = 1; if ($lang eq "perl") { $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; if ($lang eq "pascal") { $pascal = 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 $categoryClass = ""; # my $classtype = ""; # my $inClass = 0; my $pushParserStateAfterToken = 0; my $pushParserStateAfterWordToken = 0; my $pushParserStateAtBrace = 0; my $occPushParserStateOnWordTokenAfterNext = 0; $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 "INCOMING INPUTCOUNTER: $inputCounter\n" if ($HeaderDoc::inputCounterDebug); while ($continue && ($inputCounter <= $nlines)) { $HeaderDoc::CurLine = $inputCounter + $fileoffset; my $line = $inputLines[$inputCounter++]; print STDERR "GOT LINE: $line\n" if (($localDebug && $apDebug) || $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 "CHANGED LINE FROM \"$line\" to \"$1\"\n" if ($localDebug || $liteDebug); $line = $1."\n"; } } print STDERR "LINE[$inputCounter] : $line\n" if ($offsetDebug); # The tokenizer if ($lang eq "perl" || $lang eq "shell") { @parts = split(/("|'|\#|\{|\}|\(|\)|\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) {foreach my $partlist (@parts) {print STDERR "PARTLIST: \"$partlist\"\n"; }} # 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; # print STDERR "CHECK LINE $line\n"; if ($line =~ /^\s*#include (.*)$/) { my $rest = $1; $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 "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; while ($pos < scalar(@parts)) { my $part = $parts[$pos]; my $noCPPThisToken = 0; if (length($part)) { if (!$inChar && !$inString && !$inComment && !$inSLC) { if ($parserState->{NEXTTOKENNOCPP} == 1) { # We're in an "if" block. if ($part eq "defined") { $parserState->{NEXTTOKENNOCPP} = 3; } } elsif ($parserState->{NEXTTOKENNOCPP} == 2) { # 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) { # 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)/) { $parserState->{NEXTTOKENNOCPP} = 2; } elsif ($inCPPSpecial && $part =~ /if/) { $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 $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 $soc) { print STDERR "SOC\n"if ($cppleaddebug); $inComment = 1; } elsif (!$inComment && ($part eq $ilc || $part eq $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) { ($newpart, $hasargs) = 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) { $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 \"$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; } } 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) { print STDERR "CPPS: \"$cppstring\"\n"; warn "Non-terminated macro.\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 "CHANGED LINE FROM \"$line\" to \"$1\"\n" if ($localDebug || $liteDebug); $line = $1."\n"; } } print STDERR "INCREMENTED INPUTCOUNTER [2]\n" if ($HeaderDoc::inputCounterDebug); # @parts = split(/(\W)/, $line); if ($lang eq "perl" || $lang eq "shell") { @parts = split(/("|'|\#|\{|\}|\(|\)|\s|;|\\|\W)/, $line); } else { @parts = split(/("|'|\/\/|\/\*|\*\/|::|==|<=|>=|!=|\<\<|\>\>|\{|\}|\(|\)|\s|;|\\|\W)/, $line); } } } until (!$incppargs && !$inComment); # The tokenizer if ($lang eq "perl" || $lang eq "shell") { @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); # 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; $treeSkip = 0; # $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); $forcenobreak = 0; if ($nextpart eq "\r") { $nextpart = "\n"; } if ($localDebug && $nextpart eq "\n") { print STDERR "NEXTPART IS NEWLINE!\n"; } if ($localDebug && $part eq "\n") { 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); print STDERR "CURLINE IS \"$curline\"\n" if ($localDebug || $hangDebug); 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); } } elsif ($occPushParserStateOnWordTokenAfterNext) { # if ($part !~ /(\s|<)/) if ($part =~ /(\/\/|\/\*|\-|\+|\w|\@)/) { $parserState->{lastTreeNode} = $treeCur; print STDERR "parserState pushed onto stack[occPushParserStateOnWordTokenAfterNext]\n" if ($parserStackDebug); $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 0; $parserState->{lang} = $lang; $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++; } 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} inRegexp: $inRegexp\n"; print STDERR "PART: regexpNoInterpolate: $regexpNoInterpolate\n"; 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 ($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); printf("PART: $part TEMPAVAIL: $tempavail\n") if ($localDebug || $gccAttributeDebug); if ($tempavail && ($tempavail ne "1") && ($tempavail ne "2")) { $parserState->{availability} = $tempavail; } elsif ($tempavail eq "2") { # Reusing the GCC attribute handling code because that does exactly what we need. print STDERR "Function-like availability macro detected. Collecting.\n" if ($localDebug || $gccAttributeDebug); $parserState->{attributeState} = 1; $parserState->{attributeParts} = (); # Add __attribute__ as the next token. $treeCur = $treeCur->addSibling($part, 0); 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; } # Handle the GCC "__attribute__" extension outside the context of # the parser because it isn't part of the language and massively # breaks the syntax. if ($lang eq "C" && isKeyword($part, $keywordhashref, $case_sensitive) == 2) { print STDERR "GCC attribute detected. Collecting.\n" if ($localDebug || $gccAttributeDebug); $parserState->{attributeState} = 1; $parserState->{attributeParts} = (); # Add __attribute__ as the next token. $treeCur = $treeCur->addSibling($part, 0); push(@treeStack, $treeCur); # Nest all contents one level lower. $treeCur = $treeCur->addChild("", 0); $part = $nextpart; next; } elsif ($parserState->{attributeState} == 1) { if ($part eq "(") { print STDERR "GCC attribute open paren\n" if ($localDebug || $gccAttributeDebug); $parserState->{attributeState} = -1; } $treeCur = $treeCur->addSibling($part, 0); $part = $nextpart; next; } elsif ($parserState->{attributeState} < 0) { if ($part eq "(") { $parserState->{attributeState}--; print STDERR "GCC attribute open paren, count=".(0-$parserState->{attributeState})."\n" if ($localDebug || $gccAttributeDebug); } elsif ($part eq ")") { $parserState->{attributeState}++; print STDERR "GCC attribute close paren, count=".(0-$parserState->{attributeState})."\n" if ($localDebug || $gccAttributeDebug); } $treeCur = $treeCur->addSibling($part, 0); if (($localDebug || $gccAttributeDebug) && !$parserState->{attributeState}) { print STDERR "GCC attribute: done collecting.\n"; # Get back to where we started. $treeCur = pop(@treeStack); } $part = $nextpart; next; } # Here be the parser. Abandon all hope, ye who enter here. $treepart = ""; 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 print STDERR "parserState pushed onto stack[PROTOCOL]\n" if ($parserStackDebug); $parserState->{inProtocol} = -1; $parserState->{lastTreeNode} = $treeCur; $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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); # $parserState->{lastTreeNode} = $treeCur; # push(@parserStack, $parserState); # $parserState = HeaderDoc::ParserState->new(); # $parserState->{lang} = $lang; # $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); $parserState->{lastTreeNode} = $treeCur; print STDERR "parserState pushed onto stack[cparen2]\n" if ($parserStackDebug); $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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"; if ($part eq ":") { print STDERR "INCLASS COLON\n" if ($parseDebug || $classDebug); $parserState->{forceClassName} = $parserState->{sodname}; $parserState->{forceClassSuper} = ""; # print STDERR "XSUPER: $parserState->{forceClassSuper}\n"; } elsif ($part eq "{" || $part eq ";") { print STDERR "INCLASS BRCSEMI\n" if ($parseDebug || $classDebug); $parserState->{forceClassDone} = 1; if ($parserState->{classIsObjC} && $part eq "{") { $parserState->{ISFORWARDDECLARATION} = 0; $parserState->{lastTreeNode} = $treeCur; print STDERR "parserState pushed onto stack[OCC-BRCSEMI]\n" if ($parserStackDebug); $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 0; $parserState->{lang} = $lang; $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}) { 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->{classIsObjC}) { print STDERR "INCLASS NOTOBJC (OTHER)\n" if ($parseDebug || $classDebug); 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}; } # } 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 $ilc || $part eq $ilc_b) && ($lang ne "perl" || $lasttoken ne "\$")) { # print STDERR "should be ILC?\n"; # } else { # print STDERR "NO CHANEC: PART \"$part\" ILC \"$ilc\" ILC_B: \"ilc_b\" LANG: \"$lang\" LASTTOKEN: \"$lasttoken\"\n"; # } SWITCH: { # Blank declaration handlers (mostly for misuse of # OSMetaClassDeclareReservedUsed and similar) (($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; }; # 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 "$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|pragma|import|include)/ && ($part ne $definename)) || ($parserState->{inMacro} == 0 && $macrore_nopound ne "" && $part =~ /$macrore_nopound/)) # (($parserState->{inMacro} == 1 && $part =~ /(if|ifdef|ifndef|endif|else|undef|elif|pragma|import|include)/ )) && do (!$parserState->{inComment} && (($parserState->{inMacro} == 1 && $macrore_pound ne "" && $part =~ /^$macrore_pound$/ && ($part ne $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|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 "$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|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 "$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 $soc) && ($part ne $eoc) && $part =~ /\s/) && do { $treepart = $part; $part = ""; last SWITCH; }; ($parserState->{inMacro} == 1 && ($part ne $soc) && ($part ne $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 $soc) && ($part ne $eoc)) && do { print STDERR "INMACRO OTHERTOKEN: CASE 06\n" if ($liteDebug); print STDERR "INMACRO > 1, PART NE //" if ($parseDebug || $localDebug); if ($part eq "\\") { $parserState->addBackslash(); } elsif ($part !~ /[ \t]/) { $parserState->addBackslash(); } print STDERR "PART: $part\n" if ($macroDebug); if ($parserState->{seenMacroPart} && $HeaderDoc::truncate_inline) { 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; } elsif ($part =~ /[\{\(]/o) { print STDERR "MACRO: BRACE\n" if ($macroDebug); if (!$parserState->{macroNoTrunc}) { # $parserState->{seenBraces} = 1; $HeaderDoc::hidetokens = 3; } } else { print STDERR "MACRO: OTHERTOKEN\n" if ($macroDebug); $parserState->{macroNoTrunc} = 2; } } } if ($part =~ /[\{\(]/o) { push(@braceStack, $part); print STDERR "PUSH\n" if ($macroDebug); } elsif ($part =~ /[\}\)]/o) { if ($part ne peekmatch(\@braceStack, $filename, $inputCounter)) { if ($parserState->{macroNoTrunc} == 1) { # We haven't reached the end of the first part of the declaration, so this is an error. warn("$filename:$inputCounter: warning: Initial braces in macro name do not match.\nWe may have a problem.\n"); } } pop(@braceStack); print STDERR "POP\n" if ($macroDebug); } 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 # print STDERR "IRE: $inRegexp IRT: $inRegexpTrailer IS: $parserState->{inString} ICo $parserState->{inComment} ILC: $parserState->{inInlineComment} ICh $parserState->{inChar}\n"; (length($regexppattern) && $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? $inRegexp = 2; } else { $inRegexp = 4; # print STDERR "REGEXP PART IS \"$part\"\n"; if ($part eq "tr") { $regexpNoInterpolate = 1; } # if ($part =~ /tr/) { $regexpNoInterpolate = 1; } } last SWITCH; }; # end regexppattern (($inRegexp || $parserState->{lastsymbol} eq "~") && (length($regexpcharpattern) && $part =~ /^($regexpcharpattern)$/ && (!scalar(@regexpStack) || $part eq peekmatch(\@regexpStack, $filename, $inputCounter)))) && do { print STDERR "REGEXP CHARACTER: CASE 08\n" if ($liteDebug); print STDERR "REGEXP?\n" if ($regexpDebug); if (!$inRegexp) { $inRegexp = 2; } # if ($lasttoken eq "\\") if ($parserState->isQuoted($lang. $sublang)) { # jump to next match. $lasttoken = $part; $parserState->{lastsymbol} = $part; next SWITCH; } print STDERR "REGEXP POINT A\n" if ($regexpDebug); $lasttoken = $part; $parserState->{lastsymbol} = $part; if ($part eq "#" && ((scalar(@regexpStack) != 1) || (peekmatch(\@regexpStack, $filename, $inputCounter) ne "#"))) { if ($nextpart =~ /^\s/o) { # it's a comment. jump to next match. next SWITCH; } } print STDERR "REGEXP POINT B\n" if ($regexpDebug); if (!scalar(@regexpStack)) { push(@regexpStack, $part); $inRegexp--; } else { my $match = peekmatch(\@regexpStack, $filename, $inputCounter); my $tos = pop(@regexpStack); if (!scalar(@regexpStack) && ($match eq $part)) { $inRegexp--; if ($inRegexp == 2 && $tos eq "/") { # we don't double the slash in the # middle of a s/foo/bar/g style # expression. $inRegexp--; } if ($inRegexp) { push(@regexpStack, $tos); } } elsif (scalar(@regexpStack) == 1) { push(@regexpStack, $tos); if ($tos =~ /['"`]/o || $regexpNoInterpolate) { # these don't interpolate. next SWITCH; } } else { push(@regexpStack, $tos); if ($tos =~ /['"`]/o || $regexpNoInterpolate) { # these don't interpolate. next SWITCH; } push(@regexpStack, $part); } } print STDERR "REGEXP POINT C\n" if ($regexpDebug); if (!$inRegexp) { $inRegexpTrailer = 2; } last SWITCH; }; # end regexpcharpattern # Start of preprocessor macros ($part eq "$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); } 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 "$sofunction" || $part eq "$soprocedure") && do { print STDERR "SOFUNC: CASE 10\n" if ($liteDebug); $parserState->{sodclass} = "function"; print STDERR "K&R C FUNCTION FOUND [1].\n" if ($localDebug); $parserState->{kr_c_function} = 1; $parserState->{typestring} = "function"; $parserState->{startOfDec} = 2; $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); last SWITCH; }; # C++ destructor handler. ($part =~ /\~/o && $lang eq "C" && $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 && $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; $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) && do { print STDERR "NEWLINE: CASE 13\n" if ($liteDebug); # NEWLINE FOUND $treepart = $part; if ($inRegexp) { warn "$filename:$inputCounter: warning: multi-line regular expression\n"; } print STDERR "NLCR\n" if ($tsDebug || $treeDebug || $localDebug); 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; } else { $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); print STDERR "skipped pushing CPP directive $parsedParam into parsedParamList [1]\n" if ($parmDebug || $cppDebug || $localDebug); $parsedParam = ""; } } } if ($treePopOnNewLine < 0) { # pop once for //, possibly again for macro $treePopOnNewLine = 0 - $treePopOnNewLine; $treeCur = $treeCur->addSibling($treepart, 0); bless($treeCur, "HeaderDoc::ParseTree"); # push(@treeStack, $treeCur); $treeSkip = 1; $treeCur = pop(@treeStack); if (!$treeCur) { $treeCur = $treeTop; warn "$filename:$inputCounter: warning: Attempted to pop off top of tree\n"; } $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [1]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if ($treePopOnNewLine == 1 || ($treePopOnNewLine && !$parserState->isQuoted())) { # $parserState->{lastsymbol} ne "\\" $treeCur = $treeCur->addSibling($treepart, 0); bless($treeCur, "HeaderDoc::ParseTree"); # push(@treeStack, $treeCur); $treeSkip = 1; $treeCur = pop(@treeStack); if (!$treeCur) { $treeCur = $treeTop; warn "$filename:$inputCounter: warning: Attempted to pop off top of tree\n"; } $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->addSibling("", 0); # empty token print STDERR "TSPOP [1a]\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 $sotemplate && !$parserState->{seenBraces} && ($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(@braceStack, $part); pbs(@braceStack); if (!$parserState->{seenBraces}) { # TREEDONE $treeNest = 1; 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 $eotemplate && !$parserState->{seenBraces} && ($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); if (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [2]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if ($top ne "$sotemplate") { warn("$filename:$inputCounter: warning: Template (angle) brackets do not match.\nWe may have a problem.\n"); } } last SWITCH; }; # # Handles C++ access control state, e.g. "public:" # ($part eq ":") && 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 (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) { 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); $parserState->{hollow} = undef; $parserState->{onlyComments} = 1; print STDERR "hollowskip -> 1 (ACS)\n" if ($parserStateInsertDebug); $hollowskip = 1; $HeaderDoc::AccessControlState = $1; $lastACS = $1; last SWITCH; } elsif ($parserState->{typestring} eq "struct") { if (!(scalar(@braceStack) - $parserState->{initbsCount})) { if (!$parserState->{structClassName}) { $parserState->{structClassName} = $parserState->{lastsymbol}; $parserState->{bracePending} = 2; } } } } }; (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 MATCH: \"$part\"\n" if ($localDebug || $parseDebug); $hollowskip = 1; print STDERR "hollowskip -> 1 (requiredregexp)\n" if ($parserStateInsertDebug); last SWITCH; }; # # C++ copy constructor handler. For example: # # char *class(void *a, void *b) : # class(pri_type, pri_type); # ($part eq ":") && 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" && $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\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 (!$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 { next SWITCH; } }; # Non-newline, non-carriage-return whitespace handler. ($part =~ /\s/o) && do { print STDERR "Whitespace: CASE 19\n" if ($liteDebug); # 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 "\"") && 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})) { $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 (!$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 (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [3]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } } $parserState->{inString} = (1-$parserState->{inString}); } } $lastchar = $part; $parserState->{lastsymbol} = ""; last SWITCH; }; ($part eq "[") && do { print STDERR "LEFT BRACKET: CASE 22\n" if ($liteDebug); # left square bracket (square brace) if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate)) { 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(@braceStack, $part); pbs(@braceStack); if (!$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; } $lastchar = $part; last SWITCH; }; ($part eq "]") && do { print STDERR "CLOSE BRACKET: CASE 23\n" if ($liteDebug); # right square bracket (square brace) if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate)) { print STDERR "rbracket\n" if ($localDebug); if (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inString})) { $parserState->{onlyComments} = 0; print STDERR "[g]onlyComments -> 0\n" if ($macroDebug); } my $top = pop(@braceStack); if (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [4]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if ($top ne "[") { warn("$filename:$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; } $lastchar = $part; last SWITCH; }; ($part eq "'") && do { print STDERR "SINGLE QUOTE: CASE 24\n" if ($liteDebug); print STDERR "squo\n" if ($localDebug); if (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inString})) { # 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 (!$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 (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [5]\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 $ilc || $part eq $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} = 4; print STDERR "inInlineComment -> 1\n" if ($ilcDebug); $curline = spacefix($curline, $part, $lastchar, $soc, $eoc, $ilc, $ilc_b); if (!$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("$filename:$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 $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 (!$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("$filename:$linenum: warning: Nested comment found [2]. Ignoring.\n"); } } $parserState->{lastsymbol} = ""; $lastchar = $part; last SWITCH; }; ($part eq $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; $curline = spacefix($curline, $part, $lastchar); $ppSkipOneToken = 1; if (!$parserState->{seenBraces}) { $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [6]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } } elsif (!$parserState->{inComment} && !$parserState->{inInlineComment} && !$parserState->{inString} && !$parserState->{inChar} && !$inRegexp) { my $linenum = $inputCounter + $fileoffset; warn("$filename:$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::test_mode)) { warn("$filename:$linenum: warning: Nested comment found [3]. Ignoring.\n"); } } $parserState->{lastsymbol} = ""; $lastchar = $part; last SWITCH; }; # Parenthesis and brace handlers. ($part eq "(") && do { print STDERR "OPEN PAREN: CASE 28\n" if ($liteDebug); my @tempppl = undef; if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate)) { if (!(scalar(@braceStack)-$parserState->{initbsCount})) { # start parameter parsing after this token print STDERR "parsedParamParse -> 2\n" if ($parmDebug); $parsedParamParse = 2; 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"; # 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->{returntype} = "$declaration$curline"; } elsif (!$parserState->{freezereturn} && !$parserState->{hollow}) { $parserState->{returntype} = "$curline"; $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); 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"; # $parserState->{callbackName} = ""; $parserState->{functionReturnsCallback}++; print "Function returning callback. NAME: $parserState->{cbsodname}\n" if ($parmDebug || $localDebug || $parseDebug); print STDERR "parsedParamParse -> 2\n" if ($parmDebug); $parsedParamParse = 2; print STDERR "parsedParamList wiped\n" if ($parmDebug); @tempppl = @{$parserState->{parsedParamList}}; @{$parserState->{parsedParamList}} = (); $parsedParam = ""; } } if ($parserState->{inOperator} == 1) { $parserState->{inOperator} = 2; } push(@braceStack, $part); pbs(@braceStack); if (!$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) { $parserState->{sodclass} = "function"; $parserState->{freezereturn} = 1; $parserState->{returntype} =~ s/^\s*//so; $parserState->{returntype} =~ s/\s*$//so; } $parserState->{startOfDec} = 0; 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 "OUTGOING CURLINE: \"$curline\"\n" if ($localDebug); last SWITCH; }; ($part eq ")") && do { print STDERR "CLOSE PAREN: CASE 29\n" if ($liteDebug); if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate && (peek(\@regexpStack) ne "("))) { if ((scalar(@braceStack)-$parserState->{initbsCount} - $parserState->{functionReturnsCallback}) == 1) { # stop parameter parsing $parsedParamParse = 0; print STDERR "parsedParamParse -> 0\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 = pop(@braceStack); pbs(@braceStack); if (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [6a]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if (!($test eq "(")) { # ) brace hack for vi warn("$filename:$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; 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; }; (casecmp($part, $lbrace, $case_sensitive)) && do { print STDERR "LEFT BRACE: CASE 30\n" if ($liteDebug); if ($parserState->{onlyComments} && !$parserState->{inComment} && !$parserState->{inInlineComment} && !$parserState->{inChar} && !($inRegexp && $regexpNoInterpolate) && scalar(@parserStack)) { # 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 && $regexpNoInterpolate)) { $parserState->{bracePending} = 0; print STDERR "bracePending -> 0 [brace]\n" if ($localDebug); $parserState->{onlyComments} = 0; print STDERR "[k]onlyComments -> 0\n" if ($macroDebug); 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\n" if ($parmDebug); } # start parameter parsing after this token print STDERR "parsedParamParse -> 2\n" if ($parmDebug); $parsedParamParse = 2; # 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 "seenBraces -> 1\n" if ($parseDebug); $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(@braceStack, $part); pbs(@braceStack); if (!$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; 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; }; (casecmp($part, $rbrace, $case_sensitive)) && do { print STDERR "RIGHT BRACE: CASE 31\n" if ($liteDebug); if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate && (peek(\@regexpStack) ne "$lbrace"))) { 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); my $bsCount = scalar(@braceStack); if (scalar(@parserStack) && !($bsCount - $parserState->{initbsCount})) { print STDERR "parserState: ENDOFSTATE\n" if ($parserStackDebug); if ($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}; $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; $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 [1a]\n" if ($localDebug || $liteDebug); $parserState->{noInsert} = 0; $continue = 0; print STDERR "AT END: REALPS IS ".$parserState->{REALPS}."\n" if ($parserStackDebug || $localDebug); print STDERR "STACK COUNT: ".scalar(@parserStack)."\n" if ($parserStackDebug || $localDebug); } if ($lang eq "php" || ($lang eq "C" && $sublang eq "IDL")) { # print STDERR "PHP OUT OF BRACES?: ".scalar(@braceStack)."\n"; if (scalar(@braceStack) == 1) { # PHP and IDL classes end at # the brace. print STDERR "continue -> 0 [1a]\n" if ($localDebug || $liteDebug); $continue = 0; } } 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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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); } if ((scalar(@braceStack)-$parserState->{initbsCount}) == 1) { # stop parameter parsing $parsedParamParse = 0; print STDERR "parsedParamParse -> 0\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 = ""; } else { # start parameter parsing after this token print STDERR "parsedParamParse -> 2\n" if ($parmDebug); $parsedParamParse = 2; } 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\n" if ($parmDebug); } print STDERR "rbrace\n" if ($localDebug); my $test = pop(@braceStack); pbs(@braceStack); if (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [7]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if (!($test eq "$lbrace") && (!length($structname) || (!($test eq $structname) && $structisbrace))) { warn("$filename:$inputCounter: warning: Braces do not match.\nWe may have a problem.\n"); warn("Declaration to date: $declaration$curline\n"); } $curline = spacefix($curline, $part, $lastchar); $parserState->{lastsymbol} = ""; $lastchar = $part; $parserState->{startOfDec} = 0; 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($propname) && $propname =~ /\@/) || length($objcdynamicname) || length($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 $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 $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 $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 $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, $filename, $inputCounter)) { warn("$filename:inputCounter: warning: Class braces do not match.\nWe may have a problem.\n"); } $parserState->{seenBraces} = 1; pop(@braceStack); $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [6]\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; $HeaderDoc::module = $parserState->{MODULE}; $continue = 0; print STDERR "continue -> 0 [occend]\n" if ($localDebug); } 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}; $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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $parserState->{inputCounter} = $inputCounter; $parserState->{initbsCount} = scalar(@braceStack); } print STDERR "parserState popped from parserStack[\@end]\n" if ($parserStackDebug); $parserState = pop(@parserStack) || $parserState; $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. ### ($sotemplate, $eotemplate, $operator, $soc, $eoc, $ilc, $ilc_b, $sofunction, ### $soprocedure, $sopreproc, $lbrace, $rbrace, $unionname, $structname, ### $enumname, ### $typedefname, $varname, $constname, $structisbrace, $macronameref, ### $classregexp, $classbraceregexp, $classclosebraceregexp, $accessregexp, ### $requiredregexp, $propname, $objcdynamicname, $objcsynthesizename, $moduleregexp, $definename) = parseTokens($lang, $sublang); ### print STDERR "PROPNAME NOW $propname\n" if ($localDebug || $parseDebug || $classDebug); my $localclasstype = $1; if ($part =~ /^\@/) { $part =~ s/^\@//s; } if (!(scalar(@braceStack)-$parserState->{initbsCount})) { if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) { print STDERR "ITISACLASS\n" if ($localDebug); if (!length($parserState->{sodclass})) { 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"; $parserState->{classtype} = $localclasstype; $parserState->{preclasssodtype} = $parserState->{sodtype} . $part; $parserState->{sodtype} = ""; $parserState->{startOfDec} = 1; $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(@braceStack, $localclasstype); pbs(@braceStack); $treeNest = 1; if ($treeDebug) { print STDERR "TS TREENEST -> 1 [17]\n"; } # } else { # print STDERR "CBRE: \"$classbraceregexp\"\n"; } ($lang, $sublang) = getLangAndSublangFromClassType($localclasstype); $HeaderDoc::lang = $lang; $HeaderDoc::sublang = $sublang; ($sotemplate, $eotemplate, $operator, $soc, $eoc, $ilc, $ilc_b, $sofunction, $soprocedure, $sopreproc, $lbrace, $rbrace, $unionname, $structname, $enumname, $typedefname, $varname, $constname, $structisbrace, $macronameref, $classregexp, $classbraceregexp, $classclosebraceregexp, $accessregexp, $requiredregexp, $propname, $objcdynamicname, $objcsynthesizename, $moduleregexp, $definename) = parseTokens($lang, $sublang); my $macrore = macroRegexpFromList($macronameref); # print STDERR "PROPNAME2: $propname\n"; print STDERR "ARP: $accessregexp\n" if ($localDebug); last SWITCH; } } } }; ($part eq $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 $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 $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 $structname || $part eq $enumname || $part eq $unionname) && do { print STDERR "STRUCT/ENUM/UNION: CASE 36\n" if ($liteDebug); if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) { if ($structisbrace) { if ($parserState->{sodclass} eq "function") { $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(@braceStack, $part); pbs(@braceStack); if (!$parserState->{seenBraces}) { # 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; 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 (!$parserState->{seenBraces}) { # TREEDONE # $treePopTwo++; # $treeNest = 1; # push(@treeStack, $treeCur); # $treeCur = $treeCur->addChild($part, 0); $treeSkip = 1; # bless($treeCur, "HeaderDoc::ParseTree"); # } } $parserState->{onlyComments} = 0; print STDERR "[n]onlyComments -> 0\n" if ($macroDebug); $continuation = 1; # $parserState->{simpleTypedef} = 0; if ($parserState->{basetype} eq "") { $parserState->{basetype} = $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 "sodname cleared (seu)\n" if ($sodDebug); } $lastchar = $part; }; # end if }; # end do ($part =~ /^$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; $parserState->{simpleTypedef} = 1; print STDERR "simpleTypedef -> 1\n" if ($localDebug); # previous case falls through, so be explicit. if ($part =~ /^$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 "sodname cleared ($typedefname)\n" if ($sodDebug); } $lastchar = $part; }; # end if }; # end do # C++ operator keyword handler ($part eq "$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->{lastsymbol} = $part; $lastchar = $part; last SWITCH; # next; }; # Punctuation handlers ($part =~ /;/o) && do { print STDERR "SEMICOLON: CASE 39\n" if ($liteDebug); if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) { if ($parsedParamParse) { $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 $parsedParamParse = 2; $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; $continuation = 1; if ($parserState->{occmethod}) { $prespaceadjust = -$prespace; } # previous case falls through, so be explicit. if ($part =~ /;/o && !$parserState->{inMacroLine} && !$parserState->{inMacro}) { my $bsCount = scalar(@braceStack)-$parserState->{initbsCount}; if (!$bsCount && !$parserState->{kr_c_function}) { if ($parserState->{startOfDec} == 2) { $parserState->{sodclass} = "constant"; $parserState->{startOfDec} = 1; } elsif (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar} || $parserState->{inString})) { $parserState->{startOfDec} = 1; } # $parserState->{lastsymbol} .= $part; } if (!$bsCount) { $treeCur = $treeCur->addSibling(";"); $treepart = " "; # $treeSkip = 1; if (0) { $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [8]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } # $parserState->{lastTreeNode} = $treeCur; # print STDERR "LASTTREENODE -> $treeCur (".$treeCur->token().")\n"; while ($parserState->{treePopTwo}--) { $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [9]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } $parserState->{treePopTwo} = 0; } } $lastchar = $part; }; # end if }; # end do ($part eq "=" && ($parserState->{lastsymbol} ne "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 "[q]onlyComments -> 0\n" if ($macroDebug); if ($part =~ /=/o && !(scalar(@braceStack)-$parserState->{initbsCount}) && $nextpart !~ /=/o && $lastchar !~ /=/o && $parserState->{sodclass} ne "function" && !$inPType) { print STDERR "valuepending -> 1\n" if ($valueDebug); $parserState->{valuepending} = 1; $parserState->{preEqualsSymbol} = $parserState->{lastsymbol}; $parserState->{sodclass} = "constant"; $parserState->{startOfDec} = 0; }; # 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); } if ($part =~ /,/o && $parsedParamParse && !($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && ((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 $parsedParamParse = 2; print STDERR "parsedParamParse -> 2\n" if ($parmDebug); }; # end if }; # end do ($part =~ /[*^]/) && do { if ($lastnspart eq "(" && # ")" !($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !$parserState->{callbackNamePending} && ((scalar(@braceStack)-$parserState->{initbsCount}) == 1)) { # print "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})) { if (!ignore($part, $ignoreref, $perheaderignoreref)) { 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 (!$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}; $parsedParamParse = 1; print STDERR "parsedParamParse -> 1\n" if ($parmDebug); } } } } $lastchar = $part; if ($part =~ /\w/o || $part eq "::") { if ($parserState->{callbackNamePending} == 1) { if (!($part eq $structname || $part eq $enumname || $part eq $unionname || $part eq $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} = ""; $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"; $parserState->{sodclass} = "constant"; $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 !~ /[,;\[\]]/o && !$parserState->{inBrackets}) { my $opttilde = ""; if ($parserState->{seenTilde}) { $opttilde = "~"; } 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}) { print STDERR "Setting sodname (maybe type) to \"$part\"\n" if ($sodDebug); $parserState->{sodname} = $opttilde.$part; if ($part =~ /\w/o) { $parserState->{startOfDec}++; } } 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}) { if ($parserState->{inOperator} == 1) { $parserState->{sodname} .= $part; } else { if (length($parserState->{sodname})) { $parserState->{sodtype} .= " $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; } } elsif ($part eq "[") { # if ($part !~ /[;\[\]]/o) $parserState->{inBrackets} += 1; print STDERR "inBrackets -> $parserState->{inBrackets}\n" if ($sodDebug); } elsif ($part eq "]") { $parserState->{inBrackets} -= 1; print STDERR "inBrackets -> $parserState->{inBrackets}\n" if ($sodDebug); } # end if ($part !~ /[;\[\]]/o) if (!($part eq $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 $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 ($parserState->{seenBraces}) { # print "SEENBRACES. TP: $treepart PT: $part\n"; if ($treepart) { $parserState->{functionContents} .= $treepart; } else { $parserState->{functionContents} .= $part; } # print "SEENBRACES. FC: ".$parserState->{functionContents}."\n"; } 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 $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); 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 (!$parserState->{seenBraces}) { # 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); } $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); } } 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; setHollowWithLineNumbers(\$parserState, $treeCur, $fileoffset, $inputCounter); $sethollow = 0; } print STDERR "TSPUSH\n" if ($tsDebug || $treeDebug); push(@treeStack, $treeCur); $treeCur = $treeCur->addChild("", 0); bless($treeCur, "HeaderDoc::ParseTree"); } } } 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}) { # print STDERR "WARNING: RETURN TYPE CHANGE[A]".$parserState->{returntype}." CHANGED TO $declaration$curline.\n"; $parserState->{returntype} = "$declaration$curline"; } elsif (!$parserState->{freezereturn} && !$parserState->{hollow}) { # print STDERR "WARNING: RETURN TYPE CHANGE[B]".$parserState->{returntype}." CHANGED TO $curline.\n"; $parserState->{returntype} = "$curline"; $declaration = ""; # } else { # print STDERR "WARNING: LEAVING RETURN TYPE ALONE: ".$parserState->{returntype}." NOT CHANGED TO $curline.\n"; } # 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. if (($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) || !$ignoretoken) { if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !$ppSkipOneToken) { if ($parsedParamParse == 1) { $parsedParam .= $part; } elsif ($parsedParamParse == 2) { $parsedParamParse = 1; print STDERR "parsedParamParse -> 1\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 (!$parserState->{seenBraces}) { # 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); print STDERR "KRC: $parserState->{kr_c_function} SB: $parserState->{seenBraces}\n" if ($localDebug); if (!($bsCount - $parserState->{initbsCount}) && $parserState->{lastsymbol} =~ /;\s*$/o) { # print STDERR "DPA\n"; if ((!$parserState->{kr_c_function} || $parserState->{seenBraces}) && !$parserState->{inMacro}) { # print STDERR "DPB\n"; if (!scalar(@parserStack)) { $continue = 0; print STDERR "continue -> 0 [3]\n" if ($localDebug); } elsif (!$parserState->{onlyComments}) { # Process entry here if ($parserState->{noInsert}) { print STDERR "parserState insertion skipped[SEMI-1]\n" if ($parserStackDebug); } elsif ($parserState->{hollow}) { my $treeRef = $parserState->{hollow}; $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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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 "bsCount: $bsCount - $parserState->{initbsCount}, ls: $parserState->{lastsymbol}\n" if ($localDebug); pbs(@braceStack); } if (!($bsCount - $parserState->{initbsCount}) && $parserState->{seenBraces} && ($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}) { # Fix nesting. # print STDERR "LASTTREENODE -> $treeCur (".$treeCur->token().")\n"; while ($parserState->{treePopTwo}--) { $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [13]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } $treeCur = $treeCur->addSibling(";", 0); $parserState->{lastTreeNode} = $treeCur; $parserState->{treePopTwo} = 0; } if (!scalar(@parserStack)) { $continue = 0; print STDERR "continue -> 0 [4]\n" if ($localDebug); } elsif (!$parserState->{onlyComments}) { # Process entry here if ($parserState->{noInsert}) { print STDERR "parserState insertion skipped[SEMI-2]\n" if ($parserStackDebug); } elsif ($parserState->{hollow}) { my $treeRef = $parserState->{hollow}; $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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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 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 ($localDebug || $liteDebug); } 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}); } else { cpp_add($parserState->{hollow}, 1); $HeaderDoc::skipNextPDefine = 0; } } if ($parserState->{noInsert}) { print STDERR "parserState insertion skipped\n" if ($parserStackDebug); } elsif ($parserState->{hollow}) { my $treeRef = $parserState->{hollow}; $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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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 "$filename:$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) { print STDERR "parserState pushed onto stack[token]\n" if ($parserStackDebug); $parserState->{lastTreeNode} = $treeCur; $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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); $parserState->{lastTreeNode} = $treeCur; $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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, $lbrace, $case_sensitive)) { $parserState->{ISFORWARDDECLARATION} = 0; 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; # } $parserState->{lastTreeNode} = $treeCur; $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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 (!casecmp($tok, $rbrace, $case_sensitive) && $part !~ /\)/) { # $parserState->{hollow} = $treeCur; setHollowWithLineNumbers(\$parserState, $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 (!casecmp($tok, $rbrace, $case_sensitive) && $part !~ /\)/) { setHollowWithLineNumbers(\$parserState, $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; } # end foreach (parts of the current line) } # end while (continue && ...) 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); $parserState->{lastTreeNode} = $treeCur; $parserState->{inputCounter} = $inputCounter; print STDERR "PARSERSTATE: $parserState\n" if ($localDebug); if ($parserState->{inMacro} == 3) { if (!$HeaderDoc::skipNextPDefine) { cpp_add($treeTop); } else { cpp_add($treeTop, 1); $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); while ($tempParserState) { $parserState = $tempParserState; $tempParserState = pop(@parserStack); } $HeaderDoc::module = $parserState->{MODULE}; if ($localDebug || $apDebug || $liteDebug || $parseDebug) { 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 "FC: ".$parserState->{functionContents}."\n"; return blockParseReturnState($parserState, $treeTop, $argparse, $declaration, $inPrivateParamTypes, $publicDeclaration, $lastACS, $retDebug, $fileoffset, 0, $definename, $inputCounter); } extendsClass: implementsClass: -=: LIST OF PARSED PARAMETERS :=- -=: DUMP OF PARSE TREE :=- +---sub +--- +---blockParse +---[ NEWLINE ] -=: COMPUTED VALUE :=- SUCCESS: 0 VALUE: 0 -=: CPP CHANGES :=- NO CPP CHANGES -=: FOUND MATCH :=- 1 -=: NAMED OBJECTS :=- TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::Header NAME: Perl function 2 APIUID: //test_ref/doc/header/Perl_function_2.test ABSTRACT: "" DISCUSSION: "

" UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::Header" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TREE COUNT: 1 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::Function NAME: blockParse APIUID: //test_ref/perl/func/blockParse ABSTRACT: "" DISCUSSION: "

The blockParse function is the core of HeaderDoc's parse engine. " UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "default_function_group" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::Function" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "0" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TAGGED PARAMETERS: TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::MinorAPIElement NAME: filename TYPE: APIUID: //test_ref/doc/functionparam/blockParse/filename ABSTRACT: "" DISCUSSION: "

the filename being parser." UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::MinorAPIElement" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::MinorAPIElement NAME: fileoffset TYPE: APIUID: //test_ref/doc/functionparam/blockParse/fileoffset ABSTRACT: "" DISCUSSION: "

the line number where the current block begins. The line number printed is (fileoffset + inputCounter)." UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::MinorAPIElement" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::MinorAPIElement NAME: inputLinesRef TYPE: APIUID: //test_ref/doc/functionparam/blockParse/inputLinesRef ABSTRACT: "" DISCUSSION: "

a reference to an array of code lines." UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::MinorAPIElement" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::MinorAPIElement NAME: inputCounter TYPE: APIUID: //test_ref/doc/functionparam/blockParse/inputCounter ABSTRACT: "" DISCUSSION: "

the offset within the array. This is added to fileoffset when printing the line number." UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::MinorAPIElement" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::MinorAPIElement NAME: argparse TYPE: APIUID: //test_ref/doc/functionparam/blockParse/argparse ABSTRACT: "" DISCUSSION: "

disable warnings when parsing arguments to avoid seeing them twice." UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::MinorAPIElement" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::MinorAPIElement NAME: ignoreref TYPE: APIUID: //test_ref/doc/functionparam/blockParse/ignoreref ABSTRACT: "" DISCUSSION: "

a reference to a hash of tokens to ignore on all headers." UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::MinorAPIElement" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::MinorAPIElement NAME: perheaderignoreref TYPE: APIUID: //test_ref/doc/functionparam/blockParse/perheaderignoreref ABSTRACT: "" DISCUSSION: "

a reference to a hash of tokens, generated from @ignore headerdoc comments." UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::MinorAPIElement" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::MinorAPIElement NAME: perheaderignorefuncmacrosref TYPE: APIUID: //test_ref/doc/functionparam/blockParse/perheaderignorefuncmacrosref ABSTRACT: "" DISCUSSION: "

a reference to a hash of tokens, generated from @ignorefunmacro headerdoc comments." UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::MinorAPIElement" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::MinorAPIElement NAME: keywordhashref TYPE: APIUID: //test_ref/doc/functionparam/blockParse/keywordhashref ABSTRACT: "" DISCUSSION: "

a reference to a hash of keywords." UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::MinorAPIElement" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::MinorAPIElement NAME: case_sensitive TYPE: APIUID: //test_ref/doc/functionparam/blockParse/case_sensitive ABSTRACT: "" DISCUSSION: "

boolean: controls whether keywords should be processed in a case-sensitive fashion." UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::MinorAPIElement" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: -=: NAMED OBJECT PARSE TREES :=- OBJECT: blockParse (HeaderDoc::Function) +---sub +--- +---blockParse +---[ NEWLINE ] END OF OBJECT -=: HTML OUTPUT OF PARSE TREES :=- OBJECT: blockParse (HeaderDoc::Function) sub blockParse END OF OBJECT $496862|-=: TOP LEVEL COMMENT PARSE VALUES :=- inHeader: 0 inClass: 0 inInterface: 0 inCPPHeader: 0 inOCCHeader: 0 inPerlScript: 0 inShellScript: 0 inPHPScript: 0 inJavaSource: 0 inFunctionGroup: 0 inGroup: 0 inFunction: 0 inPDefine: 0 inTypedef: 0 inUnion: 0 inStruct: 0 inConstant: 0 inVar: 0 inEnum: 0 inMethod: 0 inAvailabilityMacro: 0 inUnknown: 1 classType: unknown inputCounter: 0 blockOffset: 0 fullpath: /test_suite_bogus_path/Perl_function_2.test -=: BLOCKPARSE PARSER STATE KEYS :=- $parserState->{FULLPATH} => /test_suite_bogus_path/Perl_function_2.test $parserState->{NEXTTOKENNOCPP} => 0 $parserState->{availability} => $parserState->{backslashcount} => 0 $parserState->{basetype} => $parserState->{bracePending} => 0 $parserState->{callbackIsTypedef} => 0 $parserState->{callbackName} => $parserState->{callbackNamePending} => -1 $parserState->{categoryClass} => $parserState->{classtype} => $parserState->{curvarstars} => ********************************************************************************* $parserState->{freezeStack} => ARRAY(OBJID) $parserState->{freezereturn} => 1 $parserState->{frozensodname} => blockParse $parserState->{functionContents} => { my $filename = 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 $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 $cbnDebug = 0; my $macroDebug = 0; my $apDebug = 0; my $tsDebug = 0; my $treeDebug = 0; my $ilcDebug = 0; my $regexpDebug = 0; my $parserStackDebug = 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 $liteDebug = 0 || $HeaderDoc::fileDebug; # Just prints the tokens. my $parserStateInsertDebug = 0; $cppDebug = $cppDebugDefault || $HeaderDoc::fileDebug; # State variables (part 1 of 3) # my $typestring = ""; my $continue = 1; # set low when we're done. my $parsedParamParse = 0; # set high when current token is part of param. # 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 $perl_or_shell = 0; 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; 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" || $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(); # $parserState->{hollow} = $treeTop; setHollowWithLineNumbers(\$parserState, $treeTop, $fileoffset, $inputCounter); $parserState->{lang} = $lang; $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 $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 perl regexp. 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 ($sotemplate, $eotemplate, $operator, $soc, $eoc, $ilc, $ilc_b, $sofunction, $soprocedure, $sopreproc, $lbrace, $rbrace, $unionname, $structname, $enumname, $typedefname, $varname, $constname, $structisbrace, $macronameref, $classregexp, $classbraceregexp, $classclosebraceregexp, $accessregexp, $requiredregexp, $propname, $objcdynamicname, $objcsynthesizename, $moduleregexp, $definename) = parseTokens($lang, $sublang); my $macrore_pound = macroRegexpFromList($macronameref, 1); my $macrore_nopound = macroRegexpFromList($macronameref, 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 $propname\n"; if ($parseDebug) { print STDERR "SOT: $sotemplate EOF: $eotemplate OP: $operator SOC: $soc EOC: $eoc ILC: $ilc ILC_B: $ilc_b\n"; print STDERR "SOFUNC: $sofunction SOPROC: $soprocedure SOPREPROC: $sopreproc LBRACE: $lbrace RBRACE: $rbrace\n"; print STDERR "UNION: $unionname STRUCT: $structname TYPEDEF: $typedefname VAR: $varname CONST: $constname\n"; print STDERR "STRUCTISBRACE: $structisbrace MACRONAMEREF: $macronameref 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") { $perl_or_shell = 1; if ($lang eq "perl") { $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; if ($lang eq "pascal") { $pascal = 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 $categoryClass = ""; # my $classtype = ""; # my $inClass = 0; my $pushParserStateAfterToken = 0; my $pushParserStateAfterWordToken = 0; my $pushParserStateAtBrace = 0; my $occPushParserStateOnWordTokenAfterNext = 0; $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 "INCOMING INPUTCOUNTER: $inputCounter\n" if ($HeaderDoc::inputCounterDebug); while ($continue && ($inputCounter <= $nlines)) { $HeaderDoc::CurLine = $inputCounter + $fileoffset; my $line = $inputLines[$inputCounter++]; print STDERR "GOT LINE: $line\n" if (($localDebug && $apDebug) || $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 "CHANGED LINE FROM \"$line\" to \"$1\"\n" if ($localDebug || $liteDebug); $line = $1."\n"; } } print STDERR "LINE[$inputCounter] : $line\n" if ($offsetDebug); # The tokenizer if ($lang eq "perl" || $lang eq "shell") { @parts = split(/("|'|\#|\{|\}|\(|\)|\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) {foreach my $partlist (@parts) {print STDERR "PARTLIST: \"$partlist\"\n"; }} # 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; # print STDERR "CHECK LINE $line\n"; if ($line =~ /^\s*#include (.*)$/) { my $rest = $1; $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 "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; while ($pos < scalar(@parts)) { my $part = $parts[$pos]; my $noCPPThisToken = 0; if (length($part)) { if (!$inChar && !$inString && !$inComment && !$inSLC) { if ($parserState->{NEXTTOKENNOCPP} == 1) { # We're in an "if" block. if ($part eq "defined") { $parserState->{NEXTTOKENNOCPP} = 3; } } elsif ($parserState->{NEXTTOKENNOCPP} == 2) { # 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) { # 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)/) { $parserState->{NEXTTOKENNOCPP} = 2; } elsif ($inCPPSpecial && $part =~ /if/) { $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 $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 $soc) { print STDERR "SOC\n"if ($cppleaddebug); $inComment = 1; } elsif (!$inComment && ($part eq $ilc || $part eq $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) { ($newpart, $hasargs) = 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) { $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 \"$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; } } 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) { print STDERR "CPPS: \"$cppstring\"\n"; warn "Non-terminated macro.\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 "CHANGED LINE FROM \"$line\" to \"$1\"\n" if ($localDebug || $liteDebug); $line = $1."\n"; } } print STDERR "INCREMENTED INPUTCOUNTER [2]\n" if ($HeaderDoc::inputCounterDebug); # @parts = split(/(\W)/, $line); if ($lang eq "perl" || $lang eq "shell") { @parts = split(/("|'|\#|\{|\}|\(|\)|\s|;|\\|\W)/, $line); } else { @parts = split(/("|'|\/\/|\/\*|\*\/|::|==|<=|>=|!=|\<\<|\>\>|\{|\}|\(|\)|\s|;|\\|\W)/, $line); } } } until (!$incppargs && !$inComment); # The tokenizer if ($lang eq "perl" || $lang eq "shell") { @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); # 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; $treeSkip = 0; # $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); $forcenobreak = 0; if ($nextpart eq "\r") { $nextpart = "\n"; } if ($localDebug && $nextpart eq "\n") { print STDERR "NEXTPART IS NEWLINE!\n"; } if ($localDebug && $part eq "\n") { 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); print STDERR "CURLINE IS \"$curline\"\n" if ($localDebug || $hangDebug); 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); } } elsif ($occPushParserStateOnWordTokenAfterNext) { # if ($part !~ /(\s|<)/) if ($part =~ /(\/\/|\/\*|\-|\+|\w|\@)/) { $parserState->{lastTreeNode} = $treeCur; print STDERR "parserState pushed onto stack[occPushParserStateOnWordTokenAfterNext]\n" if ($parserStackDebug); $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 0; $parserState->{lang} = $lang; $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++; } 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} inRegexp: $inRegexp\n"; print STDERR "PART: regexpNoInterpolate: $regexpNoInterpolate\n"; 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 ($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); printf("PART: $part TEMPAVAIL: $tempavail\n") if ($localDebug || $gccAttributeDebug); if ($tempavail && ($tempavail ne "1") && ($tempavail ne "2")) { $parserState->{availability} = $tempavail; } elsif ($tempavail eq "2") { # Reusing the GCC attribute handling code because that does exactly what we need. print STDERR "Function-like availability macro detected. Collecting.\n" if ($localDebug || $gccAttributeDebug); $parserState->{attributeState} = 1; $parserState->{attributeParts} = (); # Add __attribute__ as the next token. $treeCur = $treeCur->addSibling($part, 0); 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; } # Handle the GCC "__attribute__" extension outside the context of # the parser because it isn't part of the language and massively # breaks the syntax. if ($lang eq "C" && isKeyword($part, $keywordhashref, $case_sensitive) == 2) { print STDERR "GCC attribute detected. Collecting.\n" if ($localDebug || $gccAttributeDebug); $parserState->{attributeState} = 1; $parserState->{attributeParts} = (); # Add __attribute__ as the next token. $treeCur = $treeCur->addSibling($part, 0); push(@treeStack, $treeCur); # Nest all contents one level lower. $treeCur = $treeCur->addChild("", 0); $part = $nextpart; next; } elsif ($parserState->{attributeState} == 1) { if ($part eq "(") { print STDERR "GCC attribute open paren\n" if ($localDebug || $gccAttributeDebug); $parserState->{attributeState} = -1; } $treeCur = $treeCur->addSibling($part, 0); $part = $nextpart; next; } elsif ($parserState->{attributeState} < 0) { if ($part eq "(") { $parserState->{attributeState}--; print STDERR "GCC attribute open paren, count=".(0-$parserState->{attributeState})."\n" if ($localDebug || $gccAttributeDebug); } elsif ($part eq ")") { $parserState->{attributeState}++; print STDERR "GCC attribute close paren, count=".(0-$parserState->{attributeState})."\n" if ($localDebug || $gccAttributeDebug); } $treeCur = $treeCur->addSibling($part, 0); if (($localDebug || $gccAttributeDebug) && !$parserState->{attributeState}) { print STDERR "GCC attribute: done collecting.\n"; # Get back to where we started. $treeCur = pop(@treeStack); } $part = $nextpart; next; } # Here be the parser. Abandon all hope, ye who enter here. $treepart = ""; 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 print STDERR "parserState pushed onto stack[PROTOCOL]\n" if ($parserStackDebug); $parserState->{inProtocol} = -1; $parserState->{lastTreeNode} = $treeCur; $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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); # $parserState->{lastTreeNode} = $treeCur; # push(@parserStack, $parserState); # $parserState = HeaderDoc::ParserState->new(); # $parserState->{lang} = $lang; # $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); $parserState->{lastTreeNode} = $treeCur; print STDERR "parserState pushed onto stack[cparen2]\n" if ($parserStackDebug); $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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"; if ($part eq ":") { print STDERR "INCLASS COLON\n" if ($parseDebug || $classDebug); $parserState->{forceClassName} = $parserState->{sodname}; $parserState->{forceClassSuper} = ""; # print STDERR "XSUPER: $parserState->{forceClassSuper}\n"; } elsif ($part eq "{" || $part eq ";") { print STDERR "INCLASS BRCSEMI\n" if ($parseDebug || $classDebug); $parserState->{forceClassDone} = 1; if ($parserState->{classIsObjC} && $part eq "{") { $parserState->{ISFORWARDDECLARATION} = 0; $parserState->{lastTreeNode} = $treeCur; print STDERR "parserState pushed onto stack[OCC-BRCSEMI]\n" if ($parserStackDebug); $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 0; $parserState->{lang} = $lang; $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}) { 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->{classIsObjC}) { print STDERR "INCLASS NOTOBJC (OTHER)\n" if ($parseDebug || $classDebug); 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}; } # } 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 $ilc || $part eq $ilc_b) && ($lang ne "perl" || $lasttoken ne "\$")) { # print STDERR "should be ILC?\n"; # } else { # print STDERR "NO CHANEC: PART \"$part\" ILC \"$ilc\" ILC_B: \"ilc_b\" LANG: \"$lang\" LASTTOKEN: \"$lasttoken\"\n"; # } SWITCH: { # Blank declaration handlers (mostly for misuse of # OSMetaClassDeclareReservedUsed and similar) (($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; }; # 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 "$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|pragma|import|include)/ && ($part ne $definename)) || ($parserState->{inMacro} == 0 && $macrore_nopound ne "" && $part =~ /$macrore_nopound/)) # (($parserState->{inMacro} == 1 && $part =~ /(if|ifdef|ifndef|endif|else|undef|elif|pragma|import|include)/ )) && do (!$parserState->{inComment} && (($parserState->{inMacro} == 1 && $macrore_pound ne "" && $part =~ /^$macrore_pound$/ && ($part ne $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|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 "$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|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 "$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 $soc) && ($part ne $eoc) && $part =~ /\s/) && do { $treepart = $part; $part = ""; last SWITCH; }; ($parserState->{inMacro} == 1 && ($part ne $soc) && ($part ne $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 $soc) && ($part ne $eoc)) && do { print STDERR "INMACRO OTHERTOKEN: CASE 06\n" if ($liteDebug); print STDERR "INMACRO > 1, PART NE //" if ($parseDebug || $localDebug); if ($part eq "\\") { $parserState->addBackslash(); } elsif ($part !~ /[ \t]/) { $parserState->addBackslash(); } print STDERR "PART: $part\n" if ($macroDebug); if ($parserState->{seenMacroPart} && $HeaderDoc::truncate_inline) { 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; } elsif ($part =~ /[\{\(]/o) { print STDERR "MACRO: BRACE\n" if ($macroDebug); if (!$parserState->{macroNoTrunc}) { # $parserState->{seenBraces} = 1; $HeaderDoc::hidetokens = 3; } } else { print STDERR "MACRO: OTHERTOKEN\n" if ($macroDebug); $parserState->{macroNoTrunc} = 2; } } } if ($part =~ /[\{\(]/o) { push(@braceStack, $part); print STDERR "PUSH\n" if ($macroDebug); } elsif ($part =~ /[\}\)]/o) { if ($part ne peekmatch(\@braceStack, $filename, $inputCounter)) { if ($parserState->{macroNoTrunc} == 1) { # We haven't reached the end of the first part of the declaration, so this is an error. warn("$filename:$inputCounter: warning: Initial braces in macro name do not match.\nWe may have a problem.\n"); } } pop(@braceStack); print STDERR "POP\n" if ($macroDebug); } 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 # print STDERR "IRE: $inRegexp IRT: $inRegexpTrailer IS: $parserState->{inString} ICo $parserState->{inComment} ILC: $parserState->{inInlineComment} ICh $parserState->{inChar}\n"; (length($regexppattern) && $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? $inRegexp = 2; } else { $inRegexp = 4; # print STDERR "REGEXP PART IS \"$part\"\n"; if ($part eq "tr") { $regexpNoInterpolate = 1; } # if ($part =~ /tr/) { $regexpNoInterpolate = 1; } } last SWITCH; }; # end regexppattern (($inRegexp || $parserState->{lastsymbol} eq "~") && (length($regexpcharpattern) && $part =~ /^($regexpcharpattern)$/ && (!scalar(@regexpStack) || $part eq peekmatch(\@regexpStack, $filename, $inputCounter)))) && do { print STDERR "REGEXP CHARACTER: CASE 08\n" if ($liteDebug); print STDERR "REGEXP?\n" if ($regexpDebug); if (!$inRegexp) { $inRegexp = 2; } # if ($lasttoken eq "\\") if ($parserState->isQuoted($lang. $sublang)) { # jump to next match. $lasttoken = $part; $parserState->{lastsymbol} = $part; next SWITCH; } print STDERR "REGEXP POINT A\n" if ($regexpDebug); $lasttoken = $part; $parserState->{lastsymbol} = $part; if ($part eq "#" && ((scalar(@regexpStack) != 1) || (peekmatch(\@regexpStack, $filename, $inputCounter) ne "#"))) { if ($nextpart =~ /^\s/o) { # it's a comment. jump to next match. next SWITCH; } } print STDERR "REGEXP POINT B\n" if ($regexpDebug); if (!scalar(@regexpStack)) { push(@regexpStack, $part); $inRegexp--; } else { my $match = peekmatch(\@regexpStack, $filename, $inputCounter); my $tos = pop(@regexpStack); if (!scalar(@regexpStack) && ($match eq $part)) { $inRegexp--; if ($inRegexp == 2 && $tos eq "/") { # we don't double the slash in the # middle of a s/foo/bar/g style # expression. $inRegexp--; } if ($inRegexp) { push(@regexpStack, $tos); } } elsif (scalar(@regexpStack) == 1) { push(@regexpStack, $tos); if ($tos =~ /['"`]/o || $regexpNoInterpolate) { # these don't interpolate. next SWITCH; } } else { push(@regexpStack, $tos); if ($tos =~ /['"`]/o || $regexpNoInterpolate) { # these don't interpolate. next SWITCH; } push(@regexpStack, $part); } } print STDERR "REGEXP POINT C\n" if ($regexpDebug); if (!$inRegexp) { $inRegexpTrailer = 2; } last SWITCH; }; # end regexpcharpattern # Start of preprocessor macros ($part eq "$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); } 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 "$sofunction" || $part eq "$soprocedure") && do { print STDERR "SOFUNC: CASE 10\n" if ($liteDebug); $parserState->{sodclass} = "function"; print STDERR "K&R C FUNCTION FOUND [1].\n" if ($localDebug); $parserState->{kr_c_function} = 1; $parserState->{typestring} = "function"; $parserState->{startOfDec} = 2; $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); last SWITCH; }; # C++ destructor handler. ($part =~ /\~/o && $lang eq "C" && $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 && $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; $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) && do { print STDERR "NEWLINE: CASE 13\n" if ($liteDebug); # NEWLINE FOUND $treepart = $part; if ($inRegexp) { warn "$filename:$inputCounter: warning: multi-line regular expression\n"; } print STDERR "NLCR\n" if ($tsDebug || $treeDebug || $localDebug); 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; } else { $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); print STDERR "skipped pushing CPP directive $parsedParam into parsedParamList [1]\n" if ($parmDebug || $cppDebug || $localDebug); $parsedParam = ""; } } } if ($treePopOnNewLine < 0) { # pop once for //, possibly again for macro $treePopOnNewLine = 0 - $treePopOnNewLine; $treeCur = $treeCur->addSibling($treepart, 0); bless($treeCur, "HeaderDoc::ParseTree"); # push(@treeStack, $treeCur); $treeSkip = 1; $treeCur = pop(@treeStack); if (!$treeCur) { $treeCur = $treeTop; warn "$filename:$inputCounter: warning: Attempted to pop off top of tree\n"; } $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [1]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if ($treePopOnNewLine == 1 || ($treePopOnNewLine && !$parserState->isQuoted())) { # $parserState->{lastsymbol} ne "\\" $treeCur = $treeCur->addSibling($treepart, 0); bless($treeCur, "HeaderDoc::ParseTree"); # push(@treeStack, $treeCur); $treeSkip = 1; $treeCur = pop(@treeStack); if (!$treeCur) { $treeCur = $treeTop; warn "$filename:$inputCounter: warning: Attempted to pop off top of tree\n"; } $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->addSibling("", 0); # empty token print STDERR "TSPOP [1a]\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 $sotemplate && !$parserState->{seenBraces} && ($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(@braceStack, $part); pbs(@braceStack); if (!$parserState->{seenBraces}) { # TREEDONE $treeNest = 1; 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 $eotemplate && !$parserState->{seenBraces} && ($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); if (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [2]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if ($top ne "$sotemplate") { warn("$filename:$inputCounter: warning: Template (angle) brackets do not match.\nWe may have a problem.\n"); } } last SWITCH; }; # # Handles C++ access control state, e.g. "public:" # ($part eq ":") && 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 (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) { 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); $parserState->{hollow} = undef; $parserState->{onlyComments} = 1; print STDERR "hollowskip -> 1 (ACS)\n" if ($parserStateInsertDebug); $hollowskip = 1; $HeaderDoc::AccessControlState = $1; $lastACS = $1; last SWITCH; } elsif ($parserState->{typestring} eq "struct") { if (!(scalar(@braceStack) - $parserState->{initbsCount})) { if (!$parserState->{structClassName}) { $parserState->{structClassName} = $parserState->{lastsymbol}; $parserState->{bracePending} = 2; } } } } }; (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 MATCH: \"$part\"\n" if ($localDebug || $parseDebug); $hollowskip = 1; print STDERR "hollowskip -> 1 (requiredregexp)\n" if ($parserStateInsertDebug); last SWITCH; }; # # C++ copy constructor handler. For example: # # char *class(void *a, void *b) : # class(pri_type, pri_type); # ($part eq ":") && 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" && $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\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 (!$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 { next SWITCH; } }; # Non-newline, non-carriage-return whitespace handler. ($part =~ /\s/o) && do { print STDERR "Whitespace: CASE 19\n" if ($liteDebug); # 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 "\"") && 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})) { $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 (!$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 (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [3]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } } $parserState->{inString} = (1-$parserState->{inString}); } } $lastchar = $part; $parserState->{lastsymbol} = ""; last SWITCH; }; ($part eq "[") && do { print STDERR "LEFT BRACKET: CASE 22\n" if ($liteDebug); # left square bracket (square brace) if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate)) { 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(@braceStack, $part); pbs(@braceStack); if (!$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; } $lastchar = $part; last SWITCH; }; ($part eq "]") && do { print STDERR "CLOSE BRACKET: CASE 23\n" if ($liteDebug); # right square bracket (square brace) if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate)) { print STDERR "rbracket\n" if ($localDebug); if (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inString})) { $parserState->{onlyComments} = 0; print STDERR "[g]onlyComments -> 0\n" if ($macroDebug); } my $top = pop(@braceStack); if (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [4]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if ($top ne "[") { warn("$filename:$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; } $lastchar = $part; last SWITCH; }; ($part eq "'") && do { print STDERR "SINGLE QUOTE: CASE 24\n" if ($liteDebug); print STDERR "squo\n" if ($localDebug); if (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inString})) { # 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 (!$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 (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [5]\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 $ilc || $part eq $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} = 4; print STDERR "inInlineComment -> 1\n" if ($ilcDebug); $curline = spacefix($curline, $part, $lastchar, $soc, $eoc, $ilc, $ilc_b); if (!$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("$filename:$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 $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 (!$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("$filename:$linenum: warning: Nested comment found [2]. Ignoring.\n"); } } $parserState->{lastsymbol} = ""; $lastchar = $part; last SWITCH; }; ($part eq $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; $curline = spacefix($curline, $part, $lastchar); $ppSkipOneToken = 1; if (!$parserState->{seenBraces}) { $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [6]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } } elsif (!$parserState->{inComment} && !$parserState->{inInlineComment} && !$parserState->{inString} && !$parserState->{inChar} && !$inRegexp) { my $linenum = $inputCounter + $fileoffset; warn("$filename:$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::test_mode)) { warn("$filename:$linenum: warning: Nested comment found [3]. Ignoring.\n"); } } $parserState->{lastsymbol} = ""; $lastchar = $part; last SWITCH; }; # Parenthesis and brace handlers. ($part eq "(") && do { print STDERR "OPEN PAREN: CASE 28\n" if ($liteDebug); my @tempppl = undef; if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate)) { if (!(scalar(@braceStack)-$parserState->{initbsCount})) { # start parameter parsing after this token print STDERR "parsedParamParse -> 2\n" if ($parmDebug); $parsedParamParse = 2; 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"; # 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->{returntype} = "$declaration$curline"; } elsif (!$parserState->{freezereturn} && !$parserState->{hollow}) { $parserState->{returntype} = "$curline"; $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); 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"; # $parserState->{callbackName} = ""; $parserState->{functionReturnsCallback}++; print "Function returning callback. NAME: $parserState->{cbsodname}\n" if ($parmDebug || $localDebug || $parseDebug); print STDERR "parsedParamParse -> 2\n" if ($parmDebug); $parsedParamParse = 2; print STDERR "parsedParamList wiped\n" if ($parmDebug); @tempppl = @{$parserState->{parsedParamList}}; @{$parserState->{parsedParamList}} = (); $parsedParam = ""; } } if ($parserState->{inOperator} == 1) { $parserState->{inOperator} = 2; } push(@braceStack, $part); pbs(@braceStack); if (!$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) { $parserState->{sodclass} = "function"; $parserState->{freezereturn} = 1; $parserState->{returntype} =~ s/^\s*//so; $parserState->{returntype} =~ s/\s*$//so; } $parserState->{startOfDec} = 0; 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 "OUTGOING CURLINE: \"$curline\"\n" if ($localDebug); last SWITCH; }; ($part eq ")") && do { print STDERR "CLOSE PAREN: CASE 29\n" if ($liteDebug); if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate && (peek(\@regexpStack) ne "("))) { if ((scalar(@braceStack)-$parserState->{initbsCount} - $parserState->{functionReturnsCallback}) == 1) { # stop parameter parsing $parsedParamParse = 0; print STDERR "parsedParamParse -> 0\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 = pop(@braceStack); pbs(@braceStack); if (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [6a]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if (!($test eq "(")) { # ) brace hack for vi warn("$filename:$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; 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; }; (casecmp($part, $lbrace, $case_sensitive)) && do { print STDERR "LEFT BRACE: CASE 30\n" if ($liteDebug); if ($parserState->{onlyComments} && !$parserState->{inComment} && !$parserState->{inInlineComment} && !$parserState->{inChar} && !($inRegexp && $regexpNoInterpolate) && scalar(@parserStack)) { # 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 && $regexpNoInterpolate)) { $parserState->{bracePending} = 0; print STDERR "bracePending -> 0 [brace]\n" if ($localDebug); $parserState->{onlyComments} = 0; print STDERR "[k]onlyComments -> 0\n" if ($macroDebug); 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\n" if ($parmDebug); } # start parameter parsing after this token print STDERR "parsedParamParse -> 2\n" if ($parmDebug); $parsedParamParse = 2; # 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 "seenBraces -> 1\n" if ($parseDebug); $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(@braceStack, $part); pbs(@braceStack); if (!$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; 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; }; (casecmp($part, $rbrace, $case_sensitive)) && do { print STDERR "RIGHT BRACE: CASE 31\n" if ($liteDebug); if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate && (peek(\@regexpStack) ne "$lbrace"))) { 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); my $bsCount = scalar(@braceStack); if (scalar(@parserStack) && !($bsCount - $parserState->{initbsCount})) { print STDERR "parserState: ENDOFSTATE\n" if ($parserStackDebug); if ($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}; $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; $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 [1a]\n" if ($localDebug || $liteDebug); $parserState->{noInsert} = 0; $continue = 0; print STDERR "AT END: REALPS IS ".$parserState->{REALPS}."\n" if ($parserStackDebug || $localDebug); print STDERR "STACK COUNT: ".scalar(@parserStack)."\n" if ($parserStackDebug || $localDebug); } if ($lang eq "php" || ($lang eq "C" && $sublang eq "IDL")) { # print STDERR "PHP OUT OF BRACES?: ".scalar(@braceStack)."\n"; if (scalar(@braceStack) == 1) { # PHP and IDL classes end at # the brace. print STDERR "continue -> 0 [1a]\n" if ($localDebug || $liteDebug); $continue = 0; } } 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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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); } if ((scalar(@braceStack)-$parserState->{initbsCount}) == 1) { # stop parameter parsing $parsedParamParse = 0; print STDERR "parsedParamParse -> 0\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 = ""; } else { # start parameter parsing after this token print STDERR "parsedParamParse -> 2\n" if ($parmDebug); $parsedParamParse = 2; } 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\n" if ($parmDebug); } print STDERR "rbrace\n" if ($localDebug); my $test = pop(@braceStack); pbs(@braceStack); if (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [7]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if (!($test eq "$lbrace") && (!length($structname) || (!($test eq $structname) && $structisbrace))) { warn("$filename:$inputCounter: warning: Braces do not match.\nWe may have a problem.\n"); warn("Declaration to date: $declaration$curline\n"); } $curline = spacefix($curline, $part, $lastchar); $parserState->{lastsymbol} = ""; $lastchar = $part; $parserState->{startOfDec} = 0; 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($propname) && $propname =~ /\@/) || length($objcdynamicname) || length($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 $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 $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 $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 $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, $filename, $inputCounter)) { warn("$filename:inputCounter: warning: Class braces do not match.\nWe may have a problem.\n"); } $parserState->{seenBraces} = 1; pop(@braceStack); $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [6]\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; $HeaderDoc::module = $parserState->{MODULE}; $continue = 0; print STDERR "continue -> 0 [occend]\n" if ($localDebug); } 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}; $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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $parserState->{inputCounter} = $inputCounter; $parserState->{initbsCount} = scalar(@braceStack); } print STDERR "parserState popped from parserStack[\@end]\n" if ($parserStackDebug); $parserState = pop(@parserStack) || $parserState; $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. ### ($sotemplate, $eotemplate, $operator, $soc, $eoc, $ilc, $ilc_b, $sofunction, ### $soprocedure, $sopreproc, $lbrace, $rbrace, $unionname, $structname, ### $enumname, ### $typedefname, $varname, $constname, $structisbrace, $macronameref, ### $classregexp, $classbraceregexp, $classclosebraceregexp, $accessregexp, ### $requiredregexp, $propname, $objcdynamicname, $objcsynthesizename, $moduleregexp, $definename) = parseTokens($lang, $sublang); ### print STDERR "PROPNAME NOW $propname\n" if ($localDebug || $parseDebug || $classDebug); my $localclasstype = $1; if ($part =~ /^\@/) { $part =~ s/^\@//s; } if (!(scalar(@braceStack)-$parserState->{initbsCount})) { if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) { print STDERR "ITISACLASS\n" if ($localDebug); if (!length($parserState->{sodclass})) { 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"; $parserState->{classtype} = $localclasstype; $parserState->{preclasssodtype} = $parserState->{sodtype} . $part; $parserState->{sodtype} = ""; $parserState->{startOfDec} = 1; $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(@braceStack, $localclasstype); pbs(@braceStack); $treeNest = 1; if ($treeDebug) { print STDERR "TS TREENEST -> 1 [17]\n"; } # } else { # print STDERR "CBRE: \"$classbraceregexp\"\n"; } ($lang, $sublang) = getLangAndSublangFromClassType($localclasstype); $HeaderDoc::lang = $lang; $HeaderDoc::sublang = $sublang; ($sotemplate, $eotemplate, $operator, $soc, $eoc, $ilc, $ilc_b, $sofunction, $soprocedure, $sopreproc, $lbrace, $rbrace, $unionname, $structname, $enumname, $typedefname, $varname, $constname, $structisbrace, $macronameref, $classregexp, $classbraceregexp, $classclosebraceregexp, $accessregexp, $requiredregexp, $propname, $objcdynamicname, $objcsynthesizename, $moduleregexp, $definename) = parseTokens($lang, $sublang); my $macrore = macroRegexpFromList($macronameref); # print STDERR "PROPNAME2: $propname\n"; print STDERR "ARP: $accessregexp\n" if ($localDebug); last SWITCH; } } } }; ($part eq $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 $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 $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 $structname || $part eq $enumname || $part eq $unionname) && do { print STDERR "STRUCT/ENUM/UNION: CASE 36\n" if ($liteDebug); if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) { if ($structisbrace) { if ($parserState->{sodclass} eq "function") { $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(@braceStack, $part); pbs(@braceStack); if (!$parserState->{seenBraces}) { # 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; 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 (!$parserState->{seenBraces}) { # TREEDONE # $treePopTwo++; # $treeNest = 1; # push(@treeStack, $treeCur); # $treeCur = $treeCur->addChild($part, 0); $treeSkip = 1; # bless($treeCur, "HeaderDoc::ParseTree"); # } } $parserState->{onlyComments} = 0; print STDERR "[n]onlyComments -> 0\n" if ($macroDebug); $continuation = 1; # $parserState->{simpleTypedef} = 0; if ($parserState->{basetype} eq "") { $parserState->{basetype} = $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 "sodname cleared (seu)\n" if ($sodDebug); } $lastchar = $part; }; # end if }; # end do ($part =~ /^$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; $parserState->{simpleTypedef} = 1; print STDERR "simpleTypedef -> 1\n" if ($localDebug); # previous case falls through, so be explicit. if ($part =~ /^$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 "sodname cleared ($typedefname)\n" if ($sodDebug); } $lastchar = $part; }; # end if }; # end do # C++ operator keyword handler ($part eq "$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->{lastsymbol} = $part; $lastchar = $part; last SWITCH; # next; }; # Punctuation handlers ($part =~ /;/o) && do { print STDERR "SEMICOLON: CASE 39\n" if ($liteDebug); if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) { if ($parsedParamParse) { $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 $parsedParamParse = 2; $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; $continuation = 1; if ($parserState->{occmethod}) { $prespaceadjust = -$prespace; } # previous case falls through, so be explicit. if ($part =~ /;/o && !$parserState->{inMacroLine} && !$parserState->{inMacro}) { my $bsCount = scalar(@braceStack)-$parserState->{initbsCount}; if (!$bsCount && !$parserState->{kr_c_function}) { if ($parserState->{startOfDec} == 2) { $parserState->{sodclass} = "constant"; $parserState->{startOfDec} = 1; } elsif (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar} || $parserState->{inString})) { $parserState->{startOfDec} = 1; } # $parserState->{lastsymbol} .= $part; } if (!$bsCount) { $treeCur = $treeCur->addSibling(";"); $treepart = " "; # $treeSkip = 1; if (0) { $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [8]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } # $parserState->{lastTreeNode} = $treeCur; # print STDERR "LASTTREENODE -> $treeCur (".$treeCur->token().")\n"; while ($parserState->{treePopTwo}--) { $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [9]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } $parserState->{treePopTwo} = 0; } } $lastchar = $part; }; # end if }; # end do ($part eq "=" && ($parserState->{lastsymbol} ne "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 "[q]onlyComments -> 0\n" if ($macroDebug); if ($part =~ /=/o && !(scalar(@braceStack)-$parserState->{initbsCount}) && $nextpart !~ /=/o && $lastchar !~ /=/o && $parserState->{sodclass} ne "function" && !$inPType) { print STDERR "valuepending -> 1\n" if ($valueDebug); $parserState->{valuepending} = 1; $parserState->{preEqualsSymbol} = $parserState->{lastsymbol}; $parserState->{sodclass} = "constant"; $parserState->{startOfDec} = 0; }; # 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); } if ($part =~ /,/o && $parsedParamParse && !($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && ((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 $parsedParamParse = 2; print STDERR "parsedParamParse -> 2\n" if ($parmDebug); }; # end if }; # end do ($part =~ /[*^]/) && do { if ($lastnspart eq "(" && # ")" !($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !$parserState->{callbackNamePending} && ((scalar(@braceStack)-$parserState->{initbsCount}) == 1)) { # print "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})) { if (!ignore($part, $ignoreref, $perheaderignoreref)) { 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 (!$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}; $parsedParamParse = 1; print STDERR "parsedParamParse -> 1\n" if ($parmDebug); } } } } $lastchar = $part; if ($part =~ /\w/o || $part eq "::") { if ($parserState->{callbackNamePending} == 1) { if (!($part eq $structname || $part eq $enumname || $part eq $unionname || $part eq $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} = ""; $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"; $parserState->{sodclass} = "constant"; $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 !~ /[,;\[\]]/o && !$parserState->{inBrackets}) { my $opttilde = ""; if ($parserState->{seenTilde}) { $opttilde = "~"; } 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}) { print STDERR "Setting sodname (maybe type) to \"$part\"\n" if ($sodDebug); $parserState->{sodname} = $opttilde.$part; if ($part =~ /\w/o) { $parserState->{startOfDec}++; } } 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}) { if ($parserState->{inOperator} == 1) { $parserState->{sodname} .= $part; } else { if (length($parserState->{sodname})) { $parserState->{sodtype} .= " $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; } } elsif ($part eq "[") { # if ($part !~ /[;\[\]]/o) $parserState->{inBrackets} += 1; print STDERR "inBrackets -> $parserState->{inBrackets}\n" if ($sodDebug); } elsif ($part eq "]") { $parserState->{inBrackets} -= 1; print STDERR "inBrackets -> $parserState->{inBrackets}\n" if ($sodDebug); } # end if ($part !~ /[;\[\]]/o) if (!($part eq $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 $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 ($parserState->{seenBraces}) { # print "SEENBRACES. TP: $treepart PT: $part\n"; if ($treepart) { $parserState->{functionContents} .= $treepart; } else { $parserState->{functionContents} .= $part; } # print "SEENBRACES. FC: ".$parserState->{functionContents}."\n"; } 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 $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); 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 (!$parserState->{seenBraces}) { # 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); } $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); } } 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; setHollowWithLineNumbers(\$parserState, $treeCur, $fileoffset, $inputCounter); $sethollow = 0; } print STDERR "TSPUSH\n" if ($tsDebug || $treeDebug); push(@treeStack, $treeCur); $treeCur = $treeCur->addChild("", 0); bless($treeCur, "HeaderDoc::ParseTree"); } } } 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}) { # print STDERR "WARNING: RETURN TYPE CHANGE[A]".$parserState->{returntype}." CHANGED TO $declaration$curline.\n"; $parserState->{returntype} = "$declaration$curline"; } elsif (!$parserState->{freezereturn} && !$parserState->{hollow}) { # print STDERR "WARNING: RETURN TYPE CHANGE[B]".$parserState->{returntype}." CHANGED TO $curline.\n"; $parserState->{returntype} = "$curline"; $declaration = ""; # } else { # print STDERR "WARNING: LEAVING RETURN TYPE ALONE: ".$parserState->{returntype}." NOT CHANGED TO $curline.\n"; } # 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. if (($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) || !$ignoretoken) { if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !$ppSkipOneToken) { if ($parsedParamParse == 1) { $parsedParam .= $part; } elsif ($parsedParamParse == 2) { $parsedParamParse = 1; print STDERR "parsedParamParse -> 1\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 (!$parserState->{seenBraces}) { # 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); print STDERR "KRC: $parserState->{kr_c_function} SB: $parserState->{seenBraces}\n" if ($localDebug); if (!($bsCount - $parserState->{initbsCount}) && $parserState->{lastsymbol} =~ /;\s*$/o) { # print STDERR "DPA\n"; if ((!$parserState->{kr_c_function} || $parserState->{seenBraces}) && !$parserState->{inMacro}) { # print STDERR "DPB\n"; if (!scalar(@parserStack)) { $continue = 0; print STDERR "continue -> 0 [3]\n" if ($localDebug); } elsif (!$parserState->{onlyComments}) { # Process entry here if ($parserState->{noInsert}) { print STDERR "parserState insertion skipped[SEMI-1]\n" if ($parserStackDebug); } elsif ($parserState->{hollow}) { my $treeRef = $parserState->{hollow}; $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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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 "bsCount: $bsCount - $parserState->{initbsCount}, ls: $parserState->{lastsymbol}\n" if ($localDebug); pbs(@braceStack); } if (!($bsCount - $parserState->{initbsCount}) && $parserState->{seenBraces} && ($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}) { # Fix nesting. # print STDERR "LASTTREENODE -> $treeCur (".$treeCur->token().")\n"; while ($parserState->{treePopTwo}--) { $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [13]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } $treeCur = $treeCur->addSibling(";", 0); $parserState->{lastTreeNode} = $treeCur; $parserState->{treePopTwo} = 0; } if (!scalar(@parserStack)) { $continue = 0; print STDERR "continue -> 0 [4]\n" if ($localDebug); } elsif (!$parserState->{onlyComments}) { # Process entry here if ($parserState->{noInsert}) { print STDERR "parserState insertion skipped[SEMI-2]\n" if ($parserStackDebug); } elsif ($parserState->{hollow}) { my $treeRef = $parserState->{hollow}; $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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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 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 ($localDebug || $liteDebug); } 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}); } else { cpp_add($parserState->{hollow}, 1); $HeaderDoc::skipNextPDefine = 0; } } if ($parserState->{noInsert}) { print STDERR "parserState insertion skipped\n" if ($parserStackDebug); } elsif ($parserState->{hollow}) { my $treeRef = $parserState->{hollow}; $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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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 "$filename:$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) { print STDERR "parserState pushed onto stack[token]\n" if ($parserStackDebug); $parserState->{lastTreeNode} = $treeCur; $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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); $parserState->{lastTreeNode} = $treeCur; $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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, $lbrace, $case_sensitive)) { $parserState->{ISFORWARDDECLARATION} = 0; 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; # } $parserState->{lastTreeNode} = $treeCur; $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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 (!casecmp($tok, $rbrace, $case_sensitive) && $part !~ /\)/) { # $parserState->{hollow} = $treeCur; setHollowWithLineNumbers(\$parserState, $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 (!casecmp($tok, $rbrace, $case_sensitive) && $part !~ /\)/) { setHollowWithLineNumbers(\$parserState, $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; } # end foreach (parts of the current line) } # end while (continue && ...) 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); $parserState->{lastTreeNode} = $treeCur; $parserState->{inputCounter} = $inputCounter; print STDERR "PARSERSTATE: $parserState\n" if ($localDebug); if ($parserState->{inMacro} == 3) { if (!$HeaderDoc::skipNextPDefine) { cpp_add($treeTop); } else { cpp_add($treeTop, 1); $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); while ($tempParserState) { $parserState = $tempParserState; $tempParserState = pop(@parserStack); } $HeaderDoc::module = $parserState->{MODULE}; if ($localDebug || $apDebug || $liteDebug || $parseDebug) { 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 "FC: ".$parserState->{functionContents}."\n"; return blockParseReturnState($parserState, $treeTop, $argparse, $declaration, $inPrivateParamTypes, $publicDeclaration, $lastACS, $retDebug, $fileoffset, 0, $definename, $inputCounter); } $parserState->{functionReturnsCallback} => 0 $parserState->{hollow} => HeaderDoc::ParseTree=HASH(OBJID) $parserState->{inBrackets} => 0 $parserState->{inChar} => $parserState->{inClass} => 0 $parserState->{inComment} => 0 $parserState->{inInlineComment} => 0 $parserState->{inMacro} => 0 $parserState->{inMacroLine} => 0 $parserState->{inOperator} => 0 $parserState->{inPrivateParamTypes} => 0 $parserState->{inString} => 0 $parserState->{inTemplate} => 0 $parserState->{initbsCount} => 0 $parserState->{inputCounter} => 3647 $parserState->{kr_c_function} => 0 $parserState->{kr_c_name} => $parserState->{lang} => perl $parserState->{lastTreeNode} => HeaderDoc::ParseTree=HASH(OBJID) $parserState->{lastsymbol} => $parserState->{macroNoTrunc} => 1 $parserState->{name} => blockParse $parserState->{namePending} => 0 $parserState->{noInsert} => 0 $parserState->{occmethod} => 0 $parserState->{occmethodname} => $parserState->{occparmlabelfound} => 2 $parserState->{onlyComments} => 0 $parserState->{parsedParamList} => ARRAY(OBJID) $parserState->{parsedParamParse} => 0 $parserState->{posstypes} => $parserState->{posstypesPending} => 0 $parserState->{pplStack} => ARRAY(OBJID) $parserState->{preEqualsSymbol} => $parserState->{preTemplateSymbol} => $parserState->{prekeywordsodname} => $parserState->{prekeywordsodtype} => $parserState->{returntype} => sub blockParse $parserState->{seenBraces} => 1 $parserState->{seenMacroPart} => 0 $parserState->{seenTilde} => 0 $parserState->{simpleTDcontents} => $parserState->{simpleTypedef} => 0 $parserState->{sodclass} => function $parserState->{sodname} => blockParse $parserState->{sodtype} => $parserState->{stackFrozen} => 1 $parserState->{startOfDec} => 0 $parserState->{sublang} => perl $parserState->{temponlyComments} => 0 $parserState->{typestring} => function $parserState->{value} => $parserState->{valuepending} => 0 -=: BLOCKPARSE RETURN VALUES :=- newcount: 3647 typelist: function namelist: blockParse posstypes: function method value: returntype: pridec: simpleTDcontents: bpavail: blockOffset: 0 conformsToList: functionContents: { my $filename = 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 $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 $cbnDebug = 0; my $macroDebug = 0; my $apDebug = 0; my $tsDebug = 0; my $treeDebug = 0; my $ilcDebug = 0; my $regexpDebug = 0; my $parserStackDebug = 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 $liteDebug = 0 || $HeaderDoc::fileDebug; # Just prints the tokens. my $parserStateInsertDebug = 0; $cppDebug = $cppDebugDefault || $HeaderDoc::fileDebug; # State variables (part 1 of 3) # my $typestring = ""; my $continue = 1; # set low when we're done. my $parsedParamParse = 0; # set high when current token is part of param. # 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 $perl_or_shell = 0; 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; 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" || $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(); # $parserState->{hollow} = $treeTop; setHollowWithLineNumbers(\$parserState, $treeTop, $fileoffset, $inputCounter); $parserState->{lang} = $lang; $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 $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 perl regexp. 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 ($sotemplate, $eotemplate, $operator, $soc, $eoc, $ilc, $ilc_b, $sofunction, $soprocedure, $sopreproc, $lbrace, $rbrace, $unionname, $structname, $enumname, $typedefname, $varname, $constname, $structisbrace, $macronameref, $classregexp, $classbraceregexp, $classclosebraceregexp, $accessregexp, $requiredregexp, $propname, $objcdynamicname, $objcsynthesizename, $moduleregexp, $definename) = parseTokens($lang, $sublang); my $macrore_pound = macroRegexpFromList($macronameref, 1); my $macrore_nopound = macroRegexpFromList($macronameref, 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 $propname\n"; if ($parseDebug) { print STDERR "SOT: $sotemplate EOF: $eotemplate OP: $operator SOC: $soc EOC: $eoc ILC: $ilc ILC_B: $ilc_b\n"; print STDERR "SOFUNC: $sofunction SOPROC: $soprocedure SOPREPROC: $sopreproc LBRACE: $lbrace RBRACE: $rbrace\n"; print STDERR "UNION: $unionname STRUCT: $structname TYPEDEF: $typedefname VAR: $varname CONST: $constname\n"; print STDERR "STRUCTISBRACE: $structisbrace MACRONAMEREF: $macronameref 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") { $perl_or_shell = 1; if ($lang eq "perl") { $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; if ($lang eq "pascal") { $pascal = 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 $categoryClass = ""; # my $classtype = ""; # my $inClass = 0; my $pushParserStateAfterToken = 0; my $pushParserStateAfterWordToken = 0; my $pushParserStateAtBrace = 0; my $occPushParserStateOnWordTokenAfterNext = 0; $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 "INCOMING INPUTCOUNTER: $inputCounter\n" if ($HeaderDoc::inputCounterDebug); while ($continue && ($inputCounter <= $nlines)) { $HeaderDoc::CurLine = $inputCounter + $fileoffset; my $line = $inputLines[$inputCounter++]; print STDERR "GOT LINE: $line\n" if (($localDebug && $apDebug) || $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 "CHANGED LINE FROM \"$line\" to \"$1\"\n" if ($localDebug || $liteDebug); $line = $1."\n"; } } print STDERR "LINE[$inputCounter] : $line\n" if ($offsetDebug); # The tokenizer if ($lang eq "perl" || $lang eq "shell") { @parts = split(/("|'|\#|\{|\}|\(|\)|\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) {foreach my $partlist (@parts) {print STDERR "PARTLIST: \"$partlist\"\n"; }} # 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; # print STDERR "CHECK LINE $line\n"; if ($line =~ /^\s*#include (.*)$/) { my $rest = $1; $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 "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; while ($pos < scalar(@parts)) { my $part = $parts[$pos]; my $noCPPThisToken = 0; if (length($part)) { if (!$inChar && !$inString && !$inComment && !$inSLC) { if ($parserState->{NEXTTOKENNOCPP} == 1) { # We're in an "if" block. if ($part eq "defined") { $parserState->{NEXTTOKENNOCPP} = 3; } } elsif ($parserState->{NEXTTOKENNOCPP} == 2) { # 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) { # 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)/) { $parserState->{NEXTTOKENNOCPP} = 2; } elsif ($inCPPSpecial && $part =~ /if/) { $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 $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 $soc) { print STDERR "SOC\n"if ($cppleaddebug); $inComment = 1; } elsif (!$inComment && ($part eq $ilc || $part eq $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) { ($newpart, $hasargs) = 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) { $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 \"$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; } } 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) { print STDERR "CPPS: \"$cppstring\"\n"; warn "Non-terminated macro.\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 "CHANGED LINE FROM \"$line\" to \"$1\"\n" if ($localDebug || $liteDebug); $line = $1."\n"; } } print STDERR "INCREMENTED INPUTCOUNTER [2]\n" if ($HeaderDoc::inputCounterDebug); # @parts = split(/(\W)/, $line); if ($lang eq "perl" || $lang eq "shell") { @parts = split(/("|'|\#|\{|\}|\(|\)|\s|;|\\|\W)/, $line); } else { @parts = split(/("|'|\/\/|\/\*|\*\/|::|==|<=|>=|!=|\<\<|\>\>|\{|\}|\(|\)|\s|;|\\|\W)/, $line); } } } until (!$incppargs && !$inComment); # The tokenizer if ($lang eq "perl" || $lang eq "shell") { @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); # 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; $treeSkip = 0; # $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); $forcenobreak = 0; if ($nextpart eq "\r") { $nextpart = "\n"; } if ($localDebug && $nextpart eq "\n") { print STDERR "NEXTPART IS NEWLINE!\n"; } if ($localDebug && $part eq "\n") { 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); print STDERR "CURLINE IS \"$curline\"\n" if ($localDebug || $hangDebug); 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); } } elsif ($occPushParserStateOnWordTokenAfterNext) { # if ($part !~ /(\s|<)/) if ($part =~ /(\/\/|\/\*|\-|\+|\w|\@)/) { $parserState->{lastTreeNode} = $treeCur; print STDERR "parserState pushed onto stack[occPushParserStateOnWordTokenAfterNext]\n" if ($parserStackDebug); $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 0; $parserState->{lang} = $lang; $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++; } 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} inRegexp: $inRegexp\n"; print STDERR "PART: regexpNoInterpolate: $regexpNoInterpolate\n"; 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 ($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); printf("PART: $part TEMPAVAIL: $tempavail\n") if ($localDebug || $gccAttributeDebug); if ($tempavail && ($tempavail ne "1") && ($tempavail ne "2")) { $parserState->{availability} = $tempavail; } elsif ($tempavail eq "2") { # Reusing the GCC attribute handling code because that does exactly what we need. print STDERR "Function-like availability macro detected. Collecting.\n" if ($localDebug || $gccAttributeDebug); $parserState->{attributeState} = 1; $parserState->{attributeParts} = (); # Add __attribute__ as the next token. $treeCur = $treeCur->addSibling($part, 0); 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; } # Handle the GCC "__attribute__" extension outside the context of # the parser because it isn't part of the language and massively # breaks the syntax. if ($lang eq "C" && isKeyword($part, $keywordhashref, $case_sensitive) == 2) { print STDERR "GCC attribute detected. Collecting.\n" if ($localDebug || $gccAttributeDebug); $parserState->{attributeState} = 1; $parserState->{attributeParts} = (); # Add __attribute__ as the next token. $treeCur = $treeCur->addSibling($part, 0); push(@treeStack, $treeCur); # Nest all contents one level lower. $treeCur = $treeCur->addChild("", 0); $part = $nextpart; next; } elsif ($parserState->{attributeState} == 1) { if ($part eq "(") { print STDERR "GCC attribute open paren\n" if ($localDebug || $gccAttributeDebug); $parserState->{attributeState} = -1; } $treeCur = $treeCur->addSibling($part, 0); $part = $nextpart; next; } elsif ($parserState->{attributeState} < 0) { if ($part eq "(") { $parserState->{attributeState}--; print STDERR "GCC attribute open paren, count=".(0-$parserState->{attributeState})."\n" if ($localDebug || $gccAttributeDebug); } elsif ($part eq ")") { $parserState->{attributeState}++; print STDERR "GCC attribute close paren, count=".(0-$parserState->{attributeState})."\n" if ($localDebug || $gccAttributeDebug); } $treeCur = $treeCur->addSibling($part, 0); if (($localDebug || $gccAttributeDebug) && !$parserState->{attributeState}) { print STDERR "GCC attribute: done collecting.\n"; # Get back to where we started. $treeCur = pop(@treeStack); } $part = $nextpart; next; } # Here be the parser. Abandon all hope, ye who enter here. $treepart = ""; 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 print STDERR "parserState pushed onto stack[PROTOCOL]\n" if ($parserStackDebug); $parserState->{inProtocol} = -1; $parserState->{lastTreeNode} = $treeCur; $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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); # $parserState->{lastTreeNode} = $treeCur; # push(@parserStack, $parserState); # $parserState = HeaderDoc::ParserState->new(); # $parserState->{lang} = $lang; # $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); $parserState->{lastTreeNode} = $treeCur; print STDERR "parserState pushed onto stack[cparen2]\n" if ($parserStackDebug); $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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"; if ($part eq ":") { print STDERR "INCLASS COLON\n" if ($parseDebug || $classDebug); $parserState->{forceClassName} = $parserState->{sodname}; $parserState->{forceClassSuper} = ""; # print STDERR "XSUPER: $parserState->{forceClassSuper}\n"; } elsif ($part eq "{" || $part eq ";") { print STDERR "INCLASS BRCSEMI\n" if ($parseDebug || $classDebug); $parserState->{forceClassDone} = 1; if ($parserState->{classIsObjC} && $part eq "{") { $parserState->{ISFORWARDDECLARATION} = 0; $parserState->{lastTreeNode} = $treeCur; print STDERR "parserState pushed onto stack[OCC-BRCSEMI]\n" if ($parserStackDebug); $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 0; $parserState->{lang} = $lang; $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}) { 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->{classIsObjC}) { print STDERR "INCLASS NOTOBJC (OTHER)\n" if ($parseDebug || $classDebug); 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}; } # } 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 $ilc || $part eq $ilc_b) && ($lang ne "perl" || $lasttoken ne "\$")) { # print STDERR "should be ILC?\n"; # } else { # print STDERR "NO CHANEC: PART \"$part\" ILC \"$ilc\" ILC_B: \"ilc_b\" LANG: \"$lang\" LASTTOKEN: \"$lasttoken\"\n"; # } SWITCH: { # Blank declaration handlers (mostly for misuse of # OSMetaClassDeclareReservedUsed and similar) (($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; }; # 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 "$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|pragma|import|include)/ && ($part ne $definename)) || ($parserState->{inMacro} == 0 && $macrore_nopound ne "" && $part =~ /$macrore_nopound/)) # (($parserState->{inMacro} == 1 && $part =~ /(if|ifdef|ifndef|endif|else|undef|elif|pragma|import|include)/ )) && do (!$parserState->{inComment} && (($parserState->{inMacro} == 1 && $macrore_pound ne "" && $part =~ /^$macrore_pound$/ && ($part ne $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|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 "$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|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 "$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 $soc) && ($part ne $eoc) && $part =~ /\s/) && do { $treepart = $part; $part = ""; last SWITCH; }; ($parserState->{inMacro} == 1 && ($part ne $soc) && ($part ne $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 $soc) && ($part ne $eoc)) && do { print STDERR "INMACRO OTHERTOKEN: CASE 06\n" if ($liteDebug); print STDERR "INMACRO > 1, PART NE //" if ($parseDebug || $localDebug); if ($part eq "\\") { $parserState->addBackslash(); } elsif ($part !~ /[ \t]/) { $parserState->addBackslash(); } print STDERR "PART: $part\n" if ($macroDebug); if ($parserState->{seenMacroPart} && $HeaderDoc::truncate_inline) { 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; } elsif ($part =~ /[\{\(]/o) { print STDERR "MACRO: BRACE\n" if ($macroDebug); if (!$parserState->{macroNoTrunc}) { # $parserState->{seenBraces} = 1; $HeaderDoc::hidetokens = 3; } } else { print STDERR "MACRO: OTHERTOKEN\n" if ($macroDebug); $parserState->{macroNoTrunc} = 2; } } } if ($part =~ /[\{\(]/o) { push(@braceStack, $part); print STDERR "PUSH\n" if ($macroDebug); } elsif ($part =~ /[\}\)]/o) { if ($part ne peekmatch(\@braceStack, $filename, $inputCounter)) { if ($parserState->{macroNoTrunc} == 1) { # We haven't reached the end of the first part of the declaration, so this is an error. warn("$filename:$inputCounter: warning: Initial braces in macro name do not match.\nWe may have a problem.\n"); } } pop(@braceStack); print STDERR "POP\n" if ($macroDebug); } 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 # print STDERR "IRE: $inRegexp IRT: $inRegexpTrailer IS: $parserState->{inString} ICo $parserState->{inComment} ILC: $parserState->{inInlineComment} ICh $parserState->{inChar}\n"; (length($regexppattern) && $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? $inRegexp = 2; } else { $inRegexp = 4; # print STDERR "REGEXP PART IS \"$part\"\n"; if ($part eq "tr") { $regexpNoInterpolate = 1; } # if ($part =~ /tr/) { $regexpNoInterpolate = 1; } } last SWITCH; }; # end regexppattern (($inRegexp || $parserState->{lastsymbol} eq "~") && (length($regexpcharpattern) && $part =~ /^($regexpcharpattern)$/ && (!scalar(@regexpStack) || $part eq peekmatch(\@regexpStack, $filename, $inputCounter)))) && do { print STDERR "REGEXP CHARACTER: CASE 08\n" if ($liteDebug); print STDERR "REGEXP?\n" if ($regexpDebug); if (!$inRegexp) { $inRegexp = 2; } # if ($lasttoken eq "\\") if ($parserState->isQuoted($lang. $sublang)) { # jump to next match. $lasttoken = $part; $parserState->{lastsymbol} = $part; next SWITCH; } print STDERR "REGEXP POINT A\n" if ($regexpDebug); $lasttoken = $part; $parserState->{lastsymbol} = $part; if ($part eq "#" && ((scalar(@regexpStack) != 1) || (peekmatch(\@regexpStack, $filename, $inputCounter) ne "#"))) { if ($nextpart =~ /^\s/o) { # it's a comment. jump to next match. next SWITCH; } } print STDERR "REGEXP POINT B\n" if ($regexpDebug); if (!scalar(@regexpStack)) { push(@regexpStack, $part); $inRegexp--; } else { my $match = peekmatch(\@regexpStack, $filename, $inputCounter); my $tos = pop(@regexpStack); if (!scalar(@regexpStack) && ($match eq $part)) { $inRegexp--; if ($inRegexp == 2 && $tos eq "/") { # we don't double the slash in the # middle of a s/foo/bar/g style # expression. $inRegexp--; } if ($inRegexp) { push(@regexpStack, $tos); } } elsif (scalar(@regexpStack) == 1) { push(@regexpStack, $tos); if ($tos =~ /['"`]/o || $regexpNoInterpolate) { # these don't interpolate. next SWITCH; } } else { push(@regexpStack, $tos); if ($tos =~ /['"`]/o || $regexpNoInterpolate) { # these don't interpolate. next SWITCH; } push(@regexpStack, $part); } } print STDERR "REGEXP POINT C\n" if ($regexpDebug); if (!$inRegexp) { $inRegexpTrailer = 2; } last SWITCH; }; # end regexpcharpattern # Start of preprocessor macros ($part eq "$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); } 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 "$sofunction" || $part eq "$soprocedure") && do { print STDERR "SOFUNC: CASE 10\n" if ($liteDebug); $parserState->{sodclass} = "function"; print STDERR "K&R C FUNCTION FOUND [1].\n" if ($localDebug); $parserState->{kr_c_function} = 1; $parserState->{typestring} = "function"; $parserState->{startOfDec} = 2; $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); last SWITCH; }; # C++ destructor handler. ($part =~ /\~/o && $lang eq "C" && $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 && $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; $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) && do { print STDERR "NEWLINE: CASE 13\n" if ($liteDebug); # NEWLINE FOUND $treepart = $part; if ($inRegexp) { warn "$filename:$inputCounter: warning: multi-line regular expression\n"; } print STDERR "NLCR\n" if ($tsDebug || $treeDebug || $localDebug); 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; } else { $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); print STDERR "skipped pushing CPP directive $parsedParam into parsedParamList [1]\n" if ($parmDebug || $cppDebug || $localDebug); $parsedParam = ""; } } } if ($treePopOnNewLine < 0) { # pop once for //, possibly again for macro $treePopOnNewLine = 0 - $treePopOnNewLine; $treeCur = $treeCur->addSibling($treepart, 0); bless($treeCur, "HeaderDoc::ParseTree"); # push(@treeStack, $treeCur); $treeSkip = 1; $treeCur = pop(@treeStack); if (!$treeCur) { $treeCur = $treeTop; warn "$filename:$inputCounter: warning: Attempted to pop off top of tree\n"; } $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [1]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if ($treePopOnNewLine == 1 || ($treePopOnNewLine && !$parserState->isQuoted())) { # $parserState->{lastsymbol} ne "\\" $treeCur = $treeCur->addSibling($treepart, 0); bless($treeCur, "HeaderDoc::ParseTree"); # push(@treeStack, $treeCur); $treeSkip = 1; $treeCur = pop(@treeStack); if (!$treeCur) { $treeCur = $treeTop; warn "$filename:$inputCounter: warning: Attempted to pop off top of tree\n"; } $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->addSibling("", 0); # empty token print STDERR "TSPOP [1a]\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 $sotemplate && !$parserState->{seenBraces} && ($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(@braceStack, $part); pbs(@braceStack); if (!$parserState->{seenBraces}) { # TREEDONE $treeNest = 1; 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 $eotemplate && !$parserState->{seenBraces} && ($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); if (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [2]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if ($top ne "$sotemplate") { warn("$filename:$inputCounter: warning: Template (angle) brackets do not match.\nWe may have a problem.\n"); } } last SWITCH; }; # # Handles C++ access control state, e.g. "public:" # ($part eq ":") && 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 (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) { 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); $parserState->{hollow} = undef; $parserState->{onlyComments} = 1; print STDERR "hollowskip -> 1 (ACS)\n" if ($parserStateInsertDebug); $hollowskip = 1; $HeaderDoc::AccessControlState = $1; $lastACS = $1; last SWITCH; } elsif ($parserState->{typestring} eq "struct") { if (!(scalar(@braceStack) - $parserState->{initbsCount})) { if (!$parserState->{structClassName}) { $parserState->{structClassName} = $parserState->{lastsymbol}; $parserState->{bracePending} = 2; } } } } }; (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 MATCH: \"$part\"\n" if ($localDebug || $parseDebug); $hollowskip = 1; print STDERR "hollowskip -> 1 (requiredregexp)\n" if ($parserStateInsertDebug); last SWITCH; }; # # C++ copy constructor handler. For example: # # char *class(void *a, void *b) : # class(pri_type, pri_type); # ($part eq ":") && 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" && $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\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 (!$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 { next SWITCH; } }; # Non-newline, non-carriage-return whitespace handler. ($part =~ /\s/o) && do { print STDERR "Whitespace: CASE 19\n" if ($liteDebug); # 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 "\"") && 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})) { $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 (!$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 (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [3]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } } $parserState->{inString} = (1-$parserState->{inString}); } } $lastchar = $part; $parserState->{lastsymbol} = ""; last SWITCH; }; ($part eq "[") && do { print STDERR "LEFT BRACKET: CASE 22\n" if ($liteDebug); # left square bracket (square brace) if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate)) { 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(@braceStack, $part); pbs(@braceStack); if (!$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; } $lastchar = $part; last SWITCH; }; ($part eq "]") && do { print STDERR "CLOSE BRACKET: CASE 23\n" if ($liteDebug); # right square bracket (square brace) if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate)) { print STDERR "rbracket\n" if ($localDebug); if (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inString})) { $parserState->{onlyComments} = 0; print STDERR "[g]onlyComments -> 0\n" if ($macroDebug); } my $top = pop(@braceStack); if (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [4]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if ($top ne "[") { warn("$filename:$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; } $lastchar = $part; last SWITCH; }; ($part eq "'") && do { print STDERR "SINGLE QUOTE: CASE 24\n" if ($liteDebug); print STDERR "squo\n" if ($localDebug); if (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inString})) { # 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 (!$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 (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [5]\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 $ilc || $part eq $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} = 4; print STDERR "inInlineComment -> 1\n" if ($ilcDebug); $curline = spacefix($curline, $part, $lastchar, $soc, $eoc, $ilc, $ilc_b); if (!$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("$filename:$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 $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 (!$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("$filename:$linenum: warning: Nested comment found [2]. Ignoring.\n"); } } $parserState->{lastsymbol} = ""; $lastchar = $part; last SWITCH; }; ($part eq $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; $curline = spacefix($curline, $part, $lastchar); $ppSkipOneToken = 1; if (!$parserState->{seenBraces}) { $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [6]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } } elsif (!$parserState->{inComment} && !$parserState->{inInlineComment} && !$parserState->{inString} && !$parserState->{inChar} && !$inRegexp) { my $linenum = $inputCounter + $fileoffset; warn("$filename:$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::test_mode)) { warn("$filename:$linenum: warning: Nested comment found [3]. Ignoring.\n"); } } $parserState->{lastsymbol} = ""; $lastchar = $part; last SWITCH; }; # Parenthesis and brace handlers. ($part eq "(") && do { print STDERR "OPEN PAREN: CASE 28\n" if ($liteDebug); my @tempppl = undef; if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate)) { if (!(scalar(@braceStack)-$parserState->{initbsCount})) { # start parameter parsing after this token print STDERR "parsedParamParse -> 2\n" if ($parmDebug); $parsedParamParse = 2; 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"; # 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->{returntype} = "$declaration$curline"; } elsif (!$parserState->{freezereturn} && !$parserState->{hollow}) { $parserState->{returntype} = "$curline"; $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); 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"; # $parserState->{callbackName} = ""; $parserState->{functionReturnsCallback}++; print "Function returning callback. NAME: $parserState->{cbsodname}\n" if ($parmDebug || $localDebug || $parseDebug); print STDERR "parsedParamParse -> 2\n" if ($parmDebug); $parsedParamParse = 2; print STDERR "parsedParamList wiped\n" if ($parmDebug); @tempppl = @{$parserState->{parsedParamList}}; @{$parserState->{parsedParamList}} = (); $parsedParam = ""; } } if ($parserState->{inOperator} == 1) { $parserState->{inOperator} = 2; } push(@braceStack, $part); pbs(@braceStack); if (!$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) { $parserState->{sodclass} = "function"; $parserState->{freezereturn} = 1; $parserState->{returntype} =~ s/^\s*//so; $parserState->{returntype} =~ s/\s*$//so; } $parserState->{startOfDec} = 0; 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 "OUTGOING CURLINE: \"$curline\"\n" if ($localDebug); last SWITCH; }; ($part eq ")") && do { print STDERR "CLOSE PAREN: CASE 29\n" if ($liteDebug); if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate && (peek(\@regexpStack) ne "("))) { if ((scalar(@braceStack)-$parserState->{initbsCount} - $parserState->{functionReturnsCallback}) == 1) { # stop parameter parsing $parsedParamParse = 0; print STDERR "parsedParamParse -> 0\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 = pop(@braceStack); pbs(@braceStack); if (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [6a]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if (!($test eq "(")) { # ) brace hack for vi warn("$filename:$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; 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; }; (casecmp($part, $lbrace, $case_sensitive)) && do { print STDERR "LEFT BRACE: CASE 30\n" if ($liteDebug); if ($parserState->{onlyComments} && !$parserState->{inComment} && !$parserState->{inInlineComment} && !$parserState->{inChar} && !($inRegexp && $regexpNoInterpolate) && scalar(@parserStack)) { # 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 && $regexpNoInterpolate)) { $parserState->{bracePending} = 0; print STDERR "bracePending -> 0 [brace]\n" if ($localDebug); $parserState->{onlyComments} = 0; print STDERR "[k]onlyComments -> 0\n" if ($macroDebug); 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\n" if ($parmDebug); } # start parameter parsing after this token print STDERR "parsedParamParse -> 2\n" if ($parmDebug); $parsedParamParse = 2; # 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 "seenBraces -> 1\n" if ($parseDebug); $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(@braceStack, $part); pbs(@braceStack); if (!$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; 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; }; (casecmp($part, $rbrace, $case_sensitive)) && do { print STDERR "RIGHT BRACE: CASE 31\n" if ($liteDebug); if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !($inRegexp && $regexpNoInterpolate && (peek(\@regexpStack) ne "$lbrace"))) { 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); my $bsCount = scalar(@braceStack); if (scalar(@parserStack) && !($bsCount - $parserState->{initbsCount})) { print STDERR "parserState: ENDOFSTATE\n" if ($parserStackDebug); if ($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}; $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; $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 [1a]\n" if ($localDebug || $liteDebug); $parserState->{noInsert} = 0; $continue = 0; print STDERR "AT END: REALPS IS ".$parserState->{REALPS}."\n" if ($parserStackDebug || $localDebug); print STDERR "STACK COUNT: ".scalar(@parserStack)."\n" if ($parserStackDebug || $localDebug); } if ($lang eq "php" || ($lang eq "C" && $sublang eq "IDL")) { # print STDERR "PHP OUT OF BRACES?: ".scalar(@braceStack)."\n"; if (scalar(@braceStack) == 1) { # PHP and IDL classes end at # the brace. print STDERR "continue -> 0 [1a]\n" if ($localDebug || $liteDebug); $continue = 0; } } 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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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); } if ((scalar(@braceStack)-$parserState->{initbsCount}) == 1) { # stop parameter parsing $parsedParamParse = 0; print STDERR "parsedParamParse -> 0\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 = ""; } else { # start parameter parsing after this token print STDERR "parsedParamParse -> 2\n" if ($parmDebug); $parsedParamParse = 2; } 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\n" if ($parmDebug); } print STDERR "rbrace\n" if ($localDebug); my $test = pop(@braceStack); pbs(@braceStack); if (!$parserState->{seenBraces}) { # TREEDONE $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [7]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } if (!($test eq "$lbrace") && (!length($structname) || (!($test eq $structname) && $structisbrace))) { warn("$filename:$inputCounter: warning: Braces do not match.\nWe may have a problem.\n"); warn("Declaration to date: $declaration$curline\n"); } $curline = spacefix($curline, $part, $lastchar); $parserState->{lastsymbol} = ""; $lastchar = $part; $parserState->{startOfDec} = 0; 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($propname) && $propname =~ /\@/) || length($objcdynamicname) || length($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 $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 $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 $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 $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, $filename, $inputCounter)) { warn("$filename:inputCounter: warning: Class braces do not match.\nWe may have a problem.\n"); } $parserState->{seenBraces} = 1; pop(@braceStack); $treeCur->addSibling($part, 0); $treeSkip = 1; $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [6]\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; $HeaderDoc::module = $parserState->{MODULE}; $continue = 0; print STDERR "continue -> 0 [occend]\n" if ($localDebug); } 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}; $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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $parserState->{inputCounter} = $inputCounter; $parserState->{initbsCount} = scalar(@braceStack); } print STDERR "parserState popped from parserStack[\@end]\n" if ($parserStackDebug); $parserState = pop(@parserStack) || $parserState; $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. ### ($sotemplate, $eotemplate, $operator, $soc, $eoc, $ilc, $ilc_b, $sofunction, ### $soprocedure, $sopreproc, $lbrace, $rbrace, $unionname, $structname, ### $enumname, ### $typedefname, $varname, $constname, $structisbrace, $macronameref, ### $classregexp, $classbraceregexp, $classclosebraceregexp, $accessregexp, ### $requiredregexp, $propname, $objcdynamicname, $objcsynthesizename, $moduleregexp, $definename) = parseTokens($lang, $sublang); ### print STDERR "PROPNAME NOW $propname\n" if ($localDebug || $parseDebug || $classDebug); my $localclasstype = $1; if ($part =~ /^\@/) { $part =~ s/^\@//s; } if (!(scalar(@braceStack)-$parserState->{initbsCount})) { if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) { print STDERR "ITISACLASS\n" if ($localDebug); if (!length($parserState->{sodclass})) { 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"; $parserState->{classtype} = $localclasstype; $parserState->{preclasssodtype} = $parserState->{sodtype} . $part; $parserState->{sodtype} = ""; $parserState->{startOfDec} = 1; $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(@braceStack, $localclasstype); pbs(@braceStack); $treeNest = 1; if ($treeDebug) { print STDERR "TS TREENEST -> 1 [17]\n"; } # } else { # print STDERR "CBRE: \"$classbraceregexp\"\n"; } ($lang, $sublang) = getLangAndSublangFromClassType($localclasstype); $HeaderDoc::lang = $lang; $HeaderDoc::sublang = $sublang; ($sotemplate, $eotemplate, $operator, $soc, $eoc, $ilc, $ilc_b, $sofunction, $soprocedure, $sopreproc, $lbrace, $rbrace, $unionname, $structname, $enumname, $typedefname, $varname, $constname, $structisbrace, $macronameref, $classregexp, $classbraceregexp, $classclosebraceregexp, $accessregexp, $requiredregexp, $propname, $objcdynamicname, $objcsynthesizename, $moduleregexp, $definename) = parseTokens($lang, $sublang); my $macrore = macroRegexpFromList($macronameref); # print STDERR "PROPNAME2: $propname\n"; print STDERR "ARP: $accessregexp\n" if ($localDebug); last SWITCH; } } } }; ($part eq $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 $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 $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 $structname || $part eq $enumname || $part eq $unionname) && do { print STDERR "STRUCT/ENUM/UNION: CASE 36\n" if ($liteDebug); if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) { if ($structisbrace) { if ($parserState->{sodclass} eq "function") { $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(@braceStack, $part); pbs(@braceStack); if (!$parserState->{seenBraces}) { # 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; 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 (!$parserState->{seenBraces}) { # TREEDONE # $treePopTwo++; # $treeNest = 1; # push(@treeStack, $treeCur); # $treeCur = $treeCur->addChild($part, 0); $treeSkip = 1; # bless($treeCur, "HeaderDoc::ParseTree"); # } } $parserState->{onlyComments} = 0; print STDERR "[n]onlyComments -> 0\n" if ($macroDebug); $continuation = 1; # $parserState->{simpleTypedef} = 0; if ($parserState->{basetype} eq "") { $parserState->{basetype} = $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 "sodname cleared (seu)\n" if ($sodDebug); } $lastchar = $part; }; # end if }; # end do ($part =~ /^$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; $parserState->{simpleTypedef} = 1; print STDERR "simpleTypedef -> 1\n" if ($localDebug); # previous case falls through, so be explicit. if ($part =~ /^$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 "sodname cleared ($typedefname)\n" if ($sodDebug); } $lastchar = $part; }; # end if }; # end do # C++ operator keyword handler ($part eq "$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->{lastsymbol} = $part; $lastchar = $part; last SWITCH; # next; }; # Punctuation handlers ($part =~ /;/o) && do { print STDERR "SEMICOLON: CASE 39\n" if ($liteDebug); if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar})) { if ($parsedParamParse) { $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 $parsedParamParse = 2; $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; $continuation = 1; if ($parserState->{occmethod}) { $prespaceadjust = -$prespace; } # previous case falls through, so be explicit. if ($part =~ /;/o && !$parserState->{inMacroLine} && !$parserState->{inMacro}) { my $bsCount = scalar(@braceStack)-$parserState->{initbsCount}; if (!$bsCount && !$parserState->{kr_c_function}) { if ($parserState->{startOfDec} == 2) { $parserState->{sodclass} = "constant"; $parserState->{startOfDec} = 1; } elsif (!($parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar} || $parserState->{inString})) { $parserState->{startOfDec} = 1; } # $parserState->{lastsymbol} .= $part; } if (!$bsCount) { $treeCur = $treeCur->addSibling(";"); $treepart = " "; # $treeSkip = 1; if (0) { $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [8]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } # $parserState->{lastTreeNode} = $treeCur; # print STDERR "LASTTREENODE -> $treeCur (".$treeCur->token().")\n"; while ($parserState->{treePopTwo}--) { $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [9]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } $parserState->{treePopTwo} = 0; } } $lastchar = $part; }; # end if }; # end do ($part eq "=" && ($parserState->{lastsymbol} ne "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 "[q]onlyComments -> 0\n" if ($macroDebug); if ($part =~ /=/o && !(scalar(@braceStack)-$parserState->{initbsCount}) && $nextpart !~ /=/o && $lastchar !~ /=/o && $parserState->{sodclass} ne "function" && !$inPType) { print STDERR "valuepending -> 1\n" if ($valueDebug); $parserState->{valuepending} = 1; $parserState->{preEqualsSymbol} = $parserState->{lastsymbol}; $parserState->{sodclass} = "constant"; $parserState->{startOfDec} = 0; }; # 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); } if ($part =~ /,/o && $parsedParamParse && !($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && ((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 $parsedParamParse = 2; print STDERR "parsedParamParse -> 2\n" if ($parmDebug); }; # end if }; # end do ($part =~ /[*^]/) && do { if ($lastnspart eq "(" && # ")" !($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !$parserState->{callbackNamePending} && ((scalar(@braceStack)-$parserState->{initbsCount}) == 1)) { # print "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})) { if (!ignore($part, $ignoreref, $perheaderignoreref)) { 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 (!$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}; $parsedParamParse = 1; print STDERR "parsedParamParse -> 1\n" if ($parmDebug); } } } } $lastchar = $part; if ($part =~ /\w/o || $part eq "::") { if ($parserState->{callbackNamePending} == 1) { if (!($part eq $structname || $part eq $enumname || $part eq $unionname || $part eq $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} = ""; $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"; $parserState->{sodclass} = "constant"; $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 !~ /[,;\[\]]/o && !$parserState->{inBrackets}) { my $opttilde = ""; if ($parserState->{seenTilde}) { $opttilde = "~"; } 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}) { print STDERR "Setting sodname (maybe type) to \"$part\"\n" if ($sodDebug); $parserState->{sodname} = $opttilde.$part; if ($part =~ /\w/o) { $parserState->{startOfDec}++; } } 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}) { if ($parserState->{inOperator} == 1) { $parserState->{sodname} .= $part; } else { if (length($parserState->{sodname})) { $parserState->{sodtype} .= " $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; } } elsif ($part eq "[") { # if ($part !~ /[;\[\]]/o) $parserState->{inBrackets} += 1; print STDERR "inBrackets -> $parserState->{inBrackets}\n" if ($sodDebug); } elsif ($part eq "]") { $parserState->{inBrackets} -= 1; print STDERR "inBrackets -> $parserState->{inBrackets}\n" if ($sodDebug); } # end if ($part !~ /[;\[\]]/o) if (!($part eq $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 $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 ($parserState->{seenBraces}) { # print "SEENBRACES. TP: $treepart PT: $part\n"; if ($treepart) { $parserState->{functionContents} .= $treepart; } else { $parserState->{functionContents} .= $part; } # print "SEENBRACES. FC: ".$parserState->{functionContents}."\n"; } 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 $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); 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 (!$parserState->{seenBraces}) { # 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); } $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); } } 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; setHollowWithLineNumbers(\$parserState, $treeCur, $fileoffset, $inputCounter); $sethollow = 0; } print STDERR "TSPUSH\n" if ($tsDebug || $treeDebug); push(@treeStack, $treeCur); $treeCur = $treeCur->addChild("", 0); bless($treeCur, "HeaderDoc::ParseTree"); } } } 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}) { # print STDERR "WARNING: RETURN TYPE CHANGE[A]".$parserState->{returntype}." CHANGED TO $declaration$curline.\n"; $parserState->{returntype} = "$declaration$curline"; } elsif (!$parserState->{freezereturn} && !$parserState->{hollow}) { # print STDERR "WARNING: RETURN TYPE CHANGE[B]".$parserState->{returntype}." CHANGED TO $curline.\n"; $parserState->{returntype} = "$curline"; $declaration = ""; # } else { # print STDERR "WARNING: LEAVING RETURN TYPE ALONE: ".$parserState->{returntype}." NOT CHANGED TO $curline.\n"; } # 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. if (($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) || !$ignoretoken) { if (!($parserState->{inString} || $parserState->{inComment} || $parserState->{inInlineComment} || $parserState->{inChar}) && !$ppSkipOneToken) { if ($parsedParamParse == 1) { $parsedParam .= $part; } elsif ($parsedParamParse == 2) { $parsedParamParse = 1; print STDERR "parsedParamParse -> 1\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 (!$parserState->{seenBraces}) { # 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); print STDERR "KRC: $parserState->{kr_c_function} SB: $parserState->{seenBraces}\n" if ($localDebug); if (!($bsCount - $parserState->{initbsCount}) && $parserState->{lastsymbol} =~ /;\s*$/o) { # print STDERR "DPA\n"; if ((!$parserState->{kr_c_function} || $parserState->{seenBraces}) && !$parserState->{inMacro}) { # print STDERR "DPB\n"; if (!scalar(@parserStack)) { $continue = 0; print STDERR "continue -> 0 [3]\n" if ($localDebug); } elsif (!$parserState->{onlyComments}) { # Process entry here if ($parserState->{noInsert}) { print STDERR "parserState insertion skipped[SEMI-1]\n" if ($parserStackDebug); } elsif ($parserState->{hollow}) { my $treeRef = $parserState->{hollow}; $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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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 "bsCount: $bsCount - $parserState->{initbsCount}, ls: $parserState->{lastsymbol}\n" if ($localDebug); pbs(@braceStack); } if (!($bsCount - $parserState->{initbsCount}) && $parserState->{seenBraces} && ($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}) { # Fix nesting. # print STDERR "LASTTREENODE -> $treeCur (".$treeCur->token().")\n"; while ($parserState->{treePopTwo}--) { $treeCur = pop(@treeStack) || $treeTop; $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); $treeCur = $treeCur->lastSibling(); $treeCur->parsedParamCopy(\@{$parserState->{parsedParamList}}); print STDERR "TSPOP [13]\n" if ($tsDebug || $treeDebug); bless($treeCur, "HeaderDoc::ParseTree"); } $treeCur = $treeCur->addSibling(";", 0); $parserState->{lastTreeNode} = $treeCur; $parserState->{treePopTwo} = 0; } if (!scalar(@parserStack)) { $continue = 0; print STDERR "continue -> 0 [4]\n" if ($localDebug); } elsif (!$parserState->{onlyComments}) { # Process entry here if ($parserState->{noInsert}) { print STDERR "parserState insertion skipped[SEMI-2]\n" if ($parserStackDebug); } elsif ($parserState->{hollow}) { my $treeRef = $parserState->{hollow}; $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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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 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 ($localDebug || $liteDebug); } 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}); } else { cpp_add($parserState->{hollow}, 1); $HeaderDoc::skipNextPDefine = 0; } } if ($parserState->{noInsert}) { print STDERR "parserState insertion skipped\n" if ($parserStackDebug); } elsif ($parserState->{hollow}) { my $treeRef = $parserState->{hollow}; $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(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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 "$filename:$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) { print STDERR "parserState pushed onto stack[token]\n" if ($parserStackDebug); $parserState->{lastTreeNode} = $treeCur; $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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); $parserState->{lastTreeNode} = $treeCur; $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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, $lbrace, $case_sensitive)) { $parserState->{ISFORWARDDECLARATION} = 0; 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; # } $parserState->{lastTreeNode} = $treeCur; $curline = ""; push(@parserStack, $parserState); $parserState = HeaderDoc::ParserState->new(); $parserState->{skiptoken} = 1; $parserState->{lang} = $lang; $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 (!casecmp($tok, $rbrace, $case_sensitive) && $part !~ /\)/) { # $parserState->{hollow} = $treeCur; setHollowWithLineNumbers(\$parserState, $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 (!casecmp($tok, $rbrace, $case_sensitive) && $part !~ /\)/) { setHollowWithLineNumbers(\$parserState, $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; } # end foreach (parts of the current line) } # end while (continue && ...) 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); $parserState->{lastTreeNode} = $treeCur; $parserState->{inputCounter} = $inputCounter; print STDERR "PARSERSTATE: $parserState\n" if ($localDebug); if ($parserState->{inMacro} == 3) { if (!$HeaderDoc::skipNextPDefine) { cpp_add($treeTop); } else { cpp_add($treeTop, 1); $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); while ($tempParserState) { $parserState = $tempParserState; $tempParserState = pop(@parserStack); } $HeaderDoc::module = $parserState->{MODULE}; if ($localDebug || $apDebug || $liteDebug || $parseDebug) { 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 "FC: ".$parserState->{functionContents}."\n"; return blockParseReturnState($parserState, $treeTop, $argparse, $declaration, $inPrivateParamTypes, $publicDeclaration, $lastACS, $retDebug, $fileoffset, 0, $definename, $inputCounter); } extendsClass: implementsClass: -=: LIST OF PARSED PARAMETERS :=- -=: DUMP OF PARSE TREE :=- +---sub +--- +---blockParse +---[ NEWLINE ] -=: COMPUTED VALUE :=- SUCCESS: 0 VALUE: 0 -=: CPP CHANGES :=- NO CPP CHANGES -=: FOUND MATCH :=- 1 -=: NAMED OBJECTS :=- TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::Header NAME: Perl function 2 APIUID: //test_ref/doc/header/Perl_function_2.test ABSTRACT: "" DISCUSSION: "

" UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::Header" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TREE COUNT: 1 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::Function NAME: blockParse APIUID: //test_ref/perl/func/blockParse ABSTRACT: "" DISCUSSION: "

The blockParse function is the core of HeaderDoc's parse engine. " UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "default_function_group" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::Function" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "0" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TAGGED PARAMETERS: TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::MinorAPIElement NAME: filename TYPE: APIUID: //test_ref/doc/functionparam/blockParse/filename ABSTRACT: "" DISCUSSION: "

the filename being parser." UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::MinorAPIElement" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::MinorAPIElement NAME: fileoffset TYPE: APIUID: //test_ref/doc/functionparam/blockParse/fileoffset ABSTRACT: "" DISCUSSION: "

the line number where the current block begins. The line number printed is (fileoffset + inputCounter)." UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::MinorAPIElement" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::MinorAPIElement NAME: inputLinesRef TYPE: APIUID: //test_ref/doc/functionparam/blockParse/inputLinesRef ABSTRACT: "" DISCUSSION: "

a reference to an array of code lines." UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::MinorAPIElement" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::MinorAPIElement NAME: inputCounter TYPE: APIUID: //test_ref/doc/functionparam/blockParse/inputCounter ABSTRACT: "" DISCUSSION: "

the offset within the array. This is added to fileoffset when printing the line number." UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::MinorAPIElement" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::MinorAPIElement NAME: argparse TYPE: APIUID: //test_ref/doc/functionparam/blockParse/argparse ABSTRACT: "" DISCUSSION: "

disable warnings when parsing arguments to avoid seeing them twice." UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::MinorAPIElement" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::MinorAPIElement NAME: ignoreref TYPE: APIUID: //test_ref/doc/functionparam/blockParse/ignoreref ABSTRACT: "" DISCUSSION: "

a reference to a hash of tokens to ignore on all headers." UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::MinorAPIElement" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::MinorAPIElement NAME: perheaderignoreref TYPE: APIUID: //test_ref/doc/functionparam/blockParse/perheaderignoreref ABSTRACT: "" DISCUSSION: "

a reference to a hash of tokens, generated from @ignore headerdoc comments." UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::MinorAPIElement" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::MinorAPIElement NAME: perheaderignorefuncmacrosref TYPE: APIUID: //test_ref/doc/functionparam/blockParse/perheaderignorefuncmacrosref ABSTRACT: "" DISCUSSION: "

a reference to a hash of tokens, generated from @ignorefunmacro headerdoc comments." UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::MinorAPIElement" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::MinorAPIElement NAME: keywordhashref TYPE: APIUID: //test_ref/doc/functionparam/blockParse/keywordhashref ABSTRACT: "" DISCUSSION: "

a reference to a hash of keywords." UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::MinorAPIElement" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: TREE COUNT: 0 INDEX GROUP: IS BLOCK: OBJECT TYPE: HeaderDoc::MinorAPIElement NAME: case_sensitive TYPE: APIUID: //test_ref/doc/functionparam/blockParse/case_sensitive ABSTRACT: "" DISCUSSION: "

boolean: controls whether keywords should be processed in a case-sensitive fashion." UPDATED: "" COPYRIGHT: "" HTMLMETA: "" PRIVATEDECLARATION: "" GROUP: "" INDEXGROUP: "" THROWS: "" XMLTHROWS: "" UPDATED: "" LINKAGESTATE: "" ACCESSCONTROL: "" AVAILABILITY: "" LINKUID: "" ORIGCLASS: "" ISDEFINE: "" ISTEMPLATE: "" VALUE: "UNKNOWN" RETURNTYPE: "" LINENUM: "" CLASS: "HeaderDoc::MinorAPIElement" MASTERENUM: "" APIREFSETUPDONE: "1" TPCDONE: "" NOREGISTERUID: "" SUPPRESSCHILDREN: "" NAMELINE_DISCUSSION: "" HIDEDOC: "" HIDESINGLETONS: "" HIDECONTENTS: "" MAINOBJECT: "" LIST ATTRIBUTES: SHORT ATTRIBUTES: LONG ATTRIBUTES: -=: NAMED OBJECT PARSE TREES :=- OBJECT: blockParse (HeaderDoc::Function) +---sub +--- +---blockParse +---[ NEWLINE ] END OF OBJECT -=: HTML OUTPUT OF PARSE TREES :=- OBJECT: blockParse (HeaderDoc::Function) sub blockParse END OF OBJECT _$97|/Users/dg/headerdoc-techpubs/Modules/HeaderDoc//../../testsuite/parser_tests/Perl_function_2.test$4|perl$15|Perl function 2$4|perl$6|parser