sbsv1/abld/e32util/h2inc.pl
changeset 599 fa7a3cc6effd
child 606 30b30f9da0b7
equal deleted inserted replaced
596:9f25be3da657 599:fa7a3cc6effd
       
     1 # Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 # All rights reserved.
       
     3 # This component and the accompanying materials are made available
       
     4 # under the terms of "Eclipse Public License v1.0"
       
     5 # which accompanies this distribution, and is available
       
     6 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 #
       
     8 # Initial Contributors:
       
     9 # Nokia Corporation - initial contribution.
       
    10 #
       
    11 # Contributors:
       
    12 #
       
    13 # Description:
       
    14 # e32toolp\e32util\h2inc.pl
       
    15 # Convert structures in C++ include files to assembler format
       
    16 # Syntax:
       
    17 # perl h2inc.pl <input.h> <output.inc> <format>
       
    18 # where <format>=arm or x86
       
    19 # 
       
    20 #
       
    21 
       
    22 %basictypes = (
       
    23 	TInt8		=>	1,
       
    24 	TUint8		=>	1,
       
    25 	TInt16		=>	2,
       
    26 	TUint16		=>	2,
       
    27 	TInt32		=>	4,
       
    28 	TUint32		=>	4,
       
    29 	TInt		=>	4,
       
    30 	TUint		=>	4,
       
    31 	TInt64		=>	8,
       
    32 	TUint64		=>	8,
       
    33 	TLinAddr	=>	4,
       
    34 	TVersion	=>	4,
       
    35 	TPde		=>	4,
       
    36 	TPte		=>	4,
       
    37 	TProcessPriority => 4
       
    38 );
       
    39 
       
    40 if (scalar(@ARGV)!=3) {
       
    41 	die "perl h2inc.pl <input.h> <output.inc> <format>\n";
       
    42 }
       
    43 my ($infile, $outfile, $format) = @ARGV;
       
    44 open IN, $infile or die "Can't open $infile for input\n";
       
    45 my $in;
       
    46 while (<IN>) {
       
    47 	$in.=$_;
       
    48 }
       
    49 close IN;
       
    50 $format = uc($format);
       
    51 $format_sub = undef();
       
    52 $comment_sub = undef();
       
    53 $end_sub = undef();
       
    54 if ($format eq "ARMASM") {
       
    55 	$format_sub = \&armasm_format;
       
    56 	$comment_sub = \&armasm_comment;
       
    57 	$end_sub = \&armasm_end;
       
    58 } elsif ($format eq "AS") {
       
    59 	$format_sub = \&as_format;
       
    60 	$comment_sub = \&as_comment;
       
    61 	$end_sub = \&as_end;
       
    62 } elsif ($format eq "TASM") {
       
    63 	$format_sub = \&tasm_format;
       
    64 	$comment_sub = \&tasm_comment;
       
    65 	$end_sub = \&tasm_end;
       
    66 } else {
       
    67 	die "Format $format unknown\nOnly ARMASM, AS or TASM supported\n";
       
    68 }
       
    69 
       
    70 # First remove any backslash-newline combinations
       
    71 $in =~ s/\\\n//gms;
       
    72 
       
    73 # Change escaped quotes to double quotes
       
    74 $in =~ s/\\\"/\"\"/gms;
       
    75 $in =~ s/\\\'/\'\'/gms;
       
    76 
       
    77 # Remove any character constants
       
    78 $in =~  s/\'(.?(${0})*?)\'//gms;
       
    79 
       
    80 # Remove any string literals
       
    81 $in =~ s/\"(.*?)\"//gms;
       
    82 
       
    83 # Strip comments
       
    84 $in =~ s/\/\*(.*?)\*\//\n/gms;
       
    85 $in =~ s/\/\/(.*?)\n/\n/gms;
       
    86 
       
    87 # Collapse whitespace into a single space or newline
       
    88 $in =~ s/\t/\ /gms;
       
    89 $in =~ s/\r/\ /gms;
       
    90 $in =~ s/(\ )+/\ /gms;
       
    91 $in =~ s/\n(\ )*/\n/gms;
       
    92 $in =~ s/(\ )*\n/\n/gms;
       
    93 
       
    94 # Tokenize on non-identifier characters
       
    95 my @tokens0 = split(/(\W)/,$in);
       
    96 my @tokens;
       
    97 foreach $t (@tokens0) {
       
    98 	next if ($t eq " " or $t eq "");
       
    99 	push @tokens, $t;
       
   100 }
       
   101 
       
   102 my %macros;
       
   103 my %filescope;
       
   104 $filescope{file}=1;
       
   105 $filescope{name}='*** FILE SCOPE ***';
       
   106 my @ftypedefs;
       
   107 $filescope{typedefs}=\@ftypedefs;
       
   108 my $line=1;
       
   109 parse_scope(\%filescope, \@tokens, \$line);
       
   110 
       
   111 
       
   112 my @output;
       
   113 push @output, &$comment_sub('*' x 80);
       
   114 push @output, &$comment_sub($outfile);
       
   115 push @output, &$comment_sub('*' x 80);
       
   116 push @output, &$comment_sub("GENERATED FILE - DO NOT EDIT");
       
   117 push @output, "";
       
   118 
       
   119 output_scope(\%filescope, \@output);
       
   120 
       
   121 push @output, &$end_sub();
       
   122 push @output, "";
       
   123 
       
   124 open OUT, ">$outfile" or die "Can't open $outfile for write\n";
       
   125 print OUT join("\n", @output);
       
   126 print OUT "\n\n";
       
   127 close OUT;
       
   128 
       
   129 sub get_token($$) {
       
   130 	my ($tokenlist,$line) = @_;
       
   131 	while (scalar(@$tokenlist)) {
       
   132 		my $t = shift @$tokenlist;
       
   133 		return $t if (!defined($t));
       
   134 		return $t if ($t !~ /^\s*$/);
       
   135 		++$$line;
       
   136 	}
       
   137 }
       
   138 
       
   139 sub skip_qualifiers($) {
       
   140 	my ($tokens) = @_;
       
   141 	my $f=0;
       
   142 	my %quals = (
       
   143 		EXPORT_C => 1,
       
   144 		IMPORT_C => 1,
       
   145 		inline => 1,
       
   146 		const => 0,
       
   147 		volatile => 0,
       
   148 		static => 0,
       
   149 		extern => 0,
       
   150 		LOCAL_C => 0,
       
   151 		LOCAL_D => 0,
       
   152 		GLDEF_C => 0,
       
   153 		GLREF_C => 0,
       
   154 		GLDEF_D => 0,
       
   155 		GLREF_D => 0
       
   156 		);
       
   157 	for (;;) {
       
   158 		my $t = $$tokens[0];
       
   159 		my $q = $quals{$t};
       
   160 		last unless (defined ($q));
       
   161 		$f |= $q;
       
   162 		shift @$tokens;
       
   163 	}
       
   164 	return $f;
       
   165 }
       
   166 
       
   167 sub parse_indirection($) {
       
   168 	my ($tokens) = @_;
       
   169 	my $level = 0;
       
   170 	for (;;) {
       
   171 		my $t = $$tokens[0];
       
   172 		if ($t eq '*') {
       
   173 			++$level;
       
   174 			shift @$tokens;
       
   175 			next;
       
   176 		}
       
   177 		last if ($t ne "const" and $t ne "volatile");
       
   178 		shift @$tokens;
       
   179 	}
       
   180 	return $level;
       
   181 }
       
   182 
       
   183 sub parse_scope($$$) {
       
   184 	my ($scope, $tokens, $line) = @_;
       
   185 	my $state = 0;
       
   186 	my %values;
       
   187 	my @classes;
       
   188 	my @enums;
       
   189 	my $curr_offset=0;
       
   190 	my $overall_align=0;
       
   191 	$scope->{values}=\%values;
       
   192 	$scope->{classes}=\@classes;
       
   193 	$scope->{enums}=\@enums;
       
   194 	while (scalar(@$tokens)) {
       
   195 		my $t = shift @$tokens;
       
   196 		if ($state>=-1 and $t eq "\n") {
       
   197 			++$$line;
       
   198 			$state=1;
       
   199 			next;
       
   200 		} elsif ($state==-1 and $t ne "\n") {
       
   201 			next;
       
   202 		} elsif ($state==-2 and $t ne ';') {
       
   203 			next;
       
   204 		}
       
   205 		if ($state>0 and $t eq '#') {
       
   206 			if ($scope->{scope}) {
       
   207 				warn "Preprocessor directive in class/struct at line $$line\n";
       
   208 			}
       
   209 			$t = shift @$tokens;
       
   210 			if ($t eq 'define') {
       
   211 				my $ident = shift @$tokens;
       
   212 				my $defn = shift @$tokens;
       
   213 				if ($defn ne '(') {	# don't do macros with parameters
       
   214 					$macros{$ident} = $defn;
       
   215 				}
       
   216 			}
       
   217 			$state=-1;	# skip to next line
       
   218 			next;
       
   219 		}
       
   220 		if ($t eq "struct" or $t eq "class") {
       
   221 			next if ($state==0);
       
   222 			$state=0;
       
   223 			my %cl;
       
   224 			$cl{specifier}=$t;
       
   225 			$cl{scope}=$scope;
       
   226 			my @members;
       
   227 			my @typedefs;
       
   228 			$cl{members}=\@members;
       
   229 			$cl{typedefs}=\@typedefs;
       
   230 			my $new_class = \%cl;
       
   231 			my $n = get_token($tokens,$line);
       
   232 			if ($n !~ /\w+/) {
       
   233 				die "Unnamed $t not supported at line $$line\n";
       
   234 			}
       
   235 			$new_class->{name}=$n;
       
   236 			my @class_match = grep {$_->{name} eq $n} @classes;
       
   237 			my $exists = scalar(@class_match);
       
   238 			my $b = get_token($tokens,$line);
       
   239 			if ($b eq ':') {
       
   240 				die "Inheritance not supported at line $$line\n";
       
   241 			} elsif ($b eq ';') {
       
   242 				# forward declaration
       
   243 				push @classes, $new_class unless ($exists);
       
   244 				next;
       
   245 			} elsif ($b ne '{') {
       
   246 				die "Syntax error at line $$line\n";
       
   247 			}
       
   248 			if ($exists) {
       
   249 				$new_class = $class_match[0];
       
   250 				if ($new_class->{complete}) {
       
   251 					die "Duplicate definition of $cl{specifier} $n\n";
       
   252 				}
       
   253 			}
       
   254 			push @classes, $new_class unless ($exists);
       
   255 			parse_scope($new_class, $tokens, $line);
       
   256 			next;
       
   257 		} elsif ($t eq "enum") {
       
   258 			$state=0;
       
   259 			my $n = get_token($tokens,$line);
       
   260 			my $name="";
       
   261 			if ($n =~ /\w+/) {
       
   262 				$name = $n;
       
   263 				$n = get_token($tokens,$line);
       
   264 			}
       
   265 			push @enums, $name;
       
   266 			if ($n ne '{') {
       
   267 				die "Syntax error at line $$line\n";
       
   268 			}
       
   269 			parse_enum($scope, $tokens, $line, $name);
       
   270 			next;
       
   271 		} elsif ($t eq '}') {
       
   272 			$state=0;
       
   273 			if ($scope->{scope}) {
       
   274 				$t = get_token($tokens,$line);
       
   275 				if ($t eq ';') {
       
   276 					$scope->{complete}=1;
       
   277 					last;
       
   278 				}
       
   279 			}
       
   280 			die "Syntax error at line $$line\n";
       
   281 		}
       
   282 		$state=0;
       
   283 		if ($scope->{scope}) {
       
   284 			if ($t eq "public" or $t eq "private" or $t eq "protected") {
       
   285 				if (shift (@$tokens) eq ':') {
       
   286 					next;	# ignore access specifiers
       
   287 				}
       
   288 			die "Syntax error at line $$line\n";
       
   289 			}
       
   290 		}
       
   291 		unshift @$tokens, $t;
       
   292 		my @currdecl = parse_decl_def($scope, $tokens, $line);
       
   293 		if ($t eq 'static') {
       
   294 			next;	# skip static members
       
   295 		}
       
   296 		my $typedef;
       
   297 		if ($t eq 'typedef') {
       
   298 			$typedef = 1;
       
   299 			$t = shift @currdecl;
       
   300 			$t = $currdecl[0];
       
   301 		} else {
       
   302 			$typedef = 0;
       
   303 		}
       
   304 		next if (scalar(@currdecl)==0);
       
   305 		if ($t eq "const") {
       
   306 			# check for constant declaration
       
   307 			my $ctype = lookup_type($scope, $currdecl[1]);
       
   308 			if ($ctype->{basic} and $currdecl[2]=~/^\w+$/ and $currdecl[3] eq '=') {
       
   309 				if ($typedef!=0) {
       
   310 					die "Syntax error at line $$line\n";
       
   311 				}
       
   312 				shift @currdecl;
       
   313 				shift @currdecl;
       
   314 				my $type = $ctype->{name};
       
   315 				my $name = shift @currdecl;
       
   316 				my $size = $ctype->{size};
       
   317 				shift @currdecl;
       
   318 				my $value = get_constant_expr($scope,\@currdecl,$line);
       
   319 				$values{$name} = {type=>$type, size=>$size, value=>$value};
       
   320 				next;
       
   321 			}
       
   322 		}
       
   323 		if (skip_qualifiers(\@currdecl)!=0 or ($scope->{file} and !$typedef)) {
       
   324 			next;	# function declaration or stuff at file scope
       
   325 		}
       
   326 		my $type1 = shift @currdecl;	# type, type pointed to or return type
       
   327 		if ($type1 !~ /^\w+$/) {
       
   328 			die "Syntax error at line $$line\n";
       
   329 		}
       
   330 		my $ind1 = parse_indirection(\@currdecl);
       
   331 		my $ident;	# identifier being declared
       
   332 		my $size = -1;
       
   333 		my $array = -1;
       
   334 		my $align = 0;
       
   335 		my $alias;
       
   336 		my $category;
       
   337 		if ($currdecl[0] eq '(' and $currdecl[1] eq '*' and $currdecl[2]=~/^\w+$/) {
       
   338 			# function pointer
       
   339 			$ident = $currdecl[2];
       
   340 			$size = 4;
       
   341 			$category = 'fptr';
       
   342 			shift @currdecl;
       
   343 			shift @currdecl;
       
   344 			shift @currdecl;
       
   345 		} elsif ($currdecl[0]=~/^\w+$/) {
       
   346 			$ident = shift @currdecl;
       
   347 			if ($currdecl[0] ne '(') {
       
   348 				# not function declaration
       
   349 				if ($ind1>0) {
       
   350 					# pointer
       
   351 					$category = 'ptr';
       
   352 					$size = 4;
       
   353 				} else {
       
   354 					my $type2 = lookup_type($scope, $type1);
       
   355 					if (!defined($type2)) {
       
   356 						die "Unrecognised type $type1 at line $$line\n";
       
   357 					}
       
   358 					if ($type2->{basic}) {
       
   359 						$alias = $type2->{name};
       
   360 						$size = $type2->{size};
       
   361 						$category = 'basic';
       
   362 					} elsif ($type2->{enum}) {
       
   363 						$alias = $type2->{name};
       
   364 						$category = 'enum';
       
   365 						$size = 4;
       
   366 					} elsif ($type2->{class}) {
       
   367 						$alias = $type2->{name};
       
   368 						$size = $type2->{class}->{size};
       
   369 						$category = 'class';
       
   370 						$align = $type2->{class}->{align};
       
   371 					} elsif ($type->{ptr}) {
       
   372 						$size = 4;
       
   373 						$category = 'ptr';
       
   374 						$align = 4;
       
   375 					} elsif ($type->{fptr}) {
       
   376 						$size = 4;
       
   377 						$category = 'ptr';
       
   378 						$align = 4;
       
   379 					}
       
   380 				}
       
   381 			}
       
   382 		}
       
   383 		if ($size>0) {
       
   384 			# data member declared
       
   385 			# check for array
       
   386 			if ($currdecl[0] eq '[') {
       
   387 				shift @currdecl;
       
   388 				$array = get_constant_expr($scope, \@currdecl, $line);
       
   389 				if ($array<=0) {
       
   390 					die "Bad array size at line $$line\n";
       
   391 				}
       
   392 				if ($currdecl[0] ne ']') {
       
   393 					die "Syntax error at line $$line\n";
       
   394 				}
       
   395 			}
       
   396 			my $members = $scope->{members};
       
   397 			my $typedefs = $scope->{typedefs};
       
   398 			if ($align==0) {
       
   399 				$align = $size;
       
   400 			}
       
   401 			my $am = $align-1;
       
   402 			unless ($typedef) {
       
   403 				my $al = $curr_offset & $am;
       
   404 				if ($align==8 and $al!=0) {
       
   405 					die "Bad alignment of 64-bit data $ident at line $$line\n";
       
   406 				}
       
   407 				$curr_offset += ($align-$al) if ($al!=0);
       
   408 			}
       
   409 			if ($array>0) {
       
   410 				$size = ($size + $am) &~ $am;
       
   411 				if ($typedef) {
       
   412 					push @$typedefs, {name=>$ident, category=>$category, alias=>$alias, size=>$size*$array, spacing=>$size, array=>$array};
       
   413 				} else {
       
   414 					push @$members, {name=>$ident, size=>$size*$array, offset=>$curr_offset, spacing=>$size};
       
   415 				}
       
   416 				$size *= $array;
       
   417 			} else {
       
   418 				if ($typedef) {
       
   419 					push @$typedefs, {name=>$ident, category=>$category, alias=>$alias, size=>$size};
       
   420 				} else {
       
   421 					push @$members, {name=>$ident, size=>$size, offset=>$curr_offset};
       
   422 				}
       
   423 			}
       
   424 			unless ($typedef) {
       
   425 				$curr_offset += $size;
       
   426 				if ($align > $overall_align) {
       
   427 					$overall_align = $align;
       
   428 				}
       
   429 			}
       
   430 		}
       
   431 	}
       
   432 	if ($scope->{scope}) {
       
   433 		if ($state==-2) {
       
   434 			die "Missing ; at end of file\n";
       
   435 		}
       
   436 		if (!$scope->{complete}) {
       
   437 			die "Unexpected end of file at line $$line\n";
       
   438 		}
       
   439 		my $total_size = ($curr_offset + $overall_align - 1) &~ ($overall_align - 1);
       
   440 		$scope->{size} = $total_size;
       
   441 		$scope->{align} = $overall_align;
       
   442 	}
       
   443 }
       
   444 
       
   445 sub get_operand($$$) {
       
   446 	my ($scope,$tokens,$line) = @_;
       
   447 	my $t = get_token($tokens,$line);
       
   448 	if ($t eq '-') {
       
   449 		my $x = get_operand($scope,$tokens,$line);
       
   450 		return -$x;
       
   451 	} elsif ($t eq '+') {
       
   452 		my $x = get_operand($scope,$tokens,$line);
       
   453 		return $x;
       
   454 	} elsif ($t eq '~') {
       
   455 		my $x = get_operand($scope,$tokens,$line);
       
   456 		return ~$x;
       
   457 	} elsif ($t eq '!') {
       
   458 		my $x = get_operand($scope,$tokens,$line);
       
   459 		return $x ? 0 : 1;
       
   460 	} elsif ($t eq '(') {
       
   461 		my $x = get_constant_expr($scope,$tokens,$line);
       
   462 		my $t = get_token($tokens,$line);
       
   463 		if ($t ne ')') {
       
   464 			die "Missing ) at line $$line\n";
       
   465 		}
       
   466 		return $x;
       
   467 	} elsif ($t eq "sizeof") {
       
   468 		my $ident = get_token($tokens,$line);
       
   469 		if ($ident eq '(') {
       
   470 			$ident = get_token($tokens,$line);
       
   471 			my $cb = get_token($tokens,$line);
       
   472 			if ($cb ne ')') {
       
   473 				die "Bad sizeof() syntax at line $$line\n";
       
   474 			}
       
   475 		}
       
   476 		$ident = look_through_macros($ident);
       
   477 		if ($ident !~ /^\w+$/) {
       
   478 			die "Bad sizeof() syntax at line $$line\n";
       
   479 		}
       
   480 		my $type = lookup_type($scope, $ident);
       
   481 		if (!defined $type) {
       
   482 			die "Unrecognised type $ident at line $$line\n";
       
   483 		}
       
   484 		if ($type->{basic}) {
       
   485 			return $type->{size};
       
   486 		} elsif ($type->{enum}) {
       
   487 			return 4;
       
   488 		} elsif ($type->{ptr}) {
       
   489 			return 4;
       
   490 		} elsif ($type->{fptr}) {
       
   491 			return 4;
       
   492 		}
       
   493 		my $al = $type->{class}->{align};
       
   494 		my $sz = $type->{class}->{size};
       
   495 		return ($sz+$al-1)&~($al-1);
       
   496 	}
       
   497 	$t = look_through_macros($t);
       
   498 	if ($t =~ /^0x[0-9a-f]+/i) {
       
   499 		return oct($t);
       
   500 	} elsif ($t =~ /^\d/) {
       
   501 		return $t;
       
   502 	} elsif ($t =~ /^\w+$/) {
       
   503 		my $x = lookup_value($scope,$t);
       
   504 		die "Unrecognised identifier '$t' at line $$line\n" unless defined($x);
       
   505 		return $x;
       
   506 	} else {
       
   507 		die "Syntax error at line $$line\n";
       
   508 	}
       
   509 }
       
   510 
       
   511 sub look_through_macros($) {
       
   512 	my ($ident) = @_;
       
   513 	while ($ident and $macros{$ident}) {
       
   514 		$ident = $macros{$ident};
       
   515 	}
       
   516 	return $ident;
       
   517 }
       
   518 
       
   519 sub lookup_value($$) {
       
   520 	my ($scope,$ident) = @_;
       
   521 	while ($scope) {
       
   522 		my $vl = $scope->{values};
       
   523 		if (defined($vl->{$ident})) {
       
   524 			return $vl->{$ident}->{value};
       
   525 		}
       
   526 		$scope = $scope->{scope};
       
   527 	}
       
   528 	return undef();
       
   529 }
       
   530 
       
   531 sub lookup_type($$) {
       
   532 	my ($scope,$ident) = @_;
       
   533 	if ($basictypes{$ident}) {
       
   534 		return {scope=>$scope, basic=>1, name=>$ident, size=>$basictypes{$ident} };
       
   535 	}
       
   536 	while ($scope) {
       
   537 		if ($basictypes{$ident}) {
       
   538 			return {scope=>$scope, basic=>1, name=>$ident, size=>$basictypes{$ident} };
       
   539 		}
       
   540 		my $el = $scope->{enums};
       
   541 		my $cl = $scope->{classes};
       
   542 		my $td = $scope->{typedefs};
       
   543 		if (grep {$_ eq $ident} @$el) {
       
   544 			return {scope=>$scope, enum=>1, name=>$ident, size=>4 };
       
   545 		}
       
   546 		my @match_class = (grep {$_->{name} eq $ident} @$cl);
       
   547 		if (scalar(@match_class)) {
       
   548 			return {scope=>$scope, class=>$match_class[0]};
       
   549 		}
       
   550 		my @match_td = (grep {$_->{name} eq $ident} @$td);
       
   551 		if (scalar(@match_td)) {
       
   552 			my $tdr = $match_td[0];
       
   553 			my $cat = $tdr->{category};
       
   554 			if ($cat eq 'basic' or $cat eq 'enum' or $cat eq 'class') {
       
   555 				$ident = $tdr->{alias};
       
   556 				next;
       
   557 			} else {
       
   558 				return { scope=>$scope, $cat=>1, $size=>$tdr->{size} };
       
   559 			}
       
   560 		}
       
   561 		$scope = $scope->{scope};
       
   562 	}
       
   563 	return undef();
       
   564 }
       
   565 
       
   566 sub get_mult_expr($$$) {
       
   567 	my ($scope,$tokens,$line) = @_;
       
   568 	my $x = get_operand($scope,$tokens,$line);
       
   569 	my $t;
       
   570 	for (;;) {
       
   571 		$t = get_token($tokens,$line);
       
   572 		if ($t eq '*') {
       
   573 			my $y = get_operand($scope,$tokens,$line);
       
   574 			$x = $x * $y;
       
   575 		} elsif ($t eq '/') {
       
   576 			my $y = get_operand($scope,$tokens,$line);
       
   577 			$x = int($x / $y);
       
   578 		} elsif ($t eq '%') {
       
   579 			my $y = get_operand($scope,$tokens,$line);
       
   580 			$x = int($x % $y);
       
   581 		} else {
       
   582 			last;
       
   583 		}
       
   584 	}
       
   585 	unshift @$tokens, $t;
       
   586 	return $x;
       
   587 }
       
   588 
       
   589 sub get_add_expr($$$) {
       
   590 	my ($scope,$tokens,$line) = @_;
       
   591 	my $x = get_mult_expr($scope,$tokens,$line);
       
   592 	my $t;
       
   593 	for (;;) {
       
   594 		$t = get_token($tokens,$line);
       
   595 		if ($t eq '+') {
       
   596 			my $y = get_mult_expr($scope,$tokens,$line);
       
   597 			$x = $x + $y;
       
   598 		} elsif ($t eq '-') {
       
   599 			my $y = get_mult_expr($scope,$tokens,$line);
       
   600 			$x = $x - $y;
       
   601 		} else {
       
   602 			last;
       
   603 		}
       
   604 	}
       
   605 	unshift @$tokens, $t;
       
   606 	return $x;
       
   607 }
       
   608 
       
   609 sub get_shift_expr($$$) {
       
   610 	my ($scope,$tokens,$line) = @_;
       
   611 	my $x = get_add_expr($scope,$tokens,$line);
       
   612 	my $t, $t2;
       
   613 	for (;;) {
       
   614 		$t = get_token($tokens,$line);
       
   615 		if ($t eq '<' or $t eq '>') {
       
   616 			$t2 = get_token($tokens,$line);
       
   617 			if ($t2 ne $t) {
       
   618 				unshift @$tokens, $t2;
       
   619 				last;
       
   620 			}
       
   621 		}
       
   622 		if ($t eq '<') {
       
   623 			my $y = get_add_expr($scope,$tokens,$line);
       
   624 			$x = $x << $y;
       
   625 		} elsif ($t eq '>') {
       
   626 			my $y = get_add_expr($scope,$tokens,$line);
       
   627 			$x = $x >> $y;
       
   628 		} else {
       
   629 			last;
       
   630 		}
       
   631 	}
       
   632 	unshift @$tokens, $t;
       
   633 	return $x;
       
   634 }
       
   635 
       
   636 sub get_and_expr($$$) {
       
   637 	my ($scope,$tokens,$line) = @_;
       
   638 	my $x = get_shift_expr($scope,$tokens,$line);
       
   639 	my $t;
       
   640 	for (;;) {
       
   641 		$t = get_token($tokens,$line);
       
   642 		if ($t eq '&') {
       
   643 			my $y = get_shift_expr($scope,$tokens,$line);
       
   644 			$x = $x & $y;
       
   645 		} else {
       
   646 			last;
       
   647 		}
       
   648 	}
       
   649 	unshift @$tokens, $t;
       
   650 	return $x;
       
   651 }
       
   652 
       
   653 sub get_xor_expr($$$) {
       
   654 	my ($scope,$tokens,$line) = @_;
       
   655 	my $x = get_and_expr($scope,$tokens,$line);
       
   656 	my $t;
       
   657 	for (;;) {
       
   658 		$t = get_token($tokens,$line);
       
   659 		if ($t eq '^') {
       
   660 			my $y = get_and_expr($scope,$tokens,$line);
       
   661 			$x = $x ^ $y;
       
   662 		} else {
       
   663 			last;
       
   664 		}
       
   665 	}
       
   666 	unshift @$tokens, $t;
       
   667 	return $x;
       
   668 }
       
   669 
       
   670 sub get_ior_expr($$$) {
       
   671 	my ($scope,$tokens,$line) = @_;
       
   672 	my $x = get_xor_expr($scope,$tokens,$line);
       
   673 	my $t;
       
   674 	for (;;) {
       
   675 		$t = get_token($tokens,$line);
       
   676 		if ($t eq '|') {
       
   677 			my $y = get_xor_expr($scope,$tokens,$line);
       
   678 			$x = $x | $y;
       
   679 		} else {
       
   680 			last;
       
   681 		}
       
   682 	}
       
   683 	unshift @$tokens, $t;
       
   684 	return $x;
       
   685 }
       
   686 
       
   687 sub get_constant_expr($$$) {
       
   688 	my ($scope,$tokens,$line) = @_;
       
   689 	my $x = get_ior_expr($scope,$tokens,$line);
       
   690 	return $x;
       
   691 }
       
   692 
       
   693 sub parse_enum($$$$) {
       
   694 	my ($scope,$tokens,$line,$enum_name) = @_;
       
   695 	my $vl = $scope->{values};
       
   696 	my $x = 0;
       
   697 	for (;;) {
       
   698 		my $t = get_token($tokens,$line);
       
   699 		last if ($t eq '}');
       
   700 		if (!defined($t)) {
       
   701 			die "Unexpected end of file at line $$line\n";
       
   702 		}
       
   703 		if ($t !~ /^\w+$/) {
       
   704 			die "Syntax error at line $$line\n";
       
   705 		}
       
   706 		if (defined($vl->{$t})) {
       
   707 			die "Duplicate identifier at line $$line\n";
       
   708 		}
       
   709 		my $t2 = get_token($tokens,$line);
       
   710 		if ($t2 eq ',') {
       
   711 			$vl->{$t} = {type=>$enum_name, size=>4, value=>$x, enum=>1};
       
   712 			++$x;
       
   713 		} elsif ($t2 eq '}') {
       
   714 			$vl->{$t} = {type=>$enum_name, size=>4, value=>$x, enum=>1};
       
   715 			++$x;
       
   716 			last;
       
   717 		} elsif ($t2 eq '=') {
       
   718 			$x = get_constant_expr($scope, $tokens, $line);
       
   719 			$vl->{$t} = {type=>$enum_name, size=>4, value=>$x, enum=>1};
       
   720 			++$x;
       
   721 			$t2 = get_token($tokens,$line);
       
   722 			last if ($t2 eq '}');
       
   723 			next if ($t2 eq ',');
       
   724 			die "Syntax error at line $$line\n";
       
   725 		} else {
       
   726 			unshift @$tokens, $t2;
       
   727 		}
       
   728 	}
       
   729 	my $t = get_token($tokens,$line);
       
   730 	if ($t ne ';') {
       
   731 		die "Missing ; at line $$line\n";
       
   732 	}
       
   733 }
       
   734 
       
   735 sub parse_decl_def($$$) {
       
   736 	my ($scope,$tokens,$line) = @_;
       
   737 	my $level=0;
       
   738 	my @decl;
       
   739 	while ( scalar(@$tokens) ) {
       
   740 		my $t = get_token($tokens, $line);
       
   741 		if ($t eq ';' and $level==0) {
       
   742 			return @decl;
       
   743 		}
       
   744 		push @decl, $t;
       
   745 		if ($t eq '{') {
       
   746 			++$level;
       
   747 		}
       
   748 		if ($t eq '}') {
       
   749 			if ($level==0) {
       
   750 				die "Syntax error at line $$line\n";
       
   751 			}
       
   752 			if (--$level==0) {
       
   753 				return ();	# end of function definition reached
       
   754 			}
       
   755 		}
       
   756 	}
       
   757 	die "Unexpected end of file at line $$line\n";
       
   758 }
       
   759 
       
   760 sub dump_scope($) {
       
   761 	my ($scope) = @_;
       
   762 	my $el = $scope->{enums};
       
   763 	my $cl = $scope->{classes};
       
   764 	my $vl = $scope->{values};
       
   765 	print "SCOPE: $scope->{name}\n";
       
   766 	if (scalar(@$el)) {
       
   767 		print "\tenums:\n";
       
   768 		foreach (@$el) {
       
   769 			print "\t\t$_\n";
       
   770 		}
       
   771 	}
       
   772 	if (scalar(keys(%$vl))) {
       
   773 		print "\tvalues:\n";
       
   774 		foreach $vname (keys(%$vl)) {
       
   775 			my $v = $vl->{$vname};
       
   776 			my $x = $v->{value};
       
   777 			my $t = $v->{type};
       
   778 			my $sz = $v->{size};
       
   779 			if ($v->{enum}) {
       
   780 				print "\t\t$vname\=$x (enum $t) size=$sz\n";
       
   781 			} else {
       
   782 				print "\t\t$vname\=$x (type $t) size=$sz\n";
       
   783 			}
       
   784 		}
       
   785 	}
       
   786 	if ($scope->{scope}) {
       
   787 		my $members = $scope->{members};
       
   788 		foreach (@$members) {
       
   789 			my $n = $_->{name};
       
   790 			my $sz = $_->{size};
       
   791 			my $off = $_->{offset};
       
   792 			my $spc = $_->{spacing};
       
   793 			if (defined $spc) {
       
   794 				print "\t$n\[\]\: spacing $spc size $sz offset $off\n";
       
   795 			} else {
       
   796 				print "\t$n\: size $sz offset $off\n";
       
   797 			}
       
   798 		}
       
   799 		print "\tOverall size : $scope->{size}\n";
       
   800 		print "\tOverall align: $scope->{align}\n";
       
   801 	}
       
   802 	foreach $s (@$cl) {
       
   803 		dump_scope($s);
       
   804 	}
       
   805 }
       
   806 
       
   807 sub output_scope($$) {
       
   808 	my ($scope, $out) = @_;
       
   809 	my $el = $scope->{enums};
       
   810 	my $cl = $scope->{classes};
       
   811 	my $vl = $scope->{values};
       
   812 	my $sn = scope_full_name($scope);
       
   813 	my $sp = ($scope->{file}) ? "" : $sn."_";
       
   814 	if ($scope->{file}) {
       
   815 		push @$out, "";
       
   816 		push @$out, &$comment_sub("FILE SCOPE");
       
   817 		push @$out, "";
       
   818 	} else {
       
   819 		push @$out, "";
       
   820 		push @$out, &$comment_sub($scope->{specifier}." ".$scope->{name});
       
   821 		push @$out, "";
       
   822 	}
       
   823 	if (scalar(keys(%$vl))) {
       
   824 		foreach $vname (keys(%$vl)) {
       
   825 			my $v = $vl->{$vname};
       
   826 			my $x = $v->{value};
       
   827 			my $t = $v->{type};
       
   828 			my $sz = $v->{size};
       
   829 			push @$out, &$format_sub($sp.$vname, $x);
       
   830 		}
       
   831 	}
       
   832 	if ($scope->{scope}) {
       
   833 		my $members = $scope->{members};
       
   834 		foreach (@$members) {
       
   835 			my $n = $_->{name};
       
   836 			my $sz = $_->{size};
       
   837 			my $off = $_->{offset};
       
   838 			my $spc = $_->{spacing};
       
   839 			push @$out, &$format_sub($sp.$n, $off);
       
   840 			if (defined $spc) {
       
   841 				push @$out, &$format_sub($sp.$n."_spc", $spc);
       
   842 			}
       
   843 		}
       
   844 		push @$out, &$format_sub($sp."sz", $scope->{size});
       
   845 	}
       
   846 	foreach $s (@$cl) {
       
   847 		if ($s->{complete})	{
       
   848 			output_scope($s, $out);
       
   849 		}
       
   850 	}
       
   851 }
       
   852 
       
   853 sub scope_full_name($) {
       
   854 	my ($scope) = @_;
       
   855 	if ($scope->{file}) {
       
   856 		return "";
       
   857 	}
       
   858 	my $parent = $scope->{scope};
       
   859 	if ($parent->{file}) {
       
   860 		return $scope->{name};
       
   861 	}
       
   862 	return scope_full_name($parent)."_".$scope->{name};
       
   863 }
       
   864 
       
   865 sub pad($$) {
       
   866 	my ($lineref, $n) = @_;
       
   867 	my $l = length ($$lineref);
       
   868 	if ($l < $n) {
       
   869 		$$lineref .= ' 'x($n-$l);
       
   870 	}
       
   871 }
       
   872 
       
   873 #
       
   874 # Subroutines for ARMASM compatible output
       
   875 #
       
   876 sub armasm_format($$;$) {
       
   877 	my ($name, $value, $comment) = @_;
       
   878 	my $r = "$name ";
       
   879 	pad(\$r, 40);
       
   880 	$r .= sprintf("EQU 0x%08x", $value & 0xFFFFFFFF);
       
   881 	if ($comment and $comment!~/^\s*$/) {
       
   882 		$r .= " ";
       
   883 		pad(\$r, 60);
       
   884 		$r .= "; $comment";
       
   885 	}
       
   886 	return $r;
       
   887 }
       
   888 
       
   889 sub armasm_comment($) {
       
   890 	my ($comment) = @_;
       
   891 	return "; $comment";
       
   892 }
       
   893 
       
   894 sub armasm_end() {
       
   895 	return "\n\tEND\n";
       
   896 }
       
   897 
       
   898 #
       
   899 # Subroutines for GNU AS compatible output
       
   900 #
       
   901 sub as_format($$;$) {
       
   902 	my ($name, $value, $comment) = @_;
       
   903 	my $r = "    .equ $name, ";
       
   904 	pad(\$r, 50);
       
   905 	$r .= sprintf("0x%08x", $value & 0xFFFFFFFF);
       
   906 	if ($comment and $comment!~/^\s*$/) {
       
   907 		$r .= " ";
       
   908 		pad(\$r, 65);
       
   909 		$r .= "/* $comment */";
       
   910 	}
       
   911 	return $r;
       
   912 }
       
   913 
       
   914 sub as_comment($) {
       
   915 	my ($comment) = @_;
       
   916 	if (length ($comment) > 0) {
       
   917 		return "/* $comment */";
       
   918 	} else {
       
   919 		return "";
       
   920 	}
       
   921 }
       
   922 
       
   923 sub as_end() {
       
   924 	return "";
       
   925 }
       
   926 
       
   927 #
       
   928 # Subroutines for Turbo Assembler compatible output
       
   929 #
       
   930 sub tasm_format($$;$) {
       
   931 	my ($name, $value, $comment) = @_;
       
   932 	my $r = "$name ";
       
   933 	pad(\$r, 40);
       
   934 	$r .= sprintf("EQU 0%08xh", $value & 0xFFFFFFFF);
       
   935 	if ($comment and $comment!~/^\s*$/) {
       
   936 		$r .= " ";
       
   937 		pad(\$r, 60);
       
   938 		$r .= "; $comment";
       
   939 	}
       
   940 	return $r;
       
   941 }
       
   942 
       
   943 sub tasm_comment($) {
       
   944 	my ($comment) = @_;
       
   945 	return "; $comment";
       
   946 }
       
   947 
       
   948 sub tasm_end() {
       
   949 	return "";
       
   950 }