gecko-dev/js2/tools/gencode.pl
2004-04-25 15:37:13 +00:00

284 lines
8.5 KiB
Perl

#!/usr/bin/perl
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is JavaScript 2 Prototype.
#
# The Initial Developer of the Original Code is
# Netscape Communications Corporation.
# Portions created by the Initial Developer are Copyright (C) 1997-1999
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
use strict;
use jsicodes;
##############################################################################
# HELLO, ARE YOU READING THIS?
# The opcode definition is now in jsicodes.pm, please go there to make changes.
##############################################################################
my $tab = " ";
my $init_tab = $tab;
my $enum_decs = "";
my $class_decs = "";
my @name_array;
my $opcode_maxlen = 0;
my $k;
if (!$ARGV[0]) {
# no args, collect all opcodes
for $k (sort(keys(%jsicodes::ops))) {
&collect($k);
}
} else {
# collect defs for only the opcodes specified on the command line
while ($k = pop(@ARGV)) {
&collect (uc($k));
}
}
&spew;
sub collect {
# grab the info from the $k record in $ops, and append it to
# $enum_decs, @name_array, and $class_decs.
my ($k) = @_;
if (length($k) > $opcode_maxlen) {
$opcode_maxlen = length($k);
}
my $c = $jsicodes::ops{$k};
if (!$c) {
die ("Unknown opcode, $k\n");
}
my $opname = $k;
my $cname = jsicodes::get_classname ($k);
my $super = $c->{"super"};
my $constructor = $super;
my @params;
if ($c->{"params"}) {
@params = @{$c->{"params"}};
} else {
@params = ();
}
my $rem = $c->{"rem"};
my ($dec_list, $call_list, $template_list) =
&get_paramlists(@params);
my @types = split (", ", $template_list);
my $constr_params = $call_list ? $opname . ", " . $call_list : $opname;
if ($super =~ /Instruction_\d/) {
$super .= "<" . $template_list . ">";
}
push (@name_array, $opname);
$enum_decs .= "$init_tab$tab$opname, /* $rem */\n";
if ($super) {
$class_decs .= ($init_tab . "class $cname : public $super {\n" .
$init_tab . "public:\n" .
$init_tab . $tab . "/* $rem */\n" .
$init_tab . $tab . "$cname ($dec_list) :\n" .
$init_tab . $tab . $tab . "$super\n" .
"$init_tab$tab$tab($constr_params) " .
"{};\n");
if (!$c->{"super_has_print"}) {
$class_decs .= ($init_tab . $tab .
"virtual Formatter& print(Formatter& f) {\n" .
$init_tab . $tab . $tab . "f << opcodeNames[$opname]" .
&get_print_body(@types) . ";\n" .
$init_tab . $tab . $tab . "return f;\n" .
$init_tab . $tab . "}\n");
my $printops_body = &get_printops_body(@types);
my $printops_decl = "virtual Formatter& printOperands(Formatter& f, ";
# $printops_decl .= ($dec_list =~ /ArgumentList/) ?
# "const JSValues& registers" :
# "const JSValues& registers";
$printops_decl .= ($printops_body eq "") ?
"const JSValues& /*registers*/" :
"const JSValues& registers";
$printops_decl .= ") {\n";
$class_decs .= ($init_tab . $tab .
$printops_decl .
$printops_body .
$init_tab . $tab . $tab . "return f;\n" .
$init_tab . $tab . "}\n");
} else {
$class_decs .= $init_tab . $tab .
"/* print() and printOperands() inherited from $super */\n";
}
$class_decs .= $init_tab . "};\n\n";
}
}
sub spew {
# print the info in $enum_decs, @name_aray, and $class_decs to stdout.
my $opname;
print "// THIS FILE IS MACHINE GENERATED! DO NOT EDIT BY HAND!\n\n";
print "#if !defined(OPCODE_NAMES)\n\n";
print $tab . "enum {\n$enum_decs$tab};\n\n";
print $class_decs;
print "#else\n\n";
print $tab . "char *opcodeNames[] = {\n";
for $opname (@name_array) {
print "$tab$tab\"$opname";
for (0 .. $opcode_maxlen - length($opname) - 1) {
print " ";
}
print "\",\n"
}
print "$tab};\n\n";
print "#endif\n\n"
}
sub get_paramlists {
# parse the params entry (passed into @types) into various parameter lists
# used in the class declaration
my @types = @_;
my @dec;
my @call;
my @tostr;
my @template;
my $op = 1;
my $type;
for $type (@types) {
my $pfx;
my $deref;
my $member;
my $default;
($type, $default) = split (" = ", $type);
if ($default ne "") {
$default = " = " . $default;
}
$pfx = $deref = "";
$member = "mOp$op";
push (@dec, "$type aOp$op" . "$default");
push (@call, "aOp$op");
push (@template, $type);
$op++;
}
return (join (", ", @dec), join (", ", @call), join (", ", @template));
}
sub get_print_body {
# generate the body of the print() function
my (@types) = @_;
my $type;
my @oplist;
my $op = 1;
my $in = $init_tab . $tab . $tab;
for $type (@types) {
if ($type eq "TypedRegister") {
push (@oplist, "mOp$op" );
} elsif ($type eq "Label*") {
push (@oplist, "\"Offset \" << ((mOp$op) ? mOp$op->mOffset : NotAnOffset)")
} elsif ($type =~ /String/) {
push (@oplist, "\"'\" << *mOp$op << \"'\"");
} elsif ($type =~ /JSType *\*/) {
push (@oplist, "\"'\" << mOp$op->getName() << \"'\"");
} elsif ($type =~ /JSFunction *\*/) {
push (@oplist, "\"JSFunction\"");
} elsif ($type =~ /bool/) {
push (@oplist, "\"'\" << ((mOp$op) ? \"true\" : \"false\") << \"'\"");
} elsif ($type =~ /ICodeModule/) {
push (@oplist, "\"ICodeModule\"");
} elsif ($type =~ /FunctionDefinition/) {
push (@oplist, "\"FunctionDefinition\"");
} elsif ($type =~ /JSClass *\*/) {
push (@oplist, "mOp$op->getName()");
} else {
push (@oplist, "mOp$op");
}
$op++;
}
my $rv = join (" << \", \" << ", @oplist);
if ($rv ne "") {
$rv = " << \"\\t\" << " . $rv;
}
return $rv;
}
sub get_printops_body {
# generate the body of the printOperands() function
my (@types) = @_;
my $type;
my @oplist;
my $op = 1;
my $in = $init_tab . $tab . $tab;
for $type (@types) {
if ($type eq "TypedRegister") {
push (@oplist, "getRegisterValue(registers, mOp$op.first)");
# push (@oplist, "mOp$op.first");
# push (@oplist, "\"R\" << mOp$op.first << '=' << registers[mOp$op.first]");
} elsif ($type eq "ArgumentList") {
push (@oplist, "ArgList(mOp$op, registers)");
}
$op++;
}
my $rv = join (" << \", \" << ", @oplist);
if ($rv ne "") {
$rv = $init_tab . $tab . $tab . "f << " . $rv . ";\n";
}
return $rv;
}