kerneltest/e32utils/trace/btracevw.pl
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 #
       
     2 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 # All rights reserved.
       
     4 # This component and the accompanying materials are made available
       
     5 # under the terms of the License "Eclipse Public License v1.0"
       
     6 # which accompanies this distribution, and is available
       
     7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 #
       
     9 # Initial Contributors:
       
    10 # Nokia Corporation - initial contribution.
       
    11 #
       
    12 # Contributors:
       
    13 #
       
    14 # Description:
       
    15 #
       
    16 
       
    17 #!/usr/bin/perl
       
    18 
       
    19 use File::Find;
       
    20 use File::Spec::Functions;
       
    21 
       
    22 
       
    23 	my $TraceFileName;
       
    24 	
       
    25 	my $PrintFlagFilePos = 0;
       
    26 	my $PrintFlagHdrLen = 0;
       
    27 	my $PrintFlagHdrFlags = 0;
       
    28 	my $PrintFlagFormatString = 0;
       
    29 	my $VerboseMode = 0;
       
    30 	my $RawMode = 0;
       
    31 	my $FormatIdIsSubCategory = 0;
       
    32 	my $OutputSawDictionaryMode = 0;
       
    33 	
       
    34 	# for the category range 0-191, the format string is indexed by the category & subcategory
       
    35 	%FormatTables = 
       
    36 		(
       
    37 		0 => 			# ERDebugPrintf
       
    38 			{
       
    39 			0 => "ThreadId %h, %s",
       
    40 			},
       
    41 	
       
    42 		1 => 			# ERKernPrintf
       
    43 			{
       
    44 			0 => "ThreadId %h, %s",
       
    45 			},
       
    46 
       
    47 		3 =>			# EThreadIdentification
       
    48 			{	
       
    49 			0 => "ENanoThreadCreate, NThread %x",
       
    50 			1 => "ENanoThreadDestroy, NThread %x",
       
    51 			2 => "EThreadCreate, NThread %x, DProcess %x, name %s",
       
    52 			3 => "EThreadDestroy, NThread %x, DProcess %x, Id %x",
       
    53 			4 => "EThreadName, NThread %x, DProcess %x, name %s",
       
    54 			5 => "EProcessName, NThread %x, DProcess %x, name %s",
       
    55 			6 => "EThreadId, NThread %x, DProcess %x, Id %x",
       
    56 			7 => "EProcessCreate, DProcess %x",
       
    57 			8 => "EProcessDestroy, DProcess %x",
       
    58 			},
       
    59 		);
       
    60 
       
    61 	my @typedefs;
       
    62 	my @members;
       
    63 	my %values	= (
       
    64 #		UTF::KInitialClientFormat		=>	{type=>"TFormatId", size=>2, value=>512}
       
    65 		KMaxTUint8						=> {type=>"TUint8", size=>1, value=>255},
       
    66 		KMaxTUint16						=> {type=>"TUint16", size=>2, value=>65535}
       
    67 	);
       
    68 	my %macros;
       
    69 	my @classes;
       
    70 	my @enums;
       
    71 	my %formatStrings;		# each enum may have it's own format string
       
    72 	my %formatCategories;	# each enum may have it's own format category
       
    73 	
       
    74 	my %filescope;
       
    75 	$filescope{file}=1;
       
    76 	undef $filescope{name};	
       
    77 
       
    78 	$filescope{typedefs}=\@typedefs;
       
    79 	$filescope{members}=\@members;
       
    80 	$filescope{values}=\%values;
       
    81 	$filescope{macros} = \%macros;
       
    82 	$filescope{FormatTables} = \%FormatTables;
       
    83 	
       
    84 	$filescope{classes} = \@classes;
       
    85 	$filescope{enums} = \@enums;
       
    86 
       
    87 	$filescope{formatStrings} =\%formatStrings;
       
    88 	$filescope{formatCategories} = \%formatCategories;
       
    89 	
       
    90 		
       
    91 		
       
    92 	if (@ARGV == 0)
       
    93   		{
       
    94   		print "BTraceVw.pl \n";
       
    95   		print "An unsupported utility which extracts UTrace-style format-strings\n";
       
    96   		print "from header files & uses these to decode a BTrace output file\n";
       
    97   		print "Syntax : BTraceVw.pl [-v] [-r] [-sd] [-i <IncFilePath>] [<BTrace file>]\n";
       
    98   		print "where  : -v  = verbose mode\n";
       
    99   		print "       : -r  = raw output mode\n";
       
   100   		print "       : -sd = produce SAW trace viewer dictionary file\n";
       
   101   		print "       :       this file then needs to be merged into the 'com.symbian.analysis.trace.ui.prefs' file\n";
       
   102   		print "       :       located under the carbide workspace directory\n";
       
   103 		print "\n";
       
   104   		
       
   105 		print "e.g. (this decodes a trace file & produces a comma-separated output file) : \n";
       
   106 		print "btracevw.pl -i /os/kernelhwsrv/userlibandfileserver/fileserver/inc/f32tracedef.h -i /os/kernelhwsrv/userlibandfileserver/fileserver/inc/utraceefsrv.h -i /os/kernelhwsrv/userlibandfileserver/fileserver/inc/utraceefile.h trace.utf >trace.csv\n";
       
   107 		print "\n";
       
   108 		print "e.g. (this overwrites the SAW dictioany file) : \n";
       
   109 		print "btracevw.pl -sd -i /os/kernelhwsrv/userlibandfileserver/fileserver/inc/f32tracedef.h -i /os/kernelhwsrv/userlibandfileserver/fileserver/inc/utraceefsrv.h -i /os/kernelhwsrv/userlibandfileserver/fileserver/inc/utraceefile.h >com.symbian.analysis.trace.ui.prefs\n";
       
   110   		
       
   111 		exit;
       
   112 		}
       
   113 
       
   114 	while (@ARGV > 0)
       
   115 		{
       
   116 		
       
   117 		if ($ARGV[0] eq "-i")
       
   118 	        {
       
   119 	        shift @ARGV;
       
   120 		    ($FilePath) = @ARGV;
       
   121 	        shift @ARGV;
       
   122 
       
   123 	        undef @incFiles;
       
   124 		    @incFiles;
       
   125 		
       
   126 		    find sub { push @incFiles, $File::Find::name if m/\.h$/i;}, $FilePath ;
       
   127 		    foreach $incFile (@incFiles)
       
   128 		        {
       
   129 				H2Trace($incFile, \%filescope);
       
   130 		        }
       
   131 	        }
       
   132 		elsif ($ARGV[0] eq "-r")
       
   133 	        {
       
   134 		    $RawMode = 1;
       
   135    	        shift @ARGV;
       
   136 	        }
       
   137 		elsif ($ARGV[0] eq "-sd")
       
   138 	        {
       
   139 		    $OutputSawDictionaryMode = 1;
       
   140    	        shift @ARGV;
       
   141 	        }
       
   142 		elsif ($ARGV[0] eq "-v")
       
   143 	        {
       
   144 		    $VerboseMode = 1;
       
   145    	        shift @ARGV;
       
   146 	        }
       
   147 	    else
       
   148 	    	{
       
   149 			$TraceFileName = "$ARGV[0]";
       
   150 	        shift @ARGV;
       
   151 	    	}
       
   152         }
       
   153 		
       
   154 	if ($VerboseMode)
       
   155 		{
       
   156 		dump_scope(\%filescope);
       
   157 		PrintFormatTables(\%FormatTables);
       
   158 		}
       
   159 	if ($OutputSawDictionaryMode)
       
   160 		{
       
   161 		OutputSawDictionary(\%FormatTables);
       
   162 		}
       
   163 
       
   164     if (defined ($TraceFileName))
       
   165         {
       
   166         ReadTraceFile($RawMode);
       
   167         }
       
   168 
       
   169         
       
   170         
       
   171         
       
   172 sub ReadTraceFile($)
       
   173     {
       
   174 	(my $RawMode) = @_;
       
   175 #	print "Trace file is $TraceFileName, RawMode $RawMode, VerboseMode $VerboseMode\n\n";
       
   176 
       
   177 	open (LOGFILE, "<$TraceFileName") or die "Can't open $TraceFileName: $!\n";
       
   178 	binmode (LOGFILE);
       
   179 
       
   180 	my $val = 0;
       
   181 
       
   182 
       
   183 	# enum TFlags from e32btrace.h
       
   184 	$EHeader2Present	= 1<<0;
       
   185 	$ETimestampPresent	= 1<<1;
       
   186 	$ETimestamp2Present	= 1<<2;
       
   187 	$EContextIdPresent	= 1<<3;
       
   188 	$EPcPresent			= 1<<4;
       
   189 	$EExtraPresent		= 1<<5;
       
   190 	$ERecordTruncated	= 1<<6;
       
   191 	$EMissingRecord		= 1<<7;
       
   192 	
       
   193 	# enum TFlags2 from e32btrace.h
       
   194 	$EMultipartFlagMask	= 3<<0;
       
   195 	$ECpuIdMask			= 0xfff<<20;
       
   196 
       
   197 	# enum TMultiPart from e32btrace.h
       
   198 	$EMultipartFirst	= 1;
       
   199 	$EMultipartMiddle	= 2;
       
   200 	$EMultipartLast		= 3;
       
   201 	
       
   202 	$EMaxBTraceDataArray = 80;
       
   203 	
       
   204 	# enum TCategory from e32btrace.h
       
   205 	$EThreadIdentification = 3;
       
   206 	
       
   207 	# enum TThreadIdentification from e32btrace.h
       
   208 	$EThreadCreate = 2;
       
   209 	$EThreadName = 4;
       
   210 	$EProcessName = 5;
       
   211 	$EThreadId = 6;
       
   212 	
       
   213 	# Context Id bits from e32btrace.h
       
   214 	$EContextIdMask = 0x00000003;
       
   215 	$EContextIdThread = 0;
       
   216 	$EContextIdFIQ = 0x1;
       
   217 	$EContextIdIRQ = 0x2;
       
   218 	$EContextIdIDFC = 0x3;
       
   219 
       
   220 	# enum TClassificationRange from e32btraceu.h
       
   221 	$EAllRangeFirst = 192;
       
   222 	$EAllRangeLast = 222;
       
   223 
       
   224 	%TCategoryIdToString = 
       
   225 		(
       
   226 		0 => "ERDebugPrintf",
       
   227 		1 => "EKernPrintf",
       
   228 		2 => "EPlatsecPrintf",
       
   229 		3 => "EThreadIdentification",
       
   230 		4 => "ECpuUsage",
       
   231         5 => "EKernPerfLog",
       
   232         6 => "EClientServer",
       
   233         7 => "ERequests",
       
   234         8 => "EChunks",
       
   235         9 => "ECodeSegs",
       
   236 		10 => "EPaging",
       
   237 		11 => "EThreadPriority",
       
   238 		12 => "EPagingMedia",
       
   239 		13 => "EKernelMemory",
       
   240 		14 => "EHeap",
       
   241 		15 => "EMetaTrace",
       
   242 		16 => "ERamAllocator",
       
   243 		17 => "EFastMutex",
       
   244 		18 => "EProfiling", 
       
   245         19 => "EResourceManager",
       
   246         20 => "EResourceManagerUs",
       
   247 		21 => "ERawEvent ",
       
   248 		128 => "EPlatformSpecificFirst",
       
   249 		191 => "EPlatformSpecificLast",
       
   250 		192 => "ESymbianExtentionsFirst",
       
   251 
       
   252 		# UTrace "ALL" range 
       
   253 		192 => "EPanic",
       
   254 		193 => "EError",
       
   255 		194 => "EWarning", 
       
   256 		195 => "EBorder", 
       
   257 		196 => "EState", 
       
   258 		197 => "EInternals", 
       
   259 		198 => "EDump", 
       
   260 		199 => "EFlow", 
       
   261 		200 => "ESystemCharacteristicMetrics", 
       
   262 		201 => "EAdhoc",
       
   263 
       
   264 		253 => "ESymbianExtentionsLast",
       
   265 		254 => "ETest1",
       
   266 		255 => "ETest2",
       
   267 		);
       
   268 
       
   269 
       
   270 	%ProcessNames;
       
   271 	%ThreadNames;
       
   272 	%ThreadIds;
       
   273 	
       
   274 	
       
   275 	# print column titles
       
   276 	if ($PrintFlagFilePos) {printf "FilePos, ";}	# col #0
       
   277 	if ($PrintFlagHdrLen) {	printf "Len, ";}		# col #1
       
   278 	if ($PrintFlagHdrFlags) {printf "Flags, "; }	# col #2
       
   279 	printf "Category, ";			# col #3
       
   280 	printf "TimeStamp, ";			# col #4
       
   281 	printf "Delta, ";				# col #5
       
   282 	printf "context Id, ";			# col #6
       
   283 	printf "PC, ";					# col #7
       
   284 	printf "UID, ";					# col #8
       
   285 	if ($PrintFlagFormatString){printf "Format string, ";}	# col #9
       
   286 	printf "Formatted text, ";		# col #10
       
   287 	print "\n\n";
       
   288 
       
   289 	
       
   290 	while (1)
       
   291 		{
       
   292 		my $pos = tell (LOGFILE);
       
   293 		
       
   294 		# print file pos (col #0)
       
   295 		if ($PrintFlagFilePos){	printf ("0x%08X, ", $pos);}
       
   296 		
       
   297 		my $category;
       
   298 		my $subCategory;
       
   299 		my $multipartFlags = 0;
       
   300 		my $recordData = "";
       
   301 		my $recordLen;
       
   302 		my $recordPos = 0;
       
   303 		
       
   304 		$recordLen = ReadRecord(LOGFILE, \$pos, \$recordData, \$category, \$subCategory, \$multipartFlags, $RawMode);
       
   305 		if ($recordLen == -1)
       
   306 			{last;}
       
   307 
       
   308 			
       
   309 		if (!$RawMode && ($multipartFlags == $EMultipartMiddle || $multipartFlags == $EMultipartLast))
       
   310 			{next;}
       
   311 					
       
   312 #		print record contents
       
   313 #		my $buf;
       
   314 #					for (my $i=0; $i < $recordLen; $i+=4)
       
   315 #						{
       
   316 #		$buf.= sprintf ("%08X ", unpack("V", substr($recordData, $recordPos+$i, 4)));
       
   317 #						}
       
   318 #		printf "\n[$buf\n]";				
       
   319 
       
   320 
       
   321 		# for UTrace "ALL" range, read UID 
       
   322 		if ($category >= $EAllRangeFirst && $category <= $EAllRangeLast && 
       
   323 			(!$RawMode) && $multipartFlags != $EMultipartMiddle && $multipartFlags != $EMultipartLast)
       
   324 			{
       
   325 			$uid = unpack("V", substr($recordData, $recordPos, 4));
       
   326 			$recordPos+= 4;	
       
   327 
       
   328 			# then read formatID			
       
   329 			$FormatIdIsSubCategory = ($subCategory != 0) ? 1 : 0;
       
   330 			if ($FormatIdIsSubCategory)
       
   331 				{
       
   332 				$formatId = $subCategory
       
   333 				}
       
   334 			else				
       
   335 				{
       
   336 				$formatId = unpack("V", substr($recordData, $recordPos, 4));
       
   337   				$recordPos+= 4;
       
   338 				}
       
   339 			}
       
   340 		
       
   341 					
       
   342 		# print UID (col #8)
       
   343 		printf "0x%08X, ", $uid;
       
   344 
       
   345 			
       
   346 		my $formatTable;
       
   347 		my $formatString;
       
   348 		if ($category >= $EAllRangeFirst && $category <= $EAllRangeLast)
       
   349 			{
       
   350 			$formatString = $FormatTables{$uid}{$formatId};
       
   351 			}
       
   352 		else
       
   353 			{
       
   354 			$formatString = $FormatTables{$category}{$subCategory};
       
   355 			}
       
   356 
       
   357 
       
   358 		# Get thread names
       
   359 		if ($category == $EThreadIdentification)
       
   360 			{
       
   361 			if ($subCategory == $EProcessName)
       
   362 				{
       
   363 				my $process = unpack("V", substr($recordData, 4, 4));
       
   364 				my $processName = substr($recordData, 8, $recordLen - 8);	
       
   365 #				printf ("\nprocess [%08X] processName [$processName]\n", $process);
       
   366 				$ProcessNames{$process} = $processName;
       
   367 				}
       
   368 			elsif ($subCategory == $EThreadCreate || $subCategory == $EThreadName)
       
   369 				{
       
   370 				my $thread = unpack("V", substr($recordData, 0, 4));
       
   371 				my $process = unpack("V", substr($recordData, 4, 4));
       
   372 				my $threadName = substr($recordData, 8, $recordLen - 8);	
       
   373 #				printf ("\nprocess [%08X] thread [%08X] threadName [$threadName]\n", $process, $thread, $threadName);
       
   374 				$ThreadNames{$thread} = $ProcessNames{$process} . "::" . $threadName;
       
   375 				}
       
   376 			elsif ($subCategory == $EThreadId)
       
   377 				{
       
   378 				my $thread = unpack("V", substr($recordData, 0, 4));
       
   379 				my $process = unpack("V", substr($recordData, 4, 4));
       
   380 				my $threadId = unpack("V", substr($recordData, 8, 4));
       
   381 #				printf ("\nprocess [%08X] thread [%08X] threadId [%08X]\n", $process, $thread, $threadId);
       
   382 				$ThreadIds{$thread} = $threadId;
       
   383 				}
       
   384 			}
       
   385 			
       
   386 			
       
   387 		# print Format string (col #9)
       
   388 		if ($PrintFlagFormatString)
       
   389 			{
       
   390 			my $formatStringWithoutCommas = $formatString;
       
   391 			$formatStringWithoutCommas=~ s/,/ /g;
       
   392 			printf "%s, ", $formatStringWithoutCommas;
       
   393 			}
       
   394 
       
   395 		my $formattedText;
       
   396 		
       
   397 		my $lenFormatString = length($formatString);
       
   398 		if ($lenFormatString && !$RawMode && $multipartFlags != $EMultipartMiddle && $multipartFlags != $EMultipartLast)
       
   399 			{
       
   400 			for (my $i=0; $i<$lenFormatString; $i++)
       
   401 				{
       
   402 				my $c = (substr ($formatString, $i, 1));
       
   403 #				printf "$c\n";
       
   404 				if ($c eq "%")
       
   405 					{
       
   406 					undef my $fieldLen;
       
   407 					$i++;
       
   408 	        		$c = (substr ($formatString, $i, 1));
       
   409 					if ($c eq "%")
       
   410 						{
       
   411 						$formattedText.= substr ($formatString, $i, 1);
       
   412 						next;
       
   413 						}
       
   414 					if ($c eq "*")	## take length from buffer
       
   415 						{
       
   416 						$fieldLen = unpack("V", substr($recordData, $recordPos, 4));
       
   417 						if ($fieldLen > $recordLen-$recordPos)
       
   418 							{
       
   419 							$formattedText.= "*** Invalid field length ***";
       
   420 							last;
       
   421 							}
       
   422 						$recordPos+= 4;
       
   423 						$i++;
       
   424 		        		$c = (substr ($formatString, $i, 1));
       
   425 						}
       
   426 					if (lc $c eq "x" || $c eq "h")
       
   427 						{
       
   428 						if (defined $fieldLen)
       
   429 							{
       
   430 							if (($fieldLen & 3) == 0)
       
   431 								{
       
   432 								for (my $i=0; $i< $fieldLen; $i+= 4)
       
   433 									{
       
   434 									$formattedText.= sprintf ("%08X ", unpack("V", substr($recordData, $recordPos, 4)));
       
   435 									$recordPos+= 4;
       
   436 									}
       
   437 								}
       
   438 							else
       
   439 								{
       
   440 								for (my $i=0; $i< $fieldLen; $i++)
       
   441 									{
       
   442 									$formattedText.= sprintf ("%02X ", unpack("C", substr($recordData, $recordPos, 1)));
       
   443 									$recordPos++;
       
   444 									}
       
   445 								}
       
   446 							}
       
   447 						else
       
   448 							{
       
   449 							$formattedText.= sprintf ("0x%08X", unpack("V", substr($recordData, $recordPos, 4)));
       
   450 							$recordPos+= 4;
       
   451 							}
       
   452 						$recordPos = ($recordPos + 3) & ~3;
       
   453 						next;
       
   454 						}
       
   455 					# display "%ld" as hex for now as don't know how to get perl to use or display a 64 decimal value
       
   456 					elsif (lc $c eq "l" && substr ($formatString, $i+1, 1) eq "d")
       
   457 						{
       
   458 						$i++;
       
   459 						my $loWord = unpack("V", substr($recordData, $recordPos, 4));
       
   460 						$recordPos+= 4;
       
   461 						my $hiWord = unpack("V", substr($recordData, $recordPos, 4));
       
   462 						$recordPos+= 4;
       
   463 						$formattedText.= sprintf ("0x%X:%08X", $hiWord, $loWord);
       
   464 						}
       
   465 					elsif (lc $c eq "l" && substr ($formatString, $i+1, 1) eq "x")
       
   466 						{
       
   467 						$i++;
       
   468 						my $loWord = unpack("V", substr($recordData, $recordPos, 4));
       
   469 						$recordPos+= 4;
       
   470 						my $hiWord = unpack("V", substr($recordData, $recordPos, 4));
       
   471 						$recordPos+= 4;
       
   472 						$formattedText.= sprintf ("0x%X:%08X", $hiWord, $loWord);
       
   473 						}
       
   474 					elsif (lc $c eq "d")
       
   475 						{
       
   476 						$formattedText.= sprintf ("%d", unpack("V", substr($recordData, $recordPos, 4)));
       
   477 						$recordPos+= 4;
       
   478 						$recordPos = ($recordPos + 3) & ~3;
       
   479 						next;
       
   480 						}
       
   481 					elsif ($c eq "s")
       
   482 						{
       
   483 						if (!defined $fieldLen) 
       
   484 							{$fieldLen = $recordLen - $recordPos;}
       
   485 						$formattedText.= substr($recordData, $recordPos, $fieldLen);
       
   486 						$recordPos+= $fieldLen; 
       
   487 						$recordPos = ($recordPos + 3) & ~3;
       
   488 						next;
       
   489 						}
       
   490 					elsif ($c eq "S")
       
   491 						{
       
   492 						if (!defined $fieldLen) 
       
   493 							{$fieldLen = $recordLen-$recordPos;}
       
   494 						for (my $j=0; $j < $fieldLen; $j+=2)
       
   495 							{
       
   496 					        my $byte = unpack("c", substr ($recordData, $recordPos+$j, 1));
       
   497  							$formattedText.= sprintf ("%c", $byte);
       
   498 							}
       
   499 						$recordPos+= $fieldLen; 
       
   500 						$recordPos = ($recordPos + 3) & ~3;
       
   501 						next;
       
   502 						}
       
   503 					elsif ($c eq "c")
       
   504 						{
       
   505 				        my $byte = unpack("c", substr ($recordData, $recordPos, 1));
       
   506 						$formattedText.= sprintf ("%c", $byte);
       
   507 						}
       
   508 					}
       
   509 				else
       
   510 					{
       
   511 					$formattedText.= $c;
       
   512 					}
       
   513 				}
       
   514 			}
       
   515 		else	# no format string : print as hex
       
   516 			{
       
   517 			for (my $i=0; $i < $recordLen; $i+=4)
       
   518 				{
       
   519 				$formattedText.= sprintf ("%08X ", unpack("V", substr($recordData, $i, 4)));
       
   520 				}
       
   521 			$recordPos+= $recordLen; $recordLen = 0;
       
   522 			
       
   523 			}
       
   524 		
       
   525 
       
   526 		# print Formatted text (col #10)
       
   527 		$formattedText=~ s/,/;/g;
       
   528 		$formattedText=~ s/\r//g;
       
   529 		$formattedText=~ s/\n/,/g;
       
   530 		printf "%s", $formattedText;
       
   531 
       
   532 		printf("\n");
       
   533 
       
   534 		if ($len < 0 || $recordLen < 0)	{die "truncated file";}
       
   535   
       
   536 
       
   537 		$pos+= ($len +3) & ~3;
       
   538 		seek (LOGFILE, $pos, SEEK_SET) or die "truncated file";
       
   539 		$i++;
       
   540 		}
       
   541 
       
   542 	close (LOGFILE);
       
   543 
       
   544 	if ($VerboseMode)
       
   545 		{
       
   546 		print "*** Processes ***\n";
       
   547 		for $id ( keys %ProcessNames )
       
   548 			{
       
   549 			printf ("process %08X ProcessName %s\n", $id, $ProcessNames{$id});
       
   550 			}
       
   551 		print "*** Thread ***\n";
       
   552 		for $id ( keys %ThreadNames )
       
   553 			{
       
   554 			printf ("thread %08X ThreadName %s::%X\n", $id, $ThreadNames{$id}, $ThreadIds{$id});
       
   555 			}
       
   556 		}
       
   557 
       
   558     }
       
   559 
       
   560     
       
   561 sub ReadSingleRecord
       
   562 	{
       
   563 	($fh, $data, $dataLen, $recordLen, $category, $subCategory, $multipartFlags, $extraN, $totalLen, $offset, $RawMode) = @_;	
       
   564 	
       
   565 	my $hdr;
       
   566 	my $flags;
       
   567 	my $header2;
       
   568 	my $timestamp;
       
   569 	my $timestamp2;
       
   570 	my $contextId;
       
   571 	my $programConter;	
       
   572 	
       
   573 	my $recordOffset = 0;
       
   574 	
       
   575 	$timestampLast;	
       
   576 	my $timestampDelta = 0;	
       
   577 	
       
   578 	my $bytesRead = read($fh, $hdr, 4);
       
   579 	
       
   580 	
       
   581 	if ($bytesRead < 4)	
       
   582 		{return -1;}
       
   583 
       
   584 	($$recordLen,$flags,$$category,$$subCategory) = unpack("CCCC", $hdr);
       
   585 	$$dataLen = $$recordLen-4;
       
   586 	
       
   587 	if ($flags & $EHeader2Present)
       
   588 		{$$multipartFlags = (ReadDword($fh) & $EMultipartFlagMask); $$dataLen-= 4}
       
   589 	else
       
   590 		{$$multipartFlags = 0;}
       
   591 	if ($flags & $ETimestampPresent)
       
   592 		{$timestamp = ReadDword($fh); $$dataLen-= 4;}
       
   593 	if ($flags & $ETimestamp2Present)
       
   594 		{$timestamp2 = ReadDword($fh); $$dataLen-= 4;}
       
   595 	if ($flags & $EContextIdPresent)
       
   596 		{$contextId = ReadDword($fh); $$dataLen-= 4;}
       
   597 	if ($flags & $EPcPresent)
       
   598 		{$programConter = ReadDword($fh); $$dataLen-= 4;}
       
   599 	if ($flags & $EExtraPresent)
       
   600 		{$$extraN = ReadDword($fh); $$dataLen-= 4;}
       
   601 	if ($$multipartFlags != 0)
       
   602 		{
       
   603 		$$totalLen = ReadDword($fh);  $$dataLen-= 4;
       
   604 		if ($$multipartFlags == $EMultipartMiddle || $$multipartFlags == $EMultipartLast)
       
   605 			{$$offset = ReadDword($fh);  $$totalLen-= 4; $$dataLen-= 4;}
       
   606 		}				
       
   607 
       
   608 	$timestampDelta = $timestamp - $timestampLast;
       
   609 	$timestampLast = $timestamp;
       
   610 
       
   611 	read($fh, $$data, ($$dataLen + 3) & ~3);
       
   612 
       
   613 
       
   614 	if ($RawMode || $$multipartFlags == $EMultipartFirst || $$multipartFlags == 0)
       
   615 		{
       
   616 		# print header len (col #1)
       
   617 		if ($PrintFlagHdrLen){printf ("0x%02X, ", $$recordLen);}
       
   618 	
       
   619 		# print header flags (col #2)
       
   620 		if ($PrintFlagHdrFlags)
       
   621 			{
       
   622 			printf ("%02X ", $flags);
       
   623 			if ($flags & $EHeader2Present) {printf "EHeader2Present ";}
       
   624 			if ($flags & $ETimestampPresent) {printf "ETimestampPresent ";}
       
   625 			if ($flags & $ETimestamp2Present) {printf "ETimestamp2Present ";}
       
   626 			if ($flags & $EContextIdPresent) {printf "EContextIdPresent ";}
       
   627 			if ($flags & $EPcPresent) {printf "EPcPresent ";}
       
   628 			if ($$multipartFlags != 0)
       
   629 				{
       
   630 				printf "EExtraPresent ";
       
   631 				if ($$multipartFlags == $EMultipartFirst) {print "EMultipartFirst ";}
       
   632 				elsif ($$multipartFlags == $EMultipartMiddle) {print "EMultipartMiddle ";}
       
   633 				elsif ($$multipartFlags == $EMultipartLast) {print "EMultipartLast ";}
       
   634 				printf ("ExtraN(0x%08X) ", $$extraN);
       
   635 				}
       
   636 			if ($flags & $ERecordTruncated) {printf "ERecordTruncated ";}
       
   637 			if ($flags & $EMissingRecord) {printf "EMissingRecord ";}
       
   638 			print ",";
       
   639 			}
       
   640 				
       
   641 		# print category (col #3)
       
   642 		printf "(%d;%d) $categoryString  , ", $$category, $$subCategory;
       
   643 	
       
   644 		# print timestamp(s) (col #4)
       
   645 		printf "0x";
       
   646 		if (defined $timestamp2) {printf "%08X : ", $timestamp2;}
       
   647 		printf "%08X", $timestamp;
       
   648 		printf ", ";;
       
   649 	
       
   650 		# print timestamp delta (col #5)
       
   651 		printf "0x%08X, ", $timestampDelta;
       
   652 
       
   653 		# print context Id (col #6)
       
   654 		if (!$RawMode && defined $ThreadNames{$contextId})
       
   655 			{
       
   656 			printf ("%s::%X, ", $ThreadNames{$contextId}, $ThreadIds{$contextId});
       
   657 			}
       
   658 		else			
       
   659 			{
       
   660 			if ((($contextId & $EContextIdMask) == $EContextIdThread) || $RawMode)
       
   661 				{printf "0x%08X, ", $contextId;}
       
   662 			elsif (($contextId & $EContextIdMask) == $EContextIdFIQ)
       
   663 				{printf "FIQ, ";}
       
   664 			elsif (($contextId & $EContextIdMask) == $EContextIdIRQ)
       
   665 				{printf "IRQ, ";}
       
   666 			elsif (($contextId & $EContextIdMask) == $EContextIdIDFC)
       
   667 				{printf "IDFC, ";}
       
   668 			}
       
   669 	
       
   670 		# print Program Counter (col #7)
       
   671 		printf "0x%08X, ", $programConter;
       
   672 		}
       
   673 
       
   674 		
       
   675 	
       
   676 	
       
   677 #########################################################
       
   678 #	my $hex;
       
   679 #	for (my $i=0; $i < $$dataLen; $i+=4)
       
   680 #		{
       
   681 #		$hex.= sprintf ("%08X ", unpack("V", substr($$data, $i, 4)));
       
   682 #		}
       
   683 #	printf "\nadding [$hex]\n";
       
   684 #########################################################
       
   685 	return $bytesRead
       
   686 	}
       
   687 
       
   688 	      
       
   689 sub ReadRecord 
       
   690 	{
       
   691 	($fh, $recordPos, $recordData, $category, $subCategory, $multipartFlags, $RawMode) = @_;
       
   692 #	printf "CurrentPos %08X\n", $pos;
       
   693 
       
   694 
       
   695 
       
   696 	seek ($fh, $$recordPos, SEEK_SET) or die "truncated file";
       
   697 	my $recordLen;
       
   698 	my $extraN;
       
   699 	my $totalLen;
       
   700 	my $offset;
       
   701 	my $dataLen;
       
   702 	my $data;
       
   703 	my $bytesRead;
       
   704 	
       
   705 	
       
   706 	$bytesRead = ReadSingleRecord($fh,  \$data, \$dataLen, \$recordLen, \$$category, \$$subCategory, \$$multipartFlags, \$extraN, \$totalLen, \$offset, $RawMode);
       
   707 
       
   708 	if ($bytesRead == -1)	# eof ?
       
   709 		{return -1; }
       
   710 	$$recordPos+= ($recordLen +3) & ~3;
       
   711 	
       
   712 	$$recordData = $data;
       
   713     $offset = $dataLen;
       
   714 
       
   715 	$offset-= 4;		# subtract 4 bytes for UID ?????????
       
   716     
       
   717     if ($RawMode || $$multipartFlags != $EMultipartFirst)
       
   718     	{return $dataLen;}
       
   719 
       
   720     $pos = $$recordPos;
       
   721 
       
   722 	while (1)
       
   723 		{
       
   724 		
       
   725 		# find next record, i.e. look for a record which matches $extraN 
       
   726 		
       
   727 		seek ($fh, $pos, SEEK_SET) or die "truncated file";
       
   728 
       
   729 		my $recordLen;
       
   730 		
       
   731 		my $category;
       
   732 		my $subCategory;
       
   733 		my $multipartFlags;
       
   734 		my $currentExtraN;
       
   735 		my $currentOffset;
       
   736 		
       
   737 		my $totalLen;
       
   738 		my $currentDataLen;
       
   739 		my $data;
       
   740 		$bytesRead = ReadSingleRecord($fh, \$data, \$currentDataLen, \$recordLen, \$category, \$subCategory, \$multipartFlags, \$currentExtraN, \$totalLen, \$currentOffset, $RawMode);
       
   741 		if ($bytesRead == -1)	# eof ?
       
   742 			{return -1; }
       
   743 		$pos+= ($recordLen +3) & ~3;
       
   744 		
       
   745 #		printf "\npos %08X, Seaching for (extra %08X, offset %08X), found (extra %08X, offset %08X)\n",
       
   746 #			$pos, $extraN, $offset, $currentExtraN, $currentOffset;
       
   747 
       
   748 		if ($currentExtraN == $extraN && $currentOffset == $offset)
       
   749 			{
       
   750 			$$recordData.= $data;
       
   751 			$offset+= $currentDataLen;
       
   752 			$dataLen+= $currentDataLen;
       
   753 			}
       
   754 			
       
   755 		if ($multipartFlags == $EMultipartLast)
       
   756 			{last;}
       
   757 		}
       
   758 	
       
   759 	return $dataLen;
       
   760 	}	
       
   761 
       
   762 sub ReadDword {
       
   763 	(my $fh) = @_;
       
   764 	my $buffer;
       
   765 
       
   766 	$bytesRead = read($fh, $buffer, 4);
       
   767 	if ($bytesRead < 4) 	{die "truncated file";}
       
   768 
       
   769 	my $dword = unpack("V", $buffer);
       
   770 
       
   771 	return $dword
       
   772 	};
       
   773 
       
   774 sub ReadByte {
       
   775 	(my $fh) = @_;
       
   776 	my $buffer;
       
   777 
       
   778 	$bytesRead = read($fh, $buffer, 1);
       
   779 	if ($bytesRead < 1) 	{die "truncated file";}
       
   780 
       
   781 	my $byte = unpack("C", $buffer);
       
   782 
       
   783 	return $byte
       
   784 	};
       
   785 
       
   786     
       
   787 	
       
   788 sub PrintFormatTables($)
       
   789 	{
       
   790 	my ($formatTables) = @_;
       
   791 		
       
   792 	for $tableIndex ( sort keys %$formatTables )
       
   793 		{
       
   794 		printf ("SYMTraceFormatCategory %08X:\n", $tableIndex);
       
   795 		for $formatId (sort keys %{ $$formatTables{$tableIndex} } )
       
   796 			{
       
   797 			printf ("%08X => %s\n", $formatId, $$formatTables{$tableIndex}{$formatId});
       
   798 			}
       
   799 			print "\n";
       
   800 		}
       
   801 	}
       
   802         
       
   803 
       
   804 
       
   805 sub OutputSawDictionary($)
       
   806 	{
       
   807 	my ($formatTables) = @_;
       
   808 
       
   809 
       
   810 	# SAW enums
       
   811 	$EFieldTypeHexDump = 0;
       
   812 	$EFieldTypeHex = 1;
       
   813 	$EFieldTypeDecimal = 2;
       
   814 	$EFieldTypeStringToEnd = 3;
       
   815 	$EFieldTypeNullTerminatedString = 4;
       
   816 	$EFieldTypeHexDumpToEnd = 5;
       
   817 	$EFieldTypeUnicodeToEnd = 6;
       
   818 	$EFieldTypeNullTerminatedUnicode = 7;
       
   819 	$EFieldTypeCountedUnicode = 8;
       
   820 	$EFieldTypeCountedHexDump = 9;
       
   821 	$EFieldTypeCountedString = 10;
       
   822 
       
   823 	my $moduleIds;	# string containg all UIDs separared by semi-colons
       
   824 		
       
   825 	for $tableIndex ( sort keys %$formatTables )
       
   826 		{
       
   827 		if ($tableIndex < 256)
       
   828 			{
       
   829 			next;
       
   830 			}
       
   831 		$moduleIds.= sprintf ("%08X;", $tableIndex);
       
   832 		
       
   833 		printf ("MODULEID_%08X_DESC=\n", $tableIndex);
       
   834 		printf ("MODULEID_%08X_NAME=%08X\n", $tableIndex, $tableIndex);
       
   835 		
       
   836 		my $formatIds;
       
   837 		$formatIds = sprintf ("MODULEID_%08X_FORMATIDS=", $tableIndex);
       
   838 		
       
   839 		for $formatId  (sort keys %{ $$formatTables{$tableIndex} } )
       
   840 			{
       
   841 			$formatIds.= sprintf ("%d;", $formatId);
       
   842 			}
       
   843 		printf ("$formatIds\n");
       
   844 		
       
   845 		
       
   846 		for $formatId (sort keys %{ $$formatTables{$tableIndex} } )
       
   847 			{
       
   848 			my $fieldCount = 0;
       
   849 			my $formatString = $$formatTables{$tableIndex}{$formatId};
       
   850 			
       
   851 #printf ("formatString = (%s)\n", $formatString);
       
   852 
       
   853 			# format name is the first format string up until the first space or '%' character or end-of line ...
       
   854 			$formatString=~ m/^[^%\s]*/;
       
   855 			my $formatName = $&;
       
   856 			
       
   857 			# thow the format name away
       
   858 			$formatString = $';
       
   859 			
       
   860 			# strip the leading space
       
   861 			$formatString=~ s/\s*//;
       
   862 
       
   863 			printf ("MODULEID_%08X_FORMATID_%d_NAME=%s\n", $tableIndex, $formatId, $formatName);
       
   864 #printf ("MODULEID_%08X_FORMATID_%d_DESC=\n", $tableIndex, $formatId);
       
   865 
       
   866 			my $lenFormatString = length($formatString);
       
   867 			
       
   868 			my $formattedText;
       
   869 			my $fieldType = $EFieldTypeHex;
       
   870 			my $fieldLen = 0;
       
   871 			while (length($formatString))
       
   872 				{
       
   873 				my $c = (substr ($formatString, 0, 1));
       
   874 #print ("[$formatString][$c]\n");				
       
   875 				$formatString=~ s/.//;	# strip the leading space
       
   876 				if ($c eq "%")
       
   877 					{
       
   878 #print "found %\n";							
       
   879 					my $fieldLenSpecified = 0;
       
   880 	        		$c = (substr ($formatString, 0, 1));
       
   881 					$formatString=~ s/.//;	# discard char
       
   882 #print "c2=$c\n";							
       
   883 					if ($c eq "%")
       
   884 						{
       
   885 						$formattedText.= substr ($formatString, 0, 1);
       
   886 						next;
       
   887 						}
       
   888 					if ($c eq "*")	## take length from buffer
       
   889 						{
       
   890 						$fieldLenSpecified = 1;
       
   891 		        		$c = (substr ($formatString, 0, 1));
       
   892 						$formatString=~ s/.//;	# discard char
       
   893 						}
       
   894 					if (lc $c eq "x" || $c eq "h")
       
   895 						{
       
   896 						## deal wilth $fieldLenSpecified
       
   897 						if ($fieldLenSpecified)
       
   898 							{
       
   899 							$fieldType = $EFieldTypeCountedHexDump;
       
   900 							$fieldLen = 0;
       
   901 							}
       
   902 						else
       
   903 							{
       
   904 							$fieldType = $EFieldTypeHex;
       
   905 							$fieldLen = 4;
       
   906 							}
       
   907 						}
       
   908 					elsif (lc $c eq "l" && substr ($formatString, 0, 1) eq "d")
       
   909 						{
       
   910 						$formatString=~ s/.//;	# discard char
       
   911 						$fieldType = $EFieldTypeDecimal;
       
   912 						$fieldLen = 8;
       
   913 						}
       
   914 					elsif (lc $c eq "l" && substr ($formatString, 0, 1) eq "x")
       
   915 						{
       
   916 						$formatString=~ s/.//;	# discard char
       
   917 						$fieldType = $EFieldTypeHex;
       
   918 						$fieldLen = 8;
       
   919 						}
       
   920 					elsif (lc $c eq "d")
       
   921 						{
       
   922 						$fieldType = $EFieldTypeDecimal;
       
   923 						$fieldLen = 4;
       
   924 						}
       
   925 					elsif ($c eq "s")
       
   926 						{
       
   927 						## deal wilth $fieldLenSpecified
       
   928 						if ($fieldLenSpecified)
       
   929 							{
       
   930 							$fieldType = $EFieldTypeCountedString;
       
   931 							$fieldLen = 0;
       
   932 							}
       
   933 						else
       
   934 							{
       
   935 							$fieldType = $EFieldTypeStringToEnd;
       
   936 							$fieldLen = 0;
       
   937 							}
       
   938 						}
       
   939 					elsif ($c eq "S")
       
   940 						{
       
   941 						## deal wilth $fieldLenSpecified
       
   942 						if ($fieldLenSpecified)
       
   943 							{
       
   944 							$fieldType = $EFieldTypeCountedUnicode;
       
   945 							$fieldLen = 0;
       
   946 							}
       
   947 						else
       
   948 							{
       
   949 							$fieldType = EFieldTypeUnicodeToEnd;
       
   950 							$fieldLen = 0;
       
   951 							}
       
   952 						}
       
   953 					elsif ($c eq "c")
       
   954 						{
       
   955 						$fieldType = $EFieldTypeHex;
       
   956 						$fieldLen = 1;
       
   957 						}
       
   958 					printf ("MODULEID_%08X_FORMATID_%d_FIELD_%d_NAME=%s\n", $tableIndex, $formatId, $fieldCount, $formattedText);
       
   959 					printf ("MODULEID_%08X_FORMATID_%d_FIELD_%d_TYPE=%s\n", $tableIndex, $formatId, $fieldCount, $fieldType);
       
   960 					if ($fieldLen > 0)
       
   961 						{printf ("MODULEID_%08X_FORMATID_%d_FIELD_%d_LENGTH=%s\n", $tableIndex, $formatId, $fieldCount, $fieldLen);}
       
   962 					$fieldCount++;
       
   963 					$formattedText="";
       
   964 					
       
   965 					$formatString=~ s/\s//;	# strip the leading space
       
   966 					}
       
   967 				else
       
   968 					{
       
   969 #					if ($c eq ":") {$formattedText.= '\\'; }
       
   970 					$formattedText.= $c;
       
   971 					}
       
   972 				}
       
   973 			printf ("MODULEID_%08X_FORMATID_%d_FIELDS=%d\n", $tableIndex, $formatId, $fieldCount);
       
   974 			
       
   975 			}
       
   976 		print "MODULEIDS=$moduleIds\n";
       
   977 		}
       
   978 	}
       
   979 	
       
   980 	
       
   981 	
       
   982 	
       
   983 	
       
   984 	
       
   985 	        
       
   986         
       
   987 sub H2Trace($$)
       
   988 {
       
   989 	%basictypes = (
       
   990 		TInt8		=>	1,
       
   991 		TUint8		=>	1,
       
   992 		TInt16		=>	2,
       
   993 		TUint16		=>	2,
       
   994 		TInt32		=>	4,
       
   995 		TUint32		=>	4,
       
   996 		TInt		=>	4,
       
   997 		TUint		=>	4,
       
   998 		TBool		=>	4,
       
   999 		TInt64		=>	8,
       
  1000 		TUint64		=>	8,
       
  1001 		TLinAddr	=>	4,
       
  1002 		TVersion	=>	4,
       
  1003 		TPde		=>	4,
       
  1004 		TPte		=>	4,
       
  1005 		TProcessPriority => 4,
       
  1006 		TFormatId	=>  2,
       
  1007 	);
       
  1008 	
       
  1009 	if (scalar(@_)!= 2) {
       
  1010 		die "perl h2trace.pl <input.h>\n";
       
  1011 	}
       
  1012 	my ($infile, $filescope) = @_;
       
  1013 	
       
  1014 	if ($VerboseMode)
       
  1015 		{print "\nOpening $infile\n";}
       
  1016 	
       
  1017 	open IN, $infile or die "Can't open $infile for input\n";
       
  1018 	my $in;
       
  1019 	while (<IN>) {
       
  1020 		$in.=$_;
       
  1021 	}
       
  1022 	close IN;
       
  1023 	
       
  1024 	# First remove any backslash-newline combinations
       
  1025 	$in =~ s/\\\n//gms;
       
  1026 	
       
  1027 	# Remove any character constants
       
  1028 	$in =~  s/\'(.?(${0})*?)\'//gms;
       
  1029 	
       
  1030 	# Strip comments beginning with //
       
  1031 	$in =~ s/\/\/(.*?)\n/\n/gms;    #//(.*?)\n
       
  1032 	
       
  1033 	# Strip comments (/* */) but leave doxygen comments (/** */)
       
  1034 	$in =~ s/\/\*[^*](.*?)\*\//\n/gms;  #/*(.*?)*/
       
  1035 	
       
  1036 	
       
  1037 	# Collapse whitespace into a single space or newline
       
  1038 	$in =~ s/\t/\ /gms;
       
  1039 	$in =~ s/\r/\ /gms;
       
  1040 	
       
  1041 	# Tokenize on non-identifier characters
       
  1042 	my @tokens0 = split(/(\W)/,$in);
       
  1043 	my @tokens;
       
  1044 	my $inString = 0;
       
  1045 	my $inComment = 0;
       
  1046 	my $string;
       
  1047 	foreach $t (@tokens0) {
       
  1048 		next if ($t eq "");
       
  1049 		next if (!$inString && ($t eq " " or $t eq ""));
       
  1050 		if ($inComment == 0) 
       
  1051 			{
       
  1052 			if ($t eq "/")
       
  1053 				{$inComment = 1;}
       
  1054 			}
       
  1055 		elsif ($inComment == 1) 
       
  1056 			{
       
  1057 			if ($t eq "*")
       
  1058 				{$inComment = 2;}
       
  1059 			else
       
  1060 				{$inComment = 0;}
       
  1061 			}
       
  1062 		elsif ($inComment == 2) 
       
  1063 			{
       
  1064 			if ($t eq "*")
       
  1065 				{$inComment = 3;}
       
  1066 			}
       
  1067 		elsif ($inComment == 3) 
       
  1068 			{
       
  1069 			if ($t eq "/")
       
  1070 				{
       
  1071 				$inComment = 0;
       
  1072 		        # if we were in a string, need to push previous '*'
       
  1073 		        if ($inString)
       
  1074 		          {
       
  1075 		          push @tokens, "*";
       
  1076 		          }
       
  1077 				$inString = 0;	# end of comment aborts a string
       
  1078 				$string = "";
       
  1079 				}
       
  1080 			else
       
  1081 				{$inComment = 2;}
       
  1082 			}
       
  1083 			
       
  1084 		if ($t eq "\"")
       
  1085 			{
       
  1086 			if (!$inString) 
       
  1087 				{
       
  1088 				$inString=1;
       
  1089 				next;
       
  1090 				}
       
  1091 			else
       
  1092 				{
       
  1093 				$inString=0;
       
  1094 				$t = $string;
       
  1095 				$string = "";
       
  1096 #				if ($VerboseMode) {print "string : [$t]\n";	}
       
  1097 				}
       
  1098 			}
       
  1099 			
       
  1100 		if ($inString)
       
  1101 			{
       
  1102 			$string.= $t;
       
  1103 			next;
       
  1104 			}
       
  1105 		push @tokens, $t;
       
  1106 	}
       
  1107 	
       
  1108 	my $CurrentTraceFormatString;
       
  1109 	my $CurrentTraceFormatCategory;
       
  1110 	# format Key as specified by the @TraceFormatCategory tag is either the current category 
       
  1111 	# or the current UID
       
  1112 	my $CurrentFormatTableKey;	
       
  1113 	
       
  1114 	
       
  1115 	my $line=1;
       
  1116 	parse_scope($filescope, \@tokens, \$line);
       
  1117 
       
  1118 	#print $in;
       
  1119 	#print join (" ", @tokens);
       
  1120 }	# end of     H2Trace
       
  1121 	
       
  1122 
       
  1123 
       
  1124 	sub parse_scope($$$) {
       
  1125 		my ($scope, $tokens, $line) = @_;
       
  1126 		my $state = 1;
       
  1127 		
       
  1128 		my @classes;
       
  1129 		my $curr_offset=0;
       
  1130 		my $overall_align=0;
       
  1131 #		print ">parse_scope $scope->{name}\n";
       
  1132 		
       
  1133 		while (scalar(@$tokens))
       
  1134 			{
       
  1135 			my $t = shift @$tokens;
       
  1136 #			printf "t: [$t] [$$line]\n";
       
  1137 	    	if (!defined ($t)) {
       
  1138 	      		printf "undefined !";
       
  1139 	      		next;
       
  1140 	      	}
       
  1141 			if ($state>=-1 and $t eq "\n") {
       
  1142 				++$$line;
       
  1143 				$state=1;
       
  1144 				next;
       
  1145 			} elsif ($state==-1 and $t ne "\n") {
       
  1146 				next;
       
  1147 			} elsif ($state==-2 and $t ne ';') {
       
  1148 				next;
       
  1149 			}
       
  1150 			
       
  1151 			if ($state>0 and $t eq '#') {
       
  1152 				$t = shift @$tokens;
       
  1153 				if ($t eq 'define') {
       
  1154 					my $ident = shift @$tokens;
       
  1155 					my $defn = shift @$tokens;
       
  1156 					if ($defn ne '(') {	# don't do macros with parameters
       
  1157 #					print "MACRO: $ident :== $defn\n";
       
  1158 					$macros{$ident} = $defn;
       
  1159 					}
       
  1160 				}
       
  1161 				$state=-1;	# skip to next line
       
  1162 				next;
       
  1163 			}
       
  1164 			
       
  1165 			
       
  1166 			if (parse_doxygen($scope,$tokens, $line, $t) == 1)
       
  1167 				{next;}
       
  1168 	
       
  1169 			if ($t eq "namespace" ) {
       
  1170 				$state=0;
       
  1171 				my %cl;
       
  1172 				$cl{specifier}=$t;
       
  1173 				$cl{scope}=$scope;
       
  1174 				$cl{values}=$scope->{values};
       
  1175 				$cl{members}=\$scope->{members};
       
  1176 				$cl{typedefs}=\$scope->{typedefs};
       
  1177 				$cl{FormatTables}=$scope->{FormatTables};
       
  1178 				$cl{formatStrings} =$scope->{formatStrings};
       
  1179 				$cl{formatCategories} =$scope->{formatCategories};
       
  1180 				
       
  1181 				my $new_namespace = \%cl;
       
  1182 				my $n = get_token($scope,$tokens,$line);
       
  1183 				if ($n !~ /\w+/) {
       
  1184 					warn "Unnamed $t not supported at line $$line\n";
       
  1185 					return;
       
  1186 				}
       
  1187 				$new_namespace->{name}=$n;
       
  1188 				my @class_match = grep {$_->{name} eq $n} @classes;
       
  1189 				my $exists = scalar(@class_match);
       
  1190 				my $b = get_token($scope,$tokens,$line);
       
  1191 				if ($b eq ':') {
       
  1192 					die "Inheritance not supported at line $$line\n";
       
  1193 				} elsif ($b eq ';') {
       
  1194 					# forward declaration
       
  1195 					push @classes, $new_namespace unless ($exists);
       
  1196 					next;
       
  1197 				} elsif ($b ne '{') {
       
  1198 					warn "Syntax error#1 at line $$line\n";
       
  1199 					return;
       
  1200 				}
       
  1201 				if ($exists) {
       
  1202 					$new_namespace = $class_match[0];
       
  1203 					if ($new_namespace->{complete}) {
       
  1204 						warn "Duplicate definition of $cl{specifier} $n\n";
       
  1205 					}
       
  1206 				}
       
  1207 				push @classes, $new_namespace unless ($exists);
       
  1208 				parse_scope($new_namespace, $tokens, $line);
       
  1209 				next;
       
  1210 			}
       
  1211 			
       
  1212 			if ($t eq "struct" or $t eq "class" or $t eq "NONSHARABLE_CLASS") {
       
  1213 				next if ($state==0);
       
  1214 				$state=0;
       
  1215 				my %cl;
       
  1216 				$cl{specifier}=$t;
       
  1217 				$cl{scope}=$scope;
       
  1218 				my @members;
       
  1219 				my @typedefs;
       
  1220 				$cl{members}=\@members;
       
  1221 				$cl{typedefs}=\@typedefs;
       
  1222 				$cl{FormatTables}=$scope->{FormatTables};
       
  1223 				my $new_class = \%cl;
       
  1224 				my $n;
       
  1225 
       
  1226 				if ($t eq "NONSHARABLE_CLASS")
       
  1227 					{
       
  1228 					my $b = get_token($scope,$tokens,$line);
       
  1229 					if ($b !~ /\(/) {die "Syntax error at line $$line\n";}
       
  1230 					$n = get_token($scope,$tokens,$line);
       
  1231   				$b = get_token($scope,$tokens,$line);
       
  1232 					if ($b !~ /\)/) {die "Syntax error at line $$line\n";}
       
  1233 					}
       
  1234 				else					
       
  1235 					{
       
  1236 					$n = get_token($scope,$tokens,$line);
       
  1237 					}
       
  1238 								
       
  1239 				
       
  1240 				if ($n !~ /\w+/) {
       
  1241 					warn "Unnamed $t not supported at line $$line\n";
       
  1242 					return;
       
  1243 				}
       
  1244 				$new_class->{name}=$n;
       
  1245 				my @class_match = grep {$_->{name} eq $n} @classes;
       
  1246 				my $exists = scalar(@class_match);
       
  1247 				my $b = get_token($scope,$tokens,$line);
       
  1248 				#skip inheritance etc until we get to a '{' or \ ';'
       
  1249 				while ($b ne '{' && $b ne ';')
       
  1250 					{
       
  1251 			        $b = get_token($scope,$tokens,$line);
       
  1252 			        die "Syntax error#2 at line $$line\n" if  (!defined $b);
       
  1253 					}
       
  1254 				if ($b eq ';') {
       
  1255 					# forward declaration
       
  1256 					push @classes, $new_class unless ($exists);
       
  1257 					next;
       
  1258 				} 
       
  1259 				if ($exists) {
       
  1260 					$new_class = $class_match[0];
       
  1261 					if ($new_class->{complete}) {
       
  1262 						warn "Duplicate definition of $cl{specifier} $n\n";
       
  1263 					}
       
  1264 				}
       
  1265 				push @classes, $new_class unless ($exists);
       
  1266 				parse_scope($new_class, $tokens, $line);
       
  1267 				next;
       
  1268 			} elsif ($t eq "enum") {
       
  1269 				$state=0;
       
  1270 				my $n = get_token($scope,$tokens,$line);
       
  1271 				my $name="";
       
  1272 				if ($n =~ /\w+/) {
       
  1273 					$name = $n;
       
  1274 					$n = get_token($scope,$tokens,$line);
       
  1275 				}
       
  1276 				push @enums, $name;
       
  1277 				if ($n ne '{') {
       
  1278 					die "Syntax error#4 at line $$line\n";
       
  1279 				}
       
  1280 				parse_enum($scope, $tokens, $line, $name);
       
  1281 				next;
       
  1282 			} elsif ($t eq '}') {
       
  1283 				$state=0;
       
  1284 				if ($scope->{scope}) {
       
  1285 			        if ($scope->{specifier} eq "namespace")
       
  1286 			        	{
       
  1287 						$scope->{complete}=1;
       
  1288 #						print "Scope completed\n";
       
  1289 						last;
       
  1290 						}
       
  1291 					$t = get_token($scope,$tokens,$line);
       
  1292 					# skip to next ';'
       
  1293 					while (defined ($t) and $t ne ';')
       
  1294 						{$t = get_token($scope,$tokens,$line);}
       
  1295 					die "Syntax error#5 at line $$line\n" if ($t ne ';');
       
  1296 					$scope->{complete}=1;
       
  1297 #					print "Scope completed\n";
       
  1298 					last;
       
  1299 				}
       
  1300 				warn "Syntax error#5 at line $$line\n";
       
  1301 				return;
       
  1302 			}
       
  1303 			$state=0;
       
  1304 			if ($scope->{scope}) {
       
  1305 				if ($t eq "public" or $t eq "private" or $t eq "protected") {
       
  1306 					if (shift (@$tokens) eq ':') {
       
  1307 						next;	# ignore access specifiers
       
  1308 					}
       
  1309 				die "Syntax error#6 at line $$line\n";
       
  1310 				}
       
  1311 			}
       
  1312 			unshift @$tokens, $t;
       
  1313 			
       
  1314 			my @currdecl = parse_decl_def($scope, $tokens, $line);
       
  1315 #			print scalar (@currdecl), "\n";
       
  1316 			if ($t eq 'static') {
       
  1317 				next;	# skip static members
       
  1318 			}
       
  1319 			my $typedef;
       
  1320 			if ($t eq 'typedef') {
       
  1321 #			print "TYPEDEF\n";
       
  1322 				$typedef = 1;
       
  1323 				$t = shift @currdecl;
       
  1324 				$t = $currdecl[0];
       
  1325 			} else {
       
  1326 #			print "NOT TYPEDEF\n";
       
  1327 				$typedef = 0;
       
  1328 			}
       
  1329 #			print "$currdecl[0]\n";
       
  1330 			next if (scalar(@currdecl)==0);
       
  1331 			
       
  1332 			if ($t eq "const") {
       
  1333 				# check for constant declaration
       
  1334 #				print "CONST $currdecl[1] $currdecl[2] $currdecl[3]\n";
       
  1335 				my $ctype = lookup_type($scope, $currdecl[1]);
       
  1336 #				print "$ctype->{basic}    $ctype->{size}\n";
       
  1337 				if ($ctype->{basic} and $currdecl[2]=~/^\w+$/ and $currdecl[3] eq '=') {
       
  1338 					if ($typedef!=0) {
       
  1339 						die "Syntax error#7 at line $$line\n";
       
  1340 					}
       
  1341 					shift @currdecl;
       
  1342 					shift @currdecl;
       
  1343 					my $type = $ctype->{name};
       
  1344 					my $name;		#### = shift @currdecl;
       
  1345 
       
  1346 					if ($scope->{name})
       
  1347 						{	
       
  1348 						$name = $scope->{name} . "::" . shift @currdecl;
       
  1349 						}
       
  1350 					else
       
  1351 						{
       
  1352 						$name = shift @currdecl;
       
  1353 						}
       
  1354 #					printf "[$name,$scope->{name}]";
       
  1355 					my $size = $ctype->{size};
       
  1356 					shift @currdecl;
       
  1357 					my $value = get_constant_expr($scope,\@currdecl,$line);
       
  1358 					$values{$name} = {type=>$type, size=>$size, value=>$value};
       
  1359 					next;
       
  1360 				}
       
  1361 			}
       
  1362 			
       
  1363 			
       
  1364 			
       
  1365 		}
       
  1366 	}
       
  1367 	
       
  1368 	sub get_token($$$) {
       
  1369 		my ($scope,$tokenlist,$line) = @_;
       
  1370 		while (scalar(@$tokenlist)) {
       
  1371 			my $t = shift @$tokenlist;
       
  1372 			return $t if (!defined($t));
       
  1373 			if (parse_doxygen($scope,$tokenlist, $line, $t) == 1)
       
  1374 				{next;}
       
  1375 			if ($t !~ /^[\s]*$/)
       
  1376 				{
       
  1377 				if ($$tokenlist[0] eq ":" and $$tokenlist[1] eq ":")
       
  1378 					{
       
  1379 					$t.= shift @$tokenlist;
       
  1380 					$t.= shift @$tokenlist;
       
  1381 					$t.= shift @$tokenlist;
       
  1382 #					print "Colon-separated token";
       
  1383 					}
       
  1384 				return $t
       
  1385 				}
       
  1386 			++$$line;
       
  1387 		}
       
  1388   		return undef;
       
  1389 	}
       
  1390 	
       
  1391 	sub skip_qualifiers($) {
       
  1392 		my ($tokens) = @_;
       
  1393 		my $f=0;
       
  1394 		my %quals = (
       
  1395 			EXPORT_C => 1,
       
  1396 			IMPORT_C => 1,
       
  1397 			inline => 1,
       
  1398 			virtual => 0,
       
  1399 			const => 0,
       
  1400 			volatile => 0,
       
  1401 			static => 0,
       
  1402 			extern => 0,
       
  1403 			LOCAL_C => 0,
       
  1404 			LOCAL_D => 0,
       
  1405 			GLDEF_C => 0,
       
  1406 			GLREF_C => 0,
       
  1407 			GLDEF_D => 0,
       
  1408 			GLREF_D => 0
       
  1409 			);
       
  1410 		for (;;) {
       
  1411 			my $t = $$tokens[0];
       
  1412 			my $q = $quals{$t};
       
  1413 			last unless (defined ($q));
       
  1414 			$f |= $q;
       
  1415 			shift @$tokens;
       
  1416 		}
       
  1417 		return $f;
       
  1418 	}
       
  1419 	
       
  1420 	sub parse_indirection($) {
       
  1421 		my ($tokens) = @_;
       
  1422 		my $level = 0;
       
  1423 		for (;;) {
       
  1424 			my $t = $$tokens[0];
       
  1425 			if ($t eq '*') {
       
  1426 				++$level;
       
  1427 				shift @$tokens;
       
  1428 				next;
       
  1429 			}
       
  1430 			last if ($t ne "const" and $t ne "volatile");
       
  1431 			shift @$tokens;
       
  1432 		}
       
  1433 		return $level;
       
  1434 	}
       
  1435 	
       
  1436 	sub get_operand($$$) {
       
  1437 		my ($scope,$tokens,$line) = @_;
       
  1438 		my $t = get_token($scope,$tokens,$line);
       
  1439 		if ($t eq '-') {
       
  1440 			my $x = get_operand($scope,$tokens,$line);
       
  1441 			return -$x;
       
  1442 		} elsif ($t eq '+') {
       
  1443 			my $x = get_operand($scope,$tokens,$line);
       
  1444 			return $x;
       
  1445 		} elsif ($t eq '~') {
       
  1446 			my $x = get_operand($scope,$tokens,$line);
       
  1447 			return ~$x;
       
  1448 		} elsif ($t eq '!') {
       
  1449 			my $x = get_operand($scope,$tokens,$line);
       
  1450 			return $x ? 0 : 1;
       
  1451 		} elsif ($t eq '(') {
       
  1452 			my $x = get_constant_expr($scope,$tokens,$line);
       
  1453 			my $t = get_token($scope,$tokens,$line);
       
  1454 			if ($t ne ')') {
       
  1455 				warn "Missing ) at line $$line\n";
       
  1456 				return undefined;
       
  1457 			}
       
  1458 			return $x;
       
  1459 		} elsif ($t eq "sizeof") {
       
  1460 			my $ident = get_token($scope,$tokens,$line);
       
  1461 			if ($ident eq '(') {
       
  1462 				$ident = get_token($scope,$tokens,$line);
       
  1463 				my $cb = get_token($scope,$tokens,$line);
       
  1464 				if ($cb ne ')') {
       
  1465 					warn "Bad sizeof() syntax at line $$line\n";
       
  1466 					return undefined;
       
  1467 				}
       
  1468 			}
       
  1469 			$ident = look_through_macros($ident);
       
  1470 			if ($ident !~ /^\w+$/) {
       
  1471 				warn "Bad sizeof() syntax at line $$line\n";
       
  1472 				return undefined;
       
  1473 			}
       
  1474 			my $type = lookup_type($scope, $ident);
       
  1475 			if (!defined $type) {
       
  1476 				warn "Unrecognised type $ident at line $$line\n";
       
  1477 				return undefined;
       
  1478 			}
       
  1479 			if ($type->{basic}) {
       
  1480 				return $type->{size};
       
  1481 			} elsif ($type->{enum}) {
       
  1482 				return 4;
       
  1483 			} elsif ($type->{ptr}) {
       
  1484 				return 4;
       
  1485 			} elsif ($type->{fptr}) {
       
  1486 				return 4;
       
  1487 			}
       
  1488 			my $al = $type->{class}->{align};
       
  1489 			my $sz = $type->{class}->{size};
       
  1490 			return ($sz+$al-1)&~($al-1);
       
  1491 		}
       
  1492 		$t = look_through_macros($t);
       
  1493 		if ($t =~ /^0x/i) {
       
  1494 			return oct($t);
       
  1495 		} elsif ($t =~ /^\d/) {
       
  1496 			return $t;
       
  1497 		} elsif ($t =~ /^\w+$/) {
       
  1498 			my $x = lookup_value($scope,$t);
       
  1499 #			die "Unrecognised identifier '$t' at line $$line\n" unless defined($x);
       
  1500 			if (!defined($x)) {
       
  1501 				print "Unrecognised identifier '$t' at line $$line\n" ;
       
  1502 			}
       
  1503 			return $x;
       
  1504 		} elsif ($t =~ /^\w+::\w+$/) {
       
  1505 			my $x = lookup_value($scope,$t);
       
  1506 #			die "Unrecognised identifier '$t' at line $$line\n" unless defined($x);
       
  1507 			if (!defined($x)) {
       
  1508 				print "Unrecognised identifier '$t' at line $$line\n" ;
       
  1509 			}
       
  1510 			return $x;
       
  1511 		} else {
       
  1512 			warn "Syntax error#10 at line $$line\n";
       
  1513 			return undefined;
       
  1514 		}
       
  1515 	}
       
  1516 	
       
  1517 	sub look_through_macros($) {
       
  1518 		my ($ident) = @_;
       
  1519 		while ($ident and $macros{$ident}) {
       
  1520 			$ident = $macros{$ident};
       
  1521 		}
       
  1522 		return $ident;
       
  1523 	}
       
  1524 	
       
  1525 	sub lookup_value($$) {
       
  1526 		my ($scope,$ident) = @_;
       
  1527 		while ($scope) {
       
  1528 			my $vl = $scope->{values};
       
  1529 			if (defined($vl->{$ident})) {
       
  1530 				return $vl->{$ident}->{value};
       
  1531 			}
       
  1532 			$scope = $scope->{scope};
       
  1533 		}
       
  1534 		return undef();
       
  1535 	}
       
  1536 	
       
  1537 	sub lookup_type($$) {
       
  1538 		my ($scope,$ident) = @_;
       
  1539 		if ($basictypes{$ident}) {
       
  1540 			return {scope=>$scope, basic=>1, name=>$ident, size=>$basictypes{$ident} };
       
  1541 		}
       
  1542 		while ($scope) {
       
  1543 			if ($basictypes{$ident}) {
       
  1544 				return {scope=>$scope, basic=>1, name=>$ident, size=>$basictypes{$ident} };
       
  1545 			}
       
  1546 			my $el = $scope->{enums};
       
  1547 			my $cl = $scope->{classes};
       
  1548 			my $td = $scope->{typedefs};
       
  1549 			if (grep {$_ eq $ident} @$el) {
       
  1550 				return {scope=>$scope, enum=>1, name=>$ident, size=>4 };
       
  1551 			}
       
  1552 			my @match_class = (grep {$_->{name} eq $ident} @$cl);
       
  1553 			if (scalar(@match_class)) {
       
  1554 				return {scope=>$scope, class=>$match_class[0]};
       
  1555 			}
       
  1556 			my @match_td = (grep {$_->{name} eq $ident} @$td);
       
  1557 			if (scalar(@match_td)) {
       
  1558 				my $tdr = $match_td[0];
       
  1559 				my $cat = $tdr->{category};
       
  1560 				if ($cat eq 'basic' or $cat eq 'enum' or $cat eq 'class') {
       
  1561 					$ident = $tdr->{alias};
       
  1562 					next;
       
  1563 				} else {
       
  1564 					return { scope=>$scope, $cat=>1, $size=>$tdr->{size} };
       
  1565 				}
       
  1566 			}
       
  1567 			$scope = $scope->{scope};
       
  1568 		}
       
  1569 		return undef();
       
  1570 	}
       
  1571 	
       
  1572 	sub get_mult_expr($$$) {
       
  1573 		my ($scope,$tokens,$line) = @_;
       
  1574 		my $x = get_operand($scope,$tokens,$line);
       
  1575 		my $t;
       
  1576 		for (;;) {
       
  1577 			$t = get_token($scope,$tokens,$line);
       
  1578 			if ($t eq '*') {
       
  1579 				my $y = get_operand($scope,$tokens,$line);
       
  1580 				$x = $x * $y;
       
  1581 			} elsif ($t eq '/') {
       
  1582 				my $y = get_operand($scope,$tokens,$line);
       
  1583 				if ($y != 0)
       
  1584 					{$x = int($x / $y);}
       
  1585 			} elsif ($t eq '%') {
       
  1586 				my $y = get_operand($scope,$tokens,$line);
       
  1587 				if ($y != 0)
       
  1588 					{$x = int($x % $y);}
       
  1589 			} else {
       
  1590 				last;
       
  1591 			}
       
  1592 		}
       
  1593 		unshift @$tokens, $t;
       
  1594 		return $x;
       
  1595 	}
       
  1596 	
       
  1597 	sub get_add_expr($$$) {
       
  1598 		my ($scope,$tokens,$line) = @_;
       
  1599 		my $x = get_mult_expr($scope,$tokens,$line);
       
  1600 		my $t;
       
  1601 		for (;;) {
       
  1602 			$t = get_token($scope,$tokens,$line);
       
  1603 			if ($t eq '+') {
       
  1604 				my $y = get_mult_expr($scope,$tokens,$line);
       
  1605 				$x = $x + $y;
       
  1606 			} elsif ($t eq '-') {
       
  1607 				my $y = get_mult_expr($scope,$tokens,$line);
       
  1608 				$x = $x - $y;
       
  1609 			} else {
       
  1610 				last;
       
  1611 			}
       
  1612 		}
       
  1613 		unshift @$tokens, $t;
       
  1614 		return $x;
       
  1615 	}
       
  1616 	
       
  1617 	sub get_shift_expr($$$) {
       
  1618 		my ($scope,$tokens,$line) = @_;
       
  1619 		my $x = get_add_expr($scope,$tokens,$line);
       
  1620 		my $t, $t2;
       
  1621 		for (;;) {
       
  1622 			$t = get_token($scope,$tokens,$line);
       
  1623 			if ($t eq '<' or $t eq '>') {
       
  1624 				$t2 = get_token($scope,$tokens,$line);
       
  1625 				if ($t2 ne $t) {
       
  1626 					unshift @$tokens, $t2;
       
  1627 					last;
       
  1628 				}
       
  1629 			}
       
  1630 			if ($t eq '<') {
       
  1631 				my $y = get_add_expr($scope,$tokens,$line);
       
  1632 				$x = $x << $y;
       
  1633 			} elsif ($t eq '>') {
       
  1634 				my $y = get_add_expr($scope,$tokens,$line);
       
  1635 				$x = $x >> $y;
       
  1636 			} else {
       
  1637 				last;
       
  1638 			}
       
  1639 		}
       
  1640 		unshift @$tokens, $t;
       
  1641 		return $x;
       
  1642 	}
       
  1643 	
       
  1644 	sub get_and_expr($$$) {
       
  1645 		my ($scope,$tokens,$line) = @_;
       
  1646 		my $x = get_shift_expr($scope,$tokens,$line);
       
  1647 		my $t;
       
  1648 		for (;;) {
       
  1649 			$t = get_token($scope,$tokens,$line);
       
  1650 			if ($t eq '&') {
       
  1651 				my $y = get_shift_expr($scope,$tokens,$line);
       
  1652 				$x = $x & $y;
       
  1653 			} else {
       
  1654 				last;
       
  1655 			}
       
  1656 		}
       
  1657 		unshift @$tokens, $t;
       
  1658 		return $x;
       
  1659 	}
       
  1660 	
       
  1661 	sub get_xor_expr($$$) {
       
  1662 		my ($scope,$tokens,$line) = @_;
       
  1663 		my $x = get_and_expr($scope,$tokens,$line);
       
  1664 		my $t;
       
  1665 		for (;;) {
       
  1666 			$t = get_token($scope,$tokens,$line);
       
  1667 			if ($t eq '^') {
       
  1668 				my $y = get_and_expr($scope,$tokens,$line);
       
  1669 				$x = $x ^ $y;
       
  1670 			} else {
       
  1671 				last;
       
  1672 			}
       
  1673 		}
       
  1674 		unshift @$tokens, $t;
       
  1675 		return $x;
       
  1676 	}
       
  1677 	
       
  1678 	sub get_ior_expr($$$) {
       
  1679 		my ($scope,$tokens,$line) = @_;
       
  1680 		my $x = get_xor_expr($scope,$tokens,$line);
       
  1681 		my $t;
       
  1682 		for (;;) {
       
  1683 			$t = get_token($scope,$tokens,$line);
       
  1684 			if ($t eq '|') {
       
  1685 				my $y = get_xor_expr($scope,$tokens,$line);
       
  1686 				$x = $x | $y;
       
  1687 			} else {
       
  1688 				last;
       
  1689 			}
       
  1690 		}
       
  1691 		unshift @$tokens, $t;
       
  1692 		return $x;
       
  1693 	}
       
  1694 	
       
  1695 	sub get_constant_expr($$$) {
       
  1696 		my ($scope,$tokens,$line) = @_;
       
  1697 		my $x = get_ior_expr($scope,$tokens,$line);
       
  1698 		return $x;
       
  1699 	}
       
  1700 	
       
  1701 	sub parse_enum($$$$) {
       
  1702 		my ($scope,$tokens,$line,$enum_name) = @_;
       
  1703 		my $vl = $scope->{values};
       
  1704 		my $fstr = $scope->{formatStrings};
       
  1705 		my $fcat = $scope->{formatCategories};
       
  1706 		my $fmtTable = $scope->{FormatTables};
       
  1707 		
       
  1708 		my $x = 0;
       
  1709 		for (;;) {
       
  1710 			my $t = get_token($scope,$tokens,$line);
       
  1711 			last if ($t eq '}');
       
  1712 			if (!defined($t)) {
       
  1713 				die "Unexpected end of file #2 at line $$line\n";
       
  1714 			}
       
  1715 			
       
  1716 			if ($t eq '#') {
       
  1717 				next;
       
  1718 				}
       
  1719 			
       
  1720 			if ($t !~ /^\w+$/) {
       
  1721 				warn "Syntax error#11 at line $$line\n";
       
  1722 				next;
       
  1723 			}
       
  1724 
       
  1725 			if ($scope->{name})
       
  1726 				{	
       
  1727 				$t = $scope->{name} . "::" . $t;
       
  1728 				}
       
  1729 
       
  1730 			if (defined($vl->{$t})) {
       
  1731 				warn "Duplicate identifier [$t] at line $$line\n";
       
  1732 			}
       
  1733 			my $t2 = get_token($scope,$tokens,$line);
       
  1734 			if ($t2 eq ',') {
       
  1735 				$vl->{$t} = {type=>$enum_name, size=>4, value=>$x, enum=>1};
       
  1736 				$fstr->{$t} = $CurrentTraceFormatString; 
       
  1737 				$fcat->{$t} = $CurrentTraceFormatCategory; 
       
  1738 				if (defined $CurrentTraceFormatCategory && defined $CurrentTraceFormatString)
       
  1739 					{ $fmtTable->{$CurrentTraceFormatCategory}{$x} = $CurrentTraceFormatString; }
       
  1740 				undef $CurrentTraceFormatString;
       
  1741 				++$x;
       
  1742 			} elsif ($t2 eq '}') {
       
  1743 				$vl->{$t} = {type=>$enum_name, size=>4, value=>$x, enum=>1};
       
  1744 				$fstr->{$t} = $CurrentTraceFormatString; 
       
  1745 				$fcat->{$t} = $CurrentTraceFormatCategory; 
       
  1746 				if (defined $CurrentTraceFormatCategory && defined $CurrentTraceFormatString)
       
  1747 					{ $fmtTable->{$CurrentTraceFormatCategory}{$x} = $CurrentTraceFormatString; }
       
  1748 				undef $CurrentTraceFormatString;
       
  1749 				++$x;
       
  1750 				last;
       
  1751 			} elsif ($t2 eq '=') {
       
  1752 				$x = get_constant_expr($scope, $tokens, $line);
       
  1753 				$vl->{$t} = {type=>$enum_name, size=>4, value=>$x, enum=>1};
       
  1754 				$fstr->{$t} = $CurrentTraceFormatString; 
       
  1755 				$fcat->{$t} = $CurrentTraceFormatCategory;
       
  1756 				if (defined $CurrentTraceFormatCategory && defined $CurrentTraceFormatString)
       
  1757 					{ $fmtTable->{$CurrentTraceFormatCategory}{$x} = $CurrentTraceFormatString; }
       
  1758 				undef $CurrentTraceFormatString; 
       
  1759 				++$x;
       
  1760 				$t2 = get_token($scope,$tokens,$line);
       
  1761 				last if ($t2 eq '}');
       
  1762 				next if ($t2 eq ',');
       
  1763 				warn "Syntax error#12 at line $$line\n";
       
  1764 			} else {
       
  1765 				unshift @$tokens, $t2;
       
  1766 			}
       
  1767 		}
       
  1768 		my $t = get_token($scope,$tokens,$line);
       
  1769 		if ($t ne ';') {
       
  1770 			warn "Missing ; at line $$line\n";
       
  1771 		}
       
  1772 	}
       
  1773 	
       
  1774 	
       
  1775 	sub  parse_decl_def($$$) {
       
  1776 		my ($scope,$tokens,$line) = @_;
       
  1777 		my $level=0;
       
  1778 		my @decl;
       
  1779 		while ( scalar(@$tokens) ) {
       
  1780 			my $t = get_token($scope,$tokens, $line);
       
  1781 			if ( (!defined ($t) || $t eq ';') and ($level==0)) {
       
  1782 				return @decl;
       
  1783 			}
       
  1784 	
       
  1785 			if ($t eq "static")
       
  1786 				{
       
  1787 				next;
       
  1788 				}
       
  1789 	
       
  1790 			push @decl, $t;
       
  1791 			if ($t eq '{') {
       
  1792 				++$level;
       
  1793 			}
       
  1794 			if ($t eq '}') {
       
  1795 				if ($level==0) {
       
  1796 					warn "Syntax error#13 at line $$line\n";
       
  1797 					unshift @$tokens, $t;
       
  1798 					return @decl;
       
  1799 					
       
  1800 				}
       
  1801 				if (--$level==0) {
       
  1802 					return ();	# end of function definition reached
       
  1803 				}
       
  1804 			}
       
  1805 		}
       
  1806 		die "Unexpected end of file #3 at line $$line\n";
       
  1807 	}
       
  1808 	
       
  1809 	sub dump_scope($) {
       
  1810 		my ($scope) = @_;
       
  1811 		my $el = $scope->{enums};
       
  1812 		my $cl = $scope->{classes};
       
  1813 		my $vl = $scope->{values};
       
  1814 		my $fstr = $scope->{formatStrings};
       
  1815 		my $fcat = $scope->{formatCategories};
       
  1816 		print "SCOPE: $scope->{name}\n";
       
  1817 		if (scalar(@$el)) {
       
  1818 			print "\tenums:\n";
       
  1819 			foreach (@$el) {
       
  1820 				print "\t\t$_\n";
       
  1821 			}
       
  1822 		}
       
  1823 		if (scalar(keys(%$vl))) {
       
  1824 			print "\tvalues:\n";
       
  1825 			foreach $vname (keys(%$vl)) {
       
  1826 				my $v = $vl->{$vname};
       
  1827 				my $x = $v->{value};
       
  1828 				my $t = $v->{type};
       
  1829 				my $sz = $v->{size};
       
  1830 				my $fstring = $fstr->{$vname};
       
  1831 				my $fcategory = $fcat->{$vname};
       
  1832 				if ($v->{enum}) {
       
  1833 					printf ("\t\t$vname\=$x (enum $t) size=$sz fcat=[0x%x] fstr=[%s]\n", $fcategory,$fstring);
       
  1834 				} else {
       
  1835 					printf ("\t\t$vname\=$x (type $t) size=$sz fcat=[0x%x] fstr=[%s]\n", $fcategory, $fstring);
       
  1836 				}
       
  1837 			}
       
  1838 		}
       
  1839 		if ($scope->{scope}) {
       
  1840 			my $members = $scope->{members};
       
  1841 			foreach (@$members) {
       
  1842 				my $n = $_->{name};
       
  1843 				my $sz = $_->{size};
       
  1844 				my $off = $_->{offset};
       
  1845 				my $spc = $_->{spacing};
       
  1846 				if (defined $spc) {
       
  1847 					print "\t$n\[\]\: spacing $spc size $sz offset $off\n";
       
  1848 				} else {
       
  1849 					print "\t$n\: size $sz offset $off\n";
       
  1850 				}
       
  1851 			}
       
  1852 			print "\tOverall size : $scope->{size}\n";
       
  1853 			print "\tOverall align: $scope->{align}\n";
       
  1854 		}
       
  1855 		foreach $s (@$cl) {
       
  1856 			dump_scope($s);
       
  1857 		}
       
  1858 	}
       
  1859 	
       
  1860 	
       
  1861 	
       
  1862 		
       
  1863 	sub parse_doxygen($$$$) {
       
  1864 		my ($scope,$tokens,$line,$t) = @_;
       
  1865 	
       
  1866 		if ($t ne "/")
       
  1867 			{
       
  1868 			return 0;	# not a doxygen comment
       
  1869 			}
       
  1870 		if ($t eq "/") {
       
  1871 			$state=0;
       
  1872 			my $t2 = shift @$tokens;
       
  1873 			my $t3 = shift @$tokens;
       
  1874 	
       
  1875 			if ($t2 ne "*" || $t3 ne "*")
       
  1876 				{
       
  1877 				unshift @$tokens, $t3;
       
  1878 				unshift @$tokens, $t2;
       
  1879 				return 0;	# not a doxygen comment
       
  1880 				}
       
  1881 		}
       
  1882 #		printf "doxygen start on line %d\n", $$line;
       
  1883 		for (;;) {
       
  1884 			my $t = shift @$tokens;
       
  1885 			if (!defined($t)) 
       
  1886 					{
       
  1887 					warn "Unexpected end of file #4 at line $$line\n";	
       
  1888 					return
       
  1889 					}
       
  1890 			
       
  1891 			if ($t eq "\n"){++$$line };
       
  1892 			
       
  1893 			if ($t eq '*')
       
  1894 				{
       
  1895 				my $t2 = shift @$tokens;
       
  1896 				last if ($t2 eq '/');
       
  1897 				unshift @$tokens, $t2;
       
  1898 				}
       
  1899 			
       
  1900 			if ($t eq '@')
       
  1901 				{
       
  1902 				my $t2 = shift @$tokens;
       
  1903 				if ($t2 eq 'SYMTraceFormatString')
       
  1904 					{
       
  1905 					my $t3 = shift @$tokens;
       
  1906 #					if ($VerboseMode){print "SYMTraceFormatString = [$t3]\n";}
       
  1907 					$CurrentTraceFormatString = $t3;
       
  1908 					}
       
  1909 				if ($t2 eq 'SYMTraceFormatCategory')
       
  1910 					{
       
  1911 					$CurrentTraceFormatCategory = get_operand($scope,$tokens,$line);
       
  1912 #					if ($VerboseMode){printf ("SYMTraceFormatCategory = 0x%x\n", $CurrentTraceFormatCategory);}
       
  1913 					}
       
  1914 				else
       
  1915 					{
       
  1916 					unshift @$tokens, $t2;
       
  1917 					}
       
  1918 				}
       
  1919 	
       
  1920 		}
       
  1921 #		printf ("doxygen end  on line %d\n", $$line);
       
  1922 		return 1;	# is a doxygen comment
       
  1923 	}
       
  1924 	
       
  1925 
       
  1926         
       
  1927         
       
  1928         
       
  1929         
       
  1930         
       
  1931         
       
  1932         
       
  1933         
       
  1934         
       
  1935         
       
  1936         
       
  1937         
       
  1938         
       
  1939         
       
  1940         
       
  1941         
       
  1942         
       
  1943         
       
  1944         
       
  1945         
       
  1946         
       
  1947         
       
  1948         
       
  1949         
       
  1950         
       
  1951         
       
  1952