From fa2677ff75250b9ddcd2d8f977da695ec5cd62a3 Mon Sep 17 00:00:00 2001 From: DeaDDooMER Date: Sat, 1 Nov 2014 17:18:19 +0300 Subject: [PATCH] Patched for Linux --- LICENSE.txt | 17 + MPC.3.5.LINUX/Linux/mp3CC | Bin 0 -> 299587 bytes MPC.3.5.LINUX/classgen/bytecode.c | 145 + MPC.3.5.LINUX/classgen/bytecode.h | 235 + MPC.3.5.LINUX/classgen/classgen.c | 645 ++ MPC.3.5.LINUX/classgen/classgen.h | 31 + MPC.3.5.LINUX/classgen/constant_pool.c | 449 ++ MPC.3.5.LINUX/classgen/constant_pool.h | 33 + MPC.3.5.LINUX/classgen/preverify.c | 1119 ++++ MPC.3.5.LINUX/classgen/preverify.h | 79 + MPC.3.5.LINUX/lex/lex.yy.c | 560 ++ MPC.3.5.LINUX/lex/tokens.h | 85 + MPC.3.5.LINUX/main/main.c | 402 ++ MPC.3.5.LINUX/mp3CC.cbp | 222 + MPC.3.5.LINUX/mp3CC.depend | 3454 +++++++++++ MPC.3.5.LINUX/mp3CC.layout | 154 + MPC.3.5.LINUX/parser/parser.c | 6835 +++++++++++++++++++++ MPC.3.5.LINUX/parser/parser.h | 59 + MPC.3.5.LINUX/parser/stdpas.c | 3333 ++++++++++ MPC.3.5.LINUX/parser/stdpas.h | 27 + MPC.3.5.LINUX/preverifier/README.TXT | 15 + MPC.3.5.LINUX/preverifier/check_class.c | 844 +++ MPC.3.5.LINUX/preverifier/check_code.c | 3970 ++++++++++++ MPC.3.5.LINUX/preverifier/check_code.h | 160 + MPC.3.5.LINUX/preverifier/classloader.c | 1783 ++++++ MPC.3.5.LINUX/preverifier/classresolver.c | 1269 ++++ MPC.3.5.LINUX/preverifier/convert_md.c | 155 + MPC.3.5.LINUX/preverifier/convert_md.h | 22 + MPC.3.5.LINUX/preverifier/file.c | 787 +++ MPC.3.5.LINUX/preverifier/inlinejsr.c | 681 ++ MPC.3.5.LINUX/preverifier/jar.c | 727 +++ MPC.3.5.LINUX/preverifier/jar.h | 206 + MPC.3.5.LINUX/preverifier/jar_support.c | 1347 ++++ MPC.3.5.LINUX/preverifier/jarint.h | 224 + MPC.3.5.LINUX/preverifier/jartables.h | 779 +++ MPC.3.5.LINUX/preverifier/locale_md.h | 22 + MPC.3.5.LINUX/preverifier/main.c | 479 ++ MPC.3.5.LINUX/preverifier/oobj.h | 682 ++ MPC.3.5.LINUX/preverifier/opcodes.h | 248 + MPC.3.5.LINUX/preverifier/opcodes.in_out | 245 + MPC.3.5.LINUX/preverifier/opcodes.init | 271 + MPC.3.5.LINUX/preverifier/opcodes.length | 271 + MPC.3.5.LINUX/preverifier/path.h | 50 + MPC.3.5.LINUX/preverifier/path_md.h | 50 + MPC.3.5.LINUX/preverifier/signature.h | 59 + MPC.3.5.LINUX/preverifier/stubs.c | 100 + MPC.3.5.LINUX/preverifier/sys_api.h | 207 + MPC.3.5.LINUX/preverifier/sys_support.c | 475 ++ MPC.3.5.LINUX/preverifier/sysmacros_md.h | 74 + MPC.3.5.LINUX/preverifier/tree.h | 69 + MPC.3.5.LINUX/preverifier/typecodes.h | 145 + MPC.3.5.LINUX/preverifier/typedefs.h | 83 + MPC.3.5.LINUX/preverifier/typedefs_md.h | 142 + MPC.3.5.LINUX/preverifier/utf.c | 216 + MPC.3.5.LINUX/preverifier/utf.h | 32 + MPC.3.5.LINUX/preverifier/util.c | 745 +++ MPC.3.5.LINUX/readme.txt | 10 + MPC.3.5.LINUX/structures/block.c | 3040 +++++++++ MPC.3.5.LINUX/structures/block.h | 90 + MPC.3.5.LINUX/structures/identifier.c | 506 ++ MPC.3.5.LINUX/structures/identifier.h | 169 + MPC.3.5.LINUX/structures/name_table.c | 213 + MPC.3.5.LINUX/structures/name_table.h | 40 + MPC.3.5.LINUX/structures/string_list.c | 128 + MPC.3.5.LINUX/structures/string_list.h | 22 + MPC.3.5.LINUX/structures/type.c | 329 + MPC.3.5.LINUX/structures/type.h | 74 + MPC.3.5.LINUX/structures/type_list.c | 236 + MPC.3.5.LINUX/structures/type_list.h | 28 + MPC.3.5.LINUX/structures/unit.c | 75 + MPC.3.5.LINUX/structures/unit.h | 21 + MPC.3.5.LINUX/util/error.c | 203 + MPC.3.5.LINUX/util/error.h | 24 + MPC.3.5.LINUX/util/memory.c | 213 + MPC.3.5.LINUX/util/memory.h | 30 + MPC.3.5.LINUX/util/strings.c | 201 + MPC.3.5.LINUX/util/strings.h | 76 + MPS.3.1/F.java | 435 ++ MPS.3.1/FS.java | 230 + MPS.3.1/FW.java | 95 + MPS.3.1/H.java | 155 + MPS.3.1/P.java | 101 + MPS.3.1/README.txt | 9 + MPS.3.1/RS.java | 125 + MPS.3.1/Real.java | 6020 ++++++++++++++++++ MPS.3.1/S.java | 162 + MPS.3.1/SM.java | 112 + README.txt | 195 + 88 files changed, 48885 insertions(+) create mode 100644 LICENSE.txt create mode 100644 MPC.3.5.LINUX/Linux/mp3CC create mode 100644 MPC.3.5.LINUX/classgen/bytecode.c create mode 100644 MPC.3.5.LINUX/classgen/bytecode.h create mode 100644 MPC.3.5.LINUX/classgen/classgen.c create mode 100644 MPC.3.5.LINUX/classgen/classgen.h create mode 100644 MPC.3.5.LINUX/classgen/constant_pool.c create mode 100644 MPC.3.5.LINUX/classgen/constant_pool.h create mode 100644 MPC.3.5.LINUX/classgen/preverify.c create mode 100644 MPC.3.5.LINUX/classgen/preverify.h create mode 100644 MPC.3.5.LINUX/lex/lex.yy.c create mode 100644 MPC.3.5.LINUX/lex/tokens.h create mode 100644 MPC.3.5.LINUX/main/main.c create mode 100644 MPC.3.5.LINUX/mp3CC.cbp create mode 100644 MPC.3.5.LINUX/mp3CC.depend create mode 100644 MPC.3.5.LINUX/mp3CC.layout create mode 100644 MPC.3.5.LINUX/parser/parser.c create mode 100644 MPC.3.5.LINUX/parser/parser.h create mode 100644 MPC.3.5.LINUX/parser/stdpas.c create mode 100644 MPC.3.5.LINUX/parser/stdpas.h create mode 100644 MPC.3.5.LINUX/preverifier/README.TXT create mode 100644 MPC.3.5.LINUX/preverifier/check_class.c create mode 100644 MPC.3.5.LINUX/preverifier/check_code.c create mode 100644 MPC.3.5.LINUX/preverifier/check_code.h create mode 100644 MPC.3.5.LINUX/preverifier/classloader.c create mode 100644 MPC.3.5.LINUX/preverifier/classresolver.c create mode 100644 MPC.3.5.LINUX/preverifier/convert_md.c create mode 100644 MPC.3.5.LINUX/preverifier/convert_md.h create mode 100644 MPC.3.5.LINUX/preverifier/file.c create mode 100644 MPC.3.5.LINUX/preverifier/inlinejsr.c create mode 100644 MPC.3.5.LINUX/preverifier/jar.c create mode 100644 MPC.3.5.LINUX/preverifier/jar.h create mode 100644 MPC.3.5.LINUX/preverifier/jar_support.c create mode 100644 MPC.3.5.LINUX/preverifier/jarint.h create mode 100644 MPC.3.5.LINUX/preverifier/jartables.h create mode 100644 MPC.3.5.LINUX/preverifier/locale_md.h create mode 100644 MPC.3.5.LINUX/preverifier/main.c create mode 100644 MPC.3.5.LINUX/preverifier/oobj.h create mode 100644 MPC.3.5.LINUX/preverifier/opcodes.h create mode 100644 MPC.3.5.LINUX/preverifier/opcodes.in_out create mode 100644 MPC.3.5.LINUX/preverifier/opcodes.init create mode 100644 MPC.3.5.LINUX/preverifier/opcodes.length create mode 100644 MPC.3.5.LINUX/preverifier/path.h create mode 100644 MPC.3.5.LINUX/preverifier/path_md.h create mode 100644 MPC.3.5.LINUX/preverifier/signature.h create mode 100644 MPC.3.5.LINUX/preverifier/stubs.c create mode 100644 MPC.3.5.LINUX/preverifier/sys_api.h create mode 100644 MPC.3.5.LINUX/preverifier/sys_support.c create mode 100644 MPC.3.5.LINUX/preverifier/sysmacros_md.h create mode 100644 MPC.3.5.LINUX/preverifier/tree.h create mode 100644 MPC.3.5.LINUX/preverifier/typecodes.h create mode 100644 MPC.3.5.LINUX/preverifier/typedefs.h create mode 100644 MPC.3.5.LINUX/preverifier/typedefs_md.h create mode 100644 MPC.3.5.LINUX/preverifier/utf.c create mode 100644 MPC.3.5.LINUX/preverifier/utf.h create mode 100644 MPC.3.5.LINUX/preverifier/util.c create mode 100644 MPC.3.5.LINUX/readme.txt create mode 100644 MPC.3.5.LINUX/structures/block.c create mode 100644 MPC.3.5.LINUX/structures/block.h create mode 100644 MPC.3.5.LINUX/structures/identifier.c create mode 100644 MPC.3.5.LINUX/structures/identifier.h create mode 100644 MPC.3.5.LINUX/structures/name_table.c create mode 100644 MPC.3.5.LINUX/structures/name_table.h create mode 100644 MPC.3.5.LINUX/structures/string_list.c create mode 100644 MPC.3.5.LINUX/structures/string_list.h create mode 100644 MPC.3.5.LINUX/structures/type.c create mode 100644 MPC.3.5.LINUX/structures/type.h create mode 100644 MPC.3.5.LINUX/structures/type_list.c create mode 100644 MPC.3.5.LINUX/structures/type_list.h create mode 100644 MPC.3.5.LINUX/structures/unit.c create mode 100644 MPC.3.5.LINUX/structures/unit.h create mode 100644 MPC.3.5.LINUX/util/error.c create mode 100644 MPC.3.5.LINUX/util/error.h create mode 100644 MPC.3.5.LINUX/util/memory.c create mode 100644 MPC.3.5.LINUX/util/memory.h create mode 100644 MPC.3.5.LINUX/util/strings.c create mode 100644 MPC.3.5.LINUX/util/strings.h create mode 100644 MPS.3.1/F.java create mode 100644 MPS.3.1/FS.java create mode 100644 MPS.3.1/FW.java create mode 100644 MPS.3.1/H.java create mode 100644 MPS.3.1/P.java create mode 100644 MPS.3.1/README.txt create mode 100644 MPS.3.1/RS.java create mode 100644 MPS.3.1/Real.java create mode 100644 MPS.3.1/S.java create mode 100644 MPS.3.1/SM.java create mode 100644 README.txt diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..e3133e8 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,17 @@ + + + MIDletPascal compiler + Copyright (C) 2009-2013 MIDletPascal project + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . diff --git a/MPC.3.5.LINUX/Linux/mp3CC b/MPC.3.5.LINUX/Linux/mp3CC new file mode 100644 index 0000000000000000000000000000000000000000..de8ba176f01c36210804ecc7419fe116b358fd6d GIT binary patch literal 299587 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 z%0D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 ACjbBd literal 0 HcmV?d00001 diff --git a/MPC.3.5.LINUX/classgen/bytecode.c b/MPC.3.5.LINUX/classgen/bytecode.c new file mode 100644 index 0000000..847d9c3 --- /dev/null +++ b/MPC.3.5.LINUX/classgen/bytecode.c @@ -0,0 +1,145 @@ +/******************************************************************** + + bytecode.c - funcions for creating the bytecode + + Niksa Orlic, 2004-06-11 + +********************************************************************/ + +#include "bytecode.h" +#include "../util/error.h" +//#include "../util/message.h" +#include "../util/memory.h" +#include +#include +#include + +//#include "../main/static_entry.h" + +extern int linenum; + +//extern FILE* yyin; +//extern int fileSize; + +/* + Allocate a new bytecode +*/ +bytecode *bytecode_create() +{ + bytecode *new_bytecode = (bytecode*) mem_alloc(sizeof(bytecode)); + + if (new_bytecode == NULL) + die(1); + + new_bytecode->bytecode_allocated_size = 0; + new_bytecode->bytecode_pos = 0; + + return new_bytecode; +} + +/* + Destroy the bytecode +*/ +void bytecode_destroy(bytecode *code) +{ + if (code->bytecode_allocated_size > 0) + mem_free(code->bytecode); + + mem_free(code); +} + +bytecode *bytecode_duplicate(bytecode *code) +{ + bytecode *new_bytecode = bytecode_create(); + bytecode_append_bytecode(new_bytecode, code); + + return new_bytecode; +} + + +/* + Appends a single byte to the bytecode +*/ +void bytecode_append(bytecode *code, char c) +{ + //if (c == swap$) + //{ + // int a = 1; + //} + if (code->bytecode_pos == code->bytecode_allocated_size) + { + if (code->bytecode_allocated_size == 0) + code->bytecode = (char*) mem_alloc(128); + else + code->bytecode = (char*) mem_realloc(code->bytecode, + code->bytecode_allocated_size + 128); + + if (code->bytecode == NULL) + die(1); + + code->bytecode_allocated_size += 128; + } + + code->bytecode[code->bytecode_pos] = c; + code->bytecode_pos ++; +} + +/* + Append one bytecode to another. +*/ +void bytecode_append_bytecode(bytecode *dest, bytecode *src) +{ + if (src->bytecode_pos == 0) + return; + + if (dest->bytecode_allocated_size == 0) + { + dest->bytecode_allocated_size += src->bytecode_pos; + dest->bytecode = (char*) mem_alloc(dest->bytecode_allocated_size); + } + else + { + dest->bytecode_allocated_size += src->bytecode_pos; + dest->bytecode = (char*) mem_realloc(dest->bytecode, dest->bytecode_allocated_size); + } + + if (dest->bytecode == NULL) + die(1); + + memcpy(dest->bytecode + dest->bytecode_pos, src->bytecode, src->bytecode_pos); + dest->bytecode_pos += src->bytecode_pos; +} + +/* + Appends a short int to the bytecode +*/ +void bytecode_append_short_int(bytecode *code, short int s) +{ + char ch; + + ch = (char) (s >> 8); + bytecode_append(code, ch); + + ch = (char) s; + bytecode_append(code, ch); +} + +/* + Appends a long int to the bytecode +*/ +void bytecode_append_long_int(bytecode *code, long int l) +{ + char ch; + + ch = (char) (l >> 24); + bytecode_append(code, ch); + + ch = (char) (l >> 16); + bytecode_append(code, ch); + + ch = (char) (l >> 8); + bytecode_append(code, ch); + + ch = (char) l; + bytecode_append(code, ch); +} diff --git a/MPC.3.5.LINUX/classgen/bytecode.h b/MPC.3.5.LINUX/classgen/bytecode.h new file mode 100644 index 0000000..587f091 --- /dev/null +++ b/MPC.3.5.LINUX/classgen/bytecode.h @@ -0,0 +1,235 @@ +/******************************************************************** + + bytecode.h - methods for handling the bytecode + + Niksa Orlic, 2004-05-22 + +********************************************************************/ + +struct bytecode_struct +{ + int bytecode_pos; + int bytecode_allocated_size; + char *bytecode; +}; + +typedef struct bytecode_struct bytecode; + +bytecode *bytecode_create(); +void bytecode_destroy(bytecode *code); +bytecode *bytecode_duplicate(bytecode*); + +void bytecode_append(bytecode *code, char c); +void bytecode_append_short_int(bytecode *code, short int s); +void bytecode_append_long_int(bytecode *code, long int l); +void bytecode_append_bytecode(bytecode *dest, bytecode *src); + +/* Java bytecode mnemonics defines */ +enum Java_mnemonics +{ + nop$ = 0x00, + aconst_null$, + iconst_m1$, + iconst_0$, + iconst_1$, + iconst_2$, + iconst_3$, + iconst_4$, + iconst_5$, + lconst_0$, + lconst_1$, + fconst_0$, + fconst_1$, + fconst_2$, + dconst_0$, + dconst_1$, + bipush$, + sipush$, + ldc$, + ldc_w$, + ldc2_w$, + iload$, + lload$, + fload$, + dload$, + aload$, + iload_0$, + iload_1$, + iload_2$, + iload_3$, + lload_0$, + lload_1$, + lload_2$, + lload_3$, + fload_0$, + fload_1$, + fload_2$, + fload_3$, + dload_0$, + dload_1$, + dload_2$, + dload_3$, + aload_0$, + aload_1$, + aload_2$, + aload_3$, + iaload$, + laload$, + faload$, + daload$, + aaload$, + baload$, + caload$, + saload$, + istore$, + lstore$, + fstore$, + dstore$, + astore$, + istore_0$, + istore_1$, + istore_2$, + istore_3$, + lstore_0$, + lstore_1$, + lstore_2$, + lstore_3$, + fstore_0$, + fstore_1$, + fstore_2$, + fstore_3$, + dstore_0$, + dstore_1$, + dstore_2$, + dstore_3$, + astore_0$, + astore_1$, + astore_2$, + astore_3$, + iastore$, + lastore$, + fastore$, + dastore$, + aastore$, + bastore$, + castore$, + sastore$, + pop$, + pop2$, + dup$, + dup_x1$, + dup_x2$, + dup2$, + dup2_x1$, + dup2_x2$, + swap$, + iadd$, + ladd$, + fadd$, + dadd$, + isub$, + lsub$, + fsub$, + dsub$, + imul$, + lmul$, + fmul$, + dmul$, + idiv$, + ldiv$, + fdiv$, + ddiv$, + irem$, + lrem$, + frem$, + drem$, + ineg$, + lneg$, + fneg$, + dneg$, + ishl$, + lshl$, + ishr$, + lshr$, + iushr$, + lushr$, + iand$, + land$, + ior$, + lor$, + ixor$, + lxor$, + iinc$, + i2l$, + i2f$, + i2d$, + l2i$, + l2f$, + l2d$, + f2i$, + f2l$, + f2d$, + d2i$, + d2l$, + d2f$, + i2b$, + i2c$, + i2s$, + lcmp$, + fcmpl$, + fcmpg$, + dcmpl$, + dcmpg$, + ifeq$, + ifne$, + iflt$, + ifge$, + ifgt$, + ifle$, + if_icmpeq$, + if_icmpne$, + if_icmplt$, + if_icmpge$, + if_icmpgt$, + if_icmple$, + if_acmpeq$, + if_acmpne$, + goto$, + jsr$, + ret$, + tableswitch$, + lookupswitch$, + ireturn$, + lreturn$, + freturn$, + dreturn$, + areturn$, + return$, + getstatic$, + putstatic$, + getfield$, + putfield$, + invokevirtual$, + invokespecial$, + invokestatic$, + invokeinterface$, + xxxunusedxxx1$, + new$, + newarray$, + anewarray$, + arraylength$, + athrow$, + checkcast$, + instanceof$, + monitorenter$, + monitorexit$, + wide$, + multianewarray$, + ifnull$, + ifnonnull$, + goto_w$, + jsr_w$, + + break_stmt$ = 250 /* used internally by the parser to mark break statment positions */ +}; + diff --git a/MPC.3.5.LINUX/classgen/classgen.c b/MPC.3.5.LINUX/classgen/classgen.c new file mode 100644 index 0000000..32cf178 --- /dev/null +++ b/MPC.3.5.LINUX/classgen/classgen.c @@ -0,0 +1,645 @@ +/******************************************************************** + + classgen.c - methods for creating the .class binary file + + Niksa Orlic, 2004-05-16 + +********************************************************************/ + +//#include "../util/message.h" +#include "../util/error.h" +#include "../util/strings.h" +#include "../structures/type_list.h" +#include "../structures/string_list.h" +#include "../structures/type.h" +#include "../structures/identifier.h" +#include "../structures/name_table.h" +#include "../classgen/bytecode.h" +#include "../structures/block.h" +#include "../classgen/constant_pool.h" +#include "../classgen/preverify.h" +#include "../util/memory.h" + +#include +#include +#include + +#include "classgen.h" + +extern char* output_path; +extern int linenum; + +extern int detect_units_only; + +extern constant_pool *constants; +extern int constant_pool_size; + +//extern int usesFloat; +extern int mathType; + +char class_name[16]; + +/* + Creates a class file for pascal record. +*/ +void create_record_class(type *record) +{ + char class_file_name[16]; + char *output_file_name; + char copy_sig[64]; + + FILE *record_file; + + bytecode *init_method; + bytecode *copy_method; + + /* save the previous constant pool state */ + constant_pool *global_cp; + int global_cp_count; + + global_cp = constants; + global_cp_count = constant_pool_size; + + constants = NULL; + constant_pool_size = 0; + + /* check for consistency */ + if (record->type_class != record_type) + die(12); + + sprintf(class_name, "R_%d", record->unique_record_ID); + sprintf(class_file_name, "%s.class", class_name); + + if (!detect_units_only) + requires(3, class_file_name); + + output_file_name = (char*) mem_alloc(strlen(output_path) + + strlen(class_file_name) + 5); + if (output_file_name == NULL) + die (1); + + #ifdef WIN32 + sprintf(output_file_name, "%s\\%s", output_path, class_file_name); + #endif + #ifdef UNIX + sprintf(output_file_name, "%s/%s", output_path, class_file_name); + #endif + record_file = fopen(output_file_name, "wb"); + mem_free(output_file_name); + + if (record_file == NULL) + die(3); + + /* write the class file header */ + create_class_file_header(record_file); + + /* add some stuff into the constant pool */ + cp_add_class(class_name); + cp_add_class("java/lang/Object"); + cp_add_utf8(""); + cp_add_utf8("()V"); + cp_add_utf8("Code"); + cp_add_utf8("Copy"); + sprintf(copy_sig, "(LR_%d;)LR_%d;", record->unique_record_ID, record->unique_record_ID); + cp_add_utf8(copy_sig); + + create_record_fields(record); + + /* create the bytecode for the init method */ + init_method = bytecode_create(); + create_init_method(record, init_method); + + /* create the bytecode for the copy method */ + copy_method = bytecode_create(); + create_copy_method(record, copy_method); + + /* write the constant pool into the file */ + write_constant_pool(record_file); + + /* write the access flags, set to ACC_PUBLIC and ACC_SUPER */ + write_short_int(record_file, 0x0021); + + /* write the index to constat pool with this class description */ + write_short_int(record_file, cp_add_class(class_name)); + + /* write the index to constant pool with the super class description */ + write_short_int(record_file, cp_add_class("java/lang/Object")); + + /* we have no interfaces */ + write_short_int(record_file, 0); + + /* write the fields */ + write_short_int(record_file, (short) type_list_length(record->elements_type_list)); + write_record_fields(record_file, record); + + /* we have and Copy method */ + write_short_int(record_file, 2); + + /* write the init method */ + write_init_method(record_file, init_method); + + /* write the copy method */ + write_copy_method(record, record_file, copy_method); + + /* we have no attributes */ + write_short_int(record_file, 0); + + fclose(record_file); + + + /* restore the constant pool */ + constants = global_cp; + constant_pool_size = global_cp_count; +} + + +/* + Writes a class file header into the output file +*/ +void create_class_file_header(FILE *class_file) +{ + char magic[4] = { (char)0xCA, (char)0xFE, (char)0xBA, (char)0xBE }; + + fwrite(magic, 1, 4, class_file); + + /* Write the minor version number 3 */ + write_short_int(class_file, 0x0003); + + /* Wrte the major version number 45 */ + write_short_int(class_file, 0x002d); +} + + +/* + Creates entries into constant pool with names and types of + the elements of the structure. +*/ +void create_record_fields(type *record) +{ + string_list *names; + type_list *types; + char descriptor[128]; + + names = record->elements_name_list; + types = record->elements_type_list; + + while (names != NULL) + { + if (names->data != NULL) + { + lowercase(names->data->cstr); + get_field_descriptor(types->data, descriptor); + cp_add_nameandtype(names->data->cstr, descriptor); + } + + names = names->next; + types = types->next; + } +} + + +/* + Writes the fields from the record into the + class file. +*/ +void write_record_fields(FILE *class_file, type *record) +{ + string_list *names; + type_list *types; + char descriptor[128]; + int field_num = 0; + + names = record->elements_name_list; + types = record->elements_type_list; + + while (names != NULL) + { + if (names->data != NULL) + { + /* write the access flags: ACC_PUBLIC */ + write_short_int(class_file, 0x0001); + + /* write the name index */ + lowercase(names->data->cstr); + write_short_int(class_file, cp_add_utf8(names->data->cstr)); + + /* write the descriptor index */ + get_field_descriptor(types->data, descriptor); + write_short_int(class_file, cp_add_utf8(descriptor)); + + /* we have no attributes */ + write_short_int(class_file, 0); + } + + names = names->next; + types = types->next; + field_num ++; + } +} + + +/* + Writes a short int in bigendian format. If + class_file is NULL, does nothing. +*/ +void write_short_int(FILE *class_file, short int num) +{ + char ch; + + if (class_file == NULL) + return; + + ch = (char) (num >> 8); + fwrite(&ch, 1, 1, class_file); + + ch = (char) num; + fwrite(&ch, 1, 1, class_file); +} + +void write_long_int(FILE *class_file, long int num) +{ + char ch; + + if (class_file == NULL) + return; + + ch = (char) (num >> 24); + fwrite(&ch, 1, 1, class_file); + + ch = (char) (num >> 16); + fwrite(&ch, 1, 1, class_file); + + ch = (char) (num >> 8); + fwrite(&ch, 1, 1, class_file); + + ch = (char) num; + fwrite(&ch, 1, 1, class_file); + +} + +short int read_short_int(FILE *class_file) +{ + short int return_value = 0; + + return_value = fgetc(class_file) << 8; + return_value |= (fgetc(class_file) & 0x00FF); + + return return_value; +} + +long int read_long_int(FILE *class_file) +{ + long int return_value = 0; + + return_value = fgetc(class_file) << 24; + return_value |= (fgetc(class_file) & 0x00FF) << 16; + return_value |= (fgetc(class_file) & 0x00FF) << 8; + return_value |= (fgetc(class_file) & 0x00FF); + + return return_value; +} + +/* + Construct a valid Java field descriptor for a given type. +*/ +void get_field_descriptor(type *field_type, char *descriptor) +{ + switch (field_type->type_class) + { + case void_type: + sprintf(descriptor, "V"); + break; + + case integer_type: + case char_type: + case boolean_type: + sprintf(descriptor, "I"); + break; + + case real_type: + if (mathType == 1) + sprintf(descriptor, "I"); + else + sprintf(descriptor, "LReal;"); + break; + + case string_type: + sprintf(descriptor, "Ljava/lang/String;"); + break; + + case command_type: + sprintf(descriptor, "Ljavax/microedition/lcdui/Command;"); + break; + + case stream_type: + sprintf(descriptor, "Ljava/io/InputStream;"); + break; + + case record_store_type: + sprintf(descriptor, "Ljavax/microedition/rms/RecordStore;"); + break; + + case http_type: + sprintf(descriptor, "LH;"); + break; + + case alert_type: + sprintf(descriptor, "Ljavax/microedition/lcdui/AlertType;"); + break; + + case image_type: + sprintf(descriptor, "Ljavax/microedition/lcdui/Image;"); + break; + + case array_type: + { + char element_type[128]; + int i, len; + + get_field_descriptor(field_type->element_type, element_type); + + len = type_list_length(field_type->dimensions_list); + for(i=0; i < len; i++) + { + descriptor[i] = '['; + } + + descriptor[len] = '\0'; + + sprintf(descriptor + len, "%s", element_type); + } + break; + + case record_type: + sprintf(descriptor, "LR_%d;", field_type->unique_record_ID); + + break; + + case error_type: + break; + + default: + die(13); + } +} + +/* + Creates the method for records. +*/ +void create_init_method(type *record, bytecode *code) +{ + type_list *type_it; + string_list *name_it; + int counter = 0; + + if (code == NULL) + die(1); + + /* create the code */ + type_it = record->elements_type_list; + name_it = record->elements_name_list; + + bytecode_append(code, aload_0$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("java/lang/Object", "", "()V")); + + + while (type_it != NULL) + { + if ((type_it->data != NULL) && (name_it->data != NULL)) + { + block *code_wrapper; + identifier *type_wrapper; + + code_wrapper = block_create(NULL, string_create()); + code_wrapper->code = code; + + type_wrapper = identifier_create(); + type_wrapper->identifier_class = variable_name; + type_wrapper->variable_type = type_it->data; + type_wrapper->belongs_to_program_block = 1; + + /* put 'this' to the stack */ + bytecode_append(code, aload_0$); + + /* create the code to initialize the variable */ + initialize_variable(code_wrapper, type_wrapper, name_it->data->cstr, 0, class_name); + + if (type_it->data->type_class == array_type) + add_error_message(446, name_it->data->cstr, ""); + + code_wrapper->code = bytecode_create(); + block_destroy(code_wrapper); + + type_wrapper->variable_type = type_create(); + identifier_destroy(type_wrapper); + } + + type_it = type_it->next; + if (name_it != NULL) + name_it = name_it->next; + + counter ++; + } + + bytecode_append(code, return$); +} + +/* + Creates the Copy method for records. +*/ +void create_copy_method(type *record, bytecode *code) +{ + char type_name[64]; + + type_list *type_it; + string_list *name_it; + int counter = 0; + + if (code == NULL) + die(1); + + sprintf(type_name, "R_%d", record->unique_record_ID); + + /* create the code */ + type_it = record->elements_type_list; + name_it = record->elements_name_list; + + while (type_it != NULL) + { + if ((type_it->data != NULL) && (name_it->data != NULL)) + { + lowercase(name_it->data->cstr); + + if (type_it->data->type_class == record_type) + { + char copy_sig[64]; + char type_descriptor[128]; + get_field_descriptor(type_it->data, type_descriptor); + + sprintf(copy_sig, "(LR_%d;)LR_%d;", record->unique_record_ID, record->unique_record_ID); + + bytecode_append(code, aload_0$); + bytecode_append(code, getfield$); + bytecode_append_short_int(code, cp_add_fieldref(type_name, name_it->data->cstr, type_descriptor)); + + bytecode_append(code, aload_1$); + bytecode_append(code, getfield$); + bytecode_append_short_int(code, cp_add_fieldref(type_name, name_it->data->cstr, type_descriptor)); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref(type_name, "Copy", copy_sig)); + + } + else if (type_it->data->type_class == string_type) + { + bytecode_append(code, aload_0$); + + bytecode_append(code, aload_1$); + bytecode_append(code, getfield$); + bytecode_append_short_int(code, cp_add_fieldref(type_name, name_it->data->cstr, "Ljava/lang/String;")); + + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("java/lang/String")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("java/lang/String", "", "(Ljava/lang/String;)V")); + + bytecode_append(code, putfield$); + bytecode_append_short_int(code, cp_add_fieldref(type_name, name_it->data->cstr, "Ljava/lang/String;")); + } + else if ((type_it->data->type_class == real_type) && (mathType != 1)) + { + bytecode_append(code, aload_0$); + + bytecode_append(code, aload_1$); + bytecode_append(code, getfield$); + bytecode_append_short_int(code, cp_add_fieldref(type_name, name_it->data->cstr, "LReal;")); + + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(LReal;)V")); + + bytecode_append(code, putfield$); + bytecode_append_short_int(code, cp_add_fieldref(type_name, name_it->data->cstr, "LReal;")); + + } + else + { + char type_descriptor[128]; + get_field_descriptor(type_it->data, type_descriptor); + + bytecode_append(code, aload_0$); + bytecode_append(code, aload_1$); + + bytecode_append(code, getfield$); + bytecode_append_short_int(code, cp_add_fieldref(type_name, name_it->data->cstr, type_descriptor)); + + bytecode_append(code, putfield$); + bytecode_append_short_int(code, cp_add_fieldref(type_name, name_it->data->cstr, type_descriptor)); + } + } + + type_it = type_it->next; + if (name_it != NULL) + name_it = name_it->next; + + counter ++; + } + + // return this + bytecode_append(code, aload_0$); + bytecode_append(code, areturn$); +} + + +/* + Writes the method to the file. +*/ +void write_init_method(FILE *fp, bytecode *code) +{ + /* write the method headers */ + + /* write access flags, ACC_PUBLIC */ + write_short_int(fp, 0x0001); + + /* write method name '' */ + write_short_int(fp, cp_add_utf8("")); + + /* write method descriptor '()V' */ + write_short_int(fp, cp_add_utf8("()V")); + + /* write 1 attribute */ + write_short_int(fp, 1); + + /* write the Code attribute 'Code' */ + write_short_int(fp, cp_add_utf8("Code")); + write_long_int(fp, code->bytecode_pos + 12); + + /* write the max stack */ + write_short_int(fp, 10); + + /* max locals for program block */ + write_short_int(fp, 2); + + /* code length */ + write_long_int(fp, code->bytecode_pos); + + /* write the code itself */ + if (fp != NULL) + fwrite(code->bytecode, 1, code->bytecode_pos, fp); + + bytecode_destroy(code); + + write_short_int(fp, 0); + write_short_int(fp, 0); +} + +/* + Writes the Copy method to the file. +*/ +void write_copy_method(type* record, FILE *fp, bytecode *code) +{ + char method_sig[64]; + + /* write the method headers */ + + /* write access flags, ACC_PUBLIC */ + write_short_int(fp, 0x0001); + + /* write method name '' */ + write_short_int(fp, cp_add_utf8("Copy")); + + /* write method descriptor (record)record */ + sprintf(method_sig, "(LR_%d;)LR_%d;", record->unique_record_ID, record->unique_record_ID); + write_short_int(fp, cp_add_utf8(method_sig)); + + /* write 1 attribute */ + write_short_int(fp, 1); + + /* write the Code attribute 'Code' */ + write_short_int(fp, cp_add_utf8("Code")); + write_long_int(fp, code->bytecode_pos + 12); + + /* write the max stack */ + write_short_int(fp, 10); + + /* max locals for program block */ + write_short_int(fp, 2); + + /* code length */ + write_long_int(fp, code->bytecode_pos); + + /* write the code itself */ + if (fp != NULL) + fwrite(code->bytecode, 1, code->bytecode_pos, fp); + + bytecode_destroy(code); + + write_short_int(fp, 0); + write_short_int(fp, 0); +} diff --git a/MPC.3.5.LINUX/classgen/classgen.h b/MPC.3.5.LINUX/classgen/classgen.h new file mode 100644 index 0000000..f858abb --- /dev/null +++ b/MPC.3.5.LINUX/classgen/classgen.h @@ -0,0 +1,31 @@ +/******************************************************************** + + classgen.h - methods for creating the .class binary file + + Niksa Orlic, 2004-05-16 + +********************************************************************/ + + +void create_record_class(type *record_type); + +void create_class_file_header(FILE *class_file); +void write_record_constant_pool(FILE *class_file, type *record); +void create_record_fields(type *record); +void write_record_fields(FILE *class_file, type *record); +void write_constant_pool_class(FILE *class_file, char *class_name); +void write_constant_pool_utf8(FILE *class_file, char *string); +void write_constant_pool_fieldref(FILE *class_file, int type_index, int name_index); +void write_constant_pool_methodref(FILE *class_file, int, int, int); +void get_field_descriptor(type *field_type, char *descriptor); +void write_short_int(FILE *class_file, short int num); +void write_long_int(FILE *class_file, long int num); + +short int read_short_int(FILE *class_file); +long int read_long_int(FILE *class_file); + +void create_init_method(type *record, bytecode*); +void write_init_method(FILE *class_file, bytecode*); +void create_copy_method(type *record, bytecode*); +void write_copy_method(type* record, FILE *class_file, bytecode*); +void initialize_record_variable(bytecode *code, type *variable_type, int fieldref_index, int index); diff --git a/MPC.3.5.LINUX/classgen/constant_pool.c b/MPC.3.5.LINUX/classgen/constant_pool.c new file mode 100644 index 0000000..ee12f04 --- /dev/null +++ b/MPC.3.5.LINUX/classgen/constant_pool.c @@ -0,0 +1,449 @@ +/******************************************************************** + + constant_pool.c - methods for handling constant pool + + Niksa Orlic, 2004-06-11 + +********************************************************************/ + +#include +#include +#include + +#include "constant_pool.h" +//#include "../util/message.h" +#include "../util/error.h" +#include "../util/strings.h" +#include "../structures/type_list.h" +#include "../structures/string_list.h" +#include "../structures/type.h" +#include "../structures/identifier.h" +#include "../structures/name_table.h" +#include "../classgen/bytecode.h" +#include "../structures/block.h" +#include "../util/memory.h" + +#include "classgen.h" + +constant_pool *constants; +int constant_pool_size = 0; + +/* + Insert a utf8 string into the constant pool table and return its index in the table. +*/ +int cp_add_utf8(char *str) +{ + int i, j, len; + int size = 0; + constant_pool *entry; + + /* check if the string already exists in the table */ + for (i=0; itag = 1; + + /* calculate the needeed size for the string */ + len = strlen(str); + for (i=0; i 127) + size += 2; + else*/ + size ++; + } + + entry->data = (char*) mem_alloc(size + 1); + entry->data_len = size; + + if (entry->data == NULL) + die(1); + + for(i=0, j=0; idata[j] = str[i]; + j++; + /* } + else + { + entry->data[j] = (char)0xC2 | (str[i]>>7)&0x01; + j++; + entry->data[j] = (str[i] & 0x3F) | 0x80; + j++; + }*/ + } + + entry->data[j] = '\0'; + + return constant_pool_size; +} + +/* + Add a string entry into the constant pool. +*/ +int cp_add_string(char *str) +{ + int i; + constant_pool *entry; + + /* first add the utf8 constant */ + int utf8_const = cp_add_utf8(str); + + /* search if the same string already exists */ + for(i=0; itag = 8; + entry->param1 = utf8_const; + + return constant_pool_size; +} + +/* + Add an integer into the constant pool. +*/ +int cp_add_integer(int data) +{ + int i; + constant_pool *entry; + + /* check if the string already exists in the table */ + for (i=0; itag = 3; + entry->data = (char*) mem_alloc(sizeof(int)); + + if (entry->data == NULL) + die(1); + + *((int*)(entry->data)) = data; + + return constant_pool_size; +} + +/* + Add a long constant into the constant pool +*/ +int cp_add_long(long data) +{ + die(18); + + return constant_pool_size; +} + +/* + Add a float constant into the constant pool +*/ +int cp_add_double(double data) +{ + die(18); + + return constant_pool_size; +} + +/* + Add a double constant into the constant pool +*/ +int cp_add_float(float data) +{ + int i; + constant_pool *entry; + + /* check if the string already exists in the table */ + for (i=0; itag = 6; + entry->data = (char*) mem_alloc(sizeof(float)); + + if (entry->data == NULL) + die(1); + + *((float*)(entry->data)) = data; + + return constant_pool_size; +} + + +/* + Adds a class information into the constants pool +*/ +int cp_add_class(char *class_name) +{ + int i; + constant_pool *entry; + + /* first add the utf8 constant */ + int utf8_const = cp_add_utf8(class_name); + + /* search if the same string already exists */ + for(i=0; itag = 7; + entry->param1 = utf8_const; + + return constant_pool_size; +} + +/* + Add name and type entry into the constant pool +*/ +int cp_add_nameandtype(char *name, char *type) +{ + int i; + int name_index; + int type_index; + constant_pool *entry; + + /* first add the utf8 constant */ + name_index = cp_add_utf8(name); + type_index = cp_add_utf8(type); + + /* search if the same string already exists */ + for(i=0; itag = 12; + entry->param1 = name_index; + entry->param2 = type_index; + + return constant_pool_size; +} + +/* + Adds the fieldref entry into the constant pool +*/ +int cp_add_fieldref(char *class_name, char *name, char *type) +{ + int i; + int class_index; + int nameandtype_index; + constant_pool *entry; + + /* first add the utf8 constant */ + class_index = cp_add_class(class_name); + nameandtype_index = cp_add_nameandtype(name, type); + + /* search if the same string already exists */ + for(i=0; itag = 9; + entry->param1 = class_index; + entry->param2 = nameandtype_index; + + return constant_pool_size; +} + +/* + Add the fieldref entry into the constant pool +*/ +int cp_add_methodref(char *class_name, char *name, char *type) +{ + int i; + int class_index; + int nameandtype_index; + constant_pool *entry; + + /* first add the utf8 constant */ + class_index = cp_add_class(class_name); + nameandtype_index = cp_add_nameandtype(name, type); + + /* search if the same string already exists */ + for(i=0; itag = 10; + entry->param1 = class_index; + entry->param2 = nameandtype_index; + + return constant_pool_size; +} + +/* + Add the interface entry into the constant pool +*/ +int cp_add_interface(char *class_name, char *name, char *type) +{ + int i; + int class_index; + int nameandtype_index; + constant_pool *entry; + /* first add the utf8 constant */ + class_index = cp_add_class(class_name); + nameandtype_index = cp_add_nameandtype(name, type); + /* search if the same string already exists */ + for(i=0; itag = 11; + entry->param1 = class_index; + entry->param2 = nameandtype_index; + return constant_pool_size; +} + +/* + Creates a new entry in the constant pool. +*/ +constant_pool *cp_create_new_entry() +{ + constant_pool_size ++; + + if (constant_pool_size == 1) + constants = (constant_pool*) mem_alloc(sizeof(constant_pool)); + else + constants = (constant_pool*) mem_realloc(constants, + sizeof(constant_pool) * constant_pool_size); + + if (constants == NULL) + die(1); + + return &constants[constant_pool_size-1]; +} + +/* + Writes the constant pool to the disk +*/ +void write_constant_pool(FILE *fp) +{ + int i; + + /* write the constant pool count */ + write_short_int(fp, (short)(constant_pool_size + 1)); + + /* write the constant pool entries */ + for(i=0; i +#include +#include + + +//#include "../util/message.h" +#include "../util/error.h" +#include "../util/strings.h" +#include "../structures/type_list.h" +#include "../structures/string_list.h" +#include "../structures/type.h" +#include "../structures/identifier.h" +#include "../structures/name_table.h" +#include "constant_pool.h" +#include "bytecode.h" +#include "preverify.h" +#include "../util/error.h" +//#include "../util/message.h" +#include "../util/memory.h" + +extern constant_pool *constants; +extern int constant_pool_size; + +stack_map_list *pending_list; +stack_map_list *output_list; + + +stack_map_list *preverify_bytecode(bytecode *code, identifier *block_identifier) +{ + stack_map *map; + pending_list = NULL; + output_list = NULL; + + /* go through the bytecode */ + map = stack_map_create(); + map->bytecode_offset = 0; + preverify_bytecode_from(map, code, block_identifier); + stack_map_destroy(map); + + /* revisit the offsets in the pending list */ + while (pending_list != NULL) + { + map = stack_map_list_get(&pending_list); + if (map == NULL) + break; + + stack_map_list_append(&output_list, stack_map_duplicate(map)); + preverify_bytecode_from(map, code, block_identifier); + stack_map_destroy(map); + } + + output_list = sort_map_list(output_list); + + return output_list; +} + + +/* + Sorts the list according to offsets +*/ +stack_map_list* sort_map_list(stack_map_list *list) +{ + int range = 0; + + stack_map_list *it; + stack_map_list *sorted_list = NULL; + + /* repeat until the list is empty */ + while (list != NULL) + { + /* find the next smallest number */ + int smallest = 0x0fffffff; + + it = list; + while (it != NULL) + { + if ((it->data->bytecode_offset < smallest) + && (it->data->bytecode_offset >= range)) + smallest = it->data->bytecode_offset; + it = it->next; + } + + if (smallest == 0x0fffffff) + break; + + range = smallest + 1; + + /* extract the smallest number into the output list */ + it = list; + while (it != NULL) + { + if (it->data->bytecode_offset == smallest) + { + stack_map_list_append(&sorted_list, it->data); + + break; + } + it = it->next; + } + + } + + return sorted_list; +} + + +/* + Preverifies the bytecode starting with the given stackmap +*/ +void preverify_bytecode_from(stack_map *map, bytecode *code, identifier *block_identifier) +{ + int offset; + offset = map->bytecode_offset; + + while (preverify_consume_bytecode(code, map, &offset, block_identifier)) + { + /* do nothing */ + } +} + + +/* + Reads one bytecode and updates stack map. Returns 0 if + 'return' bytocode is found, or 1 otherwise. + + It seems that most of the jumps have nothing on the stack. The few + jumps that have something on the stack will only have integers. +*/ +int preverify_consume_bytecode(bytecode *code, stack_map *map, int *offset, identifier *block_identifier) +{ + unsigned char opcode = code->bytecode[*offset]; + switch ((unsigned char)(code->bytecode[*offset])) + { + case nop$: + (*offset) ++; + break; + + case aconst_null$: + (*offset) ++; + stack_map_push_entry(map, ITEM_Null, 0); + break; + + case iconst_m1$: + case iconst_0$: + case iconst_1$: + case iconst_2$: + case iconst_3$: + case iconst_4$: + case iconst_5$: + (*offset) ++; + stack_map_push_entry(map, ITEM_Integer, 0); + break; + + case lconst_0$: + case lconst_1$: + (*offset) ++; + stack_map_push_entry(map, ITEM_Long, 0); + break; + + case bipush$: + (*offset) += 2; + stack_map_push_entry(map, ITEM_Integer, 0); + break; + + case sipush$: + (*offset) += 3; + stack_map_push_entry(map, ITEM_Integer, 0); + break; + + case iload$: + (*offset) += 2; + stack_map_push_entry(map, ITEM_Integer, 0); + break; + + case lload$: + (*offset) += 2; + stack_map_push_entry(map, ITEM_Long, 0); + break; + + case iload_0$: + case iload_1$: + case iload_2$: + case iload_3$: + (*offset) ++; + stack_map_push_entry(map, ITEM_Integer, 0); + break; + + case lload_0$: + case lload_1$: + case lload_2$: + case lload_3$: + (*offset) ++; + stack_map_push_entry(map, ITEM_Long, 0); + break; + + case iaload$: + case baload$: + case caload$: + case saload$: + (*offset) ++; + stack_entry_destroy(stack_map_pop(map)); + stack_entry_destroy(stack_map_pop(map)); + stack_map_push_entry(map, ITEM_Integer, 0); + break; + + case laload$: + (*offset) ++; + stack_entry_destroy(stack_map_pop(map)); + stack_entry_destroy(stack_map_pop(map)); + stack_map_push_entry(map, ITEM_Long, 0); + break; + + case istore$: + case lstore$: + case astore$: + (*offset) += 2; + stack_entry_destroy(stack_map_pop(map)); + break; + + case istore_0$: + case istore_1$: + case istore_2$: + case istore_3$: + case lstore_0$: + case lstore_1$: + case lstore_2$: + case lstore_3$: + case astore_0$: + case astore_1$: + case astore_2$: + case astore_3$: + (*offset) ++; + stack_entry_destroy(stack_map_pop(map)); + break; + + case iastore$: + case lastore$: + case fastore$: + case dastore$: + case aastore$: + case bastore$: + case castore$: + case sastore$: + (*offset) ++; + stack_entry_destroy(stack_map_pop(map)); + stack_entry_destroy(stack_map_pop(map)); + stack_entry_destroy(stack_map_pop(map)); + break; + + case pop$: + (*offset) ++; + stack_entry_destroy(stack_map_pop(map)); + break; + + case pop2$: + (*offset) ++; + stack_entry_destroy(stack_map_pop(map)); + stack_entry_destroy(stack_map_pop(map)); + break; + + case dup$: + { + stack_entry *entry; + (*offset) ++; + entry = stack_map_pop(map); + stack_map_push(map, entry); + stack_map_push(map, entry); + stack_entry_destroy(entry); + } + break; + + case dup_x1$: + case dup_x2$: + { + stack_entry *e1, *e2; + (*offset) ++; + e1 = stack_map_pop(map); + e2 = stack_map_pop(map); + stack_map_push(map, e1); + stack_map_push(map, e2); + stack_map_push(map, e1); + stack_entry_destroy(e1); + stack_entry_destroy(e2); + } + break; + + case dup2_x1$: + { + stack_entry *e1, *e2, *e3; + (*offset) ++; + e1 = stack_map_pop(map); + e2 = stack_map_pop(map); + e3 = stack_map_pop(map); + stack_map_push(map, e2); + stack_map_push(map, e1); + stack_map_push(map, e3); + stack_map_push(map, e2); + stack_map_push(map, e1); + stack_entry_destroy(e1); + stack_entry_destroy(e2); + stack_entry_destroy(e3); + } + break; + + case swap$: + { + stack_entry *e1, *e2; + (*offset) ++; + e1 = stack_map_pop(map); + e2 = stack_map_pop(map); + stack_map_push(map, e1); + stack_map_push(map, e2); + stack_entry_destroy(e1); + stack_entry_destroy(e2); + } + break; + + case iadd$: + case ladd$: + case fadd$: + case dadd$: + case isub$: + case lsub$: + case fsub$: + case dsub$: + case imul$: + case lmul$: + case fmul$: + case dmul$: + case idiv$: + case ldiv$: + case fdiv$: + case ddiv$: + case irem$: + case lrem$: + case frem$: + case drem$: + case iand$: + case land$: + case ior$: + case lor$: + case ixor$: + case lxor$: + (*offset) ++; + stack_entry_destroy(stack_map_pop(map)); + break; + + case ineg$: + case lneg$: + case fneg$: + case dneg$: + case i2b$: + case i2c$: + case i2s$: + (*offset) ++; + break; + + case ishl$: + case lshl$: + case ishr$: + case lshr$: + case iushr$: + case lushr$: + (*offset) ++; + stack_entry_destroy(stack_map_pop(map)); + break; + + case iinc$: + (*offset) += 3; + break; + + case i2l$: + (*offset) ++; + stack_entry_destroy(stack_map_pop(map)); + stack_map_push_entry(map, ITEM_Long, 0); + break; + + case l2i$: + (*offset) ++; + stack_entry_destroy(stack_map_pop(map)); + stack_map_push_entry(map, ITEM_Integer, 0); + break; + + case lcmp$: + case fcmpl$: + case fcmpg$: + case dcmpl$: + case dcmpg$: + (*offset) ++; + stack_entry_destroy(stack_map_pop(map)); + stack_entry_destroy(stack_map_pop(map)); + stack_map_push_entry(map, ITEM_Integer, 0); + break; + + case ifeq$: + case ifne$: + case iflt$: + case ifge$: + case ifgt$: + case ifle$: + (*offset) ++; + stack_entry_destroy(stack_map_pop(map)); + process_jump(map, *offset - 1 + (int)((code->bytecode[*offset] << 8) | (unsigned char)(code->bytecode[(*offset) + 1]))); + (*offset) ++; + (*offset) ++; + break; + + case if_icmpeq$: + case if_icmpne$: + case if_icmplt$: + case if_icmpge$: + case if_icmpgt$: + case if_icmple$: + case if_acmpeq$: + case if_acmpne$: + (*offset) ++; + stack_entry_destroy(stack_map_pop(map)); + stack_entry_destroy(stack_map_pop(map)); + process_jump(map, *offset - 1 + (int)((code->bytecode[*offset] << 8) | (unsigned char)(code->bytecode[(*offset) + 1]))); + (*offset) ++; + (*offset) ++; + break; + + case goto$: + { + (*offset) ++; + process_jump(map, *offset - 1 + (int)((code->bytecode[*offset] << 8) | (unsigned char)(code->bytecode[(*offset) + 1]))); + return 0; + } + break; + + case ireturn$: + case lreturn$: + case freturn$: + case dreturn$: + case areturn$: + stack_entry_destroy(stack_map_pop(map)); + case return$: + return 0; + + case aload$: + (*offset) += 2; + stack_map_push_local(map, block_identifier, (unsigned char) code->bytecode[*offset-1]); + break; + + case aload_0$: + (*offset) ++; + stack_map_push_local(map, block_identifier, 0); + break; + + case aload_1$: + (*offset) ++; + stack_map_push_local(map, block_identifier, 1); + break; + + case aload_2$: + (*offset) ++; + stack_map_push_local(map, block_identifier, 2); + break; + + case aload_3$: + (*offset) ++; + stack_map_push_local(map, block_identifier, 3); + break; + + case aaload$: + { + char object_class[128]; + stack_entry* entry; + int classname_index; + int delta = 1; + + (*offset) ++; + stack_entry_destroy(stack_map_pop(map)); + + entry = stack_map_pop(map); + classname_index = constants[entry->additional_data - 1].param1 - 1; + strncpy(object_class, constants[classname_index].data, constants[classname_index].data_len); + object_class[constants[classname_index].data_len] = '\0'; + + if (object_class[1] == 'L') + { + delta = 2; + object_class[strlen(object_class) - 1] = '\0'; + } + stack_entry_destroy(entry); + stack_map_push_entry(map, ITEM_Object, cp_add_class(object_class + delta)); + } + break; + + case tableswitch$: + case lookupswitch$: + // TODO:: + break; + + case instanceof$: + (*offset) += 3; + stack_entry_destroy(stack_map_pop(map)); + stack_map_push_entry(map, ITEM_Integer, 0); + break; + + case ldc$: + (*offset) ++; + (*offset) ++; + stack_map_push_entry(map, ITEM_Bogus, 0); + break; + + case ldc_w$: + (*offset) += 3; + stack_map_push_entry(map, ITEM_Bogus, 0); + break; + + case getstatic$: + { + int t; + (*offset) ++; + t = code->bytecode[*offset]; + t = t << 8 | (unsigned char)(code->bytecode[(*offset) + 1]); + t = constants[t-1].param2; + t = constants[t-1].param2; + (*offset) += 2; + switch(constants[t-1].data[0]) + { + case 'L': + case '[': + { + char *class_name = (char*) mem_alloc(sizeof(char) * strlen(constants[t-1].data)); + strcpy(class_name, constants[t-1].data + 1); + class_name[strlen(constants[t-1].data) - 2] = '\0'; + stack_map_push_entry(map, ITEM_Object, cp_add_class(class_name)); + mem_free(class_name); + break; + } + // case '[': + // stack_map_push_entry(map, ITEM_Object, t); + // break; + case 'I': + stack_map_push_entry(map, ITEM_Integer, 0); + break; + default: + stack_map_push_entry(map, ITEM_Bogus, 0); + + } + } + break; + + case new$: + (*offset) += 3; + stack_map_push_entry(map, ITEM_Bogus, 0); + break; + + case getfield$: + (*offset) += 3; + break; + + case putstatic$: + (*offset) += 3; + stack_entry_destroy(stack_map_pop(map)); + break; + + case putfield$: + (*offset) += 3; + stack_entry_destroy(stack_map_pop(map)); + stack_entry_destroy(stack_map_pop(map)); + break; + + case invokevirtual$: + case invokespecial$: + case invokestatic$: + { + unsigned short int num; + int len, i = 0; + int oldstate, state = 0; + int count = 0; + int isVoid = 0; + char *descriptor; + char *class_name; + int state_machine_table[4][6] = + { /* ( ) L ; V else */ + /* 0 */ { 1, -1, -1, -1, -1, -1 }, + /* 1 */ {-1, 2, 3, -1, 1, 1 }, + /* 2 */ {-1, -1, -1, -1, -1, -1 }, + /* 3 */ { 3, 3, 3, 1, 3, 3 } + }; + + (*offset) ++; + num = (code->bytecode[*offset] << 8) | (unsigned char)(code->bytecode[(*offset) + 1]); + (*offset) += 2; + + num = constants[num-1].param2; + num = constants[num-1].param2; + len = constants[num-1].data_len; + descriptor = constants[num-1].data; + + while (i < len) + { + oldstate = state; + + switch (descriptor[i]) + { + case '(': state = state_machine_table[state][0]; break; + case ')': state = state_machine_table[state][1]; break; + case 'L': state = state_machine_table[state][2]; break; + case ';': state = state_machine_table[state][3]; break; + case 'V': state = state_machine_table[state][4]; break; + default : state = state_machine_table[state][5]; break; + } + i ++; + + if ((state == 1) && (oldstate != 0)) + count ++; + + if (state == 2) + { + if (descriptor[i] == 'V') + isVoid = 1; + + class_name = (char*) mem_alloc(len); + + strcpy(class_name, descriptor + i); + + break; + } + } + + if (opcode != invokestatic$) + stack_entry_destroy(stack_map_pop(map)); + while (count > 0) + { + stack_entry_destroy(stack_map_pop(map)); + count --; + } + + if (class_name[0] == 'L') + { + class_name[strlen(class_name) - 1] = '\0'; + if (!isVoid) + stack_map_push_entry(map, ITEM_Object, cp_add_class(class_name+1)); + } + else if (class_name[0] == 'I') + { + if (!isVoid) + stack_map_push_entry(map, ITEM_Integer,0); + } + else + { + if (!isVoid) + stack_map_push_entry(map, ITEM_Bogus, 0); + + } + + mem_free(class_name); + } + break; + + + /*case invokestatic$: + { + unsigned short int num; + int len, i = 0; + int oldstate, state = 0; + int count = 0; + int isVoid = 0; + char *descriptor; + int state_machine_table[4][6] = + { /* ( ) L ; V else + /* 0 { 1, -1, -1, -1, -1, -1 }, + /* 1 {-1, 2, 3, -1, 1, 1 }, + /* 2 {-1, -1, -1, -1, -1, -1 }, + /* 3 { 3, 3, 3, 1, 3, 3 } + }; + + (*offset) ++; + num = (code->bytecode[*offset] << 8) | (unsigned char)(code->bytecode[(*offset) + 1]); + (*offset) += 2; + + num = constants[num-1].param2; + num = constants[num-1].param2; + len = constants[num-1].data_len; + descriptor = constants[num-1].data; + + while (i < len) + { + oldstate = state; + + switch (descriptor[i]) + { + case '(': state = state_machine_table[state][0]; break; + case ')': state = state_machine_table[state][1]; break; + case 'L': state = state_machine_table[state][2]; break; + case ';': state = state_machine_table[state][3]; break; + case 'V': state = state_machine_table[state][4]; break; + default : state = state_machine_table[state][5]; break; + } + i ++; + + if ((state == 1) && (oldstate != 0)) + count ++; + + if (state == 2) + { + if (descriptor[i] == 'V') + isVoid = 1; + + break; + } + } + + while (count > 0) + { + stack_entry_destroy(stack_map_pop(map)); + count --; + } + + if (!isVoid) + stack_map_push_entry(map, ITEM_Bogus, 0); + } + break;*/ + + + case newarray$: + (*offset) += 2; + break; + + case anewarray$: + (*offset) += 3; + break; + + case arraylength$: + (*offset) ++; + stack_entry_destroy(stack_map_pop(map)); + stack_map_push_entry(map, ITEM_Integer, 0); + break; + + case multianewarray$: + { + unsigned int i, t, s; + (*offset) ++; + t = code->bytecode[*offset]; + t = t << 8 | (unsigned char)(code->bytecode[(*offset) + 1]); + (*offset) += 2; + i = code->bytecode[*offset]; + (*offset) ++; + + s = i; + while (i>0) + { + stack_entry_destroy(stack_map_pop(map)); + i --; + } + + stack_map_push_entry(map, ITEM_NewObject, *offset - 4); + break; + } + + case ifnull$: + case ifnonnull$: + stack_entry_destroy(stack_map_pop(map)); + (*offset) ++; + process_jump(map, *offset - 1 + (int)((code->bytecode[*offset] << 8) | (unsigned char)(code->bytecode[(*offset) + 1]))); + (*offset) ++; + (*offset) ++; + break; + + default: + die(22); + + } + + return 1; +} + + +/* + When a branch instruction is found, adds the target offset into the list. +*/ +void process_jump(stack_map *map, int position) +{ + stack_map *new_map; + + /* check if the position is already in the pending or output list */ + stack_map_list *it; + it = pending_list; + + while (it != NULL) + { + if (it->data->bytecode_offset == position) + return; + it = it->next; + } + + it = output_list; + + while (it != NULL) + { + if (it->data->bytecode_offset == position) + return; + it = it->next; + } + + /* if here, add the offset into the pendign list */ + new_map = stack_map_duplicate(map); + new_map->bytecode_offset = position; + stack_map_list_append(&pending_list, new_map); +} + + +/* + Create anew stack_entry object. +*/ +stack_entry* stack_entry_create() +{ + stack_entry *new_entry = (stack_entry*) mem_alloc(sizeof(stack_entry)); + + if (new_entry == NULL) + die(1); + + return new_entry; +} + + +/* + Delete all data used by stack_entry +*/ +void stack_entry_destroy(stack_entry *entry) +{ + mem_free(entry); +} + + +/* + Create a copy of the stack entry. +*/ +stack_entry* stack_entry_duplicate(stack_entry *old_entry) +{ + stack_entry* new_entry = (stack_entry*) mem_alloc(sizeof(stack_entry)); + + if (new_entry == NULL) + die(1); + + new_entry->item_type = old_entry->item_type; + new_entry->additional_data = old_entry->additional_data; + + return new_entry; +} + + +/* + Create a stackmap object +*/ +stack_map* stack_map_create() +{ + stack_map *new_map = (stack_map*) mem_alloc(sizeof(stack_map)); + + if (new_map == NULL) + die(1); + + new_map->allocated_number_of_items = 0; + new_map->number_of_items = 0; + + return new_map; +} + + +/* + Destroy the stack map +*/ +void stack_map_destroy(stack_map *map) +{ + int i; + for (i=0; inumber_of_items; i++) + { + stack_entry_destroy(map->stack[i]); + } + + if (map->allocated_number_of_items > 0) + mem_free(map->stack); + + mem_free(map); +} + + +/* + Create a copy of the map +*/ +stack_map* stack_map_duplicate(stack_map *old_map) +{ + int i; + + stack_map *new_map = (stack_map*) mem_alloc(sizeof(stack_map)); + + if (new_map == NULL) + die(1); + + new_map->number_of_items = old_map->number_of_items; + new_map->allocated_number_of_items = old_map->allocated_number_of_items; + new_map->bytecode_offset = old_map->bytecode_offset; + + if (old_map->allocated_number_of_items > 0) + { + new_map->stack = (stack_entry**) mem_alloc(sizeof(stack_entry) * old_map->allocated_number_of_items); + + if (new_map->stack == NULL) + die(1); + } + + for (i=0; inumber_of_items; i++) + new_map->stack[i] = stack_entry_duplicate(old_map->stack[i]); + + return new_map; +} + + +/* + Take the top element from the stack +*/ +stack_entry* stack_map_pop(stack_map* map) +{ + stack_entry* top_element; + + top_element = map->stack[map->number_of_items - 1]; + + map->number_of_items --; + + return top_element; +} + + +/* + Add a new element to the top of the stack +*/ +void stack_map_push(stack_map *map, stack_entry *entry) +{ + stack_map_push_entry(map, entry->item_type, entry->additional_data); +} + + +/* + Add a new element to the top of the stack. +*/ +void stack_map_push_entry(stack_map *map, enum stack_item item_type, short int additional_data) +{ + stack_entry *new_entry = stack_entry_create(); + new_entry->item_type = item_type; + new_entry->additional_data = additional_data; + + /* + Do realloc or malloc if needeed + */ + if (map->allocated_number_of_items <= map->number_of_items) + { + if (map->allocated_number_of_items == 0) + { + map->stack = (stack_entry**) mem_alloc(sizeof(stack_entry*)); + + if (map->stack == NULL) + die(1); + + map->allocated_number_of_items = 1; + } + else + { + map->stack = (stack_entry**) mem_realloc(map->stack, sizeof(stack_entry*) * (map->allocated_number_of_items + 1)); + + if (map->stack == NULL) + die(1); + + map->allocated_number_of_items ++; + } + } + + map->number_of_items ++; + map->stack[map->number_of_items - 1] = new_entry; +} + +void stack_map_list_destroy(stack_map_list*); + +/* + Push a local variable, determine its type +*/ +void stack_map_push_local(stack_map *map, identifier *block_identifier, int localNum) +{ + type *variable_type = NULL; + char descriptor[256]; + type_list *it; + int i = 0; + + if (block_identifier == NULL) + { + /* if block is the root block, this should never happen */ + stack_map_push_entry(map, ITEM_Bogus, 0); + return; + } + + it = block_identifier->parameters; + while (it != NULL) + { + if (it->data == NULL) + break; + + if (i == localNum) + { + variable_type = type_duplicate(it->data); + break; + } + i ++; + it = it->next; + } + + + if ((block_identifier->identifier_class == function_name) + && (variable_type == NULL)) + { + if (i == localNum) + variable_type = type_duplicate(block_identifier->return_type); + i ++; + } + + it = block_identifier->variables; + while ((it != NULL) && (variable_type == NULL)) + { + if (it->data == NULL) + break; + + if (i == localNum) + { + variable_type = type_duplicate(it->data); + break; + } + i ++; + it = it->next; + } + + switch (variable_type->type_class) + { + case integer_type: + case real_type: + case char_type: + case boolean_type: + stack_map_push_entry(map, ITEM_Integer, 0); + break; + + case array_type: + get_field_descriptor(variable_type, descriptor); + stack_map_push_entry(map, ITEM_Object, cp_add_class(descriptor)); + break; + + default: + get_field_descriptor(variable_type, descriptor); + descriptor[strlen(descriptor)-1] = '\0'; + stack_map_push_entry(map, ITEM_Object, cp_add_class(descriptor+1)); + break; + } + + type_destroy(variable_type); + +} + +/* + Append data to the end of the list +*/ +void stack_map_list_append(stack_map_list **list, stack_map* data) +{ + stack_map_list *it; + + if (*list == NULL) + { + *list = (stack_map_list*)mem_alloc(sizeof(stack_map_list)); + if (*list == NULL) + die(1); + + (*list)->data = data; + (*list)->next = NULL; + return; + } + + it = *list; + + while (it->next != NULL) + it = it->next; + + it->next = (stack_map_list*) mem_alloc(sizeof(stack_map_list)); + + if (it->next == NULL) + die(1); + + it->next->data = data; + it->next->next = NULL; + + +} + + +/* + Get the first element from the list +*/ +stack_map* stack_map_list_get(stack_map_list **list) +{ + stack_map_list *next; + stack_map *data; + + if (*list == NULL) + return NULL; + + next = (*list)->next; + data = (*list)->data; + + *list = next; + + return data; +} \ No newline at end of file diff --git a/MPC.3.5.LINUX/classgen/preverify.h b/MPC.3.5.LINUX/classgen/preverify.h new file mode 100644 index 0000000..a92d9fb --- /dev/null +++ b/MPC.3.5.LINUX/classgen/preverify.h @@ -0,0 +1,79 @@ +/******************************************************************** + + preverify.h - methods and structures for bytecode preverification + + Niksa Orlic, 2004-08-18 + +********************************************************************/ + + +/*** Preverifier structures ***/ +enum stack_item +{ + ITEM_Bogus = 0, + ITEM_Integer, + ITEM_Float, + ITEM_Double, + ITEM_Long, + ITEM_Null, + ITEM_InitObject, + ITEM_Object, + ITEM_NewObject +}; + +struct stack_entry_struct +{ + enum stack_item item_type; + short int additional_data; +}; + +typedef struct stack_entry_struct stack_entry; + +struct stack_map_struct +{ + int number_of_items; + int allocated_number_of_items; + stack_entry **stack; + int bytecode_offset; +}; + +typedef struct stack_map_struct stack_map; + + + +stack_entry* stack_entry_create(); +void stack_entry_destroy(stack_entry*); +stack_entry* stack_entry_duplicate(stack_entry*); + +stack_map* stack_map_create(); +void stack_map_destroy(stack_map*); +stack_map* stack_map_duplicate(stack_map*); + +stack_entry* stack_map_pop(stack_map*); +void stack_map_push(stack_map*, stack_entry*); +void stack_map_push_entry(stack_map*, enum stack_item, short int); +void stack_map_push_local(stack_map*, identifier*, int); + + +struct stack_map_list_struct +{ + struct stack_map_list_struct *next; + stack_map *data; +}; + +typedef struct stack_map_list_struct stack_map_list; + +void stack_map_list_destroy(stack_map_list*); + +void stack_map_list_append(stack_map_list**, stack_map*); +stack_map* stack_map_list_get(stack_map_list**); + + +/*** Preverifier methods ***/ +stack_map_list *preverify_bytecode(bytecode*, identifier *); +int preverify_consume_bytecode(bytecode*, stack_map*, int *offset, identifier*); +void process_jump(stack_map *map, int position); +void preverify_bytecode_from(stack_map*, bytecode*, identifier*); +stack_map_list* sort_map_list(stack_map_list*); + + diff --git a/MPC.3.5.LINUX/lex/lex.yy.c b/MPC.3.5.LINUX/lex/lex.yy.c new file mode 100644 index 0000000..4845c34 --- /dev/null +++ b/MPC.3.5.LINUX/lex/lex.yy.c @@ -0,0 +1,560 @@ +#include +#include +#include +#include "tokens.h" +#include "../util/strings.h" +#include "../util/error.h" + +extern int mathType; +extern int goverify; +char charbuf[10240]; +char textbuf[10240]; +char strconst[10240]; +int charcount; +FILE *yyin; //, *yyout; //source file +char *yytext; //current token string +string *string_constant; +char char_constant; +char boolean_constant; +float real_constant; +long int integer_constant; +int linenum; +int fileSize; +char c; + +void yyrestart(char *fname) { //FILE *new_file){ //open source file + yyin = fopen(fname, "r"); + if (yyin == NULL) die(5); + fseek(yyin, 0, SEEK_END); + fileSize = ftell(yyin); + fseek(yyin, 0, SEEK_SET); + charcount=0; + string_constant=&strconst; + yytext=&textbuf; + linenum=1; +}; + +char nextchar(){ + int d; + if (charcount>0){ + charcount--; + return charbuf[charcount]; + } + d=fgetc(yyin); + if (d==10) linenum++; + if (d==EOF) return '\255'; + return d; +} + +void backchar(int c){ //put the char back to stream + charbuf[charcount]=c; + charcount++; +}; + + +int yylex(){ //get token + int i,ncount,r; + char *p; + i = ftell(yyin); + compile_progress(i * 100 / fileSize); + do { + r=0; +//lab: + //if (linenum==1059) { + // linenum=1059; + //} + p=yytext; + *p='\0'; + c=nextchar(); + while ((c<=' ')&&(c!='\255')) c=nextchar(); + if (((c>='A') && (c<='Z')) || ((c>='a') && (c<='z')) || (c=='_')) { + while (((c>='A') && (c<='Z')) || ((c>='a') && (c<='z')) || ((c>='0') && (c<='9')) || (c=='_')) { + *p=c; + p=p+1; + c=nextchar(); + } + backchar(c); + *p='\0'; + lowercase(yytext); + if (strcmp(yytext, "begin") == 0) return KWD_BEGIN; + if (strcmp(yytext, "end") == 0) return KWD_END; + if (strcmp(yytext, "and") == 0) return OP_AND; + if (strcmp(yytext, "program") == 0) return KWD_PROGRAM; + if (strcmp(yytext, "procedure") == 0) return KWD_PROCEDURE; + if (strcmp(yytext, "function") == 0) return KWD_FUNCTION; + if (strcmp(yytext, "var") == 0) return KWD_VAR; + if (strcmp(yytext, "for") == 0) return KWD_FOR; + if (strcmp(yytext, "to") == 0) return KWD_TO; + if (strcmp(yytext, "downto") == 0) return KWD_DOWNTO; + if (strcmp(yytext, "do") == 0) return KWD_DO; + if (strcmp(yytext, "const") == 0) return KWD_CONST; + if (strcmp(yytext, "type") == 0) return KWD_TYPE; + if (strcmp(yytext, "if") == 0) return KWD_IF; + if (strcmp(yytext, "then") == 0) return KWD_THEN; + if (strcmp(yytext, "else") == 0) return KWD_ELSE; + if (strcmp(yytext, "case") == 0) return KWD_CASE; + if (strcmp(yytext, "of") == 0) return KWD_OF; + if (strcmp(yytext, "while") == 0) return KWD_WHILE; + if (strcmp(yytext, "repeat") == 0) return KWD_REPEAT; + if (strcmp(yytext, "until") == 0) return KWD_UNTIL; + if (strcmp(yytext, "forever") == 0) return KWD_FOREVER; + if (strcmp(yytext, "with") == 0) return KWD_WITH; + if (strcmp(yytext, "packed") == 0) return KWD_PACKED; + if (strcmp(yytext, "array") == 0) return KWD_ARRAY; + if (strcmp(yytext, "or") == 0) return OP_OR; + if (strcmp(yytext, "file") == 0) return KWD_FILE; + if (strcmp(yytext, "set") == 0) return KWD_SET; + if (strcmp(yytext, "record") == 0) return KWD_RECORD; + if (strcmp(yytext, "in") == 0) return OP_IN; + if (strcmp(yytext, "not") == 0) return OP_NOT; + if (strcmp(yytext, "xor") == 0) return OP_XOR; + if (strcmp(yytext, "forward") == 0) return KWD_FORWARD; + if (strcmp(yytext, "break") == 0) return KWD_BREAK; + if (strcmp(yytext, "uses") == 0) return KWD_USES; + if (strcmp(yytext, "unit") == 0) return KWD_UNIT; + if (strcmp(yytext, "interface") == 0) return KWD_INTERFACE; + if (strcmp(yytext, "implementation") == 0) return KWD_IMPLEMENTATION; + if (strcmp(yytext, "initialization") == 0) return KWD_INITIALIZATION; + if (strcmp(yytext, "finalization") == 0) return KWD_FINALIZATION; + if (strcmp(yytext, "mod") == 0) return OP_MOD; + if (strcmp(yytext, "div") == 0) return OP_DIV; + if (strcmp(yytext, "shr") == 0) return OP_SHR; //*** + if (strcmp(yytext, "shl") == 0) return OP_SHL; //*** + if (strcmp(yytext, "ushr") == 0) return OP_USHR; // j-a-s-d + if (strcmp(yytext, "inline") == 0) return KWD_INLINE; //***? + if (strcmp(yytext, "bytecode") == 0) return KWD_BYTECODE; // j-a-s-d + if (strcmp(yytext, "exit") == 0) return KWD_EXIT; // j-a-s-d + if (strcmp(yytext, "result") == 0) return KWD_RESULT; // j-a-s-d + ////// + if (strcmp(yytext, "true") == 0) {boolean_constant=1; return CST_BOOLEAN;} + if (strcmp(yytext, "false") == 0) {boolean_constant=0; return CST_BOOLEAN;} + ////// + return IDENTIFIER; + } else if ((c>='0') && (c<='9')) { + integer_constant=0; + while ((c>='0') && (c<='9')) { + integer_constant=integer_constant*10+c-48; + c=nextchar(); + } + if (c!='.') {backchar(c); return CST_INTEGER;} + c=nextchar(); + if (c=='.') {backchar(c);backchar(c);return CST_INTEGER;} + real_constant=(float)integer_constant; + ncount=1; + integer_constant=0; + while ((c>='0') && (c<='9')) { + integer_constant=integer_constant*10+c-48; + ncount++; + c=nextchar(); + } + //real_constant=real_constant+(float)integer_constant/(10*ncount); + // j-a-s-d: little but important bugfix, it was corrupting the decimal part + real_constant+=(float)integer_constant/pow(10,--ncount); + /* + i=1; + j=0; + ncount=1; + real_constant=(float)integer_constant; + while (((c>='0') && (c<='9'))) { + j=j*10+c-48; + i++; + c=nextchar(); + } + real_constant=real_constant+(j/(10*i)); + */ + backchar(c); + return CST_REAL; + } else if (c=='$') { + int ok; + integer_constant=0; + do { + c=nextchar(); + ok=0; + if ((c>='0') && (c<='9')) { + integer_constant = integer_constant*16+c-48; + ok=1; + } + if ((c>='A') && (c<='Z')) { + integer_constant = integer_constant*16+10+c-65; + ok=1; + } + if ((c>='a') && (c<='z')) { + integer_constant = integer_constant*16+10+c-97; + ok=1; + } + } while (ok==1); + backchar(c); + return CST_INTEGER; + } else if (c=='/') { + c=nextchar(); + if (c=='*') { // j-a-s-d: C-style /* */ multiline comments support + char ch=c; + while (!((c=='/')&&(ch=='*'))) {ch=c; c=nextchar();} + r=1; + } else + if (c=='/') { + while (c!=10) c=nextchar(); + //goto lab; + r=1; + } else { + backchar(c); + return OP_SLASH; + } + } else if ((c=='\'')||(c=='\"')||(c=='#')) { // j-a-s-d: C-style double-quoted strings support + char o_c = c; + i=0; + do { + if (c=='#') { + c=nextchar(); + integer_constant=0; + if (c=='$') { + int ok; + do { + c=nextchar(); + ok=0; + if ((c>='0') && (c<='9')) { + integer_constant = integer_constant*16+c-48; + ok=1; + } + if ((c>='A') && (c<='Z')) { + integer_constant = integer_constant*16+10+c-65; + ok=1; + } + if ((c>='a') && (c<='z')) { + integer_constant = integer_constant*16+10+c-97; + ok=1; + } + } while (ok==1); + } else { + while (((c>='0') && (c<='9'))) { + integer_constant=integer_constant*10+c-48; + c=nextchar(); + } + } + *p=(char)integer_constant; + p=p+1; + i=i+1; + } else { + c=nextchar(); + while (c!=o_c) { + if (c==10) { + int current_token; + add_error_message(101, "", ""); + do { + current_token = yylex(); + } while ((current_token != END_OF_INPUT) && (current_token != SEMI_COLON)); + break; + } +rep: *p=c; + p=p+1; + i++; + c=nextchar(); + } + c=nextchar(); + if (c==o_c) goto rep; + } + } while ((c==o_c)||(c=='#')); + *p='\0'; + backchar(c); + if (i==1) {p=p-1; char_constant=*p; return CST_CHAR;} + string_constant=string_from_cstr(yytext); + return CST_STRING; + } else if (c=='+') { + return OP_PLUS; + } else if (c=='-') { + return OP_MINUS; + } else if (c=='*') { + return OP_MULT; + } else if (c=='=') { + return OP_EQUAL; + } else if (c==';') { + return SEMI_COLON; + } else if (c==':') { + c=nextchar(); + if (c=='=') return OP_ASSIGN; + backchar(c); + return COLON; + } else if (c=='<') { + c=nextchar(); + if (c=='=') return OP_LESS_EQUAL; + if (c=='>') return OP_NOT_EQUAL; + if (c=='<') return OP_SHL; + backchar(c); + return OP_LESS; + } else if (c=='>') { + c=nextchar(); + if (c=='=') return OP_GREATER_EQUAL; + if (c=='>') { + c=nextchar(); + if (c=='>') return OP_USHR; + backchar(c); + return OP_SHR; + } + backchar(c); + return OP_GREATER; + } else if (c=='.') { + c=nextchar(); + if (c=='.') return DOTDOT; + backchar(c); + return DOT; + } else if (c=='[') { + return OPEN_SQ_BR; + } else if (c==']') { + return CLOSE_SQ_BR; + } else if (c=='(') { + char ch; + c=nextchar(); + if (c!='*') { + backchar(c); + return OPEN_BR; + } + ch=c; + while (!((c==')')&&(ch=='*'))) {ch=c; c=nextchar();} + //goto lab; + r=1; + } else if (c==')') { + return CLOSE_BR; + } else if (c==',') { + return COMMA; + } else if (c=='{') { //skip comment + c=nextchar(); + // j-a-s-d: removing $R and $V to avoid ambiguities + /* + if (c=='$') { + c=nextchar(); + if (c=='R') { //real type switch + c=nextchar(); + if (c=='-') mathType=1; + if (c=='+') mathType=2; + } + if (c=='V') { //preverify_bytecode switch + c=nextchar(); + if (c=='-') goverify=0; + if (c=='+') goverify=1; + } + } + */ + while (c!='}') c=nextchar(); + //goto lab; + r=1; + } + } while (r==1); + return END_OF_INPUT; +} + +//#define CST_INTEGER 0 +//#define CST_REAL 1 +//#define CST_BOOLEAN 2 +//#define CST_CHAR 3 +//#define CST_STRING 4 +// +//#define OP_MOD 5 +//#define OP_DIV 6 +//#define OP_PLUS 7 +//#define OP_MINUS 8 +//#define OP_MULT 9 +//#define OP_SLASH 10 +//#define OP_EQUAL 11 +//#define SEMI_COLON 18 +//#define COLON 19 +//#define OP_ASSIGN 20 +//#define OP_LESS 21 +//#define OP_GREATER 22 +//#define OP_LESS_EQUAL 23 +//#define OP_GREATER_EQUAL 24 +//#define OP_NOT_EQUAL 25 +//#define DOT 26 +//#define OPEN_SQ_BR 27 +//#define CLOSE_SQ_BR 28 +//#define OPEN_BR 34 +//#define CLOSE_BR 35 +//#define IDENTIFIER 57 +//#define COMMA 58 +//#define DOTDOT 59 +//#define END_OF_INPUT 100 +/* +#define CST_INTEGER 0 +#define CST_REAL 1 +#define CST_BOOLEAN 2 +#define CST_CHAR 3 +#define CST_STRING 4 +#define OP_MOD 5 +#define OP_DIV 6 +#define OP_PLUS 7 +#define OP_MINUS 8 +#define OP_MULT 9 +#define OP_SLASH 10 +#define OP_EQUAL 11 +#define KWD_BEGIN 12 +#define KWD_END 13 +#define OP_AND 14 +#define KWD_PROGRAM 15 +#define KWD_PROCEDURE 16 +#define KWD_FUNCTION 17 +#define SEMI_COLON 18 +#define COLON 19 +#define OP_ASSIGN 20 +#define OP_LESS 21 +#define OP_GREATER 22 +#define OP_LESS_EQUAL 23 +#define OP_GREATER_EQUAL 24 +#define OP_NOT_EQUAL 25 +#define DOT 26 +#define OPEN_SQ_BR 27 +#define CLOSE_SQ_BR 28 +#define KWD_VAR 29 +#define KWD_FOR 30 +#define KWD_TO 31 +#define KWD_DOWNTO 32 +#define KWD_DO 33 +#define OPEN_BR 34 +#define CLOSE_BR 35 +#define KWD_CONST 36 +#define KWD_TYPE 37 +#define KWD_IF 38 +#define KWD_THEN 39 +#define KWD_ELSE 40 +#define KWD_CASE 41 +#define KWD_OF 42 +#define KWD_WHILE 43 +#define KWD_REPEAT 44 +#define KWD_UNTIL 45 +#define KWD_WITH 46 +#define KWD_PACKED 47 +#define KWD_ARRAY 48 +#define OP_OR 49 +#define KWD_FILE 50 +#define KWD_SET 51 +#define KWD_RECORD 52 +#define OP_IN 53 +#define OP_NOT 54 +#define OP_XOR 55 +#define KWD_FORWARD 56 +#define IDENTIFIER 57 +#define COMMA 58 +#define DOTDOT 59 +#define KWD_BREAK 60 +#define KWD_USES 61 +#define KWD_UNIT 62 +#define KWD_INTERFACE 63 +#define KWD_IMPLEMENTATION 64 +#define KWD_INITIALIZATION 65 +#define KWD_FINALIZATION 66 +#define END_OF_INPUT 100 + +/* +"mod" = (OP_MOD); +"div" = (OP_DIV); +"+" = (OP_PLUS); +"-" = (OP_MINUS); +"*" = (OP_MULT); +"/" = (OP_SLASH); +"=" = (OP_EQUAL); +"begin" = (KWD_BEGIN); +"end" = (KWD_END); +"and" = (OP_AND); +"program" = (KWD_PROGRAM); +"procedure" = (KWD_PROCEDURE); +"function" = (KWD_FUNCTION); +";" = (SEMI_COLON); +":" = (COLON); +":=" = (OP_ASSIGN); +"<" = (OP_LESS); +">" = (OP_GREATER); +"<=" = (OP_LESS_EQUAL); +">=" = (OP_GREATER_EQUAL); +"<>" = (OP_NOT_EQUAL); +"." = (DOT); +".." = (DOTDOT); +"[" = (OPEN_SQ_BR); +"]" = (CLOSE_SQ_BR); +"var" = (KWD_VAR); +"for" = (KWD_FOR); +"to" = (KWD_TO); +"downto" = (KWD_DOWNTO); +"do" = (KWD_DO); +"(" = (OPEN_BR); +")" = (CLOSE_BR); +"const" = (KWD_CONST); +"type" = (KWD_TYPE); +"if" = (KWD_IF); +"then" = (KWD_THEN); +"else" = (KWD_ELSE); +"case" = (KWD_CASE); +"of" = (KWD_OF); +"while" = (KWD_WHILE); +"repeat" = (KWD_REPEAT); +"until" = (KWD_UNTIL); +"with" = (KWD_WITH); +"packed" = (KWD_PACKED); +"array" = (KWD_ARRAY); +"or" = (OP_OR); +"file" = (KWD_FILE); +"set" = (KWD_SET); +"record" = (KWD_RECORD); +"in" = (OP_IN); +"not" = (OP_NOT); +"xor" = (OP_XOR); +"forward" = (KWD_FORWARD); +"break" = (KWD_BREAK); +"," = (COMMA); +"uses" = (KWD_USES); +"unit" = (KWD_UNIT); +"interface" = (KWD_INTERFACE); +"implementation" = (KWD_IMPLEMENTATION); +"initialization" = (KWD_INITIALIZATION); +"finalization" = (KWD_FINALIZATION); +*/ + + +/* + c=nextchar(); + i=0; +rep: + while (c!='\'') { + *p=c; + p=p+1; + i++; + c=nextchar(); + } + c=nextchar(); + if (c=='\'') {*p=c; p=p+1; i=i+1; c=nextchar(); goto rep;} + if (c=='#') { + j=0; + c=nextchar(); + while (((c>='0') && (c<='9'))) { + j=j*10+c-48; + c=nextchar(); + } + *p=(char)j; + p=p+1; + i=i+1; + goto rep; + } +*/ + +/* +int getnum() { //get number + int sum; + sum=0; + ncount=1; + if (c=='$') { + c=nextchar(); + do { + if ((c >= 'A') && (c <= 'Z')) {sum = sum*16+10+c-65; ncount=ncount+1;} + else if ((c >= 'a') && (c <= 'z')) {sum = sum*16+10+c-97; ncount=ncount+1;} + else if (('0'>=c) && (c<='9')) {sum = sum*16+c-48; ncount=ncount+1;} + else break; + c=nextchar(); + } while (1==1); + } else { + while (('0'>=c) && (c<='9')) { + sum = sum*10+c-48; + ncount=ncount+1; + c=nextchar(); + } + } + //if (numcount==1) backchar(255); //bad number + return sum; +} +*/ diff --git a/MPC.3.5.LINUX/lex/tokens.h b/MPC.3.5.LINUX/lex/tokens.h new file mode 100644 index 0000000..be45532 --- /dev/null +++ b/MPC.3.5.LINUX/lex/tokens.h @@ -0,0 +1,85 @@ +/******************************************************************** + + tokens.h - definitions of token constants used by lexical + scanner and the parser. + + Niksa Orlic, 2004-04-19 + +********************************************************************/ + +#define CST_INTEGER 0 +#define CST_REAL 1 +#define CST_BOOLEAN 2 +#define CST_CHAR 3 +#define CST_STRING 4 +#define OP_MOD 5 +#define OP_DIV 6 +#define OP_PLUS 7 +#define OP_MINUS 8 +#define OP_MULT 9 +#define OP_SLASH 10 +#define OP_SHR 11 +#define OP_SHL 12 +#define OP_EQUAL 13 +#define KWD_BEGIN 14 +#define KWD_END 15 +#define OP_AND 16 +#define KWD_PROGRAM 17 +#define KWD_PROCEDURE 18 +#define KWD_FUNCTION 19 +#define SEMI_COLON 20 +#define COLON 21 +#define OP_ASSIGN 22 +#define OP_LESS 23 +#define OP_GREATER 24 +#define OP_LESS_EQUAL 25 +#define OP_GREATER_EQUAL 26 +#define OP_NOT_EQUAL 27 +#define DOT 28 +#define OPEN_SQ_BR 29 +#define CLOSE_SQ_BR 30 +#define KWD_VAR 31 +#define KWD_FOR 32 +#define KWD_TO 33 +#define KWD_DOWNTO 34 +#define KWD_DO 35 +#define OPEN_BR 36 +#define CLOSE_BR 37 +#define KWD_CONST 38 +#define KWD_TYPE 39 +#define KWD_IF 40 +#define KWD_THEN 41 +#define KWD_ELSE 42 +#define KWD_CASE 43 +#define KWD_OF 44 +#define KWD_WHILE 45 +#define KWD_REPEAT 46 +#define KWD_UNTIL 47 +#define KWD_WITH 48 +#define KWD_PACKED 49 +#define KWD_ARRAY 50 +#define OP_OR 51 +#define KWD_FILE 52 +#define KWD_SET 53 +#define KWD_RECORD 54 +#define OP_IN 55 +#define OP_NOT 56 +#define OP_XOR 57 +#define KWD_FORWARD 58 +#define IDENTIFIER 59 +#define COMMA 60 +#define DOTDOT 61 +#define KWD_BREAK 62 +#define KWD_USES 63 +#define KWD_UNIT 64 +#define KWD_INTERFACE 65 +#define KWD_IMPLEMENTATION 66 +#define KWD_INITIALIZATION 67 +#define KWD_FINALIZATION 68 +#define KWD_INLINE 69 +#define KWD_EXIT 70 +#define KWD_FOREVER 71 +#define KWD_RESULT 72 +#define KWD_BYTECODE 73 +#define OP_USHR 74 +#define END_OF_INPUT 255 diff --git a/MPC.3.5.LINUX/main/main.c b/MPC.3.5.LINUX/main/main.c new file mode 100644 index 0000000..156eaec --- /dev/null +++ b/MPC.3.5.LINUX/main/main.c @@ -0,0 +1,402 @@ +/* + + MIDletPascal-compiler 3.5.IDE (mp3CC.exe) + http://sourceforge.net/projects/midletpascal + + MPC.2.0.2: + Niksa Orlic + + MPC.3.0.003/009: + Artem (ironwoodcutter@bk.ru) + new lexer, + bytecode inline, + shl & shr operators, + smart string concatenation, + new max array size (up to 32767), + inclusion of {$R+/-} to enable/disable real numbers support, + and {$V+/-} to enable/disable internal bytecode preverification + + MPC.3.0.IDE: + Javier Santo Domingo (j-a-s-d@users.sourceforge.net) + ported to GNUCC (with coditional defines), + pascal-like errors messages and warnings, + new command-line parsing (C way), + disabled $R and $V directives (confusing overlapped functionality with the IDE), + and several other adjustments (wow64 WM_COPYDATA workaround, etc) + and bugfixes (real numbers parsing, shl & shr swapped operators, etc) + + MPC.3.1.IDE: + Javier Santo Domingo (j-a-s-d@users.sourceforge.net) + infinite-loop support (repeat/forever), + and bugfixes (complex-type bidimensional array initialization index out-of-bound, etc) + + MPC.3.2.IDE: + Javier Santo Domingo (j-a-s-d@users.sourceforge.net) + exit keyword support, + C-style multiline comments support + + MPC.3.3.IDE: + Javier Santo Domingo (j-a-s-d@users.sourceforge.net) + result keyword support, + C-style shift operators support (<< and >>), + and bugfixes (const assignment crash, etc) + + MPC.3.4.IDE: + Javier Santo Domingo (j-a-s-d@users.sourceforge.net) + Project Library Directory support via -p switch, + imported the "ASM BLOCK" from the Artem's MPC.3.0.011.SIMPLE parser.c, + bytecode keyword support, + and ushr/>>> shift operator support + + MPC.3.5.IDE: + Javier Santo Domingo (j-a-s-d@users.sourceforge.net) + C-like double quoted strings support, + negative integer constants support, + and bugfixes (consecutive same variable name declaration collision, etc) + +*/ + +// j-a-s-d: workaround for Wow64 using WM_COPYDATA +/*#ifndef LINUX + #define WOW64_WORKAROUND +#endif*/ + +#include "../util/strings.h" +#include "../util/error.h" +#include "../structures/type_list.h" +#include "../structures/string_list.h" +#include "../structures/type.h" +#include "../structures/identifier.h" +#include "../structures/name_table.h" +#include "../classgen/bytecode.h" +#include "../structures/block.h" +#include "../parser/parser.h" +#include "../util/memory.h" +#include +#include +#include +#include + +#ifdef WOW64_WORKAROUND + #include + + int ParentNotifyHandle = INVALID_HANDLE_VALUE; + COPYDATASTRUCT COMPILERMESSAGE; +#endif + +char msgstr[1024]; +int canvasType; +int mathType; +int next_record_ID; +int detect_units_only; +int goverify; + +extern FILE *yyin; +extern string *string_constant; +char *output_path; +char *source_file_name; +char *global_library_directory; +char *project_library_directory; +char *user_libraries = NULL; +char **units; + +extern short int error_count; +extern short int warning_count; + +extern int usesForms; +extern int usesSupport; +extern int usesFloat; +extern int usesRecordStore; +extern int usesHttp; +extern int usesPlayer; +extern int usesSMS; + +extern int constant_pool_size; +extern long int last_error_linenum; +extern int inside_loop; + +extern int linenum; +extern string *string_constant; + +extern int next_record_ID; + +void compileMSG() +{ +#ifdef WOW64_WORKAROUND + if (ParentNotifyHandle != INVALID_HANDLE_VALUE) { + COMPILERMESSAGE.dwData = 1; + COMPILERMESSAGE.cbData = sizeof( msgstr ); + COMPILERMESSAGE.lpData = &msgstr; + SendMessage(ParentNotifyHandle, WM_COPYDATA, + (WPARAM) 0, (LPARAM)(LPVOID) &COMPILERMESSAGE); + return; + } +#endif + printf(msgstr); + fflush(stdout); +} + +void requires(int reqkind, char* req) +{ + switch (reqkind) + { + case 0: // unit + sprintf(msgstr,"^0%s\n", req); + break; + case 1: // lib + sprintf(msgstr,"^1%s\n", req); + break; + case 2: // stub + sprintf(msgstr,"^2%s\n", req); + break; + case 3: // record + sprintf(msgstr,"^3%s\n", req); + break; + } + compileMSG(); +} + +int last_progress; + +void compile_progress(int x) +{ + if (x != last_progress) + { + last_progress = x; + sprintf(msgstr,"@%d\n", last_progress); + compileMSG(); + } +} + +void compile_terminate(){ + mem_close(); + fclose(yyin); + exit(1); +}; + +////////// + +void initialize_compiler() +{ + constant_pool_size = 0; + string_constant = NULL; + error_count = 0; + warning_count = 0; + last_error_linenum = -1; + linenum = 1; + inside_loop = 0; + goverify = 1; + usesFloat = 0; + usesForms = 0; + usesSupport = 0; + usesRecordStore = 0; + usesHttp = 0; + usesPlayer = 0; + usesSMS = 0; + user_libraries = NULL; +} + +void ShowHelp() +{ + sprintf(msgstr, + "-------------------------------------------------------------------------\n" + "MIDletPascal 3.5 Compiler\n" + "Version: MPC.3.5.IDE\n" + "Authors: Niksa Orlic (1.x-2.0), Artem (3.0), Javier Santo Domingo (3.x)\n" + "-------------------------------------------------------------------------\n" + "usage: mp3cc\n" + "\t-s\"\"\n" + "\t-o\"\"\n" + "\t-l\"\"\n" + "\t-p\"\"\n" + "\t-m\n" + "\t-c\n" + "\t-r\n" + "\t[-d] // detect units only\n" +#ifdef WOW64_WORKAROUND + "\t[-n] // outputs using WMCOPYDATA\n" +#endif + "\n" + ); + compileMSG(); + exit(2); +} + +void PrintFinalMessage () +{ + if (usesForms) { + requires(2,"FS.class"); + } + if (usesSupport) { + requires(2,"S.class"); + } + if (usesFloat == 1) { + if (mathType == 2) { + requires(2,"Real.class"); + requires(2,"Real$NumberFormat.class"); + } else { + requires(2,"F.class"); + } + } + if (usesRecordStore == 1) { + requires(2,"RS.class"); + } + if (usesHttp == 1) { + requires(2,"H.class"); + } + if (usesPlayer == 1) { + requires(2,"P.class"); + } + if (usesSMS == 1) { + requires(2,"SM.class"); + } + sprintf(msgstr,"Done - %d error(s), %d warning(s)\n", error_count, warning_count); +} + +int main(int argc, char **argv) +{ + error_count = -1; + char *source_file = NULL; + char *output_directory = NULL; + + int pos; + + if (argc >= 2) + { + // -- parse command line arguments + detect_units_only = 0; + mathType = 1; + canvasType = NORMAL; + + int c; + while ((c = getopt(argc, argv, "?:s:o:l:p:m:n:c:r:d")) != -1) { + switch(c) { + case 's': + source_file = optarg; + break; + case 'o': + output_directory = optarg; + break; + case 'l': + global_library_directory = optarg; + break; + case 'p': + project_library_directory = optarg; + break; + case 'm': + if (strcmp("2", optarg) == 0) { + mathType = 2; // REAL + } + break; + case 'n': +#ifdef WOW64_WORKAROUND + ParentNotifyHandle = atoi(optarg); +#endif + break; + case 'r': + next_record_ID = atoi(optarg); + break; + case 'c': + if (strcmp("2", optarg) == 0) { + canvasType = FULL_NOKIA; // FULL_NOKIA + } else if (strcmp("1", optarg) == 0) { + canvasType = FULL_MIDP20; // FULL_MIDP20 + } + break; + case 'd': + detect_units_only++; + break; + case '?': + default: + ShowHelp(); + } + } + + if (project_library_directory == NULL) { + sprintf(msgstr,"mp3cc: no project library directory\n"); + compileMSG(); + ShowHelp(); + } + if (global_library_directory == NULL) { + sprintf(msgstr,"mp3cc: no global library directory\n"); + compileMSG(); + ShowHelp(); + } + if (output_directory == NULL) { + sprintf(msgstr,"mp3cc: no output directory\n"); + compileMSG(); + ShowHelp(); + } + if (source_file == NULL) { + sprintf(msgstr,"mp3cc: no source file\n"); + compileMSG(); + ShowHelp(); + } + + // -- + + mem_init(); + initialize_compiler(); + units=malloc(8); + *units=malloc(8); + *units=NULL; + pos=strlen(source_file)-1; + while ((source_file[pos] == '\r') || (source_file[pos] == '\n')) pos --; + source_file[pos + 1] = '\0'; + source_file_name = (char*) mem_alloc(pos + 1); + if (source_file_name == NULL) die(1); + //pos = len - 1; + #ifdef UNIX + while ((pos >= 0) && (source_file[pos] != '/')) pos --; + #endif + #ifdef WIN32 + while ((pos >= 0) && (source_file[pos] != '\\')) pos --; + if (source_file[pos] != '\\') die(21); + #endif + //pos ++; + strcpy(source_file_name, source_file + pos + 1); + //////////////////// + pos = strlen(output_directory) - 1; + while ((output_directory[pos] == '\r')|| (output_directory[pos] == '\n')) pos --; + output_directory[pos + 1] = '\0'; + //len = strlen(output_directory); output_path = (char*) mem_alloc(len + 1); + output_path = output_directory; + //library_directory=output_directory; + yyrestart(source_file); + if ((yyin != NULL) && (output_path != NULL)) + { + if (detect_units_only) { + sprintf(msgstr,"Detecting units of \'%s\'...\n", source_file_name); + } else { + sprintf(msgstr,"Compiling \'%s\'...\n", source_file_name); + } + compileMSG(); + strcpy(output_path, output_directory); + parser_start(); + + fclose(yyin); + mem_free(output_path); + mem_free(source_file_name); + } + } + + if (string_constant != NULL) + string_destroy(string_constant); + + if (!detect_units_only) + { + switch(error_count) + { + case -1: + ShowHelp(); + case 0: + PrintFinalMessage(); + default: + sprintf(msgstr,""); + } + compileMSG(); + } + + mem_close(); + return error_count; +} diff --git a/MPC.3.5.LINUX/mp3CC.cbp b/MPC.3.5.LINUX/mp3CC.cbp new file mode 100644 index 0000000..4961fda --- /dev/null +++ b/MPC.3.5.LINUX/mp3CC.cbp @@ -0,0 +1,222 @@ + + + + + + diff --git a/MPC.3.5.LINUX/mp3CC.depend b/MPC.3.5.LINUX/mp3CC.depend new file mode 100644 index 0000000..9d4715b --- /dev/null +++ b/MPC.3.5.LINUX/mp3CC.depend @@ -0,0 +1,3454 @@ +# depslib dependency file v1.0 +1260373732 source:c:\code\mp3cc\classgen\bytecode.c + "bytecode.h" + "../util/error.h" + "../util/memory.h" + + + + +1396209483 + +1260373732 c:\code\mp3cc\classgen\bytecode.h + +1260373734 c:\code\mp3cc\util\error.h + +1267714409 c:\code\mp3cc\util\memory.h + +1267726361 source:c:\code\mp3cc\classgen\classgen.c + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../classgen/constant_pool.h" + "../classgen/preverify.h" + "../util/memory.h" + + + + "classgen.h" + +1359821690 h" + +1260373734 c:\code\mp3cc\util\strings.h + +1260373734 c:\code\mp3cc\structures\type_list.h + +1260373734 c:\code\mp3cc\structures\string_list.h + +1260373734 c:\code\mp3cc\structures\type.h + +1260373734 c:\code\mp3cc\structures\identifier.h + + +1260373734 c:\code\mp3cc\structures\name_table.h + +1260373734 c:\code\mp3cc\structures\block.h + + +1306012600 c:\code\mp3cc\classgen\constant_pool.h + +1260373733 c:\code\mp3cc\classgen\preverify.h + +1260373732 c:\code\mp3cc\classgen\classgen.h + +1306012581 source:c:\code\mp3cc\classgen\constant_pool.c + + + + "constant_pool.h" + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../util/memory.h" + "classgen.h" + +1260373733 source:c:\code\mp3cc\classgen\preverify.c + + + + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "constant_pool.h" + "bytecode.h" + "preverify.h" + "../util/error.h" + "../util/memory.h" + +1359821690 emory.h" + +1307035065 source:c:\code\mp3cc\lex\lex.yy.c + + + + "tokens.h" + "../util/strings.h" + "../util/error.h" + +1396208800 rror.h" + +1307035316 c:\code\mp3cc\lex\tokens.h + +1307037385 source:c:\code\mp3cc\parser\parser.c + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../lex/tokens.h" + "../util/memory.h" + "../structures/unit.h" + "../classgen/constant_pool.h" + + + + "../classgen/classgen.h" + "parser.h" + "stdpas.h" + +1260373734 c:\code\mp3cc\structures\unit.h + +1260373733 c:\code\mp3cc\parser\parser.h + +1260373733 c:\code\mp3cc\parser\stdpas.h + +1270062370 source:c:\code\mp3cc\parser\stdpas.c + "../util/strings.h" + "../util/error.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../classgen/constant_pool.h" + "stdpas.h" + + + + +1260373733 source:c:\code\mp3cc\preverifier\check_class.c + + "oobj.h" + "utf.h" + "tree.h" + "sys_api.h" + +1359821690 " + +1260373733 c:\code\mp3cc\preverifier\oobj.h + + + + + + + "typedefs.h" + "signature.h" + +1359821690 .h" + +1260373734 c:\code\mp3cc\preverifier\typedefs.h + "typedefs_md.h" + +1359821690 md.h" + +1260373734 c:\code\mp3cc\preverifier\typedefs_md.h + + + + + + +1396351241 > + +1260373734 c:\code\mp3cc\preverifier\signature.h + +1260373734 c:\code\mp3cc\preverifier\utf.h + +1260373734 c:\code\mp3cc\preverifier\tree.h + "oobj.h" + "typecodes.h" + +1260373734 c:\code\mp3cc\preverifier\typecodes.h + +1260373734 c:\code\mp3cc\preverifier\sys_api.h + "typedefs.h" + + "sysmacros_md.h" + +1396350064 _md.h" + +1260373734 c:\code\mp3cc\preverifier\sysmacros_md.h + + +1306020715 source:c:\code\mp3cc\preverifier\check_code.c + "check_code.h" + "opcodes.length" + "opcodes.in_out" + +1359821690 n_out" + +1260373733 c:\code\mp3cc\preverifier\check_code.h + + "oobj.h" + "opcodes.h" + "tree.h" + "sys_api.h" + +1260373733 c:\code\mp3cc\preverifier\opcodes.h + +1260373733 c:\code\mp3cc\preverifier\opcodes.length + +1260373733 c:\code\mp3cc\preverifier\opcodes.in_out + +1260373733 source:c:\code\mp3cc\preverifier\classloader.c + + + + + + + + + "jar.h" + "oobj.h" + "path.h" + "tree.h" + "signature.h" + "convert_md.h" + "sys_api.h" + + +1260373733 c:\code\mp3cc\preverifier\jar.h + "typedefs.h" + "stdio.h" + "sys/types.h" + "stddef.h" + +1260373733 c:\code\mp3cc\preverifier\path.h + + "path_md.h" + +1260373733 c:\code\mp3cc\preverifier\path_md.h + + + +1260373733 c:\code\mp3cc\preverifier\convert_md.h + +1260373733 source:c:\code\mp3cc\preverifier\classresolver.c + + + + + + + "oobj.h" + "tree.h" + "signature.h" + "path.h" + "sys_api.h" + "convert_md.h" + +1359821690 d.h" + +1260373733 source:c:\code\mp3cc\preverifier\convert_md.c + + + + + + + "oobj.h" + "utf.h" + +1260373733 source:c:\code\mp3cc\preverifier\file.c + + + + + + + + + "oobj.h" + "jar.h" + "tree.h" + "sys_api.h" + "convert_md.h" + + "opcodes.init" + +1359821690 nit" + +1260373733 c:\code\mp3cc\preverifier\opcodes.init + +1260373733 source:c:\code\mp3cc\preverifier\inlinejsr.c + "check_code.h" + +1359821690 e.h" + +1260373733 source:c:\code\mp3cc\preverifier\jar.c + + + + + "oobj.h" + "typedefs.h" + "jar.h" + "jarint.h" + "jartables.h" + +1260373733 c:\code\mp3cc\preverifier\jarint.h + +1260373733 c:\code\mp3cc\preverifier\jartables.h + +1260373733 source:c:\code\mp3cc\preverifier\jar_support.c + + + + + + + + "sys_api.h" + "path_md.h" + "path.h" + "oobj.h" + "jar.h" + "convert_md.h" + + + +1260373733 source:c:\code\mp3cc\preverifier\main.c + + + + + + + "sys_api.h" + "path_md.h" + "path.h" + "oobj.h" + "locale_md.h" + "../util/strings.h" + "../util/error.h" + "../util/message.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../parser/parser.h" + "../util/memory.h" + "../main/static_entry.h" + + + + +1260373733 c:\code\mp3cc\preverifier\locale_md.h + + +1260373734 source:c:\code\mp3cc\preverifier\stubs.c + "oobj.h" + "sys_api.h" + +1260373734 source:c:\code\mp3cc\preverifier\sys_support.c + + + + "oobj.h" + "jar.h" + "typedefs.h" + "sys_api.h" + "path.h" + +1260373734 source:c:\code\mp3cc\preverifier\utf.c + + + + "oobj.h" + "utf.h" + "sys_api.h" + +1260373734 source:c:\code\mp3cc\preverifier\util.c + + + + + "oobj.h" + "utf.h" + "sys_api.h" + "path.h" + +1304655643 source:c:\code\mp3cc\structures\block.c + "../util/strings.h" + "../util/error.h" + "../classgen/bytecode.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "unit.h" + "block.h" + "../classgen/preverify.h" + "../util/memory.h" + + + + "../classgen/constant_pool.h" + "../classgen/classgen.h" + +1359818090 en/classgen.h" + +1267714288 source:c:\code\mp3cc\structures\identifier.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "unit.h" + "../util/memory.h" + + + +1260373734 source:c:\code\mp3cc\structures\name_table.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "unit.h" + "../util/memory.h" + + + +1260373734 source:c:\code\mp3cc\structures\string_list.c + "../util/strings.h" + "../util/error.h" + "string_list.h" + + + +1260373734 source:c:\code\mp3cc\structures\type.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "../util/memory.h" + + + +1260373734 source:c:\code\mp3cc\structures\type_list.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "../util/memory.h" + + +1260373734 source:c:\code\mp3cc\structures\unit.c + "../util/strings.h" + "../util/error.h" + "../classgen/bytecode.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "block.h" + "unit.h" + "../classgen/preverify.h" + "../util/memory.h" + + + + "../classgen/constant_pool.h" + "../classgen/classgen.h" + +1307037408 source:c:\code\mp3cc\util\error.c + + + +1260373734 source:c:\code\mp3cc\util\memory.c + + + "memory.h" + "error.h" + +1260373734 source:c:\code\mp3cc\util\strings.c + "error.h" + "strings.h" + "memory.h" + + + +1307034609 source:c:\code\mp3cc\main\main.c + "../util/strings.h" + "../util/error.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../parser/parser.h" + "../util/memory.h" + + + + + + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/classgen/bytecode.c + "bytecode.h" + "../util/error.h" + "../util/memory.h" + + + + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/classgen/bytecode.h + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/util/error.h + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/util/memory.h + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/classgen/classgen.c + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../classgen/constant_pool.h" + "../classgen/preverify.h" + "../util/memory.h" + + + + "classgen.h" + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/util/strings.h + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/structures/type_list.h + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/structures/string_list.h + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/structures/type.h + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/structures/identifier.h + + +1396200141 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/structures/name_table.h + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/structures/block.h + + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/classgen/constant_pool.h + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/classgen/preverify.h + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/classgen/classgen.h + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/classgen/constant_pool.c + + + + "constant_pool.h" + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../util/memory.h" + "classgen.h" + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/classgen/preverify.c + + + + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "constant_pool.h" + "bytecode.h" + "preverify.h" + "../util/error.h" + "../util/memory.h" + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/lex/lex.yy.c + + + + "tokens.h" + "../util/strings.h" + "../util/error.h" + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/lex/tokens.h + +1396195894 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/main/main.c + "../util/strings.h" + "../util/error.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../parser/parser.h" + "../util/memory.h" + + + + + + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/parser/parser.h + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/parser/parser.c + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../lex/tokens.h" + "../util/memory.h" + "../structures/unit.h" + "../classgen/constant_pool.h" + + + + "../classgen/classgen.h" + "parser.h" + "stdpas.h" + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/structures/unit.h + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/parser/stdpas.h + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/parser/stdpas.c + "../util/strings.h" + "../util/error.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../classgen/constant_pool.h" + "stdpas.h" + + + + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/check_class.c + + "oobj.h" + "utf.h" + "tree.h" + "sys_api.h" + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/oobj.h + + + + + + + "typedefs.h" + "signature.h" + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/typedefs.h + "typedefs_md.h" + +1396195701 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/typedefs_md.h + + + + + + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/signature.h + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/utf.h + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/tree.h + "oobj.h" + "typecodes.h" + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/typecodes.h + +1396195922 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/sys_api.h + "typedefs.h" + + "sysmacros_md.h" + +1396195701 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/sysmacros_md.h + + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/check_code.c + "check_code.h" + "opcodes.length" + "opcodes.in_out" + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/check_code.h + + "oobj.h" + "opcodes.h" + "tree.h" + "sys_api.h" + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/opcodes.h + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/opcodes.length + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/opcodes.in_out + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/classloader.c + + + + + + + + + "jar.h" + "oobj.h" + "path.h" + "tree.h" + "signature.h" + "convert_md.h" + "sys_api.h" + + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/jar.h + "typedefs.h" + "stdio.h" + "sys/types.h" + "stddef.h" + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/path.h + + "path_md.h" + +1396195701 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/path_md.h + + + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/convert_md.h + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/classresolver.c + + + + + + + "oobj.h" + "tree.h" + "signature.h" + "path.h" + "sys_api.h" + "convert_md.h" + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/file.c + + + + + + + + + "oobj.h" + "jar.h" + "tree.h" + "sys_api.h" + "convert_md.h" + + "opcodes.init" + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/opcodes.init + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/inlinejsr.c + "check_code.h" + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/jar.c + + + + + "oobj.h" + "typedefs.h" + "jar.h" + "jarint.h" + "jartables.h" + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/jarint.h + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/jartables.h + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/jar_support.c + + + + + + + + "sys_api.h" + "path_md.h" + "path.h" + "oobj.h" + "jar.h" + "convert_md.h" + + + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/main.c + + + + + + + "sys_api.h" + "path_md.h" + "path.h" + "oobj.h" + "locale_md.h" + "../util/strings.h" + "../util/error.h" + "../util/message.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../parser/parser.h" + "../util/memory.h" + "../main/static_entry.h" + + + + +1359818090 /media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/locale_md.h + + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/stubs.c + "oobj.h" + "sys_api.h" + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/sys_support.c + + + + "oobj.h" + "jar.h" + "typedefs.h" + "sys_api.h" + "path.h" + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/utf.c + + + + "oobj.h" + "utf.h" + "sys_api.h" + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/util.c + + + + + "oobj.h" + "utf.h" + "sys_api.h" + "path.h" + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/structures/block.c + "../util/strings.h" + "../util/error.h" + "../classgen/bytecode.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "unit.h" + "block.h" + "../classgen/preverify.h" + "../util/memory.h" + + + + "../classgen/constant_pool.h" + "../classgen/classgen.h" + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/structures/identifier.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "unit.h" + "../util/memory.h" + + + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/structures/name_table.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "unit.h" + "../util/memory.h" + + + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/structures/string_list.c + "../util/strings.h" + "../util/error.h" + "string_list.h" + + + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/structures/type.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "../util/memory.h" + + + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/structures/type_list.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "../util/memory.h" + + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/structures/unit.c + "../util/strings.h" + "../util/error.h" + "../classgen/bytecode.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "block.h" + "unit.h" + "../classgen/preverify.h" + "../util/memory.h" + + + + "../classgen/constant_pool.h" + "../classgen/classgen.h" + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/util/error.c + + + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/util/memory.c + + + "memory.h" + "error.h" + +1359818090 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/util/strings.c + "error.h" + "strings.h" + "memory.h" + + + +1396196950 source:/media/second/Work/testmp/midletpascal-code-15/MPC.3.5.IDE/preverifier/convert_md.c + + + + + + + + "oobj.h" + "utf.h" + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/classgen/bytecode.c + "bytecode.h" + "../util/error.h" + "../util/memory.h" + + + + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/classgen/bytecode.h + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/util/error.h + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/util/memory.h + +1396210518 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/classgen/classgen.c + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../classgen/constant_pool.h" + "../classgen/preverify.h" + "../util/memory.h" + + + + "classgen.h" + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/util/strings.h + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/structures/type_list.h + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/structures/string_list.h + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/structures/type.h + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/structures/identifier.h + + +1396200141 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/structures/name_table.h + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/structures/block.h + + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/classgen/constant_pool.h + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/classgen/preverify.h + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/classgen/classgen.h + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/classgen/constant_pool.c + + + + "constant_pool.h" + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../util/memory.h" + "classgen.h" + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/classgen/preverify.c + + + + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "constant_pool.h" + "bytecode.h" + "preverify.h" + "../util/error.h" + "../util/memory.h" + +1396208800 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/lex/lex.yy.c + + + + "tokens.h" + "../util/strings.h" + "../util/error.h" + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/lex/tokens.h + +1396210518 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/parser/parser.c + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../lex/tokens.h" + "../util/memory.h" + "../structures/unit.h" + "../classgen/constant_pool.h" + + + + "../classgen/classgen.h" + "parser.h" + "stdpas.h" + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/structures/unit.h + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/parser/parser.h + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/parser/stdpas.h + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/parser/stdpas.c + "../util/strings.h" + "../util/error.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../classgen/constant_pool.h" + "stdpas.h" + + + + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/check_class.c + + "oobj.h" + "utf.h" + "tree.h" + "sys_api.h" + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/oobj.h + + + + + + + "typedefs.h" + "signature.h" + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/typedefs.h + "typedefs_md.h" + +1396195701 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/typedefs_md.h + + + + + + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/signature.h + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/utf.h + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/tree.h + "oobj.h" + "typecodes.h" + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/typecodes.h + +1396195922 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/sys_api.h + "typedefs.h" + + "sysmacros_md.h" + +1396195701 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/sysmacros_md.h + + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/check_code.c + "check_code.h" + "opcodes.length" + "opcodes.in_out" + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/check_code.h + + "oobj.h" + "opcodes.h" + "tree.h" + "sys_api.h" + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/opcodes.h + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/opcodes.length + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/opcodes.in_out + +1396211517 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/classloader.c + + + + + + + + + "jar.h" + "oobj.h" + "path.h" + "tree.h" + "signature.h" + "convert_md.h" + "sys_api.h" + + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/jar.h + "typedefs.h" + "stdio.h" + "sys/types.h" + "stddef.h" + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/path.h + + "path_md.h" + +1396209483 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/path_md.h + + + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/convert_md.h + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/classresolver.c + + + + + + + "oobj.h" + "tree.h" + "signature.h" + "path.h" + "sys_api.h" + "convert_md.h" + +1396212576 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/convert_md.c + + + + + + + + "oobj.h" + "utf.h" + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/file.c + + + + + + + + + "oobj.h" + "jar.h" + "tree.h" + "sys_api.h" + "convert_md.h" + + "opcodes.init" + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/opcodes.init + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/inlinejsr.c + "check_code.h" + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/jar.c + + + + + "oobj.h" + "typedefs.h" + "jar.h" + "jarint.h" + "jartables.h" + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/jarint.h + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/jartables.h + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/jar_support.c + + + + + + + + "sys_api.h" + "path_md.h" + "path.h" + "oobj.h" + "jar.h" + "convert_md.h" + + + +1396211001 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/main.c + + + + + + + "sys_api.h" + "path_md.h" + "path.h" + "oobj.h" + "locale_md.h" + "../util/strings.h" + "../util/error.h" + "../util/message.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../parser/parser.h" + "../util/memory.h" + "../main/static_entry.h" + + + + +1359818090 /media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/locale_md.h + + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/stubs.c + "oobj.h" + "sys_api.h" + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/sys_support.c + + + + "oobj.h" + "jar.h" + "typedefs.h" + "sys_api.h" + "path.h" + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/utf.c + + + + "oobj.h" + "utf.h" + "sys_api.h" + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/preverifier/util.c + + + + + "oobj.h" + "utf.h" + "sys_api.h" + "path.h" + +1396211001 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/structures/block.c + "../util/strings.h" + "../util/error.h" + "../classgen/bytecode.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "unit.h" + "block.h" + "../classgen/preverify.h" + "../util/memory.h" + + + + "../classgen/constant_pool.h" + "../classgen/classgen.h" + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/structures/identifier.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "unit.h" + "../util/memory.h" + + + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/structures/name_table.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "unit.h" + "../util/memory.h" + + + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/structures/string_list.c + "../util/strings.h" + "../util/error.h" + "string_list.h" + + + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/structures/type.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "../util/memory.h" + + + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/structures/type_list.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "../util/memory.h" + + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/structures/unit.c + "../util/strings.h" + "../util/error.h" + "../classgen/bytecode.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "block.h" + "unit.h" + "../classgen/preverify.h" + "../util/memory.h" + + + + "../classgen/constant_pool.h" + "../classgen/classgen.h" + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/util/error.c + + + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/util/memory.c + + + "memory.h" + "error.h" + +1359818090 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/util/strings.c + "error.h" + "strings.h" + "memory.h" + + + +1396210022 source:/media/second/Work/testmp/mp3CC-source/MPC.3.5.LINUX/main/main.c + "../util/strings.h" + "../util/error.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../parser/parser.h" + "../util/memory.h" + + + + + + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/classgen/bytecode.c + "bytecode.h" + "../util/error.h" + "../util/memory.h" + + + + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/classgen/bytecode.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/util/error.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/util/memory.h + +1396210518 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/classgen/classgen.c + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../classgen/constant_pool.h" + "../classgen/preverify.h" + "../util/memory.h" + + + + "classgen.h" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/util/strings.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/type_list.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/string_list.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/type.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/identifier.h + + +1396200141 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/name_table.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/block.h + + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/classgen/constant_pool.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/classgen/preverify.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/classgen/classgen.h + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/classgen/constant_pool.c + + + + "constant_pool.h" + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../util/memory.h" + "classgen.h" + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/classgen/preverify.c + + + + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "constant_pool.h" + "bytecode.h" + "preverify.h" + "../util/error.h" + "../util/memory.h" + +1396208800 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/lex/lex.yy.c + + + + "tokens.h" + "../util/strings.h" + "../util/error.h" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/lex/tokens.h + +1396302610 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/main/main.c + "../util/strings.h" + "../util/error.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../parser/parser.h" + "../util/memory.h" + + + + + + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/parser/parser.h + +1396210518 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/parser/parser.c + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../lex/tokens.h" + "../util/memory.h" + "../structures/unit.h" + "../classgen/constant_pool.h" + + + + "../classgen/classgen.h" + "parser.h" + "stdpas.h" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/unit.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/parser/stdpas.h + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/parser/stdpas.c + "../util/strings.h" + "../util/error.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../classgen/constant_pool.h" + "stdpas.h" + + + + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/check_class.c + + "oobj.h" + "utf.h" + "tree.h" + "sys_api.h" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/oobj.h + + + + + + + "typedefs.h" + "signature.h" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/typedefs.h + "typedefs_md.h" + +1396195701 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/typedefs_md.h + + + + + + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/signature.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/utf.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/tree.h + "oobj.h" + "typecodes.h" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/typecodes.h + +1396195922 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/sys_api.h + "typedefs.h" + + "sysmacros_md.h" + +1396195701 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/sysmacros_md.h + + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/check_code.c + "check_code.h" + "opcodes.length" + "opcodes.in_out" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/check_code.h + + "oobj.h" + "opcodes.h" + "tree.h" + "sys_api.h" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/opcodes.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/opcodes.length + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/opcodes.in_out + +1396211517 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/classloader.c + + + + + + + + + "jar.h" + "oobj.h" + "path.h" + "tree.h" + "signature.h" + "convert_md.h" + "sys_api.h" + + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/jar.h + "typedefs.h" + "stdio.h" + "sys/types.h" + "stddef.h" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/path.h + + "path_md.h" + +1396209483 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/path_md.h + + + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/convert_md.h + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/classresolver.c + + + + + + + "oobj.h" + "tree.h" + "signature.h" + "path.h" + "sys_api.h" + "convert_md.h" + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/file.c + + + + + + + + + "oobj.h" + "jar.h" + "tree.h" + "sys_api.h" + "convert_md.h" + + "opcodes.init" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/opcodes.init + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/inlinejsr.c + "check_code.h" + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/jar.c + + + + + "oobj.h" + "typedefs.h" + "jar.h" + "jarint.h" + "jartables.h" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/jarint.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/jartables.h + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/jar_support.c + + + + + + + + "sys_api.h" + "path_md.h" + "path.h" + "oobj.h" + "jar.h" + "convert_md.h" + + + +1396211001 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/main.c + + + + + + + "sys_api.h" + "path_md.h" + "path.h" + "oobj.h" + "locale_md.h" + "../util/strings.h" + "../util/error.h" + "../util/message.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../parser/parser.h" + "../util/memory.h" + "../main/static_entry.h" + + + + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/locale_md.h + + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/stubs.c + "oobj.h" + "sys_api.h" + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/sys_support.c + + + + "oobj.h" + "jar.h" + "typedefs.h" + "sys_api.h" + "path.h" + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/utf.c + + + + "oobj.h" + "utf.h" + "sys_api.h" + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/util.c + + + + + "oobj.h" + "utf.h" + "sys_api.h" + "path.h" + +1396211001 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/block.c + "../util/strings.h" + "../util/error.h" + "../classgen/bytecode.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "unit.h" + "block.h" + "../classgen/preverify.h" + "../util/memory.h" + + + + "../classgen/constant_pool.h" + "../classgen/classgen.h" + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/identifier.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "unit.h" + "../util/memory.h" + + + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/name_table.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "unit.h" + "../util/memory.h" + + + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/string_list.c + "../util/strings.h" + "../util/error.h" + "string_list.h" + + + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/type.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "../util/memory.h" + + + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/type_list.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "../util/memory.h" + + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/unit.c + "../util/strings.h" + "../util/error.h" + "../classgen/bytecode.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "block.h" + "unit.h" + "../classgen/preverify.h" + "../util/memory.h" + + + + "../classgen/constant_pool.h" + "../classgen/classgen.h" + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/util/error.c + + + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/util/memory.c + + + "memory.h" + "error.h" + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/util/strings.c + "error.h" + "strings.h" + "memory.h" + + + +1396279194 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/convert_md.c + + + + + + + + "oobj.h" + "utf.h" + +1359821690 source:d:\work\mp3cc-source\mpc.3.5.linux\classgen\bytecode.c + "bytecode.h" + "../util/error.h" + "../util/memory.h" + + + + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\classgen\bytecode.h + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\util\error.h + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\util\memory.h + +1396210518 source:d:\work\mp3cc-source\mpc.3.5.linux\classgen\classgen.c + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../classgen/constant_pool.h" + "../classgen/preverify.h" + "../util/memory.h" + + + + "classgen.h" + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\util\strings.h + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\structures\type_list.h + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\structures\string_list.h + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\structures\type.h + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\structures\identifier.h + + +1396200141 d:\work\mp3cc-source\mpc.3.5.linux\structures\name_table.h + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\structures\block.h + + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\classgen\constant_pool.h + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\classgen\preverify.h + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\classgen\classgen.h + +1359821690 source:d:\work\mp3cc-source\mpc.3.5.linux\classgen\constant_pool.c + + + + "constant_pool.h" + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../util/memory.h" + "classgen.h" + +1359821690 source:d:\work\mp3cc-source\mpc.3.5.linux\classgen\preverify.c + + + + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "constant_pool.h" + "bytecode.h" + "preverify.h" + "../util/error.h" + "../util/memory.h" + +1396208800 source:d:\work\mp3cc-source\mpc.3.5.linux\lex\lex.yy.c + + + + "tokens.h" + "../util/strings.h" + "../util/error.h" + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\lex\tokens.h + +1396302610 source:d:\work\mp3cc-source\mpc.3.5.linux\main\main.c + "../util/strings.h" + "../util/error.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../parser/parser.h" + "../util/memory.h" + + + + + + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\parser\parser.h + +1396210518 source:d:\work\mp3cc-source\mpc.3.5.linux\parser\parser.c + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../lex/tokens.h" + "../util/memory.h" + "../structures/unit.h" + "../classgen/constant_pool.h" + + + + "../classgen/classgen.h" + "parser.h" + "stdpas.h" + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\structures\unit.h + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\parser\stdpas.h + +1359821690 source:d:\work\mp3cc-source\mpc.3.5.linux\parser\stdpas.c + "../util/strings.h" + "../util/error.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../classgen/constant_pool.h" + "stdpas.h" + + + + +1359821690 source:d:\work\mp3cc-source\mpc.3.5.linux\preverifier\check_class.c + + "oobj.h" + "utf.h" + "tree.h" + "sys_api.h" + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\preverifier\oobj.h + + + + + + + "typedefs.h" + "signature.h" + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\preverifier\typedefs.h + "typedefs_md.h" + +1396351241 d:\work\mp3cc-source\mpc.3.5.linux\preverifier\typedefs_md.h + + + + + + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\preverifier\signature.h + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\preverifier\utf.h + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\preverifier\tree.h + "oobj.h" + "typecodes.h" + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\preverifier\typecodes.h + +1396350064 d:\work\mp3cc-source\mpc.3.5.linux\preverifier\sys_api.h + "typedefs.h" + + "sysmacros_md.h" + +1396195701 d:\work\mp3cc-source\mpc.3.5.linux\preverifier\sysmacros_md.h + + +1359821690 source:d:\work\mp3cc-source\mpc.3.5.linux\preverifier\check_code.c + "check_code.h" + "opcodes.length" + "opcodes.in_out" + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\preverifier\check_code.h + + "oobj.h" + "opcodes.h" + "tree.h" + "sys_api.h" + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\preverifier\opcodes.h + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\preverifier\opcodes.length + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\preverifier\opcodes.in_out + +1396211517 source:d:\work\mp3cc-source\mpc.3.5.linux\preverifier\classloader.c + + + + + + + + + "jar.h" + "oobj.h" + "path.h" + "tree.h" + "signature.h" + "convert_md.h" + "sys_api.h" + + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\preverifier\jar.h + "typedefs.h" + "stdio.h" + "sys/types.h" + "stddef.h" + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\preverifier\path.h + + "path_md.h" + +1396209483 d:\work\mp3cc-source\mpc.3.5.linux\preverifier\path_md.h + + + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\preverifier\convert_md.h + +1359821690 source:d:\work\mp3cc-source\mpc.3.5.linux\preverifier\classresolver.c + + + + + + + "oobj.h" + "tree.h" + "signature.h" + "path.h" + "sys_api.h" + "convert_md.h" + +1396279194 source:d:\work\mp3cc-source\mpc.3.5.linux\preverifier\convert_md.c + + + + + + + + "oobj.h" + "utf.h" + +1359821690 source:d:\work\mp3cc-source\mpc.3.5.linux\preverifier\file.c + + + + + + + + + "oobj.h" + "jar.h" + "tree.h" + "sys_api.h" + "convert_md.h" + + "opcodes.init" + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\preverifier\opcodes.init + +1359821690 source:d:\work\mp3cc-source\mpc.3.5.linux\preverifier\inlinejsr.c + "check_code.h" + +1359821690 source:d:\work\mp3cc-source\mpc.3.5.linux\preverifier\jar.c + + + + + "oobj.h" + "typedefs.h" + "jar.h" + "jarint.h" + "jartables.h" + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\preverifier\jarint.h + +1359821690 d:\work\mp3cc-source\mpc.3.5.linux\preverifier\jartables.h + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/classgen/bytecode.c + "bytecode.h" + "../util/error.h" + "../util/memory.h" + + + + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/classgen/bytecode.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/util/error.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/util/memory.h + +1396210518 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/classgen/classgen.c + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../classgen/constant_pool.h" + "../classgen/preverify.h" + "../util/memory.h" + + + + "classgen.h" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/util/strings.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/type_list.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/string_list.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/type.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/identifier.h + + +1396200141 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/name_table.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/block.h + + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/classgen/constant_pool.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/classgen/preverify.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/classgen/classgen.h + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/classgen/constant_pool.c + + + + "constant_pool.h" + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../util/memory.h" + "classgen.h" + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/classgen/preverify.c + + + + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "constant_pool.h" + "bytecode.h" + "preverify.h" + "../util/error.h" + "../util/memory.h" + +1396208800 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/lex/lex.yy.c + + + + "tokens.h" + "../util/strings.h" + "../util/error.h" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/lex/tokens.h + +1396302610 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/main/main.c + "../util/strings.h" + "../util/error.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../parser/parser.h" + "../util/memory.h" + + + + + + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/parser/parser.h + +1396210518 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/parser/parser.c + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../lex/tokens.h" + "../util/memory.h" + "../structures/unit.h" + "../classgen/constant_pool.h" + + + + "../classgen/classgen.h" + "parser.h" + "stdpas.h" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/unit.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/parser/stdpas.h + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/parser/stdpas.c + "../util/strings.h" + "../util/error.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../classgen/constant_pool.h" + "stdpas.h" + + + + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/check_class.c + + "oobj.h" + "utf.h" + "tree.h" + "sys_api.h" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/oobj.h + + + + + + + "typedefs.h" + "signature.h" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/typedefs.h + "typedefs_md.h" + +1396351241 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/typedefs_md.h + + + + + + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/signature.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/utf.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/tree.h + "oobj.h" + "typecodes.h" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/typecodes.h + +1396368719 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/sys_api.h + "typedefs.h" + + "sysmacros_md.h" + +1396195701 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/sysmacros_md.h + + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/check_code.c + "check_code.h" + "opcodes.length" + "opcodes.in_out" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/check_code.h + + "oobj.h" + "opcodes.h" + "tree.h" + "sys_api.h" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/opcodes.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/opcodes.length + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/opcodes.in_out + +1396211517 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/classloader.c + + + + + + + + + "jar.h" + "oobj.h" + "path.h" + "tree.h" + "signature.h" + "convert_md.h" + "sys_api.h" + + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/jar.h + "typedefs.h" + "stdio.h" + "sys/types.h" + "stddef.h" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/path.h + + "path_md.h" + +1396209483 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/path_md.h + + + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/convert_md.h + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/classresolver.c + + + + + + + "oobj.h" + "tree.h" + "signature.h" + "path.h" + "sys_api.h" + "convert_md.h" + +1396279194 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/convert_md.c + + + + + + + + "oobj.h" + "utf.h" + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/file.c + + + + + + + + + "oobj.h" + "jar.h" + "tree.h" + "sys_api.h" + "convert_md.h" + + "opcodes.init" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/opcodes.init + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/inlinejsr.c + "check_code.h" + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/jar.c + + + + + "oobj.h" + "typedefs.h" + "jar.h" + "jarint.h" + "jartables.h" + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/jarint.h + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/jartables.h + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/jar_support.c + + + + + + + + "sys_api.h" + "path_md.h" + "path.h" + "oobj.h" + "jar.h" + "convert_md.h" + + + +1396211001 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/main.c + + + + + + + "sys_api.h" + "path_md.h" + "path.h" + "oobj.h" + "locale_md.h" + "../util/strings.h" + "../util/error.h" + "../util/message.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../parser/parser.h" + "../util/memory.h" + "../main/static_entry.h" + + + + +1359818090 /media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/locale_md.h + + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/stubs.c + "oobj.h" + "sys_api.h" + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/sys_support.c + + + + "oobj.h" + "jar.h" + "typedefs.h" + "sys_api.h" + "path.h" + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/utf.c + + + + "oobj.h" + "utf.h" + "sys_api.h" + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/util.c + + + + + "oobj.h" + "utf.h" + "sys_api.h" + "path.h" + +1396211001 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/block.c + "../util/strings.h" + "../util/error.h" + "../classgen/bytecode.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "unit.h" + "block.h" + "../classgen/preverify.h" + "../util/memory.h" + + + + "../classgen/constant_pool.h" + "../classgen/classgen.h" + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/identifier.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "unit.h" + "../util/memory.h" + + + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/name_table.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "unit.h" + "../util/memory.h" + + + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/string_list.c + "../util/strings.h" + "../util/error.h" + "string_list.h" + + + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/type.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "../util/memory.h" + + + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/type_list.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "../util/memory.h" + + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/structures/unit.c + "../util/strings.h" + "../util/error.h" + "../classgen/bytecode.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "block.h" + "unit.h" + "../classgen/preverify.h" + "../util/memory.h" + + + + "../classgen/constant_pool.h" + "../classgen/classgen.h" + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/util/error.c + + + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/util/memory.c + + + "memory.h" + "error.h" + +1359818090 source:/media/second/Work/mp3CC-source/MPC.3.5.LINUX/util/strings.c + "error.h" + "strings.h" + "memory.h" + + + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/classgen/bytecode.c + "bytecode.h" + "../util/error.h" + "../util/memory.h" + + + + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/classgen/bytecode.h + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/util/error.h + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/util/memory.h + +1396210518 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/classgen/classgen.c + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../classgen/constant_pool.h" + "../classgen/preverify.h" + "../util/memory.h" + + + + "classgen.h" + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/util/strings.h + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/structures/type_list.h + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/structures/string_list.h + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/structures/type.h + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/structures/identifier.h + + +1396200141 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/structures/name_table.h + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/structures/block.h + + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/classgen/constant_pool.h + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/classgen/preverify.h + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/classgen/classgen.h + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/classgen/constant_pool.c + + + + "constant_pool.h" + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../util/memory.h" + "classgen.h" + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/classgen/preverify.c + + + + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "constant_pool.h" + "bytecode.h" + "preverify.h" + "../util/error.h" + "../util/memory.h" + +1407751994 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/lex/lex.yy.c + + + + "tokens.h" + "../util/strings.h" + "../util/error.h" + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/lex/tokens.h + +1407751870 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/main/main.c + "../util/strings.h" + "../util/error.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../parser/parser.h" + "../util/memory.h" + + + + + + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/parser/parser.h + +1396210518 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/parser/parser.c + "../util/error.h" + "../util/strings.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../lex/tokens.h" + "../util/memory.h" + "../structures/unit.h" + "../classgen/constant_pool.h" + + + + "../classgen/classgen.h" + "parser.h" + "stdpas.h" + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/structures/unit.h + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/parser/stdpas.h + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/parser/stdpas.c + "../util/strings.h" + "../util/error.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../classgen/constant_pool.h" + "stdpas.h" + + + + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/check_class.c + + "oobj.h" + "utf.h" + "tree.h" + "sys_api.h" + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/oobj.h + + + + + + + "typedefs.h" + "signature.h" + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/typedefs.h + "typedefs_md.h" + +1396351241 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/typedefs_md.h + + + + + + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/signature.h + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/utf.h + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/tree.h + "oobj.h" + "typecodes.h" + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/typecodes.h + +1396368719 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/sys_api.h + "typedefs.h" + + "sysmacros_md.h" + +1396195701 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/sysmacros_md.h + + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/check_code.c + "check_code.h" + "opcodes.length" + "opcodes.in_out" + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/check_code.h + + "oobj.h" + "opcodes.h" + "tree.h" + "sys_api.h" + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/opcodes.h + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/opcodes.length + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/opcodes.in_out + +1396211517 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/classloader.c + + + + + + + + + "jar.h" + "oobj.h" + "path.h" + "tree.h" + "signature.h" + "convert_md.h" + "sys_api.h" + + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/jar.h + "typedefs.h" + "stdio.h" + "sys/types.h" + "stddef.h" + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/path.h + + "path_md.h" + +1396209483 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/path_md.h + + + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/convert_md.h + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/classresolver.c + + + + + + + "oobj.h" + "tree.h" + "signature.h" + "path.h" + "sys_api.h" + "convert_md.h" + +1396279194 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/convert_md.c + + + + + + + + "oobj.h" + "utf.h" + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/file.c + + + + + + + + + "oobj.h" + "jar.h" + "tree.h" + "sys_api.h" + "convert_md.h" + + "opcodes.init" + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/opcodes.init + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/inlinejsr.c + "check_code.h" + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/jar.c + + + + + "oobj.h" + "typedefs.h" + "jar.h" + "jarint.h" + "jartables.h" + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/jarint.h + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/jartables.h + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/jar_support.c + + + + + + + + "sys_api.h" + "path_md.h" + "path.h" + "oobj.h" + "jar.h" + "convert_md.h" + + + +1396211001 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/main.c + + + + + + + "sys_api.h" + "path_md.h" + "path.h" + "oobj.h" + "locale_md.h" + "../util/strings.h" + "../util/error.h" + "../util/message.h" + "../structures/type_list.h" + "../structures/string_list.h" + "../structures/type.h" + "../structures/identifier.h" + "../structures/name_table.h" + "../classgen/bytecode.h" + "../structures/block.h" + "../parser/parser.h" + "../util/memory.h" + "../main/static_entry.h" + + + + +1359818090 /home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/locale_md.h + + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/stubs.c + "oobj.h" + "sys_api.h" + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/sys_support.c + + + + "oobj.h" + "jar.h" + "typedefs.h" + "sys_api.h" + "path.h" + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/utf.c + + + + "oobj.h" + "utf.h" + "sys_api.h" + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/preverifier/util.c + + + + + "oobj.h" + "utf.h" + "sys_api.h" + "path.h" + +1396211001 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/structures/block.c + "../util/strings.h" + "../util/error.h" + "../classgen/bytecode.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "unit.h" + "block.h" + "../classgen/preverify.h" + "../util/memory.h" + + + + "../classgen/constant_pool.h" + "../classgen/classgen.h" + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/structures/identifier.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "unit.h" + "../util/memory.h" + + + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/structures/name_table.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "unit.h" + "../util/memory.h" + + + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/structures/string_list.c + "../util/strings.h" + "../util/error.h" + "string_list.h" + + + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/structures/type.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "../util/memory.h" + + + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/structures/type_list.c + "../util/strings.h" + "../util/error.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "../classgen/bytecode.h" + "block.h" + "../util/memory.h" + + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/structures/unit.c + "../util/strings.h" + "../util/error.h" + "../classgen/bytecode.h" + "type_list.h" + "string_list.h" + "type.h" + "identifier.h" + "name_table.h" + "block.h" + "unit.h" + "../classgen/preverify.h" + "../util/memory.h" + + + + "../classgen/constant_pool.h" + "../classgen/classgen.h" + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/util/error.c + + + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/util/memory.c + + + "memory.h" + "error.h" + +1359818090 source:/home/deaddoomer/Work/mp3CC-source/MPC.3.5.LINUX/util/strings.c + "error.h" + "strings.h" + "memory.h" + + + diff --git a/MPC.3.5.LINUX/mp3CC.layout b/MPC.3.5.LINUX/mp3CC.layout new file mode 100644 index 0000000..62efb17 --- /dev/null +++ b/MPC.3.5.LINUX/mp3CC.layout @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MPC.3.5.LINUX/parser/parser.c b/MPC.3.5.LINUX/parser/parser.c new file mode 100644 index 0000000..a2acec5 --- /dev/null +++ b/MPC.3.5.LINUX/parser/parser.c @@ -0,0 +1,6835 @@ +/******************************************************************** + + parser.c - recursive-descent parser + + Niksa Orlic, 2004-04-19 + +********************************************************************/ + + +//#include "../util/message.h" +#include "../util/error.h" +#include "../util/strings.h" +#include "../structures/type_list.h" +#include "../structures/string_list.h" +#include "../structures/type.h" +#include "../structures/identifier.h" +#include "../structures/name_table.h" +#include "../classgen/bytecode.h" +#include "../structures/block.h" +#include "../lex/tokens.h" +#include "../util/memory.h" +#include "../structures/unit.h" + +#include "../classgen/constant_pool.h" + +#include +#include +#include + +#include "../classgen/classgen.h" + +#include "parser.h" +#include "stdpas.h" + +#pragma warning (disable: 4305) +#pragma warning (disable: 4761) + +extern int procedure_linenum; + +//extern void (*compile_terminate)(); + +extern FILE* yyin; + + +int current_token; +block *root_block; + +int next_record_ID; + +/* Scanner variables and functions */ +extern long int linenum; +extern int new_linenum; +extern long int integer_constant; +extern int error_count; +extern float real_constant; +extern char boolean_constant; +extern char char_constant; +extern string *string_constant; +extern char *yytext; +extern int yylex(); +extern FILE *yyin; +extern void backchar(int c); +extern int goverify; + +extern void VerifyFile(char*); + +extern int usesFloat; + +extern char *output_path; + +extern int detect_units_only; + +/* Small macro for outputting the yytext value */ +#define YYTEXT_STRING (current_token == END_OF_INPUT ? "" : yytext) + + +/* A macro to explicitly declare we didn't forget break inside + the case statement */ +//#define no_break /* do nothing */; + + +int inside_loop = 0; /* the counter checks if 'break' is located inside a loop */ + +int compiling_unit = 0; /* set to 1 if this is an unit */ +int inside_interface_part = 0; /* if the compiler is inside the interface part of the unit */ +int inside_implementation_part = 0; /* if the compiler is inside the implementation part of the unit */ + +int inside_routine = 0; +int routine_return_type = void_type; +int routine_return_parameters_length = 0; + +string *str_program_name; +string *str_currrent_routine_name; + +extern int mathType; + +FILE *symbols_file; + +//ASM - LABEL TABLE +int nam[1024]; +int lab[1024]; +int len[1024]; +//int ofs[1024]; +int labcount; + +/* + Starts parsing the input file. The grammar rule + used is: + + -> . <> + -> . <> +*/ +void parser_start() +{ + block *program_block; + int random_field_index; + int random_class_index; + int random_method_index; + + root_block = initialize_root_block(); + + current_token = yylex(); + + compiling_unit = 0; + + str_program_name = RD_program_header(); + + if (compiling_unit == 0) + { + RD_uses_list(); + + if (str_program_name == NULL) + str_program_name = string_from_cstr(""); + + program_block = block_create(root_block, str_program_name); + + // j-a-s-d + if (detect_units_only) + goto end_parsing; + + /* initialize the random number generator */ + random_field_index = cp_add_fieldref("M", "RNG", "Ljava/util/Random;"); + random_class_index = cp_add_class("java/util/Random"); + random_method_index = cp_add_methodref("java/util/Random", "", "()V"); + + bytecode_append(program_block->code, new$); + bytecode_append_short_int(program_block->code, random_class_index); + + bytecode_append(program_block->code, dup$); + + bytecode_append(program_block->code, invokespecial$); + bytecode_append_short_int(program_block->code, random_method_index); + + bytecode_append(program_block->code, putstatic$); + bytecode_append_short_int(program_block->code, random_field_index); + /* END initialize the random number generator */ + + /* initialize the index counter field */ + bytecode_append(program_block->code, bipush$); + bytecode_append(program_block->code, 25); + bytecode_append(program_block->code, newarray$); + bytecode_append(program_block->code, 10); + bytecode_append(program_block->code, putstatic$); + bytecode_append_short_int(program_block->code, cp_add_fieldref("M", "IC", "[I")); + /* END initialize the IC field */ + + /* reset the keyboard buffers */ + bytecode_append(program_block->code, iconst_0$); + bytecode_append(program_block->code, putstatic$); + bytecode_append_short_int(program_block->code, cp_add_fieldref("M", "KC", "I")); + bytecode_append(program_block->code, iconst_0$); + bytecode_append(program_block->code, putstatic$); + bytecode_append_short_int(program_block->code, cp_add_fieldref("M", "KP", "I")); + /* END reset the keyboard buffers */ + + RD_block(program_block); + + /* do the 'halt' at the end of program execution */ + bytecode_append(program_block->code, getstatic$); + bytecode_append_short_int(program_block->code, cp_add_fieldref("FW", "fw", "LFW;")); + bytecode_append(program_block->code, iconst_1$); + bytecode_append(program_block->code, invokevirtual$); + bytecode_append_short_int(program_block->code, cp_add_methodref("FW", "destroyApp", "(Z)V")); + + /* bytecode verififer wants this unnecessary return */ + bytecode_append(program_block->code, return$); + } + else + { + char *symbols_filename; + int filepos; + + symbols_filename = (char*) mem_alloc(strlen(output_path) + string_length(str_program_name) + 10); + #ifdef WIN32 + sprintf(symbols_filename, "%s\\%s.bsf", output_path, string_get_cstr(str_program_name)); + #endif + #ifdef UNIX + sprintf(symbols_filename, "%s/%s.bsf", output_path, string_get_cstr(str_program_name)); + #endif + symbols_file = fopen(symbols_filename, "wb"); + mem_free(symbols_filename); + + if (symbols_file == NULL) + die(7); + + program_block = block_create(root_block, str_program_name); + + lowercase(string_get_cstr(str_program_name)); + + RD_unit_interface(program_block); + RD_unit_implementation(program_block); + RD_unit_initialization(program_block); + RD_unit_finalization(program_block); + + // j-a-s-d + if (detect_units_only) { + fclose(symbols_file); + goto end_parsing; + } + + if (current_token != KWD_END) + add_error_message(203, "end", YYTEXT_STRING); + else + { + current_token = yylex(); + } + + fclose(symbols_file); + + bytecode_append(program_block->code, return$); + } + + /* check if there are forward declarations without the body */ + check_unmatched_forward_declarations(program_block, program_block->names); + + if (current_token != DOT) + { + add_error_message(200, ".", YYTEXT_STRING); + + /* Error-recovery: find the end of input */ + while (current_token != END_OF_INPUT) + current_token = yylex(); + } + else + current_token = yylex(); + + if (current_token != END_OF_INPUT) + { + add_error_message(201, YYTEXT_STRING, ""); + } + + if (error_count == 0) + { + FILE *fp; + char *output_file_name; + char *short_file_name; + + if (compiling_unit == 0) + { + output_file_name = (char*) mem_alloc(strlen(output_path) + 10); + short_file_name = (char*) mem_alloc(10); + } + else + { + output_file_name = (char*) mem_alloc(strlen(output_path) + string_length(str_program_name) + 10); + short_file_name = (char*) mem_alloc(string_length(str_program_name) + 10); + } + + if (output_file_name == NULL) + die (1); + + if (compiling_unit == 0) + { + #ifdef WIN32 + sprintf(output_file_name, "%s\\M.class", output_path); + #endif + #ifdef UNIX + sprintf(output_file_name, "%s/M.class", output_path); + #endif + sprintf(short_file_name, "M"); + } + else + { + #ifdef WIN32 + sprintf(output_file_name, "%s\\%s.class", output_path, string_get_cstr(str_program_name)); + #endif + #ifdef UNIX + sprintf(output_file_name, "%s/%s.class", output_path, string_get_cstr(str_program_name)); + #endif + sprintf(short_file_name, "%s", string_get_cstr(str_program_name)); + } + + fp = fopen(output_file_name, "wb"); + mem_free(output_file_name); + if (fp == NULL) + { + die (4); + } + create_class_file(program_block, fp); + fclose(fp); + + if (goverify!=0) VerifyFile(short_file_name); + } +// j-a-s-d +end_parsing: + string_destroy(str_program_name); + + block_destroy(program_block); + block_destroy(root_block); +} + + +/* + Program header, uses the grammar rule: + + -> [program IDENTIFIER ;] +*/ +string* RD_program_header() +{ + string *program_name = NULL; + + if ((current_token == KWD_PROGRAM) + || (current_token == KWD_UNIT)) + { + if (current_token == KWD_UNIT) + compiling_unit = 1; + + current_token = yylex(); + + if (current_token != IDENTIFIER) + { + add_error_message(202, "", ""); + } + else + program_name = string_from_cstr(YYTEXT_STRING); + + if ((compiling_unit) && (string_length(program_name) < 3)) + add_error_message(454, "", ""); + + current_token = yylex(); + + if (current_token != SEMI_COLON) + { + + add_error_message(200, ";", YYTEXT_STRING); + + /* Error-recovery: find any of the following: + CONST, TYPE, VAR, PROCEDURE, FUNCTION, BEGIN, ., EOF + */ + while ( (current_token != KWD_CONST) + && (current_token != KWD_TYPE) + && (current_token != KWD_VAR) + && (current_token != KWD_PROCEDURE) + && (current_token != KWD_FUNCTION) + && (current_token != KWD_BEGIN) + && (current_token != DOT) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + } + else + current_token = yylex(); + } + + return program_name; +} + +/* + the interface part of the unit source + + -> [interface [;] ] + + special rules apply to declarations inside the interface; global variable inside_interface_part is used to denote the special cases +*/ +void RD_unit_interface(block *current_block) +{ + if (current_token != KWD_INTERFACE) + { + if ((current_token == KWD_IMPLEMENTATION) + || (current_token == KWD_INITIALIZATION)) + return; + + add_error_message(203, "interface", YYTEXT_STRING); + + do + { + current_token = yylex(); + } + while ((current_token != KWD_IMPLEMENTATION) && (current_token != END_OF_INPUT)); + + return; + } + + current_token = yylex(); + + if (current_token == SEMI_COLON) + current_token = yylex(); + + inside_interface_part = 1; + RD_block(current_block); + inside_interface_part = 0; +} + +/* + the implementation part of the unit source + + -> implementation [;] +*/ +void RD_unit_implementation(block *current_block) +{ + if (current_token == END_OF_INPUT) + return; + + if (current_token != KWD_IMPLEMENTATION) + { + add_error_message(203, "implementation", YYTEXT_STRING); + + do + { + current_token = yylex(); + } + while (current_token != END_OF_INPUT); + + return; + } + + current_token = yylex(); + + if (current_token == SEMI_COLON) + current_token = yylex(); + + RD_uses_list(); + + // j-a-s-d + if (detect_units_only) + return; + + inside_implementation_part = 1; + RD_block(current_block); + inside_implementation_part = 0; +} + +/* + the initialization part of the unit + + -> [initialization [;] ] +*/ +void RD_unit_initialization(block* current_block) +{ + if (current_token == KWD_INITIALIZATION) + { + current_token = yylex(); + + if (current_token == SEMI_COLON) + current_token = yylex(); + + RD_block_body(current_block); + } +} + +/* + the finalization part of the unit is not supported by the compiler +*/ +void RD_unit_finalization(block *current_block) +{ + if (current_token == KWD_FINALIZATION) + { + add_error_message(220, "", ""); + current_token = yylex(); + return; + } +} + +/* + The list of 'uses' directives. + -> ( uses NAME; )* +*/ +void RD_uses_list() +{ + while (current_token == KWD_USES) + { +following_unit: + current_token = yylex(); + + if (current_token != IDENTIFIER) + { + add_error_message(202, "", ""); + + /* do error recovery */ + while ((current_token != END_OF_INPUT) + && (current_token != SEMI_COLON)) + { + current_token = yylex(); + return; + } + } + + /* process the library */ + load_extern_library(string_from_cstr(YYTEXT_STRING)); + + current_token = yylex(); + + if (current_token == COMMA) + goto following_unit; + + if (current_token != SEMI_COLON) + { + add_error_message(200, ";", YYTEXT_STRING); + + /* do error recovery */ + while ((current_token != END_OF_INPUT) + && (current_token != SEMI_COLON)) + { + current_token = yylex(); + return; + } + } + else + current_token = yylex(); + } + + if (current_token == SEMI_COLON) + current_token = yylex(); + + if (detect_units_only) + { + mem_close(); + + fclose(yyin); + + // j-a-s-d + //compile_terminate(); + exit(0); + } +} + + +/* + Program block with declarations and code. + The grammar rule used: + + -> const + | type + | var + | procedure + | function + | begin end +*/ +block* RD_block(block *current_block) +{ + switch (current_token) + { + case KWD_CONST: + { + current_token = yylex(); + RD_const_declaration(current_block); + break; + } + + case KWD_TYPE: + { + current_token = yylex(); + RD_type_declaration(current_block); + break; + } + + case KWD_VAR: + { + current_token = yylex(); + RD_var_declaration(current_block); + break; + } + + case KWD_PROCEDURE: + { + if (current_block->parent_block != root_block) + add_error_message(431, "", ""); + + current_token = yylex(); + RD_procedure_declaration(current_block); + break; + } + + case KWD_FUNCTION: + { + if (current_block->parent_block != root_block) + add_error_message(431, "", ""); + + current_token = yylex(); + RD_function_declaration(current_block); + break; + } + + case KWD_BEGIN: + { + if ((inside_interface_part) || (inside_implementation_part)) + { + add_error_message(204, YYTEXT_STRING, ""); + + do + { + current_token = yylex(); + } while (current_token != END_OF_INPUT); + + break; + } + + current_token = yylex(); + + RD_block_body(current_block); + + if (current_token != KWD_END) + { + add_error_message(203, "end", YYTEXT_STRING); + } + else + current_token = yylex(); + + break; + } + + default: + { + if ((inside_interface_part) + && ( (current_token == KWD_IMPLEMENTATION) + || (current_token == KWD_INITIALIZATION) + || (current_token == KWD_FINALIZATION) + || (current_token == KWD_END) + )) + { + return current_block; + } + + if ((inside_implementation_part) + && ( (current_token == KWD_INITIALIZATION) + || (current_token == KWD_FINALIZATION) + || (current_token == KWD_END) + )) + { + return current_block; + } + + + add_error_message(204, YYTEXT_STRING, ""); + + /* Error-recovery: find any of the following: + CONST, TYPE, VAR, PROCEDURE, FUNCTION, BEGIN, ., EOF + */ + while ( (current_token != KWD_CONST) + && (current_token != KWD_TYPE) + && (current_token != KWD_VAR) + && (current_token != KWD_PROCEDURE) + && (current_token != KWD_FUNCTION) + && (current_token != KWD_BEGIN) + && (current_token != DOT) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + break; + } + } + + return current_block; +} + + +/* + Constant declarations, the grammar rule used is: + + -> ( IDN = CONST ; )+ +*/ +void RD_const_declaration(block *current_block) +{ + int first_pass = 1; + string *constant_name; + + do + { + if (first_pass) + first_pass = 0; + else + current_token = yylex(); + + if (current_token != IDENTIFIER) + { + break; + } + + if (!block_check_name(current_block, YYTEXT_STRING)) + { + add_error_message(400, YYTEXT_STRING, ""); + } + + constant_name = string_from_cstr(YYTEXT_STRING); + + current_token = yylex(); + + if (current_token != OP_EQUAL) + { + add_error_message(200, "=", YYTEXT_STRING); + + /* Error-recovery: find the first SEMI_COLON */ + while ((current_token != SEMI_COLON) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + if (current_token == END_OF_INPUT) + { + add_error_message(207, "", ""); + string_destroy(constant_name); + return; + } + + continue; + } + + current_token = yylex(); + + // j-a-s-d: quick fix to support negative integer constants + int sign_factor = 1; + if (current_token == OP_MINUS) { + sign_factor = -1; + current_token = yylex(); + if (current_token != CST_INTEGER) { + add_error_message(206, "", ""); + return; + } + } + + switch (current_token) + { + case CST_INTEGER: + { + add_integer_constant(current_block, + integer_constant*sign_factor, string_get_cstr(constant_name)); + + if (inside_interface_part) + bsf_write_integer_constant(integer_constant, string_get_cstr(constant_name)); + + current_token = yylex(); + break; + } + + case CST_REAL: + { + add_real_constant(current_block, + real_constant, string_get_cstr(constant_name)); + + if (inside_interface_part) + bsf_write_real_constant(real_constant, string_get_cstr(constant_name)); + + current_token = yylex(); + break; + } + + case CST_BOOLEAN: + { + add_boolean_constant(current_block, + boolean_constant, string_get_cstr(constant_name)); + + if (inside_interface_part) + bsf_write_boolean_constant(boolean_constant, string_get_cstr(constant_name)); + + current_token = yylex(); + break; + } + + case CST_CHAR: + { + add_char_constant(current_block, + char_constant, string_get_cstr(constant_name)); + + if (inside_interface_part) + bsf_write_char_constant(char_constant, string_get_cstr(constant_name)); + + current_token = yylex(); + break; + } + + case CST_STRING: + { + add_string_constant(current_block, + string_constant, string_get_cstr(constant_name)); + + if (inside_interface_part) + bsf_write_string_constant(string_constant, string_get_cstr(constant_name)); + + current_token = yylex(); + break; + } + + default: + { + /* TODO:: ovo nije dobro, ovdje bi mogao pisati bilo kakav + konstantni izraz */ + add_error_message(206, "", ""); + + /* Error-recovery: find the first semi-colon */ + while ( (current_token != SEMI_COLON) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + if (current_token == END_OF_INPUT) + { + add_error_message(207, "", ""); + return; + } + + break; + } + } + + string_destroy(constant_name); + + } while (current_token == SEMI_COLON); + + RD_block(current_block); +} + + +/* + Handles variable declarations field. The grammar rule used is: + + -> ( : ;)+ +*/ +void RD_var_declaration(block *current_block) +{ + string_list *identifier_list; + type *var_type; + + do + { + identifier_list = RD_identifier_list(current_block, 1); + + if (current_token != COLON) + { + add_error_message(200, ":", YYTEXT_STRING); + + /* Error-recovery: find any of the following: + CONST, TYPE, VAR, PROCEDURE, FUNCTION, BEGIN, ., EOF + */ + while ( (current_token != KWD_CONST) + && (current_token != KWD_TYPE) + && (current_token != KWD_VAR) + && (current_token != KWD_PROCEDURE) + && (current_token != KWD_FUNCTION) + && (current_token != KWD_BEGIN) + && (current_token != DOT) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + if ((current_token == END_OF_INPUT) + || (current_token == DOT)) + { + add_error_message(207, "", ""); + return; + } + + break; + } + + current_token = yylex(); + + var_type = RD_type(current_block); + + if (var_type->type_class == interval_type) + { + add_error_message(440, "", ""); + var_type->type_class = integer_type; + } + + add_variables(current_block, identifier_list, var_type); + + if (inside_interface_part) + bsf_write_variables(identifier_list, var_type); + + type_destroy(var_type); + string_list_destroy(identifier_list); + + if (current_token != SEMI_COLON) + { + add_error_message(200, ";", YYTEXT_STRING); + + /* Error-recovery: find any of the following: + CONST, TYPE, VAR, PROCEDURE, FUNCTION, BEGIN, ., EOF + */ + while ( (current_token != KWD_CONST) + && (current_token != KWD_TYPE) + && (current_token != KWD_VAR) + && (current_token != KWD_PROCEDURE) + && (current_token != KWD_FUNCTION) + && (current_token != KWD_BEGIN) + && (current_token != DOT) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + if ((current_token == END_OF_INPUT) + || (current_token == DOT)) + { + add_error_message(207, "", ""); + return; + } + + break; + } + + current_token = yylex(); + + if (((inside_implementation_part) || (inside_interface_part)) + && ( (current_token == KWD_INITIALIZATION) + || (current_token == KWD_IMPLEMENTATION) + || (current_token == KWD_INTERFACE) + || (current_token == KWD_END) + )) + { + break; + } + + } while ( (current_token != KWD_CONST) + && (current_token != KWD_TYPE) + && (current_token != KWD_VAR) + && (current_token != KWD_PROCEDURE) + && (current_token != KWD_FUNCTION) + && (current_token != KWD_BEGIN) + && (current_token != DOT) + && (current_token != END_OF_INPUT)); + + if ((current_token == END_OF_INPUT) + || (current_token == DOT)) + { + add_error_message(207, "", ""); + return; + } + + RD_block(current_block); +} + + +/* + The list of identifiers, the rule used is: + + -> IDN (, IDN)* + + param check_valid_names should be nonzero if the function + should call block_check_name() for each identifier +*/ +string_list* RD_identifier_list(block *current_block, + int check_valid_names) +{ + string_list *return_list; + string *identifier; + + return_list = string_list_create(); + + if (current_token != IDENTIFIER) + { + add_error_message(444, "", ""); + + /* Error-recovery: find the first : or EOF */ + while ((current_token != COLON) + && (current_token != DOT) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + return return_list; + } + + if ((check_valid_names) + && (!block_check_name(current_block, YYTEXT_STRING))) + { + add_error_message(400, YYTEXT_STRING, ""); + } + + identifier = string_from_cstr(YYTEXT_STRING); + string_list_append(return_list, identifier); + string_destroy(identifier); + + current_token = yylex(); + + while (current_token == COMMA) + { + current_token = yylex(); + + if (current_token != IDENTIFIER) + { + add_error_message(202, "", ""); + + /* Error-recovery: find the first : or EOF */ + while ((current_token != COLON) + && (current_token != DOT) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + return return_list; + } + + if ((check_valid_names) + && (!block_check_name(current_block, YYTEXT_STRING))) + { + add_error_message(400, YYTEXT_STRING, ""); + } + + identifier = string_from_cstr(YYTEXT_STRING); + string_list_append(return_list, identifier); + string_destroy(identifier); + + current_token = yylex(); + } + + return return_list; +} + + +/* + Handles the declaration of a new type. The grammar + rule used is: + + -> ( IDN = ; )+ +*/ +void RD_type_declaration(block *current_block) +{ + string *type_name; + type *type_type; + + do + { + if (current_token != IDENTIFIER) + { + if (((inside_implementation_part) || (inside_interface_part)) + && ( (current_token == KWD_INITIALIZATION) + || (current_token == KWD_IMPLEMENTATION) + || (current_token == KWD_INTERFACE) + || (current_token == KWD_END) + )) + { + return; + } + + add_error_message(202, "", ""); + + /* Error-recovery: find the first ; or EOF */ + while ((current_token != SEMI_COLON) + && (current_token != DOT) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + if (current_token == SEMI_COLON) + RD_block(current_block); + + return; + } + + type_name = string_from_cstr(YYTEXT_STRING); + if (!block_check_name(current_block, YYTEXT_STRING)) + add_error_message(400, YYTEXT_STRING, ""); + + current_token = yylex(); + + if (current_token != OP_EQUAL) + { + add_error_message(205, YYTEXT_STRING, ""); + + /* Error-recovery: find the first ; or EOF */ + while ((current_token != SEMI_COLON) + && (current_token != DOT) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + if (current_token == SEMI_COLON) + RD_block(current_block); + + string_destroy(type_name); + + return; + } + + current_token = yylex(); + + type_type = RD_type(current_block); + + add_type(current_block, type_name, type_type); + + if (inside_interface_part) + bsf_write_type(type_name, type_type); + + if (current_token != SEMI_COLON) + { + add_error_message(200, ";", YYTEXT_STRING); + + /* Error-recovery: find the first ; or EOF */ + while ((current_token != SEMI_COLON) + && (current_token != DOT) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + if (current_token == SEMI_COLON) + RD_block(current_block); + + return; + } + + current_token = yylex(); + } while ( (current_token != KWD_CONST) + && (current_token != KWD_TYPE) + && (current_token != KWD_VAR) + && (current_token != KWD_PROCEDURE) + && (current_token != KWD_FUNCTION) + && (current_token != KWD_BEGIN) + && (current_token != DOT) + && (current_token != END_OF_INPUT)); + + if ((current_token == END_OF_INPUT) + || (current_token == DOT)) + { + add_error_message(207, "", ""); + return; + } + + RD_block(current_block); + +} + + +/* + Handles the procedure declaration. The grammar + rule used is: + + -> IDN ; + ; +*/ +void RD_procedure_declaration(block *current_block) +{ + string *procedure_name; + block *procedure_block; + type_list *parameters; + int forward_declaration; + type *void_return_type; + int procedure_linenum = linenum; + + int old_inside_implementation = inside_implementation_part; + + inside_implementation_part = 0; + + if (!block_check_name(current_block, YYTEXT_STRING)) + { + add_error_message(400, YYTEXT_STRING, ""); + } + + procedure_name = string_from_cstr(YYTEXT_STRING); + str_currrent_routine_name = string_from_cstr(YYTEXT_STRING); + + if (current_token != IDENTIFIER) + { + add_error_message(202, "", ""); + + /* Error-recovery: find the first ; */ + while ((current_token != SEMI_COLON) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + if (current_token == END_OF_INPUT) + return; + } + else + { + current_token = yylex(); + } + + if (STRING_COMPARE(procedure_name->cstr, "run") == 0) + add_error_message(433, "", ""); + + /* create a new block for the procedure */ + procedure_block = block_create(current_block, string_duplicate(procedure_name)); + + parameters = RD_param_list(procedure_block); + + if (current_token != SEMI_COLON) + { + add_error_message(200, ";", YYTEXT_STRING); + + /* Error-recovery: do nothing */ + } + else + current_token = yylex(); + + void_return_type = type_create(); + void_return_type->type_class = void_type; + + add_procedure(current_block, procedure_name, parameters, -1, procedure_linenum); + + if (inside_interface_part) + bsf_write_procedure(procedure_name, parameters); + + forward_declaration = RD_proc_block(procedure_block, void_return_type, parameters); + + type_destroy(void_return_type); + + add_procedure(current_block, procedure_name, parameters, forward_declaration, procedure_linenum); + + if (current_token != SEMI_COLON) + { + if (inside_interface_part == 0) + add_error_message(200, ";", YYTEXT_STRING); + + /* Error-recovery: do nothing */ + } + else + current_token = yylex(); + + inside_implementation_part = old_inside_implementation; + + RD_block(current_block); +} + + +/* + Handles the function declaration. The grammar + rule used is: + + -> IDN : IDN ; + ; +*/ +void RD_function_declaration(block *current_block) +{ + string *function_name; + block *function_block; + type_list *parameters; + int forward_declaration; + type *return_type; + identifier *return_value; + int function_linenum = linenum; + + int old_inside_implementation = inside_implementation_part; + + inside_implementation_part = 0; + + if (!block_check_name(current_block, YYTEXT_STRING)) + { + add_error_message(400, YYTEXT_STRING, ""); + } + + function_name = string_from_cstr(YYTEXT_STRING); + str_currrent_routine_name = string_from_cstr(YYTEXT_STRING); + + if (current_token != IDENTIFIER) + { + add_error_message(202, "", ""); + + /* Error-recovery: find the first ; */ + while ((current_token != SEMI_COLON) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + if (current_token == END_OF_INPUT) + return; + } + else + current_token = yylex(); + + if (STRING_COMPARE(function_name->cstr, "run") == 0) + add_error_message(433, "", ""); + + /* create a new block for the function */ + function_block = block_create(current_block, string_duplicate(function_name)); + + /* parameters start at index 0, variables follow after the return value */ + function_block->next_parameter_index = 0; + function_block->next_variable_index = 0; + + parameters = RD_param_list(function_block); + + function_block->next_variable_index ++; + + if (current_token != COLON) + { + add_error_message(200, ":", YYTEXT_STRING); + } + else + current_token = yylex(); + + return_type = type_from_name(current_block, YYTEXT_STRING); + + if (return_type->type_class == error_type) + add_error_message(406, YYTEXT_STRING, ""); + + if (return_type->type_class == interval_type) + { + add_error_message(440, "", ""); + return_type->type_class = integer_type; + } + + if (current_token != IDENTIFIER) + { + add_error_message(202, "", ""); + } + else + current_token = yylex(); + + if (current_token != SEMI_COLON) + { + add_error_message(200, ";", YYTEXT_STRING); + + /* Error-recovery: do nothing */ + } + else + current_token = yylex(); + + /* initialize the return value */ + return_value = identifier_create(); + return_value->identifier_class = variable_name; + return_value->variable_index = type_list_length(parameters); + return_value->variable_type = type_duplicate(return_type); + return_value->belongs_to_program_block = 0; + if (compiling_unit == 0) + initialize_variable(function_block, return_value, NULL, 1, "M"); + else + initialize_variable(function_block, return_value, NULL, 1, string_get_cstr(str_program_name)); + + identifier_destroy(return_value); + + add_function(current_block, function_name, parameters, + return_type, -1, function_linenum); + + forward_declaration = RD_proc_block(function_block, return_type, parameters); + + add_function(current_block, function_name, parameters, + return_type, forward_declaration, function_linenum); + + if (inside_interface_part) + bsf_write_function(function_name, parameters, return_type); + + if (current_token != SEMI_COLON) + { + if (inside_interface_part == 0) + add_error_message(200, ";", YYTEXT_STRING); + + /* Error-recovery: do nothing */ + } + else + current_token = yylex(); + + inside_implementation_part = old_inside_implementation; + + RD_block(current_block); +} + + +/* + Allows forward declarations. The rule used is: + + -> forward | + + Return nonzero value if the declaration is forward + declaration. +*/ +int RD_proc_block(block *current_block, type *return_type, type_list *parameters) +{ +routine_return_type = return_type->type_class; +routine_return_parameters_length = type_list_length(parameters); +inside_routine = 1; + int forward_declaration = 0; + + if ((current_token == KWD_FORWARD) + || (inside_interface_part)) + { + forward_declaration = 1; + + if (inside_interface_part == 0) + current_token = yylex(); + + block_destroy(current_block); + } + else + { + if (inside_interface_part) + add_error_message(221, "", ""); + + RD_block(current_block); + + /* insert current_block into it's parents block list */ + if (current_block->parent_block->children_count == 0) + { + current_block->parent_block->children = (block**) mem_alloc(sizeof(block*)); + } + else + { + current_block->parent_block->children = (block**) mem_realloc(current_block->parent_block->children, + (current_block->parent_block->children_count + 1) * sizeof(block*)); + } + + current_block->parent_block->children_count ++; + + if (current_block->parent_block->children == NULL) + die(20); + + switch(return_type->type_class) + { + case void_type: + bytecode_append(current_block->code, return$); + break; + + case real_type: + usesFloat=1; + if (mathType == 1) + { + bytecode_append(current_block->code, iload$); + bytecode_append(current_block->code, type_list_length(parameters)); + bytecode_append(current_block->code, ireturn$); + } + else + { + switch(type_list_length(parameters)) + { + case 0: + bytecode_append(current_block->code, aload_0$); + break; + case 1: + bytecode_append(current_block->code, aload_1$); + break; + case 2: + bytecode_append(current_block->code, aload_2$); + break; + case 3: + bytecode_append(current_block->code, aload_3$); + break; + default: + bytecode_append(current_block->code, aload$); + bytecode_append(current_block->code, type_list_length(parameters)); + } + + bytecode_append(current_block->code, areturn$); + } + break; + + case integer_type: + case boolean_type: + case char_type: + bytecode_append(current_block->code, iload$); + bytecode_append(current_block->code, type_list_length(parameters)); + bytecode_append(current_block->code, ireturn$); + break; + + case string_type: + case array_type: + case record_type: + case image_type: + case command_type: + case stream_type: + case record_store_type: + case http_type: + switch(type_list_length(parameters)) + { + case 0: + bytecode_append(current_block->code, aload_0$); + break; + case 1: + bytecode_append(current_block->code, aload_1$); + break; + case 2: + bytecode_append(current_block->code, aload_2$); + break; + case 3: + bytecode_append(current_block->code, aload_3$); + break; + default: + bytecode_append(current_block->code, aload$); + bytecode_append(current_block->code, type_list_length(parameters)); + } + + bytecode_append(current_block->code, areturn$); + + break; + } + + current_block->parent_block->children[current_block->parent_block->children_count-1] = current_block; + } +inside_routine = 0; + return forward_declaration; +} + + +/* + Handles the declarations of parameters to a + procedure/function. The grammar rule used is: + + -> empty + | "(" [var] : [IDN.]IDN (; [var] : [IDN.]IDN )+ ")" +*/ +type_list* RD_param_list(block *current_block) +{ + type_list *parameter_list; + string_list *identifier_list; + type *parameters_type; + int is_parameter_variable; + + int i, len; + + parameter_list = type_list_create(); + + if (current_token == OPEN_BR) + { + do + { + current_token = yylex(); + + if (current_token == END_OF_INPUT) + { + add_error_message(207, "", ""); + return parameter_list; + } + + if (current_token == CLOSE_BR) + break; + + is_parameter_variable = 0; + + if (current_token == KWD_VAR) + { + is_parameter_variable = 1; + current_token = yylex(); + add_warning_message(436, "", ""); + } + + identifier_list = RD_identifier_list(current_block, 0); + + if (current_token != COLON) + { + add_error_message(200, ":", YYTEXT_STRING); + + /* Error-recovery, find the ")" */ + while (current_token != CLOSE_BR) + { + current_token = yylex(); + } + + if (current_token == END_OF_INPUT) + return parameter_list; + + break; + + } + else + current_token = yylex(); + + parameters_type = type_from_name(current_block, YYTEXT_STRING); + + if (parameters_type->type_class == error_type) + { + /* check if the name is an unit name */ + identifier *unit; + + lowercase(YYTEXT_STRING); + + unit = get_identifier(current_block, YYTEXT_STRING); + + if (unit->identifier_class == unit_name) + { + identifier *type_identifier; + + current_token = yylex(); + + if (current_token != DOT) + add_error_message(200, ".", YYTEXT_STRING); + else + current_token = yylex(); + + type_identifier = name_table_find(unit->unit_block->names, string_from_cstr(YYTEXT_STRING)); + + if (type_identifier == NULL) + add_error_message(455, YYTEXT_STRING, ""); + else + parameters_type = type_identifier->defined_type; + } + + identifier_destroy(unit); + } + + if (parameters_type->type_class == interval_type) + { + add_error_message(440, "", ""); + parameters_type->type_class = integer_type; + } + + /* add the types into parameter_list */ + len = string_list_length(identifier_list); + for(i=0; i -> ( ; )+ +*/ +void RD_block_body(block *current_block) +{ + short int first_pass = 1; + + do + { + if (first_pass) + first_pass = 0; + else + current_token = yylex(); + + RD_statement(current_block); + + } while (current_token == SEMI_COLON); +} + + +/* + The statements rule: + + -> begin end + | empty (if current_token == end || current_token == until) + | if + | case + | while + | repeat + | for + | with + | + | break +*/ +void RD_statement(block *current_block) +{ + switch (current_token) + { + case KWD_BEGIN: + { + current_token = yylex(); + RD_block_body(current_block); + + if (current_token != KWD_END) + { + add_error_message(203, "end", YYTEXT_STRING); + } + + current_token = yylex(); + + break; + } + + case KWD_END: case KWD_UNTIL: case KWD_FOREVER: + { + return; + } + + case KWD_EXIT: + { + if (inside_routine == 0) { // j-a-s-d: in the main block treat it as a Halt() + char *halt_text; + halt_text = malloc(strlen("halt") + 1); + strcpy(halt_text, "halt"); + create_std_function_code(current_block->code, halt_text); + string_destroy(halt_text); + } else switch (routine_return_type) { + case void_type: + bytecode_append(current_block->code, return$); + break; + + case real_type: + if (mathType == 1) + { + bytecode_append(current_block->code, iload$); + bytecode_append(current_block->code, routine_return_parameters_length); + bytecode_append(current_block->code, ireturn$); + } + else + { + switch(routine_return_parameters_length) + { + case 0: + bytecode_append(current_block->code, aload_0$); + break; + case 1: + bytecode_append(current_block->code, aload_1$); + break; + case 2: + bytecode_append(current_block->code, aload_2$); + break; + case 3: + bytecode_append(current_block->code, aload_3$); + break; + default: + bytecode_append(current_block->code, aload$); + bytecode_append(current_block->code, routine_return_parameters_length); + } + + bytecode_append(current_block->code, areturn$); + } + break; + + case integer_type: + case boolean_type: + case char_type: + bytecode_append(current_block->code, iload$); + bytecode_append(current_block->code, routine_return_parameters_length); + bytecode_append(current_block->code, ireturn$); + break; + + case string_type: + case array_type: + case record_type: + case image_type: + case command_type: + case stream_type: + case record_store_type: + case http_type: + switch(routine_return_parameters_length) + { + case 0: + bytecode_append(current_block->code, aload_0$); + break; + case 1: + bytecode_append(current_block->code, aload_1$); + break; + case 2: + bytecode_append(current_block->code, aload_2$); + break; + case 3: + bytecode_append(current_block->code, aload_3$); + break; + default: + bytecode_append(current_block->code, aload$); + bytecode_append(current_block->code, routine_return_parameters_length); + } + bytecode_append(current_block->code, areturn$); + break; + } + current_token = yylex(); + break; + } + case KWD_IF: + { + current_token = yylex(); + RD_if_statement(current_block); + break; + } + + case KWD_CASE: + { + current_token = yylex(); + RD_case_statement(current_block); + break; + } + + case KWD_WHILE: + { + current_token = yylex(); + RD_while_statement(current_block); + break; + } + + case KWD_REPEAT: + { + current_token = yylex(); + RD_repeat_statement(current_block); + break; + } + + case KWD_FOR: + { + current_token = yylex(); + RD_for_statement(current_block); + break; + } + + case KWD_WITH: + { + add_error_message(215, "", ""); + current_token = yylex(); + RD_with_statement(current_block); + break; + } + + case IDENTIFIER: + case KWD_RESULT: // j-a-s-d + { + RD_assignment_or_procedure_call(current_block); + break; + } + + case KWD_BREAK: + { + current_token = yylex(); + + if (inside_loop <= 0) + add_error_message(219, "", ""); + else + { + bytecode_append(current_block->code, break_stmt$); + bytecode_append_short_int(current_block->code, 0); + } + break; + } + + case KWD_BYTECODE: + { + RD_inline_body(current_block); + if (current_token != KWD_END) { + add_error_message(200, "end ", YYTEXT_STRING); + while ((current_token != SEMI_COLON) && (current_token != END_OF_INPUT)) + current_token = yylex(); + } else current_token = yylex(); + break; + } + + case KWD_INLINE: + { + add_warning_message(464, "", ""); + current_token = yylex(); + if (current_token == OPEN_BR) { + RD_inline_body(current_block); + if (current_token != CLOSE_BR) { + add_error_message(200, ") ", YYTEXT_STRING); + while ((current_token != SEMI_COLON) && (current_token != END_OF_INPUT)) + current_token = yylex(); + } else current_token = yylex(); + } else { + add_error_message(200, "(", YYTEXT_STRING); + while ((current_token != SEMI_COLON) && (current_token != END_OF_INPUT)) + current_token = yylex(); + } + break; + } + + default: + { + add_error_message(204, YYTEXT_STRING, ""); + break; + } + } +} + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////// JAVA - ASM ///////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +/* + Handles the inline statement. The grammar rule + is: + + + + +*/ +int RD_opcodes() { + if (strcmp(yytext, "nop") == 0) return 0x00; // íè÷åãî íå äåëàåò + if (strcmp(yytext, "aconst_null") == 0) return 0x01; // çàãðóçêà â ñòåê null ( ïóñòîé ññûëêè íà îáúåêò) + if (strcmp(yytext, "iconst_m1") == 0) return 0x02; // çàãðóçêà öåëî÷èñëåííîé êîíñòàíòû -1 + if (strcmp(yytext, "iconst_0") == 0) return 0x03; // çàãðóçêà öåëî÷èñëåííîé êîíñòàíòû 0} + if (strcmp(yytext, "iconst_1") == 0) return 0x04; // çàãðóçêà öåëî÷èñëåííîé êîíñòàíòû 1} + if (strcmp(yytext, "iconst_2") == 0) return 0x05; // çàãðóçêà öåëî÷èñëåííîé êîíñòàíòû 2} + if (strcmp(yytext, "iconst_3") == 0) return 0x06; // çàãðóçêà öåëî÷èñëåííîé êîíñòàíòû 3} + if (strcmp(yytext, "iconst_4") == 0) return 0x07; // çàãðóçêà öåëî÷èñëåííîé êîíñòàíòû 4} + if (strcmp(yytext, "iconst_5") == 0) return 0x08; // çàãðóçêà öåëî÷èñëåííîé êîíñòàíòû 5} + if (strcmp(yytext, "lconst_0") == 0) return 0x09; // çàãðóçêà äëèííîé öåëî÷èñëåííîé êîíñòàíòû 0} + if (strcmp(yytext, "lconst_1") == 0) return 0x0A; // çàãðóçêà äëèííîé öåëî÷èñëåííîé êîíñòàíòû 1} + if (strcmp(yytext, "fconst_0") == 0) return 0x0B; // çàãðóçêà âåùåñòâåííîãî ÷èñëà îäèíàðíîé òî÷íîñòè 0} + if (strcmp(yytext, "fconst_1") == 0) return 0x0C; // çàãðóçêà âåùåñòâåííîãî ÷èñëà îäèíàðíîé òî÷íîñòè 1} + if (strcmp(yytext, "fconst_2") == 0) return 0x0D; // çàãðóçêà âåùåñòâåííîãî ÷èñëà îäèíàðíîé òî÷íîñòè 2} + if (strcmp(yytext, "dconst_0") == 0) return 0x0E; // çàãðóçêà âåùåñòâåííîãî ÷èñëà äâîéíîé òî÷íîñòè 0} + if (strcmp(yytext, "dconst_1") == 0) return 0x0F; // çàãðóçêà âåùåñòâåííîãî ÷èñëà äâîéíîé òî÷íîñòè 1} + if (strcmp(yytext, "bipush") == 0) return 0x10; // [1]çàãðóçêà â ñòåê îäíîáàéòîâîãî öåëîãî ñî çíàêîì} + if (strcmp(yytext, "sipush") == 0) return 0x11; // [2+-]çàãðóçêà â ñòåê äâóõáàéòîâîãî öåëîãî ñî çíàêîì} + if (strcmp(yytext, "ldc1") == 0) return 0x12; // [1]çàãðóçêà â ñòåê ýëåìåíòà èç êîíñòàíòíîãî ïóëà} + if (strcmp(yytext, "ldc2") == 0) return 0x13; // [2]çàãðóçêà â ñòåê ýëåìåíòà èç êîíñòàíòíîãî ïóëà} + if (strcmp(yytext, "ldc2w") == 0) return 0x14; // [2]çàãðóçêà â ñòåê äëèííîãî öåëîãî èëè äâîéíîãî âåùåñòâåííîãî çíà÷åíèÿ èç êîíñòàíòíîãî ïóëà} + if (strcmp(yytext, "iload") == 0) return 0x15; // [1]çàãðóçêà öåëîãî èç ëîêàëüíîé ïåðåìåííîé} + if (strcmp(yytext, "lload") == 0) return 0x16; // [1]çàãðóçêà äëèííîãî öåëîãî èç ëîêàëüíîé ïåðåìåííîé} + if (strcmp(yytext, "fload") == 0) return 0x17; // [1]çàãðóçêà âåùåñòâåííîãî îäèíàðíîé òî÷íîñòè èç ëîêàëüíîé ïåðåìåííîé} + if (strcmp(yytext, "dload") == 0) return 0x18; // [1]çàãðóçêà âåùåñòâåííîãî äâîéíîé òî÷íîñòè èç ëîêàëüíîé ïåðåìåííîé} + if (strcmp(yytext, "aload") == 0) return 0x19; // [1]çàãðóçêà îáúåêòíîé ññûëêè èç ëîêàëüíîé ïåðåìåííîé} + if (strcmp(yytext, "iload_0") == 0) return 0x1A; // çàãðóçêà öåëîãî èç ëîêàëüíîé ïåðåìåííîé 0} + if (strcmp(yytext, "iload_1") == 0) return 0x1B; // çàãðóçêà öåëîãî èç ëîêàëüíîé ïåðåìåííîé 1} + if (strcmp(yytext, "iload_2") == 0) return 0x1C; // çàãðóçêà öåëîãî èç ëîêàëüíîé ïåðåìåííîé 2} + if (strcmp(yytext, "iload_3") == 0) return 0x1D; // çàãðóçêà öåëîãî èç ëîêàëüíîé ïåðåìåííîé 3} + if (strcmp(yytext, "lload_0") == 0) return 0x1E; // çàãðóçêà äëèííîãî öåëîãî èç ëîêàëüíîé ïåðåìåííîé 0} + if (strcmp(yytext, "lload_1") == 0) return 0x1F; // çàãðóçêà äëèííîãî öåëîãî èç ëîêàëüíîé ïåðåìåííîé 1} + if (strcmp(yytext, "lload_2") == 0) return 0x20; // çàãðóçêà äëèííîãî öåëîãî èç ëîêàëüíîé ïåðåìåííîé 2} + if (strcmp(yytext, "lload_3") == 0) return 0x21; // çàãðóçêà äëèííîãî öåëîãî èç ëîêàëüíîé ïåðåìåííîé 3} + if (strcmp(yytext, "fload_0") == 0) return 0x22; // çàãðóçêà âåùåñòâåííîãî îäèíàðíîé òî÷íîñòè èç ëîêàëüíîé ïåðåìåííîé 0} + if (strcmp(yytext, "fload_1") == 0) return 0x23; // çàãðóçêà âåùåñòâåííîãî îäèíàðíîé òî÷íîñòè èç ëîêàëüíîé ïåðåìåííîé 1} + if (strcmp(yytext, "fload_2") == 0) return 0x24; // çàãðóçêà âåùåñòâåííîãî îäèíàðíîé òî÷íîñòè èç ëîêàëüíîé ïåðåìåííîé 2} + if (strcmp(yytext, "fload_3") == 0) return 0x25; // çàãðóçêà âåùåñòâåííîãî îäèíàðíîé òî÷íîñòè èç ëîêàëüíîé ïåðåìåííîé 3} + if (strcmp(yytext, "dload_0") == 0) return 0x26; // çàãðóçêà âåùåñòâåííîãî äâîéíîé òî÷íîñòè èç ëîêàëüíîé ïåðåìåííîé 0} + if (strcmp(yytext, "dload_1") == 0) return 0x27; // çàãðóçêà âåùåñòâåííîãî äâîéíîé òî÷íîñòè èç ëîêàëüíîé ïåðåìåííîé 1} + if (strcmp(yytext, "dload_2") == 0) return 0x28; // çàãðóçêà âåùåñòâåííîãî äâîéíîé òî÷íîñòè èç ëîêàëüíîé ïåðåìåííîé 2} + if (strcmp(yytext, "dload_3") == 0) return 0x29; // çàãðóçêà âåùåñòâåííîãî äâîéíîé òî÷íîñòè èç ëîêàëüíîé ïåðåìåííîé 3} + if (strcmp(yytext, "aload_0") == 0) return 0x2A; // çàãðóçêà îáúåêòíîé ññûëêè èç ëîêàëüíîé ïåðåìåííîé 0} + if (strcmp(yytext, "aload_1") == 0) return 0x2B; // çàãðóçêà îáúåêòíîé ññûëêè èç ëîêàëüíîé ïåðåìåííîé 1} + if (strcmp(yytext, "aload_2") == 0) return 0x2C; // çàãðóçêà îáúåêòíîé ññûëêè èç ëîêàëüíîé ïåðåìåííîé 2} + if (strcmp(yytext, "aload_3") == 0) return 0x2D; // çàãðóçêà îáúåêòíîé ññûëêè èç ëîêàëüíîé ïåðåìåííîé 3} + if (strcmp(yytext, "iaload") == 0) return 0x2E; // çàãðóçêà öåëîãî èç ìàññèâà} + if (strcmp(yytext, "laload") == 0) return 0x2F; // çàãðóçêà äëèííîãî öåëîãî èç ìàññèâà} + if (strcmp(yytext, "faload") == 0) return 0x30; // çàãðóçêà âåùåñòâåííîãî èç ìàññèâà} + if (strcmp(yytext, "daload") == 0) return 0x31; // çàãðóçêà äâîéíîãî âåùåñòâåííîãî èç ìàññèâà} + if (strcmp(yytext, "aaload") == 0) return 0x32; // çàãðóçêà îáúåêòíîé ññûëêè èç ìàññèâà} + if (strcmp(yytext, "baload") == 0) return 0x33; // çàãðóçêà áàéòà ñî çíàêîì èç ìàññèâà} + if (strcmp(yytext, "caload") == 0) return 0x34; // çàãðóçêà ñèìâîëà èç ìàññèâà} + if (strcmp(yytext, "saload") == 0) return 0x35; // çàãðóçêà êîðîòêîãî èç ìàññèâà} + if (strcmp(yytext, "istore") == 0) return 0x36; // [1]ñîõðàíåíèå öåëîãî çíà÷åíèÿ â ëîêàëüíîé ïåðåìåííîé} + if (strcmp(yytext, "lstore") == 0) return 0x37; // [1]ñîõðàíåíèå äëèííîãî öåëîãî â ëîêàëüíîé ïåðåìåííîé} + if (strcmp(yytext, "fstore") == 0) return 0x38; // [1]ñîõðàíåíèå âåùåñòâåííîãî îäèíàðíîé òî÷íîñòè â ëîêàëüíîé ïåðåìåííîé} + if (strcmp(yytext, "dstore") == 0) return 0x39; // [1]ñîõðàíåíèå äâîéíîãî âåùåñòâåííîãî â ëîêàëüíîé ïåðåìåííîé} + if (strcmp(yytext, "astore") == 0) return 0x3A; // [1]ñîõðàíåíèå îáúåêòíîé ññûëêè â ëîêàëüíîé ïåðåìåííîé} + if (strcmp(yytext, "istore_0") == 0) return 0x3B; // ñîõðàíåíèå öåëîãî â ëîêàëüíîé ïåðåìåííîé 0} + if (strcmp(yytext, "istore_1") == 0) return 0x3C; // ñîõðàíåíèå öåëîãî â ëîêàëüíîé ïåðåìåííîé 1} + if (strcmp(yytext, "istore_2") == 0) return 0x3D; // ñîõðàíåíèå öåëîãî â ëîêàëüíîé ïåðåìåííîé 2} + if (strcmp(yytext, "istore_3") == 0) return 0x3E; // ñîõðàíåíèå öåëîãî â ëîêàëüíîé ïåðåìåííîé 3} + if (strcmp(yytext, "lstore_0") == 0) return 0x3F; // ñîõðàíåíèå äëèííîãî öåëîãî â ëîêàëüíîé ïåðåìåííîé 0} + if (strcmp(yytext, "lstore_1") == 0) return 0x40; // ñîõðàíåíèå äëèííîãî öåëîãî â ëîêàëüíîé ïåðåìåííîé 1} + if (strcmp(yytext, "lstore_2") == 0) return 0x41; // ñîõðàíåíèå äëèííîãî öåëîãî â ëîêàëüíîé ïåðåìåííîé 2} + if (strcmp(yytext, "lstore_3") == 0) return 0x42; // ñîõðàíåíèå äëèííîãî öåëîãî â ëîêàëüíîé ïåðåìåííîé 3} + if (strcmp(yytext, "fstore_0") == 0) return 0x43; // ñîõðàíåíèå âåùåñòâåííîãî îäèíàðíîé òî÷íîñòè â ëîêàëüíîé ïåðåìåííîé 0} + if (strcmp(yytext, "fstore_1") == 0) return 0x44; // ñîõðàíåíèå âåùåñòâåííîãî îäèíàðíîé òî÷íîñòè â ëîêàëüíîé ïåðåìåííîé 1} + if (strcmp(yytext, "fstore_2") == 0) return 0x45; // ñîõðàíåíèå âåùåñòâåííîãî îäèíàðíîé òî÷íîñòè â ëîêàëüíîé ïåðåìåííîé 2} + if (strcmp(yytext, "fstore_3") == 0) return 0x46; // ñîõðàíåíèå âåùåñòâåííîãî îäèíàðíîé òî÷íîñòè â ëîêàëüíîé ïåðåìåííîé 3} + if (strcmp(yytext, "dstore_0") == 0) return 0x47; // ñîõðàíåíèå äâîéíîãî âåùåñòâåííîãî â ëîêàëüíîé ïåðåìåííîé 0} + if (strcmp(yytext, "dstore_1") == 0) return 0x48; // ñîõðàíåíèå äâîéíîãî âåùåñòâåííîãî â ëîêàëüíîé ïåðåìåííîé 1} + if (strcmp(yytext, "dstore_2") == 0) return 0x49; // ñîõðàíåíèå äâîéíîãî âåùåñòâåííîãî â ëîêàëüíîé ïåðåìåííîé 2} + if (strcmp(yytext, "dstore_3") == 0) return 0x4A; // ñîõðàíåíèå äâîéíîãî âåùåñòâåííîãî â ëîêàëüíîé ïåðåìåííîé 3} + if (strcmp(yytext, "astore_0") == 0) return 0x4B; // ñîõðàíåíèå îáúåêòíîé ññûëêè â ëîêàëüíîé ïåðåìåííîé 0} + if (strcmp(yytext, "astore_1") == 0) return 0x4C; // ñîõðàíåíèå îáúåêòíîé ññûëêè â ëîêàëüíîé ïåðåìåííîé 1} + if (strcmp(yytext, "astore_2") == 0) return 0x4D; // ñîõðàíåíèå îáúåêòíîé ññûëêè â ëîêàëüíîé ïåðåìåííîé 2} + if (strcmp(yytext, "astore_3") == 0) return 0x4E; // ñîõðàíåíèå îáúåêòíîé ññûëêè â ëîêàëüíîé ïåðåìåííîé 3} + if (strcmp(yytext, "iastore") == 0) return 0x4F; // ñîõðàíåíèå â öåëî÷èñëåííîì ìàññèâå} + if (strcmp(yytext, "lastore") == 0) return 0x50; // ñîõðàíåíèå â ìàññèâå èç äëèííûõ öåëûõ} + if (strcmp(yytext, "fastore") == 0) return 0x51; // ñîõðàíåíèå â ìàññèâå èç îäèíàðíûõ âåùåñòâåííûõ} + if (strcmp(yytext, "dastore") == 0) return 0x52; // ñîõðàíåíèå â ìàññèâå èç äâîéíûõ âåùåñòâåííûõ} + if (strcmp(yytext, "aastore") == 0) return 0x53; // ñîõðàíåíèå â ìàññèâå èç îáúåêòíûõ ññûëîê} + if (strcmp(yytext, "bastore") == 0) return 0x54; // ñîõðàíåíèå â ìàññèâå áàéòîâ ñî çíàêîì} + if (strcmp(yytext, "castore") == 0) return 0x55; // ñîõðàíåíèå â ñèìâîëüíîì ìàññèâå} + if (strcmp(yytext, "sastore") == 0) return 0x56; // ñîõðàíåíèå â ìàññèâå èç êîðîòêèõ öåëûõ} + if (strcmp(yytext, "pop") == 0) return 0x57; // èçâëå÷åíèå ñëîâà ñ âåðøèíû ñòåêà} + if (strcmp(yytext, "pop2") == 0) return 0x58; // èçâëå÷åíèå äâóõ ñëîâ ñ âåðøèíû ñòåêà} + if (strcmp(yytext, "dup") == 0) return 0x59; // äóáëèðîâàíèå ñëîâà íà âåðøèíå ñòåêà} + if (strcmp(yytext, "dup_x1") == 0) return 0x5A; // äóáëèðîâàíèå ñëîâî íà âåðøèíå ñòåêà è ïîìåùåíèå êîïèè â ñòåê íà äâà ñëîâà íèæå} + if (strcmp(yytext, "dup_x2") == 0) return 0x5B; // äóáëèðîâàíèå âåðøèíû ñòåêà è ïîìåùåíèå êîïèè íà òðè ñëîâà íèæå} + if (strcmp(yytext, "dup2") == 0) return 0x5C; // äóáëèðîâàíèå äâóõ ñëîâ íà âåðøèíå ñòåêà} + if (strcmp(yytext, "dup2_x1") == 0) return 0x5D; // äóáëèðîâàíèå äâóõ ñëîâ íà âåðøèíå ñòåêà è ïîìåùåíèå êîïèé íà äâà ñëîâà íèæå} + if (strcmp(yytext, "dup2_x2") == 0) return 0x5E; // äóáëèðîâàíèå äâóõ ñëîâ íà âåðøèíå ñòåêà è ïîìåùåíèå êîïèé íà òðè ñëîâà íèæå} + if (strcmp(yytext, "swap") == 0) return 0x5F; // îáìåí äâóõ ñëîâ íà âåðøèíå ñòåêà} + if (strcmp(yytext, "iadd") == 0) return 0x60; // ñëîæåíèå öåëûõ} + if (strcmp(yytext, "ladd") == 0) return 0x61; // ñëîæåíèå äëèííûõ öåëûõ} + if (strcmp(yytext, "fadd") == 0) return 0x62; // ñëîæåíèå îäèíàðíûõ âåùåñòâåííûõ} + if (strcmp(yytext, "dadd") == 0) return 0x63; // ñëîæåíèå äâîéíûõ âåùåñòâåííûõ} + if (strcmp(yytext, "isub") == 0) return 0x64; // âû÷èòàíèå öåëûõ} + if (strcmp(yytext, "lsub") == 0) return 0x65; // âû÷èòàíèå äëèííûõ öåëûõ} + if (strcmp(yytext, "fsub") == 0) return 0x66; // âû÷èòàíèå îäèíàðíûõ âåùåñòâåííûõ} + if (strcmp(yytext, "dsub") == 0) return 0x67; // âû÷èòàíèå äâîéíûõ âåùåñòâåííûõ} + if (strcmp(yytext, "imul") == 0) return 0x68; // óìíîæåíèå öåëûõ} + if (strcmp(yytext, "lmul") == 0) return 0x69; // óìíîæåíèå äëèííûõ öåëûõ} + if (strcmp(yytext, "fmul") == 0) return 0x6A; // óìíîæåíèå îäèíàðíûõ âåùåñòâåííûõ} + if (strcmp(yytext, "dmul") == 0) return 0x6B; // óìíîæåíèå äâîéíûõ âåùåñòâåííûõ} + if (strcmp(yytext, "idiv") == 0) return 0x6C; // äåëåíèå öåëûõ} + if (strcmp(yytext, "ldiv") == 0) return 0x6D; // äåëåíèå äëèííûõ öåëûõ} + if (strcmp(yytext, "fdiv") == 0) return 0x6E; // äåëåíèå îäèíàðíûõ âåùåñòâåííûõ} + if (strcmp(yytext, "ddiv") == 0) return 0x6F; // äåëåíèå äâîéíûõ âåùåñòâåííûõ} + if (strcmp(yytext, "irem") == 0) return 0x70; // îñòàòîê îò äåëåíèÿ öåëûõ} + if (strcmp(yytext, "lrem") == 0) return 0x71; // îñòàòîê îò äåëåíèÿ äëèííûõ öåëûõ} + if (strcmp(yytext, "frem") == 0) return 0x72; // îñòàòîê îò äåëåíèÿ îäèíàðíûõ âåùåñòâåííûõ} + if (strcmp(yytext, "drem") == 0) return 0x73; // îñòàòîê îò äåëåíèÿ äâîéíûõ âåùåñòâåííûõ} + if (strcmp(yytext, "ineg") == 0) return 0x74; // îòðèöàíèå öåëîãî} + if (strcmp(yytext, "leg") == 0) return 0x75; // îòðèöàíèå äëèííîãî öåëîãî} + if (strcmp(yytext, "fneg") == 0) return 0x76; // îòðèöàíèå îäèíàðíîãî âåùåñòâåííîãî} + if (strcmp(yytext, "dneg") == 0) return 0x77; // îòðèöàíèå äâîéíîãî âåùåñòâåííîãî ÷èñëà} + if (strcmp(yytext, "ishl") == 0) return 0x78; // ñäâèã öåëîãî âëåâî} + if (strcmp(yytext, "lshl") == 0) return 0x79; // ñäâèã äëèííîãî öåëîãî âëåâî} + if (strcmp(yytext, "ishr") == 0) return 0x7A; // àðèôìåòè÷åñêèé ñäâèã öåëîãî âïðàâî} + if (strcmp(yytext, "lshr") == 0) return 0x7B; // àðèôìåòè÷åñêèé ñäâèã äëèííîãî öåëîãî âïðàâî} + if (strcmp(yytext, "iushr") == 0) return 0x7C; // ëîãè÷åñêèé ñäâèã öåëîãî âïðàâî} + if (strcmp(yytext, "lushr") == 0) return 0x7D; // ëîãè÷åñêèé ñäâèã äëèííîãî öåëîãî âïðàâî} + if (strcmp(yytext, "iand") == 0) return 0x7E; // ëîãè÷åñêîå È ñ îïåðàíäàìè öåëîãî òèïà} + if (strcmp(yytext, "land") == 0) return 0x7F; // ëîãè÷åñêîå È ñ îïåðàíäàìè äëèííîãî öåëîãî òèïà} + if (strcmp(yytext, "ior") == 0) return 0x80; // ëîãè÷åñêîå ÈËÈ ñ öåëî÷èñëåííûìè îïåðàíäàìè} + if (strcmp(yytext, "lor") == 0) return 0x81; // ëîãè÷åñêîå ÈËÈ ñ îïåðàíäàìè äëèííîãî öåëîãî òèïà} + if (strcmp(yytext, "ixor") == 0) return 0x82; // èñêëþ÷àþùåå ÈËÈ ñ öåëî÷èñëåííûìè îïåðàíäàìè} + if (strcmp(yytext, "lxor") == 0) return 0x83; // èñêëþ÷àþùåå ÈËÈ ñ îïåðàíäàìè äëèííîãî öåëîãî òèïà} + if (strcmp(yytext, "iinc") == 0) return 0x84; // [1,1+-]óâåëè÷åíèå ëîêàëüíîé ïåðåìåííîé íà êîíñòàíòó} + if (strcmp(yytext, "i2l") == 0) return 0x85; // ïðåîáðàçîâàíèå öåëîãî â äëèííîå öåëîå} + if (strcmp(yytext, "i2f") == 0) return 0x86; // öåëîå â âåùåñòâåííîå} + if (strcmp(yytext, "i2d") == 0) return 0x87; // öåëîå â äâîéíîå âåùåñòâåííîå} + if (strcmp(yytext, "l2i") == 0) return 0x88; // äëèííîå öåëîå â öåëîå} + if (strcmp(yytext, "l2f") == 0) return 0x89; // äëèííîå öåëîå â âåùåñòâåííîå} + if (strcmp(yytext, "l2d") == 0) return 0x8A; // äëèííîå öåëîå â äâîéíîå âåùåñòâåííîå} + if (strcmp(yytext, "f2i") == 0) return 0x8B; // âåùåñòâåííîå â öåëîå} + if (strcmp(yytext, "f2l") == 0) return 0x8C; // âåùåñòâåííîå â äëèííîå öåëîå} + if (strcmp(yytext, "f2d") == 0) return 0x8D; // âåùåñòâåííîå â äâîéíîå âåùåñòâåííîå} + if (strcmp(yytext, "d2i") == 0) return 0x8E; // äâîéíîå âåùåñòâåííîå â öåëîå} + if (strcmp(yytext, "d2l") == 0) return 0x8F; // äâîéíîå âåùåñòâåííîå â äëèííîå öåëîå} + if (strcmp(yytext, "d2f") == 0) return 0x90; // äâîéíîå âåùåñòâåííîå â âåùåñòâåííîå} + if (strcmp(yytext, "int2byte") == 0) return 0x91; // öåëîå â çíàêîâûé áàéò} + if (strcmp(yytext, "int2char") == 0) return 0x92; // öåëîå â ñèìâîë} + if (strcmp(yytext, "int2short") == 0) return 0x93; // öåëîå â êîðîòêîå} + if (strcmp(yytext, "lcmp") == 0) return 0x94; // ñðàâíåíèå äëèííûõ öåëûõ} + if (strcmp(yytext, "fcmpl") == 0) return 0x95; // ñðàâíåíèå âåùåñòâåííûõ îäèíàðíîé òî÷íîñòè (-1 ïðè NaN)} + if (strcmp(yytext, "fcmpg") == 0) return 0x96; // ñðàâíåíèå âåùåñòâåííûõ îäèíàðíîé òî÷íîñòè (1 ïðè NaN)} + if (strcmp(yytext, "dcmpl") == 0) return 0x97; // ñðàâíåíèå âåùåñòâåííûõ äâîéíîé òî÷íîñòè(-1 ïðè NaN)} + if (strcmp(yytext, "dcmpg") == 0) return 0x98; // ñðàâíåíèå âåùåñòâåííûõ äâîéíîé òî÷íîñòè(1 ïðè NaN)} + if (strcmp(yytext, "ifeq") == 0) return 0x99; // [2]ïåðåõîä, åñëè ðàâíî 0} + if (strcmp(yytext, "ifne") == 0) return 0x9A; // [2]ïåðåõîä, åñëè íå ðàâíî 0} + if (strcmp(yytext, "iflt") == 0) return 0x9B; // [2]ïåðåõîä, åñëè ìåíüøå 0} + if (strcmp(yytext, "ifge") == 0) return 0x9C; // [2]ïåðåõîä, åñëè áîëüøå èëè ðàâíî 0} + if (strcmp(yytext, "ifgt") == 0) return 0x9D; // [2]ïåðåõîä, åñëè áîëüøå 0} + if (strcmp(yytext, "ifle") == 0) return 0x9E; // [2]ïåðåõîä, åñëè ìåíüøå èëè ðàâíî 0} + if (strcmp(yytext, "if_icmpeq") == 0) return 0x9F; // [2]ïåðåõîä, åñëè öåëûå ðàâíû} + if (strcmp(yytext, "if_icmpne") == 0) return 0xA0; // [2]ïåðåõîä, åñëè öåëûå íå ðàâíû} + if (strcmp(yytext, "if_icmplt") == 0) return 0xA1; // [2]ïåðåõîä, åñëè öåëîå ìåíüøå 0} + if (strcmp(yytext, "if_icmpge") == 0) return 0xA2; // [2]ïåðåõîä, åñëè öåëîå áîëüøå èëè ðàâíî} + if (strcmp(yytext, "if_icmpgt") == 0) return 0xA3; // [2]ïåðåõîä, åñëè öåëîå áîëüøå 0} + if (strcmp(yytext, "if_icmple") == 0) return 0xA4; // [2]ïåðåõîä, åñëè öåëîå ìåíüøå èëè ðàâíî} + if (strcmp(yytext, "if_acmpeq") == 0) return 0xA5; // [2]ïåðåõîä, åñëè ññûëêè íà îáúåêò ðàâíû} + if (strcmp(yytext, "if_acmpne") == 0) return 0xA6; // [2]ïåðåõîä, åñëè ññûëêè íà îáúåêò íå ðàâíû} + if (strcmp(yytext, "goto") == 0) return 0xA7; // [2]ïåðåõîä íà} + if (strcmp(yytext, "jsr") == 0) return 0xA8; // [2]ïåðåõîä íà ïîäïðîãðàììó} + if (strcmp(yytext, "ret") == 0) return 0xA9; // [1]âîçâðàò èç ïîäïðîãðàììû} + if (strcmp(yytext, "tableswitch") == 0) return 0xAA; // [tbs] äîñòóï ê òàáëèöå ïåðåõîäà ïî èíäåêñó è ïåðåõîä} + if (strcmp(yytext, "lookupswitch") == 0) return 0xAB; // [lks] äîñòóï ê òàáëèöå ïåðåõîäà ïî ñðàâíåíèþ ñ êëþ÷îì è ïåðåõîä} + if (strcmp(yytext, "ireturn") == 0) return 0xAC; // âîçâðàò öåëîãî çíà÷åíèÿ ôóíêöèè} + if (strcmp(yytext, "lreturn") == 0) return 0xAD; // âîçâðàò äëèííîãî öåëîãî çíà÷åíèÿ ôóíêöèè} + if (strcmp(yytext, "freturn") == 0) return 0xAE; // âîçâðàò îäèíàðíîãî âåùåñòâåííîãî çíà÷åíèÿ ôóíêöèè} + if (strcmp(yytext, "dreturn") == 0) return 0xAF; // âîçâðàò äâîéíîãî âåùåñòâåííîãî çíà÷åíèÿ ôóíêöèè} + if (strcmp(yytext, "areturn") == 0) return 0xB0; // âîçâðàò îáúåêòíîé ññûëêè èç ôóíêöèè} + if (strcmp(yytext, "return") == 0) return 0xB1; // âîçâðàò(îïóñòîøàþùèé) èç ïðîöåäóðû} + if (strcmp(yytext, "getstatic") == 0) return 0xB2; // [2fld]ïîëó÷åíèå ñòàòè÷åñêîãî ïîëÿ êëàññà} + if (strcmp(yytext, "putstatic") == 0) return 0xB3; // [2fld]óñòàíîâêà ñòàòè÷åñêîãî ïîëÿ â êëàññå} + if (strcmp(yytext, "getfield") == 0) return 0xB4; // [2fld]ïåðåíîñ ïîëÿ èç îáúåêòà} + if (strcmp(yytext, "putfield") == 0) return 0xB5; // [2fld]óñòàíîâêà ïîëÿ â îáúåêòå} + if (strcmp(yytext, "invokevirtual") == 0) return 0xB6; // [2mtd],âûçûâàåò ìåòîä ýêçåìïëÿðà, îñíîâûâàÿñü íà òèïå âðåìåíè âûïîëíåíèÿ} + if (strcmp(yytext, "invokenonvirtual") == 0) return 0xB7; // [2mtd],âûçûâàåò ìåòîä ýêçåìïëÿðà, îñíîâûâàÿñü íà íå âèðòóàëüíîì òèïå} + if (strcmp(yytext, "invokestatic") == 0) return 0xB8; // [2mtd]âûçîâ ìåòîäà êëàññà (ñòàòè÷åñêîãî ìåòîäà)} + if (strcmp(yytext, "invokeinterface") == 0) return 0xB9; // [2,1,1]âûçûâàåò ìåòîä èíòåðôåéñà} + if (strcmp(yytext, "new") == 0) return 0xBB; // [2]ñîçäàåò íîâûé îáúåêò} + if (strcmp(yytext, "newarray") == 0) return 0xBC; // [1]atype> T_BOOLEAN=4,T_CHAR=5,T_FLOAT=6,T_DOUBLE=7,T_BYTE=8, T_SHORT=9,T_INT=9,T_LONG=11} + if (strcmp(yytext, "anewarray") == 0) return 0xBD; // [2class]îáúÿâëåíèå íîâîãî ìàññèâà èç ññûëîê íà îáúåêòû} + if (strcmp(yytext, "arraylength") == 0) return 0xBE; // âîçâðàùàåò äëèíó ìàññèâà} + if (strcmp(yytext, "athrow") == 0) return 0xBF; // ãåíåðàöèÿ îáðàáîòêè èëè îøèáêè} + if (strcmp(yytext, "checkcast") == 0) return 0xC0; // cs 2,ïðîâåðÿåò, ÷òî îáúåêò èìååò äàííûé òèï} + if (strcmp(yytext, "instanceof") == 0) return 0xC1; // [2class]îïðåäåëÿåò, èìååò ëè îáúåêò äàííûé òèï} + if (strcmp(yytext, "monitorenter") == 0) return 0xC2; // âõîä â êîíòðîëèðóåìóþ îáëàñòü êîäà} + if (strcmp(yytext, "monitorexit") == 0) return 0xC3; // âûõîä èç êîíòðîëèðóåìîé îáëàñòè êîäà} + if (strcmp(yytext, "wide") == 0) return 0xC4; // ðàñøèðåííûé èíäåêñ äëÿ äîñòóïà ê ëîêàëüíûì ïåðåìåííûì äëÿ êîìàíä çàãðóçêè, ñîõðàíåíèÿ è ïðèðàùåíè} + if (strcmp(yytext, "multianewarray") == 0) return 0xC5; // [2cp-index,1b]ðàçìåùåíèå íîâîãî ìíîãîìåðíîãî ìàññèâà} + if (strcmp(yytext, "ifnull") == 0) return 0xC6; // [2ofs]ïåðåõîä, åñëè ïóñòîé óêàçàòåëü} + if (strcmp(yytext, "ifnonnull") == 0) return 0xC7; // [2ofs]ïåðåõîä, åñëè íå ïóñòîé óêàçàòåëü} + if (strcmp(yytext, "goto_w") == 0) return 0xC8; // [4ofs]ïåðåõîä íà (ðàñøèðåííûé èíäåêñ)} + if (strcmp(yytext, "jsr_w") == 0) return 0xC9; // [4ofs]ïåðåõîä íà ïîäïðîãðàììó (ðàñøèðåííûé èíäåêñ)} + if (strcmp(yytext, "breakpoint") == 0) return 0xCA; // îñòàíîâêà è ïåðåäà÷à êîíòðîëÿ îáðàáîò÷èêó ïðåðûâàíèé} + if (strcmp(yytext, "ret_w") == 0) return 0xD1; // [2]âîçâðàò èç ïîäïðîãðàììû (ðàñøèðåííûé èíäåêñ)} + return 0xFF; + //0x10,0xBC 1b; + //0x11 2b+-; + //0x12 1b constpool-index; + //0x13 2b constpool-index(2byte-const); + //0x14 2b constpool-index(4byte-const); + //0xB2,0xB3,0xB4,0xB5 2b constpool-field; + //0xB6,0xB7,0xB8 2b constpool-method; + //0xB9 2b constpool-method; 1b; 1b; + //0xBB 2b constpool-index; + //0xC5 2b constpool-index; 1b; + //0xBD,0xC1 2b constpool-class; + //0xC0 2b constpool-string; + //0x15,0x16,0x17,0x18,0x19 1b locvar-index; + //0x36,0x37,0x38,0x39,0x3A 1b locvar-index; + //0x84 1b; 1b+-(locvar-add-const); + //0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xC6,0xC7 2b offs; + //0xC8 4b offs; + //0xC9 4b call; + //0xA8 2b call; + //0xA9 1b ret; + //0xD1 2b ret; + //0xC4 wide...; + //0xAA tableswitch...; + //0xAB loookupswitch...; + //îñòàëüíûå êîäû ïàðàìåòðîâ íå èìåþò... +} + +int cp_index_body() +{ //ðàçáîð ìîäèôèêàöèé ññûëîê íà ïàðàìåòðû êîíñòàíòíîãî ïóëà + char p1[512]; + char p2[512]; + if (current_token == IDENTIFIER) + { + if (strcmp(yytext, "int") == 0) + { + current_token = yylex(); + if (current_token == CST_INTEGER) return cp_add_integer(integer_constant); + } + else if (strcmp(yytext, "utf8") == 0) + { + current_token = yylex(); + if ((current_token == CST_STRING)||(current_token == CST_CHAR)) return cp_add_utf8(yytext); + } + else if (strcmp(yytext, "str") == 0) + { + current_token = yylex(); + if ((current_token == CST_STRING)||(current_token == CST_CHAR)) return cp_add_string(yytext); + } + else if (strcmp(yytext, "class") == 0) + { + current_token = yylex(); + if ((current_token == CST_STRING)||(current_token == CST_CHAR)) return cp_add_class(yytext); + } + else if (strcmp(yytext, "nametype") == 0) + { + current_token = yylex(); + if ((current_token == CST_STRING)||(current_token == CST_CHAR)) + { + strcpy(&p1,yytext); + current_token = yylex(); + if (current_token == COMMA) + { + current_token = yylex(); + if ((current_token == CST_STRING)||(current_token == CST_CHAR)) return cp_add_nameandtype(p1, yytext); + } + } + } else if (strcmp(yytext, "field") == 0) + { + current_token = yylex(); + if ((current_token == CST_STRING)||(current_token == CST_CHAR)) + { + strcpy(&p1,yytext); + current_token = yylex(); + if (current_token == COMMA) + { + current_token = yylex(); + if ((current_token == CST_STRING)||(current_token == CST_CHAR)) + { + strcpy(&p2,yytext); + current_token = yylex(); + if (current_token == COMMA) + { + current_token = yylex(); + if ((current_token == CST_STRING)||(current_token == CST_CHAR)) return cp_add_fieldref(p1,p2,yytext); + } + } + } + } + } + else if (strcmp(yytext, "method") == 0) + { + current_token = yylex(); + if ((current_token == CST_STRING)||(current_token == CST_CHAR)) + { + strcpy(&p1,yytext); + current_token = yylex(); + if (current_token == COMMA) + { + current_token = yylex(); + if ((current_token == CST_STRING)||(current_token == CST_CHAR)) + { + strcpy(&p2,yytext); + current_token = yylex(); + if (current_token == COMMA) + { + current_token = yylex(); + if ((current_token == CST_STRING)||(current_token == CST_CHAR)) return cp_add_methodref(p1,p2,yytext); + } + } + } + } + } + } + else if (current_token == KWD_INTERFACE) //if (strcmp(yytext, "interface") == 0) + { + current_token = yylex(); + if ((current_token == CST_STRING)||(current_token == CST_CHAR)) + { + strcpy(&p1,yytext); + current_token = yylex(); + if (current_token == COMMA) + { + current_token = yylex(); + if ((current_token == CST_STRING)||(current_token == CST_CHAR)) + { + strcpy(&p2,yytext); + current_token = yylex(); + if (current_token == COMMA) + { + current_token = yylex(); + if ((current_token == CST_STRING)||(current_token == CST_CHAR)) return cp_add_interface(p1,p2,yytext); + } + } + } + } + } + return -1; //îøèáêà ðàçáîðà ïàðàìåòðîâ +} + + +int RD_inline_offs(block *current_block, int n, int addr) +{ + current_token = yylex(); + if (current_token == CST_INTEGER) return (short)integer_constant; //NUMBER + if (current_token == COLON) //FIND LABEL + { + current_token = yylex(); + if (current_token == CST_INTEGER) + { + int i = labcount; + nam[0] = integer_constant; + if (integer_constant==111) + integer_constant=111; + len[0] = 0; + while ((nam[i] != integer_constant) || (len[i] != 0)) i--; + if (i>0) return lab[i]-addr; + //add find block + labcount++; + nam[labcount] = integer_constant; + len[labcount] = n; //offs-type: 2bytes / 4bytes + lab[labcount] = current_block->code->bytecode_pos; + return addr; //label no found + } + } + return 0; //error! +} + + +void RD_inline_body(block *current_block) +{ + int cp_index,opcode,err,addr,offs,i,j; + labcount=0; + err=0; + do { + current_token = yylex(); + if (current_token == IDENTIFIER) + { + opcode=RD_opcodes(); + bytecode_append(current_block->code, opcode); + /////// + switch (opcode) + { + case 0x10: //1byte; + case 0xBC: + case 0x15: //1b locvar-index; + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x36: //1b locvar-index; + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0xA9: //1b ret; + err=1; + current_token = yylex(); + if ((current_token == CST_INTEGER) && (integer_constant>=0) && (integer_constant<=255)) + { + bytecode_append(current_block->code, (char)integer_constant); + err=0; + } + break; + case 0x84: //1b; 1b+-(locvar-add-const); + err=1; + current_token = yylex(); + if ((current_token == CST_INTEGER) && (integer_constant>=0) && (integer_constant<=255)) + { + bytecode_append(current_block->code, (char)integer_constant); + current_token = yylex(); + if (current_token == COMMA) + { + current_token = yylex(); + if ((current_token == CST_INTEGER) && (integer_constant>=0)&&(integer_constant<=255)) + { + bytecode_append(current_block->code, (char)integer_constant); + err=0; + } + } + } + break; + case 0x11: //2b+-; + err=1; + current_token = yylex(); + if ((current_token == CST_INTEGER) && (integer_constant>=0) && (integer_constant<=65535)) + { + bytecode_append_short_int(current_block->code, (short)integer_constant); + err=0; + } + break; + case 0x99: //2b offs; + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xC6: + case 0xC7: + case 0xA8: //2b call; + case 0xD1: //2b ret; + err=1; + addr = current_block->code->bytecode_pos-1; + offs = RD_inline_offs(current_block, 2, addr); + if (offs != 0) + { + if ((offs>=-32768) && (offs<=32767)) + { + bytecode_append_short_int(current_block->code, (short)offs); + err=0; + } + } + //current_token = yylex(); + //if ((current_token == CST_INTEGER) && (integer_constant>=0) && (integer_constant<=65535)) + //{ + // bytecode_append_short_int(current_block->code, (short)integer_constant); + // err=0; + //} + break; + case 0xC8: //4b offs; + case 0xC9: //4b call; + err=1; + addr = current_block->code->bytecode_pos-1; + offs = RD_inline_offs(current_block, 4, addr); + if (offs != 0) + { + bytecode_append_long_int(current_block->code, offs); + err=0; + } + //current_token = yylex(); + //if (current_token == CST_INTEGER) + //{ + // bytecode_append_long_int(current_block->code, integer_constant); + // err=0; + //} + break; + case 0x12: //1b constpool-index; + err=1; + current_token = yylex(); + cp_index=cp_index_body(); + if ((cp_index>=0) && (cp_index<=255)) + { + bytecode_append(current_block->code, cp_index); + err=0; + } + break; + case 0xBB: //2b constpool-index; + err=1; + current_token = yylex(); + cp_index=cp_index_body(); + if (cp_index>=0) + { + bytecode_append_short_int(current_block->code, cp_index); + err=0; + } + break; + case 0xC5: //2b constpool-index; 1b; + err=1; + current_token = yylex(); + cp_index=cp_index_body(); + if (cp_index>=0) + { + bytecode_append_short_int(current_block->code, cp_index); + current_token = yylex(); + if (current_token == COMMA) + { + current_token = yylex(); + if (current_token == CST_INTEGER) + { + if ((integer_constant>=0) && (integer_constant<=255)) + { + bytecode_append(current_block->code, (char)integer_constant); + err=0; + } + } + } + } + break; + case 0xBD: //2b constpool-class; + case 0xC1: + err=1; + current_token = yylex(); + if ((current_token == IDENTIFIER) && (strcmp(yytext, "class") == 0)) + { + cp_index=cp_index_body(); + if (cp_index>=0) + { + bytecode_append_short_int(current_block->code, cp_index); + err=0; + } + } + break; + case 0xC0: //2b constpool-string; + err=1; + current_token = yylex(); + if (current_token == IDENTIFIER) //&& (strcmp(yytext, "str") == 0)) + { + cp_index=cp_index_body(); + if (cp_index>=0) + { + bytecode_append_short_int(current_block->code, cp_index); + err=0; + } + } + break; + case 0x13: //2b constpool-index(2byte-const); + case 0x14: //2b constpool-index(4byte-const); + err=1; + current_token = yylex(); + //if ((current_token == IDENTIFIER) && (strcmp(yytext, "int") == 0)) + //{ + cp_index=cp_index_body(); + if (cp_index>=0) + { + bytecode_append_short_int(current_block->code, cp_index); + err=0; + } + //} + break; + case 0xB2: //2b constpool-field; + case 0xB3: + case 0xB4: + case 0xB5: + err=1; + current_token = yylex(); + if ((current_token == IDENTIFIER) && (strcmp(yytext, "field") == 0)) + { + cp_index=cp_index_body(); + if (cp_index>=0) + { + bytecode_append_short_int(current_block->code, cp_index); + err=0; + } + } + break; + case 0xB6: //2b constpool-method; + case 0xB7: + case 0xB8: + err=1; + current_token = yylex(); + if ((current_token == IDENTIFIER) && (strcmp(yytext, "method") == 0)) + { + cp_index=cp_index_body(); + if (cp_index>=0) + { + bytecode_append_short_int(current_block->code, cp_index); + err=0; + } + } + break; + case 0xB9: //2b constpool-method; 1b; 1b; + err=1; + current_token = yylex(); + if (current_token == KWD_INTERFACE) //&& (strcmp(yytext, "interface") != 0)) + { + cp_index=cp_index_body(); + if (cp_index>=0) + { + bytecode_append_short_int(current_block->code, cp_index); + current_token = yylex(); + if (current_token == COMMA) + { + current_token = yylex(); + if (current_token == CST_INTEGER) { + if ((integer_constant>=0) && (integer_constant<=255)) + { + bytecode_append(current_block->code, (char)integer_constant); + current_token = yylex(); + if (current_token == COMMA) + { + current_token = yylex(); + if (current_token == CST_INTEGER) + { + if ((integer_constant>=0) && (integer_constant<=255)) + { + bytecode_append(current_block->code, (char)integer_constant); + err=0; + } + } + } + } + } + } + } + } + break; + case 0xAA: //tableswitch...; + { + err=1; + addr = current_block->code->bytecode_pos-1; + while (current_block->code->bytecode_pos%4!=0) //4byte-align + bytecode_append(current_block->code, 0); + offs = RD_inline_offs(current_block, 4, addr); + if (offs != 0) + { + bytecode_append_long_int(current_block->code, offs); //default-offs + current_token = yylex(); + if (current_token == COMMA) + { + current_token = yylex(); + if (current_token == CST_INTEGER) + { + bytecode_append_long_int(current_block->code, integer_constant); //low-index + i=integer_constant; + current_token = yylex(); + if (current_token == COMMA) + { + current_token = yylex(); + if (current_token == CST_INTEGER) + { + bytecode_append_long_int(current_block->code, integer_constant); //high-index Length=high-low+1 + j=integer_constant; + current_token = yylex(); + if (current_token == COMMA) + { + err=0; + for (; i<=j; i++) + { + offs = RD_inline_offs(current_block, 4, addr); + if (icode->bytecode_pos); + err=1; + break; + } + bytecode_append_long_int(current_block->code, offs); //i-offs + } + } + } + } + } + } + } + } + break; + + case 0xAB: //loookupswitch...; + { + err=1; + addr = current_block->code->bytecode_pos-1; + while (current_block->code->bytecode_pos%4!=0) //4byte-align + bytecode_append(current_block->code, 0); + offs = RD_inline_offs(current_block, 4, addr); + if (offs != 0) + { + bytecode_append_long_int(current_block->code, offs); //default-offs + current_token = yylex(); + if (current_token == COMMA) + { + current_token = yylex(); + if (current_token == CST_INTEGER) + { + bytecode_append_long_int(current_block->code, integer_constant); //length + i=integer_constant; + current_token = yylex(); + if (current_token == COMMA) + { + err=0; + for (; i>0; i--) + { + offs = 0; + current_token = yylex(); + if (current_token == CST_INTEGER) + { + bytecode_append_long_int(current_block->code, integer_constant); + offs = RD_inline_offs(current_block, 4, addr); + if (i>1) + { + current_token = yylex(); + if (current_token != COMMA) offs = 0; + } + } + if (offs == 0) //bad label + { + add_error_message(462, 0, current_block->code->bytecode_pos); + err=1; + break; + } + bytecode_append_long_int(current_block->code, offs); //i-offs + } + } + } + } + } + } + break; + /* + case 0xC4: //wide; + break; + */ + case 0xFF: + err=1; + break; + } + } + else if (current_token == CST_INTEGER) + { + if (integer_constant<=255) bytecode_append(current_block->code, (char)integer_constant); + else if (integer_constant<=65535) bytecode_append_short_int(current_block->code, (short)integer_constant); + else bytecode_append_long_int(current_block->code, integer_constant); + err=0; + } + else if (current_token == COLON) //SET LABEL + { + err=1; + current_token = yylex(); + if (current_token == CST_INTEGER) + { + nam[0]=integer_constant; + len[0]=0; + i=labcount; + while ((nam[i]!=integer_constant) || (len[i]!=0)) i--; + if (i==0) + { + labcount++; + nam[labcount] = integer_constant; + len[labcount] = 0; + lab[labcount] = current_block->code->bytecode_pos; + err=0; + } + else + { + add_error_message(461, nam[i], current_block->code->bytecode_pos); + labcount=0; + } + + } + } + else err=1; + ///////// + if (err==0) + { + current_token = yylex(); + if (current_token != SEMI_COLON) err=1; + } + } while (err==0); + //modify old label + for (i=labcount; i>0; i--) if (len[i]>0) + { + for (j=labcount; j>i; j--) if (len[j]==0) if (nam[i]==nam[j]) break; + if (j>i) + { + int k; + offs = 0; + for (k = lab[i]; kcode->bytecode[k] & 0xff); + offs = lab[j]-offs; + for (k--; k>=lab[i]; k--) + { + current_block->code->bytecode[k] = (char)offs; + offs = offs>>8; + } + } + else add_error_message(460, nam[i], lab[i]); + } +} +/////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////// END JAVA - ASM /////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// + + + + +/* + Handles the if-then-[else] statement. The grammar rule + is: + + -> then + [ else ] + +*/ +void RD_if_statement(block *current_block) +{ + type *expression_type; + long int jump_offset_position; + signed short int offset; + + expression_type = RD_expression(current_block); + + if ((expression_type->type_class != error_type) /* a simple error-recovery */ + && (expression_type->type_class != boolean_type)) + { + add_error_message(407, "boolean", ""); + } + + type_destroy(expression_type); + + if (current_token != KWD_THEN) + { + add_error_message(216, YYTEXT_STRING, ""); + } + + current_token = yylex(); + + /* generate the code */ + bytecode_append(current_block->code, ifeq$); /* branch if comparison with zero succedd */ + jump_offset_position = current_block->code->bytecode_pos; + bytecode_append(current_block->code, 0); /* the place for offset of where to jump */ + bytecode_append(current_block->code, 0); + + RD_statement(current_block); + + while (current_token == SEMI_COLON) + current_token = yylex(); + + if (current_token == KWD_ELSE) + { + /* set the address of the next instruction */ + offset = (short) (current_block->code->bytecode_pos + 4 - jump_offset_position); + current_block->code->bytecode[jump_offset_position] = (char) (offset>>8); + current_block->code->bytecode[jump_offset_position+1] = (char) offset; + + bytecode_append(current_block->code, goto$); + jump_offset_position = current_block->code->bytecode_pos; + bytecode_append(current_block->code, 0); + bytecode_append(current_block->code, 0); + + current_token = yylex(); + + RD_statement(current_block); + + /* set the adress of the next instruction */ + offset = (short) (current_block->code->bytecode_pos - jump_offset_position + 1); + current_block->code->bytecode[jump_offset_position] = (char) (offset>>8); + current_block->code->bytecode[jump_offset_position+1] = (char) offset; + } + else + { + char *yycopy; + int i; + + /* set the address of the next instruction */ + offset = (short) (current_block->code->bytecode_pos - jump_offset_position + 1); + current_block->code->bytecode[jump_offset_position] = (char) (offset>>8); + current_block->code->bytecode[jump_offset_position+1] = (char) offset; + + /* put the current token back to stream and preceed it with ';' */ + yycopy = strdup(yytext); + + for(i = strlen(yytext) - 1; i >= 0; i--) + backchar(yycopy[i]); + backchar(';'); + free(yycopy); + + current_token = yylex(); + } +} + +/* + The case-of statement. The rule used is: + + -> OF + end +*/ +void RD_case_statement(block *current_block) +{ + type *expression_type; + expression_type = RD_expression(current_block); + + add_error_message(442, "", ""); + + if ((expression_type->type_class != error_type) /* a simple error-recovery */ + && (expression_type->type_class != integer_type) + && (expression_type->type_class != char_type) + && (expression_type->type_class != string_type)) + { + add_error_message(408, "", ""); + } + + if (current_token != KWD_OF) + { + add_error_message(203, "of", YYTEXT_STRING); + } + + current_token = yylex(); + + RD_case_list(current_block, expression_type); + + if (current_token != KWD_END) + { + add_error_message(203, "end", YYTEXT_STRING); + } + + current_token = yylex(); + type_destroy(expression_type); +} + + +/* + The case expression's list. + + -> ( CONST (, CONST)* : )+ +*/ +void RD_case_list(block *current_block, type *case_type) +{ + short int first_pass = 1; + + do + { + if (first_pass) + first_pass = 0; + else + current_token = yylex(); + + switch(current_token) + { + case CST_INTEGER: + { + if (case_type->type_class != integer_type) + { + string *expected_type_name; + expected_type_name = type_get_name(case_type); + add_error_message(409, string_get_cstr(expected_type_name), "integer"); + string_destroy(expected_type_name); + } + current_token = yylex(); + break; + } + + case CST_REAL: + { + string *expected_type_name; + expected_type_name = type_get_name(case_type); + add_error_message(409, string_get_cstr(expected_type_name), "real"); + string_destroy(expected_type_name); + + current_token = yylex(); + break; + } + + case CST_BOOLEAN: + { + + string *expected_type_name; + expected_type_name = type_get_name(case_type); + add_error_message(409, string_get_cstr(expected_type_name), "boolean"); + string_destroy(expected_type_name); + + current_token = yylex(); + break; + } + + case CST_CHAR: + { + if (case_type->type_class != char_type) + { + string *expected_type_name; + expected_type_name = type_get_name(case_type); + add_error_message(409, string_get_cstr(expected_type_name), "char"); + string_destroy(expected_type_name); + } + current_token = yylex(); + break; + } + + case CST_STRING: + { + if (case_type->type_class != string_type) + { + string *expected_type_name; + expected_type_name = type_get_name(case_type); + add_error_message(409, string_get_cstr(expected_type_name), "string"); + string_destroy(expected_type_name); + } + current_token = yylex(); + break; + } + + case IDENTIFIER: + { + /* find the constant type for the given identifier */ + type *constant_type; + + constant_type = get_constant_type(current_block, YYTEXT_STRING); + + if (constant_type->type_class == error_type) + add_error_message(410, YYTEXT_STRING, ""); + else + if (!type_equal(constant_type, case_type)) + { + string *expected_type_name; + string *constant_type_name; + + expected_type_name = type_get_name(case_type); + constant_type_name = type_get_name(constant_type); + + add_error_message(409, string_get_cstr(expected_type_name), string_get_cstr(constant_type_name)); + + string_destroy(expected_type_name); + string_destroy(constant_type_name); + } + + type_destroy(constant_type); + + current_token = yylex(); + break; + } + + default: + { + add_error_message(206, "", ""); + + /* Error-recovery: find the first : */ + while ((current_token != COLON) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + if (current_token == END_OF_INPUT) + return; + + break; + } + } + + + } while (current_token == COMMA); + + current_token = yylex(); + + if (current_token != COLON) + { + add_error_message(200, ":", YYTEXT_STRING); + + /* Error-recovery: find the first : */ + while ((current_token != COLON) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + if (current_token == END_OF_INPUT) + return; + } + + current_token = yylex(); + + RD_statement(current_block); +} + + +/* + The while-do statement. + + -> do +*/ +void RD_while_statement(block *current_block) +{ + type *expression_type; + int pos1, pos2; + int jump_offset_position; + int jump_offset; + int break_pos1, break_pos2; + + pos1 = current_block->code->bytecode_pos; + + expression_type = RD_expression(current_block); + + pos2 = current_block->code->bytecode_pos; + bytecode_append(current_block->code, ifeq$); + jump_offset_position = current_block->code->bytecode_pos; + bytecode_append_short_int(current_block->code, 0); /* make place for offset value */ + + if ((expression_type->type_class != error_type) /* a simple error-recovery */ + && (expression_type->type_class != boolean_type)) + { + add_error_message(407, "boolean", ""); + } + + type_destroy(expression_type); + + if (current_token != KWD_DO) + { + add_error_message(203, "do", YYTEXT_STRING); + } + else + current_token = yylex(); + + inside_loop++; + break_pos1 = current_block->code->bytecode_pos; + RD_statement(current_block); + break_pos2 = current_block->code->bytecode_pos; + inside_loop --; + + bytecode_append(current_block->code, goto$); + bytecode_append_short_int(current_block->code, pos1 - current_block->code->bytecode_pos + 1); + + jump_offset = current_block->code->bytecode_pos - pos2; + current_block->code->bytecode[jump_offset_position] = (char)(jump_offset >> 8); + current_block->code->bytecode[jump_offset_position + 1] = (char) jump_offset; + + transform_break_stmts(current_block->code, break_pos1, break_pos2, current_block->code->bytecode_pos); +} + + +// j-a-s-d: besides +// +// current_token = yylex(); +// +// bytecode_append(current_block->code, goto$); +// bytecode_append_short_int(current_block->code, pos1 - current_block->code->bytecode_pos + 1); +// +// transform_break_stmts(current_block->code, break_pos1, break_pos2, current_block->code->bytecode_pos); +// +// is the exact implementation of forever, +// the lesser impact implementation of repeat/forever to this MP compiler seems to be an "until false" + +type* RD_forever(block *current_block) +{ + type *return_type; + return_type = type_create(); + bytecode_append(current_block->code, iconst_0$); + current_token = yylex(); + return_type->type_class = boolean_type; + return return_type; +} + +/* + The repeat-until statement. + + -> until +*/ + +void RD_repeat_statement(block *current_block) +{ + type *expression_type; + + int pos1; + int break_pos1, break_pos2; + + pos1 = current_block->code->bytecode_pos; + inside_loop ++; + break_pos1 = current_block->code->bytecode_pos; + RD_block_body(current_block); + break_pos2 = current_block->code->bytecode_pos; + inside_loop --; + + if (current_token == KWD_FOREVER) + { + expression_type = RD_forever(current_block); + } else { + if (current_token != KWD_UNTIL) + { + add_error_message(203, "until", YYTEXT_STRING); + } + + current_token = yylex(); + + expression_type = RD_expression(current_block); + } + /* generate the code */ + bytecode_append(current_block->code, ifeq$); + bytecode_append_short_int(current_block->code, pos1 - current_block->code->bytecode_pos + 1); + + if ((expression_type->type_class != error_type) /* a simple error-recovery */ + && (expression_type->type_class != boolean_type)) + { + add_error_message(407, "boolean", ""); + } + + transform_break_stmts(current_block->code, break_pos1, break_pos2, current_block->code->bytecode_pos); + + type_destroy(expression_type); +} + + + +/* + The for statement. + + -> IDN := (to | downto) + do +*/ +void RD_for_statement(block *current_block) +{ + type *iterator_type; + type *expression1_type; + type *expression2_type; + identifier *iterator; + string *iterator_name; + int is_field; + int check_bytecode_pos; + int direction; + int evaluate_pos; + int break_pos1, break_pos2; + + iterator_type = get_variable_type(current_block, YYTEXT_STRING); + iterator = get_identifier(current_block, YYTEXT_STRING); + iterator_name = string_from_cstr(YYTEXT_STRING); + + if (iterator->identifier_class == unit_name) + { + add_error_message(456, "", ""); + current_token = yylex(); + current_token = yylex(); + } + + if ((iterator_type->type_class != integer_type) + && (iterator_type->type_class != char_type)) + { + add_error_message(411, "", ""); + } + + if (current_token != IDENTIFIER) + { + add_error_message(202, "", ""); + + /* Error-recovery: find the first := */ + while ((current_token != OP_ASSIGN) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + if (current_token == END_OF_INPUT) + { + type_destroy(iterator_type); + string_destroy(iterator_name); + return; + } + } + else + current_token = yylex(); + + if (current_token != OP_ASSIGN) + { + add_error_message(209, YYTEXT_STRING, ""); + } + else + current_token = yylex(); + + expression1_type = RD_expression(current_block); + + is_field = iterator->belongs_to_program_block; + create_put_variable_bytecode(iterator, current_block->code, iterator_name->cstr, is_field); + + if (!type_equal(iterator_type, expression1_type)) + { + string *name1, *name2; + name1 = type_get_name(iterator_type); + name2 = type_get_name(expression1_type); + + add_error_message(412, string_get_cstr(name1), string_get_cstr(name2)); + + string_destroy(name1); + string_destroy(name2); + } + + switch (current_token) + { + case KWD_TO: + { + direction = 1; + current_token = yylex(); + break; + } + + case KWD_DOWNTO: + { + direction = -1; + current_token = yylex(); + break; + } + + default: + { + add_error_message(204, YYTEXT_STRING, ""); + break; + } + } + + evaluate_pos = current_block->code->bytecode_pos; + expression2_type = RD_expression(current_block); + + create_variable_bytecode(iterator, current_block->code, iterator_name->cstr, iterator->belongs_to_program_block); + + check_bytecode_pos = current_block->code->bytecode_pos; + if (direction == 1) + bytecode_append(current_block->code, if_icmplt$); + else + bytecode_append(current_block->code, if_icmpgt$); + + bytecode_append_short_int(current_block->code, 0); + + if (!type_equal(iterator_type, expression2_type)) + { + string *name1, *name2; + name1 = type_get_name(iterator_type); + name2 = type_get_name(expression2_type); + + add_error_message(412, string_get_cstr(name1), string_get_cstr(name2)); + + string_destroy(name1); + string_destroy(name2); + } + + if (current_token != KWD_DO) + { + add_error_message(203, "do", YYTEXT_STRING); + } + else + current_token = yylex(); + + inside_loop ++; + break_pos1 = current_block->code->bytecode_pos; + RD_statement(current_block); + break_pos2 = current_block->code->bytecode_pos; + inside_loop --; + + + // TODO:: moguca optimizacija za neke slucajeve sa iinc$ naredbom + create_variable_bytecode(iterator, current_block->code, iterator_name->cstr, iterator->belongs_to_program_block); + + if (direction == 1) + bytecode_append(current_block->code, iconst_1$); + else + bytecode_append(current_block->code, iconst_m1$); + + bytecode_append(current_block->code, iadd$); + + create_put_variable_bytecode(iterator, current_block->code, iterator_name->cstr, iterator->belongs_to_program_block); + + bytecode_append(current_block->code, goto$); + bytecode_append_short_int(current_block->code, evaluate_pos - current_block->code->bytecode_pos + 1); + + current_block->code->bytecode[check_bytecode_pos + 1] = (char) ((current_block->code->bytecode_pos - check_bytecode_pos)>>8); + current_block->code->bytecode[check_bytecode_pos + 2] = (char) (current_block->code->bytecode_pos - check_bytecode_pos); + + + transform_break_stmts(current_block->code, break_pos1, break_pos2, current_block->code->bytecode_pos); + + type_destroy(iterator_type); + type_destroy(expression1_type); + type_destroy(expression2_type); + string_destroy(iterator_name); +} + + +/* + Type declaration: + + -> + | [packed] array + | record + | file + | set currently unsupported !!! +*/ +type* RD_type(block *current_block) +{ + switch (current_token) + { + case KWD_PACKED: + { + add_warning_message(210, "", ""); + current_token = yylex(); + if (current_token != KWD_ARRAY) + add_error_message(203, "array", YYTEXT_STRING); + //no_break; + } + + case KWD_ARRAY: + { + current_token = yylex(); + return RD_array_declaration(current_block); + } + + case KWD_RECORD: + { + current_token = yylex(); + return RD_record_declaration(current_block); + } + + case KWD_FILE: + { + current_token = yylex(); + return RD_file_declaration(current_block); + } + + case KWD_SET: + { + type *error; + error = type_create(); + error->type_class = error_type; + add_error_message(211, "", ""); + current_token = yylex(); + RD_set_declaration(current_block); + return error; + } + + default: + { + return RD_basic_type(current_block); + break; + } + } +} + + +/* + Basic type: + + -> [IDN .] IDN + | CONST .. CONST + | "(" IDN (, IDN)* ")" enumerated types are not supported +*/ +type* RD_basic_type(block *current_block) +{ + type *return_type; + return_type = type_create(); + return_type->type_class = error_type; + + switch (current_token) + { + case IDENTIFIER: + { + identifier* name; + type *declared_type; + declared_type = type_from_name(current_block, YYTEXT_STRING); + + lowercase(YYTEXT_STRING); + + name = get_identifier(current_block, YYTEXT_STRING); + + if (name->identifier_class == unit_name) + { + identifier* type_identifier; + + current_token = yylex(); + + if (current_token != DOT) + add_error_message(200, ".", YYTEXT_STRING); + else + current_token = yylex(); + + type_identifier = name_table_find_cstr(name->unit_block->names, YYTEXT_STRING); + + if (type_identifier == NULL) + add_error_message(455, YYTEXT_STRING, ""); + else + declared_type = type_duplicate(type_identifier->defined_type); + } + + identifier_destroy(name); + + if (declared_type->type_class != error_type) + { + type_destroy(return_type); + return_type = type_duplicate(declared_type); + current_token = yylex(); + type_destroy(declared_type); + } + else + { + identifier *constant_identifier; + constant_identifier = get_constant_identifier(current_block, YYTEXT_STRING); + + type_destroy(declared_type); + + if ((constant_identifier->identifier_class == constant_name) + && ((constant_identifier->constant_type->type_class == integer_type) + || (constant_identifier->constant_type->type_class == char_type))) + { + return_type->type_class = interval_type; + return_type->interval_base_type = constant_identifier->constant_type->type_class; + + if (constant_identifier->constant_type->type_class == integer_type) + return_type->first_element = constant_identifier->constant_int_value; + else + return_type->first_element = constant_identifier->constant_int_value; + + return_type->last_element = return_type->first_element + 1; + + identifier_destroy(constant_identifier); + + current_token = yylex(); + + if (current_token != DOTDOT) + { + add_error_message(213, YYTEXT_STRING, ""); + + /* Error-recovery */ + while ((current_token != CLOSE_SQ_BR) + && (current_token != SEMI_COLON) + && (current_token != KWD_END) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + break; + } + + current_token = yylex(); + + if (current_token == IDENTIFIER) + { + constant_identifier = get_constant_identifier(current_block, YYTEXT_STRING); + + if ((constant_identifier->identifier_class != constant_name) + || (constant_identifier->constant_type->type_class != return_type->interval_base_type)) + { + add_error_message(416, "", ""); + } + else + { + if (return_type->interval_base_type == integer_type) + return_type->last_element = constant_identifier->constant_int_value; + else + return_type->last_element = constant_identifier->constant_int_value; + } + + identifier_destroy(constant_identifier); + } + else if (current_token == CST_INTEGER) + { + if (return_type->interval_base_type != integer_type) + add_error_message(416, "", ""); + + return_type->last_element = integer_constant; + } + else if (current_token == CST_CHAR) + { + if (return_type->interval_base_type != char_type) + add_error_message(416, "", ""); + + return_type->last_element = char_constant; + } + else + { + add_error_message(416, "", ""); + } + + current_token = yylex(); + + } + else + { + add_error_message(415, YYTEXT_STRING, ""); + current_token = yylex(); + identifier_destroy(constant_identifier); + } + } + + + + break; + } + + case CST_INTEGER: + case CST_CHAR: + { + return_type->type_class = interval_type; + + if (current_token == CST_INTEGER) + { + return_type->interval_base_type = integer_type; + return_type->first_element = integer_constant; + } + else + { + return_type->interval_base_type = char_type; + return_type->first_element = (long int) char_constant; + } + + return_type->last_element = return_type->first_element + 1; + + current_token = yylex(); + + if (current_token != DOTDOT) + { + add_error_message(213, YYTEXT_STRING, ""); + } + + current_token = yylex(); + + if ((current_token != IDENTIFIER) + && (current_token != CST_INTEGER) + && (current_token != CST_CHAR)) + { + add_error_message(217, "", ""); + } + else + { + if (current_token == IDENTIFIER) + { + type *constant_type; + identifier *constant_identifier; + + constant_type = get_constant_type(current_block, YYTEXT_STRING); + + if (constant_type->type_class != return_type->interval_base_type) + { + add_error_message(413, "", ""); + } + + type_destroy(constant_type); + + constant_identifier = get_constant_identifier(current_block, YYTEXT_STRING); + + if (constant_identifier->identifier_class != constant_name) + { + add_error_message(414, YYTEXT_STRING, ""); + } + else + { + if (return_type->interval_base_type == integer_type) + return_type->last_element = constant_identifier->constant_int_value; + else + return_type->last_element = constant_identifier->constant_int_value; + } + + identifier_destroy(constant_identifier); + + } + else if (current_token == CST_INTEGER) + { + return_type->last_element = integer_constant; + } + else + { + return_type->last_element = (long int) char_constant; + } + } + + current_token = yylex(); + + break; + } + + case OPEN_BR: + { + int brack_count = 1; + add_error_message(212, "", ""); + + while (brack_count > 0) + { + current_token = yylex(); + + if (current_token == OPEN_BR) + brack_count ++; + + if (current_token == CLOSE_BR) + brack_count --; + + if (current_token == END_OF_INPUT) + return return_type; + } + + current_token = yylex(); + + break; + } + + default: + { + add_error_message(204, YYTEXT_STRING, ""); + while ((current_token != CLOSE_SQ_BR) + && (current_token != SEMI_COLON) + && (current_token != END_OF_INPUT) + && (current_token != KWD_END)) + { + current_token = yylex(); + } + + break; + } + } + + return return_type; +} + + +/* + The declaration of an array. + + -> "[" ( (, )* )+ "]" of +*/ +type* RD_array_declaration(block *current_block) +{ + type *new_type; + type *dimension; + + new_type = type_create(); + new_type->type_class = array_type; + + new_type->dimensions_list = type_list_create(); + + if (current_token != OPEN_SQ_BR) + { + add_error_message(200, "[", YYTEXT_STRING); + } + + do + { + current_token = yylex(); + + dimension = RD_basic_type(current_block); + + if (dimension->type_class != interval_type) + { + add_error_message(430, "", ""); + } + + type_list_append(new_type->dimensions_list, dimension); + type_destroy(dimension); + + if ((current_token != CLOSE_SQ_BR) + && (current_token != COMMA)) + { + add_error_message(200, ",", YYTEXT_STRING); + } + + if (current_token == END_OF_INPUT) + { + add_error_message(207, "", ""); + type_destroy(new_type); + new_type = type_create(); + new_type->type_class = error_type; + return new_type; + } + + } while (current_token != CLOSE_SQ_BR); + + current_token = yylex(); + + if (current_token != KWD_OF) + { + add_error_message(203, "of", YYTEXT_STRING); + } + + current_token = yylex(); + + new_type->element_type = RD_type(current_block); + + return new_type; +} + + +/* + The declaration of a record. + + -> ":" + ( ":" )* end +*/ +type* RD_record_declaration(block *current_block) +{ + type *new_type; + string_list *identifier_list; + type *element_type; + int old_linenum, tmp; + + short int first_pass = 1; + + new_type = type_create(); + new_type->type_class = record_type; + new_type->elements_name_list = string_list_create(); + new_type->elements_type_list = type_list_create(); + new_type->unique_record_ID = next_record_ID; + + next_record_ID ++; + + do + { + if (first_pass) + first_pass = 0; + else + current_token = yylex(); + + if ((current_token == KWD_END) + || (current_token == END_OF_INPUT)) + break; + + identifier_list = RD_identifier_list(current_block, 0); + + if (current_token != COLON) + { + add_error_message(200, ":", YYTEXT_STRING); + } + + old_linenum = linenum; + current_token = yylex(); + + element_type = RD_type(current_block); + + if (element_type->type_class == interval_type) + { + add_error_message(440, "", ""); + element_type->type_class = integer_type; + } + + tmp = linenum; + linenum = old_linenum; + + type_add_record(new_type, identifier_list, element_type); + + linenum = tmp; + + string_list_destroy(identifier_list); + type_destroy(element_type); + + } while (current_token == SEMI_COLON); + + if (current_token != KWD_END) + { + add_error_message(214, YYTEXT_STRING, ""); + } + + current_token = yylex(); + + create_record_class(new_type); + + return new_type; +} + + +/* + The declaration of a file + + -> of IDN +*/ +type* RD_file_declaration(block *current_block) +{ + type *file_type; + file_type = type_create(); + file_type->type_class = error_type; + if (current_token != KWD_OF) + { + add_error_message(203, "of", YYTEXT_STRING); + } + + current_token = yylex(); +// !!!! TODO:: dodati podrsku za fajlove + current_token = yylex(); + add_error_message(435, "", ""); + return file_type; +} + + +/* + Sets are not supported yet, however, this rule is used + as an error-recovery rule if someone tries to use sets. + + -> of +*/ +void RD_set_declaration(block *current_block) +{ + current_token = yylex(); + + RD_basic_type(current_block); +} + + +/* + Handle the expressions, the relational operators. + + -> [ ] +*/ +type* RD_expression(block *current_block) +{ + int old_linenum; + int old_token; + type *type1, *type2; + + type1 = RD_sum(current_block); + + if ((current_token == OP_LESS) + || (current_token == OP_LESS_EQUAL) + || (current_token == OP_GREATER_EQUAL) + || (current_token == OP_GREATER) + || (current_token == OP_EQUAL) + || (current_token == OP_NOT_EQUAL)) + { + old_token = current_token; + current_token = yylex(); + + old_linenum = linenum; + type2 = RD_sum(current_block); + + if ((type2->type_class != integer_type) + && (type2->type_class != real_type) + && (type2->type_class != char_type) + && (type2->type_class != string_type) + && (type2->type_class != boolean_type) + && (type2->type_class != error_type) + && (type2->type_class != command_type)) + { + new_linenum=old_linenum; + add_error_message(417, "", ""); + } + else + { + int cast; + cast = type_equal_cast(type1, type2); + + if (cast == 0){ + new_linenum=old_linenum; + add_error_message(417, "", ""); + } + + /* if operands need to be casted */ + if ((type1->type_class == integer_type) + || (type2->type_class == integer_type)) + { + if (cast != 1) + { + usesFloat=1; + + if (cast == 3) + bytecode_append(current_block->code, swap$); + + if (mathType == 1) + { + bytecode_append(current_block->code, invokestatic$); + bytecode_append_short_int(current_block->code, cp_add_methodref("F", "fI", "(I)I")); + } + else + { + bytecode_append(current_block->code, new$); + bytecode_append_short_int(current_block->code, cp_add_class("Real")); + bytecode_append(current_block->code, dup_x1$); + bytecode_append(current_block->code, swap$); + bytecode_append(current_block->code, invokespecial$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "", "(I)V")); + } + + if (cast == 3) + bytecode_append(current_block->code, swap$); + } + + } + else + { + if ((cast == 2) || (cast == 3)) + { + int method_index = cp_add_methodref("java/lang/String", "valueOf", "(C)Ljava/lang/String;"); + + if (cast == 3) + bytecode_append(current_block->code, swap$); + + /* string cast */ + bytecode_append(current_block->code, invokestatic$); + bytecode_append_short_int(current_block->code, method_index); + + if (cast == 3) + bytecode_append(current_block->code, swap$); + } + } + + if (cast == 3) /* return the real type if cast happened */ + { + type *tmp; + tmp = type2; + type2 = type1; + type1 = tmp; + } + + /* create the code */ + if ((type1->type_class == integer_type) + || (type1->type_class == boolean_type) + || (type1->type_class == char_type) + || ((type1->type_class == real_type) && (mathType == 1))) + { + if (type1->type_class == real_type) + usesFloat = 1; + + switch (old_token) + { + case OP_LESS: + bytecode_append(current_block->code, if_icmplt$); + break; + case OP_LESS_EQUAL: + bytecode_append(current_block->code, if_icmple$); + break; + case OP_GREATER_EQUAL: + bytecode_append(current_block->code, if_icmpge$); + break; + case OP_GREATER: + bytecode_append(current_block->code, if_icmpgt$); + break; + case OP_EQUAL: + bytecode_append(current_block->code, if_icmpeq$); + break; + case OP_NOT_EQUAL: + bytecode_append(current_block->code, if_icmpne$); + break; + } + + /* create the rest of the jumping and setting the whatever code */ + bytecode_append_short_int(current_block->code, 7); + bytecode_append(current_block->code, iconst_0$); + bytecode_append(current_block->code, goto$); + bytecode_append_short_int(current_block->code, 4); + bytecode_append(current_block->code, iconst_m1$); + } + + if ((type1->type_class == real_type) && (mathType != 1)) + { + usesFloat = 1; + bytecode_append(current_block->code, invokevirtual$); + + switch (old_token) + { + case OP_LESS: + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "lessThan", "(LReal;)Z")); + break; + case OP_LESS_EQUAL: + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "lessEqual", "(LReal;)Z")); + break; + case OP_GREATER_EQUAL: + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "greaterEqual", "(LReal;)Z")); + break; + case OP_GREATER: + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "greaterThan", "(LReal;)Z")); + break; + case OP_EQUAL: + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "equalTo", "(LReal;)Z")); + break; + case OP_NOT_EQUAL: + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "notEqualTo", "(LReal;)Z")); + break; + } + + /* create the rest of the jumping and setting the whatever code */ + bytecode_append(current_block->code, ifne$); + bytecode_append_short_int(current_block->code, 7); + bytecode_append(current_block->code, iconst_0$); + bytecode_append(current_block->code, goto$); + bytecode_append_short_int(current_block->code, 4); + bytecode_append(current_block->code, iconst_m1$); + } + + if (type1->type_class == command_type) + { + if (old_token == OP_EQUAL) + { + bytecode_append(current_block->code, if_acmpeq$); + } + else if (old_token == OP_NOT_EQUAL) + { + bytecode_append(current_block->code, if_acmpne$); + } + else + { + new_linenum=old_linenum; + add_error_message(417, "", ""); + } + + /* create the rest of the jumping and setting the whatever code */ + bytecode_append_short_int(current_block->code, 7); + bytecode_append(current_block->code, iconst_0$); + bytecode_append(current_block->code, goto$); + bytecode_append_short_int(current_block->code, 4); + bytecode_append(current_block->code, iconst_m1$); + } + + } + + if (type1->type_class == string_type) + { + int method_index = cp_add_methodref("java/lang/String", "compareTo", "(Ljava/lang/String;)I"); + bytecode_append(current_block->code, invokevirtual$); + bytecode_append_short_int(current_block->code, method_index); + + switch (old_token) + { + case OP_LESS: + bytecode_append(current_block->code, iflt$); + break; + case OP_LESS_EQUAL: + bytecode_append(current_block->code, ifle$); + break; + case OP_GREATER_EQUAL: + bytecode_append(current_block->code, ifge$); + break; + case OP_GREATER: + bytecode_append(current_block->code, ifgt$); + break; + case OP_EQUAL: + bytecode_append(current_block->code, ifeq$); + break; + case OP_NOT_EQUAL: + bytecode_append(current_block->code, ifne$); + break; + } + + /* create the rest of the jumping and setting the whatever code */ + bytecode_append_short_int(current_block->code, 7); + bytecode_append(current_block->code, iconst_0$); + bytecode_append(current_block->code, goto$); + bytecode_append_short_int(current_block->code, 4); + bytecode_append(current_block->code, iconst_m1$); + } + + type_destroy(type2); + type_destroy(type1); + /* the type of comparison is boolean */ + type1 = type_create(); + type1->type_class = boolean_type; + } + + return type1; +} + + +/* + Handle +, -, or, xor operators. + + -> ( )* +*/ +type* RD_sum(block *current_block) +{ + int old_linenum; + int old_token; + + type *type1, *type2; + + type1 = RD_mult(current_block); + + while ((current_token == OP_PLUS) + || (current_token == OP_MINUS) + || (current_token == OP_OR) + || (current_token == OP_XOR)) + { + old_token = current_token; + + current_token = yylex(); + + old_linenum = linenum; + + type2 = RD_mult(current_block); + + if (((type2->type_class != integer_type) + && (type2->type_class != real_type) + && (type2->type_class != char_type) + && (type2->type_class != string_type) + && (type2->type_class != boolean_type) + && (type2->type_class != error_type)) + || ((type1->type_class == string_type) + && (old_token != OP_PLUS))) + { + new_linenum=old_linenum; + add_error_message(417, "", ""); + } + else + { + int cast; + + /* if first type is char, cast it to string */ + if (type1->type_class == char_type) + { + int method_index = cp_add_methodref("java/lang/String", "valueOf", "(C)Ljava/lang/String;"); + + bytecode_append(current_block->code, swap$); + bytecode_append(current_block->code, invokestatic$); + bytecode_append_short_int(current_block->code, method_index); + bytecode_append(current_block->code, swap$); + + type1->type_class = string_type; + } + + cast = type_equal_cast(type1, type2); + + if ((cast == 0) && (type1->type_class != string_type)){ + new_linenum=old_linenum; + add_error_message(417, "", ""); + } + + /* if operands need to be casted */ + if ((type1->type_class != string_type) + && (cast != 1)) + { + usesFloat=1; + + if (cast == 3) + bytecode_append(current_block->code, swap$); + + if (mathType == 1) + { + bytecode_append(current_block->code, invokestatic$); + bytecode_append_short_int(current_block->code, cp_add_methodref("F", "fI", "(I)I")); + } + else + { + bytecode_append(current_block->code, new$); + bytecode_append_short_int(current_block->code, cp_add_class("Real")); + bytecode_append(current_block->code, dup_x1$); + bytecode_append(current_block->code, swap$); + bytecode_append(current_block->code, invokespecial$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "", "(I)V")); + } + + + if (cast == 3) + bytecode_append(current_block->code, swap$); + + if (cast == 3) /* return the real type if cast happened */ + { + type *tmp; + tmp = type2; + type2 = type1; + type1 = tmp; + } + + } + } + + + if ((type1->type_class != integer_type) + && (type1->type_class != boolean_type) + && (type1->type_class != error_type) + && ((old_token == OP_OR) || (old_token == OP_XOR))) + { + new_linenum=old_linenum; + add_error_message(417, "", ""); + } + + /* create the code */ + if ((type1->type_class == integer_type) + || (type1->type_class == boolean_type) + || ((type1->type_class == real_type) && (mathType == 1))) + { + if (type1->type_class == real_type) + usesFloat = 1; + + switch (old_token) + { + case OP_PLUS: + bytecode_append(current_block->code, iadd$); + break; + case OP_MINUS: + bytecode_append(current_block->code, isub$); + break; + case OP_OR: + bytecode_append(current_block->code, ior$); + break; + case OP_XOR: + bytecode_append(current_block->code, ixor$); + break; + } + } + + if ((type1->type_class == real_type) && (mathType != 1)) + { + usesFloat = 1; + if (old_token == OP_PLUS) + { + bytecode_append(current_block->code, new$); + bytecode_append_short_int(current_block->code, cp_add_class("Real")); + bytecode_append(current_block->code, dup_x1$); + bytecode_append(current_block->code, swap$); + bytecode_append(current_block->code, invokespecial$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "", "(LReal;)V")); + + bytecode_append(current_block->code, swap$); + + bytecode_append(current_block->code, new$); + bytecode_append_short_int(current_block->code, cp_add_class("Real")); + bytecode_append(current_block->code, dup_x1$); + bytecode_append(current_block->code, swap$); + bytecode_append(current_block->code, invokespecial$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "", "(LReal;)V")); + + bytecode_append(current_block->code, dup_x1$); + bytecode_append(current_block->code, swap$); + + bytecode_append(current_block->code, invokevirtual$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "add", "(LReal;)V")); + + } + + if (old_token == OP_MINUS) + { + bytecode_append(current_block->code, new$); + bytecode_append_short_int(current_block->code, cp_add_class("Real")); + bytecode_append(current_block->code, dup_x1$); + bytecode_append(current_block->code, swap$); + bytecode_append(current_block->code, invokespecial$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "", "(LReal;)V")); + + bytecode_append(current_block->code, swap$); + + bytecode_append(current_block->code, new$); + bytecode_append_short_int(current_block->code, cp_add_class("Real")); + bytecode_append(current_block->code, dup_x1$); + bytecode_append(current_block->code, swap$); + bytecode_append(current_block->code, invokespecial$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "", "(LReal;)V")); + + bytecode_append(current_block->code, dup_x1$); + bytecode_append(current_block->code, swap$); + + bytecode_append(current_block->code, invokevirtual$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "sub", "(LReal;)V")); + + } + } + + if ((type1->type_class == string_type) + && (old_token == OP_PLUS)) + { + int class_index; + int init_index; + int append_index; + int append2_index; + int toString_index; + + if (type2->type_class == real_type) + { + usesFloat = 1; + + if (mathType == 1) + { + bytecode_append(current_block->code, invokestatic$); + bytecode_append_short_int(current_block->code, cp_add_methodref("F", "tS", "(I)Ljava/lang/String;")); + } + else + { + bytecode_append(current_block->code, invokevirtual$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "toString", "()Ljava/lang/String;")); + } + } + + class_index = cp_add_class("java/lang/StringBuffer"); + init_index = cp_add_methodref("java/lang/StringBuffer", "", "()V"); + append_index = cp_add_methodref("java/lang/StringBuffer", "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); + toString_index = cp_add_methodref("java/lang/StringBuffer", "toString", "()Ljava/lang/String;"); + + switch(type2->type_class) + { + case string_type: + case real_type: + append2_index = cp_add_methodref("java/lang/StringBuffer", "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); + break; + case integer_type: + append2_index = cp_add_methodref("java/lang/StringBuffer", "append", "(I)Ljava/lang/StringBuffer;"); + break; + case char_type: + bytecode_append(current_block->code, i2c$); + append2_index = cp_add_methodref("java/lang/StringBuffer", "append", "(C)Ljava/lang/StringBuffer;"); + break; + case boolean_type: + bytecode_append(current_block->code, i2b$); + append2_index = cp_add_methodref("java/lang/StringBuffer", "append", "(Z)Ljava/lang/StringBuffer;"); + break; + default: + add_error_message(434, "", ""); + } + + bytecode_append(current_block->code, swap$); + + /* create new string buffer */ + bytecode_append(current_block->code, new$); + bytecode_append_short_int(current_block->code, class_index); + bytecode_append(current_block->code, dup$); + bytecode_append(current_block->code, invokespecial$); + bytecode_append_short_int(current_block->code, init_index); + + /* append the first argument */ + bytecode_append(current_block->code, swap$); + bytecode_append(current_block->code, invokevirtual$); + bytecode_append_short_int(current_block->code, append_index); + + /* append the second argument */ + bytecode_append(current_block->code, swap$); + + bytecode_append(current_block->code, invokevirtual$); + bytecode_append_short_int(current_block->code, append2_index); + + /* convert StringBuffer into the String */ + bytecode_append(current_block->code, invokevirtual$); + bytecode_append_short_int(current_block->code, toString_index); + + + + type_destroy(type2); + } + + } + + return type1; +} + + +/* + Handle * / div mod and operators. + + -> ( )* +*/ +type* RD_mult(block *current_block) +{ + int old_linenum; + int old_token; + type *type1, *type2; + + type1 = RD_not(current_block); + + while ((current_token == OP_MULT) + || (current_token == OP_SLASH) + || (current_token == OP_DIV) + || (current_token == OP_MOD) + || (current_token == OP_AND) + || (current_token == OP_SHR) + || (current_token == OP_SHL) + || (current_token == OP_USHR)) + { + old_token = current_token; + + current_token = yylex(); + + old_linenum = linenum; + + type2 = RD_not(current_block); + + if ((type2->type_class != integer_type) + && (type2->type_class != real_type) + && (type2->type_class != boolean_type) + && (type2->type_class != error_type)) + { + new_linenum=old_linenum; + add_error_message(417, "", ""); + } + else + { + int cast; + cast = type_equal_cast(type1, type2); + + if (cast == 0){ + new_linenum=old_linenum; + add_error_message(417, "", ""); + } + + if (cast != 1) + { + /* if operands need to be casted */ + usesFloat=1; + + if (cast == 3) + bytecode_append(current_block->code, swap$); + + if (mathType == 1) + { + bytecode_append(current_block->code, invokestatic$); + bytecode_append_short_int(current_block->code, cp_add_methodref("F", "fI", "(I)I")); + } + else + { + bytecode_append(current_block->code, new$); + bytecode_append_short_int(current_block->code, cp_add_class("Real")); + bytecode_append(current_block->code, dup_x1$); + bytecode_append(current_block->code, swap$); + bytecode_append(current_block->code, invokespecial$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "", "(I)V")); + } + + if (cast == 3) + bytecode_append(current_block->code, swap$); + + if (cast == 3) /* return the real type if cast happened */ + { + type *tmp; + tmp = type2; + type2 = type1; + type1 = tmp; + } + } + } + + type_destroy(type2); + + if ((type1->type_class == real_type) + && (old_token != OP_MULT) + && (old_token != OP_SLASH)) + { + new_linenum=old_linenum; + add_error_message(417, "", ""); + } + + if ((type1->type_class == boolean_type) + && (old_token != OP_AND)) + { + new_linenum=old_linenum; + add_error_message(417, "", ""); + } + + /* generate the code */ + if (type1->type_class == integer_type) + { + switch(old_token) + { + case OP_MULT: + bytecode_append(current_block->code, imul$); + break; + case OP_SLASH: + case OP_DIV: + bytecode_append(current_block->code, idiv$); + break; + case OP_MOD: + bytecode_append(current_block->code, irem$); + break; + case OP_AND: + bytecode_append(current_block->code, iand$); + break; + /////////// + case OP_SHR: + bytecode_append(current_block->code, ishr$); + break; + case OP_SHL: + bytecode_append(current_block->code, ishl$); + break; + // j-a-s-d + case OP_USHR: + bytecode_append(current_block->code, iushr$); + break; + } + } + + if (type1->type_class == real_type) + { + usesFloat = 1; + switch(old_token) + { + case OP_MULT: + { + if (mathType == 1) + { + bytecode_append(current_block->code, invokestatic$); + bytecode_append_short_int(current_block->code, + cp_add_methodref("F", "M", "(II)I")); + } + else + { + bytecode_append(current_block->code, new$); + bytecode_append_short_int(current_block->code, cp_add_class("Real")); + bytecode_append(current_block->code, dup_x1$); + bytecode_append(current_block->code, swap$); + bytecode_append(current_block->code, invokespecial$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "", "(LReal;)V")); + + bytecode_append(current_block->code, swap$); + + bytecode_append(current_block->code, new$); + bytecode_append_short_int(current_block->code, cp_add_class("Real")); + bytecode_append(current_block->code, dup_x1$); + bytecode_append(current_block->code, swap$); + bytecode_append(current_block->code, invokespecial$); /// + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "", "(LReal;)V")); + + bytecode_append(current_block->code, dup_x1$); + bytecode_append(current_block->code, swap$); + + bytecode_append(current_block->code, invokevirtual$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "mul", "(LReal;)V")); + } + } + break; + case OP_SLASH: + { + if (mathType == 1) + { + bytecode_append(current_block->code, invokestatic$); + bytecode_append_short_int(current_block->code, + cp_add_methodref("F", "D", "(II)I")); + } + else + { + bytecode_append(current_block->code, new$); + bytecode_append_short_int(current_block->code, cp_add_class("Real")); + bytecode_append(current_block->code, dup_x1$); + bytecode_append(current_block->code, swap$); + bytecode_append(current_block->code, invokespecial$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "", "(LReal;)V")); + + bytecode_append(current_block->code, swap$); + + bytecode_append(current_block->code, new$); + bytecode_append_short_int(current_block->code, cp_add_class("Real")); + bytecode_append(current_block->code, dup_x1$); + bytecode_append(current_block->code, swap$); + bytecode_append(current_block->code, invokespecial$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "", "(LReal;)V")); + + bytecode_append(current_block->code, dup_x1$); + bytecode_append(current_block->code, swap$); + + bytecode_append(current_block->code, invokevirtual$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "div", "(LReal;)V")); + } + } + break; + } + } + + if ((type1->type_class == boolean_type) + && (old_token == OP_AND)) + { + bytecode_append(current_block->code, iand$); + } + } + + return type1; +} + + +/* + The not operator. + + -> [not] +*/ +type* RD_not(block *current_block) +{ + type *type1; + int is_not = 0; + int old_linenum; + + if (current_token == OP_NOT) + { + current_token = yylex(); + is_not = 1; + } + + old_linenum = linenum; + + type1 = RD_neg(current_block); + + /* generate the code */ + if (is_not) + { + bytecode_append(current_block->code, iconst_m1$); + bytecode_append(current_block->code, ixor$); + } + + if ((is_not) + && (type1->type_class != integer_type) + && (type1->type_class != boolean_type) + && (type1->type_class != error_type)) + { + new_linenum=old_linenum; + add_error_message(417, "", ""); + } + + return type1; +} + + +/* + The - sign operator. + + -> ["-"] +*/ +type* RD_neg(block *current_block) +{ + type *type1; + int is_neg = 0; + int old_linenum; + + if (current_token == OP_MINUS) + { + current_token = yylex(); + is_neg = 1; + } + + old_linenum = linenum; + + type1 = RD_value(current_block); + + /* generate the code */ + if (is_neg) + { + if ((type1->type_class == integer_type) + || ((type1->type_class == real_type) && (mathType == 1))) + bytecode_append(current_block->code, ineg$); + + if ((type1->type_class == real_type) && (mathType != 1)) + { + usesFloat = 1; + + bytecode_append(current_block->code, new$); + bytecode_append_short_int(current_block->code, cp_add_class("Real")); + bytecode_append(current_block->code, dup_x1$); + bytecode_append(current_block->code, swap$); + bytecode_append(current_block->code, invokespecial$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "", "(LReal;)V")); + bytecode_append(current_block->code, dup$); + bytecode_append(current_block->code, invokevirtual$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "neg", "()V")); + } + } + + if ((type1->type_class != real_type) + && (type1->type_class != integer_type) + && (type1->type_class != error_type) + && (is_neg)) + { + new_linenum=old_linenum; + add_error_message(417, "", ""); + } + + return type1; +} + + +/* + The expression that calls a procedure or + assigns a value to a variable. + + + + -> IDN ["[" "]" ] (. IDN ["[" "]" ])* := + -> IDN ["(" ")"] + +*/ +void RD_assignment_or_procedure_call(block *current_block) +{ + identifier *name; + string *element_name; + char *identifier_text; + + if (current_token == KWD_RESULT) { // j-a-s-d + if (inside_routine == 0) // result in main block + { + add_error_message(463, "result", ""); + current_token = yylex(); + return; + } + name = get_identifier(current_block, string_get_cstr(str_currrent_routine_name)); + element_name = str_currrent_routine_name; + if (name->identifier_class == procedure_name) // result in procedure + { + add_error_message(463, "result", ""); + current_token = yylex(); + identifier_destroy(name); + string_destroy(element_name); + return; + } + } else { + name = get_identifier(current_block, YYTEXT_STRING); + element_name = string_from_cstr(YYTEXT_STRING); + } + + procedure_linenum = linenum; + + if ((current_token != IDENTIFIER) && (current_token != KWD_RESULT)) // j-a-s-d + { + add_error_message(202, "", ""); + + /* Error-recovery: find the first ";", end, "." or <> */ + while ((current_token != SEMI_COLON) + && (current_token != DOT) + && (current_token != KWD_END) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + string_destroy(element_name); + return; + } + + + if ((name->identifier_class == none) + || (name->identifier_class == program_name) + || (name->identifier_class == constant_name) + || (name->identifier_class == type_name)) + { + + add_error_message(428, YYTEXT_STRING, ""); + current_token = yylex(); + identifier_destroy(name); + string_destroy(element_name); + return; + } + + current_token = yylex(); + + if (name->identifier_class == unit_name) + { + identifier *unit_name; + type_list *params; + if (current_token != DOT) + { + add_error_message(200, ".", YYTEXT_STRING); + while (current_token != SEMI_COLON) + current_token = yylex(); + return; + } + + current_token = yylex(); + unit_name = name_table_find(name->unit_block->names, string_from_cstr(YYTEXT_STRING)); + identifier_text = malloc(strlen(YYTEXT_STRING) + 1); + strcpy(identifier_text, YYTEXT_STRING); + string_destroy(element_name); + element_name = string_from_cstr(YYTEXT_STRING); + + if (unit_name == NULL) + { + add_error_message(453, YYTEXT_STRING, ""); + add_error_message(200, ".", YYTEXT_STRING); + while (current_token != SEMI_COLON) + current_token = yylex(); + return; + } + + name = identifier_duplicate(unit_name); + current_token = yylex(); + + if (name->identifier_class == procedure_name) + goto procedure_call; + if (name->identifier_class == variable_name) + goto variable_lvalue; + + add_error_message(457, YYTEXT_STRING, ""); + } + + + /* the name belongs to a procedure */ + if (name->identifier_class == procedure_name) + { +procedure_call: + if (name->standard_function) + { + create_std_function_prefix(current_block->code, element_name->cstr); + } + + if (type_list_length(name->parameters) == 0) + { + int br_depth = 0; + if (current_token == OPEN_BR) + { + add_error_message(419, "", ""); + br_depth = 1; + while (br_depth > 0) + { + if ((current_token == END_OF_INPUT) + || (current_token == KWD_END)) + { + identifier_destroy(name); + string_destroy(element_name); + return; + } + + current_token = yylex(); + + if (current_token == OPEN_BR) + br_depth ++; + + if (current_token == CLOSE_BR) + br_depth --; + } + + current_token = yylex(); + } + } + else + { + if (current_token != OPEN_BR) + { + add_error_message(420, "", ""); + } + else + { + int compare_result; + int old_linenum; + type_list *parameter_list; + current_token = yylex(); + + old_linenum = linenum; + + parameter_list = RD_expression_list_cast(current_block, name->parameters); + + compare_result = type_list_different_parameter_cast(parameter_list, name->parameters); + + if (compare_result == -1) { + new_linenum=old_linenum; + add_error_message(421, "", ""); + } + + if (compare_result > 0) + { + char par_num[4]; + sprintf(par_num, "%d", compare_result); + new_linenum=old_linenum; + add_error_message(422, par_num, ""); + } + + type_list_destroy(parameter_list); + + if (current_token != CLOSE_BR) + { + add_error_message(200, ")", YYTEXT_STRING); + } + else + current_token = yylex(); + } + } + + /* create the bytecode */ + if (!name->standard_function) + { + /* the procedure is user-defined */ + int methodref_index; + identifier *block_identifier; + type_list *it; + int pos; + + char* descriptor = (char*) mem_alloc(5*1024); + if (descriptor == NULL) + die(1); + descriptor[0] = '('; + + if (!name->unit_function) + { + block_identifier = name_table_find(current_block->names, element_name); + + if (block_identifier == NULL) + block_identifier = name_table_find(current_block->parent_block->names, element_name); + } + else + { + block_identifier = name; + } + + it = block_identifier->parameters; + pos = 1; + + while(it != NULL) + { + if (it->data == NULL) + break; + + get_field_descriptor(it->data, descriptor + pos); + pos = strlen(descriptor); + it = it->next; + } + + descriptor[pos] = ')'; + pos ++; + descriptor[pos] = '\0'; + + if (block_identifier->identifier_class == procedure_name) + strcat(descriptor, "V"); + else + get_field_descriptor(block_identifier->return_type, descriptor + pos); + + + lowercase(element_name->cstr); + if (name->unit_function) + { + string *full_unit_name; + + if (name->container_unit->is_library) + full_unit_name = string_from_cstr("Lib_"); + else + full_unit_name = string_create(); + string_append(full_unit_name, name->container_unit->unit_name); + methodref_index = cp_add_methodref(full_unit_name->cstr, element_name->cstr, descriptor); + string_destroy(full_unit_name); + } + else + { + if (compiling_unit == 0) + methodref_index = cp_add_methodref("M", element_name->cstr, descriptor); + else + methodref_index = cp_add_methodref(string_get_cstr(str_program_name), element_name->cstr, descriptor); + } + bytecode_append(current_block->code, invokestatic$); /* call */ + bytecode_append_short_int(current_block->code, methodref_index); + + mem_free(descriptor); + } + else + { + /* handle standard functions and procedures */ + create_std_function_code(current_block->code, element_name->cstr); + } + } + + /* if the identifier is the function name and that is not the name of the current + block, report an error */ + if (name->identifier_class == function_name) + { + if (STRING_COMPARE(element_name->cstr, current_block->block_name->cstr) != 0) + { + add_error_message(432, element_name->cstr, ""); + } + } + + /* if an identifier is a valid l-value */ + if ((name->identifier_class == variable_name) + || (name->identifier_class == parameter_name) + || (name->identifier_class == function_name)) /* function names are treated as variables for return values */ + { + type *current_type; + type *new_type; + type *expression_type; + int assign_linenum; + int is_field = 0; + bytecode *get_bytecode; + bytecode *put_bytecode; +variable_lvalue: + is_field = 0; + get_bytecode = bytecode_create(); + put_bytecode = bytecode_create(); + + if (name->identifier_class == variable_name) + current_type = type_duplicate(name->variable_type); + + if (name->identifier_class == parameter_name) + current_type = type_duplicate(name->parameter_type); + + if (name->identifier_class == function_name) + current_type = type_duplicate(name->return_type); + + /* create the get and put bytecodes */ + is_field = name->belongs_to_program_block; + + if (name->identifier_class == function_name) + is_field = 0; + + create_variable_bytecode(name, get_bytecode, element_name->cstr, is_field); + create_put_variable_bytecode(name, put_bytecode, element_name->cstr, is_field); + + identifier_destroy(name); + name = NULL; + string_destroy(element_name); + element_name = NULL; + + while (current_token != OP_ASSIGN) + { + if ((current_token == SEMI_COLON) + || (current_token == KWD_END) + || (current_token == END_OF_INPUT)) + { + add_error_message(218, "", ""); + type_destroy(current_type); + bytecode_destroy(get_bytecode); + bytecode_destroy(put_bytecode); + return; + } + + if (current_token == DOT) + { + int fieldref_index; + char record_name[15]; + char field_descriptor[128]; + + current_token = yylex(); + + /* append the old get bytecode */ + bytecode_append_bytecode(current_block->code, get_bytecode); + + /* reset the bytecodes */ + put_bytecode->bytecode_pos = 0; + get_bytecode->bytecode_pos = 0; + + if (current_type->type_class != record_type) + { + add_error_message(424, "", ""); + + /* Error-recovery */ + while ((current_token != SEMI_COLON) + && (current_token != KWD_END) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + type_destroy(current_type); + bytecode_destroy(get_bytecode); + bytecode_destroy(put_bytecode); + return; + } + + new_type = type_find_record_element(current_type, YYTEXT_STRING); + + if (new_type == NULL) + { + add_error_message(447, YYTEXT_STRING, ""); + } + else + { + /* create the new put and get bytecodes */ + sprintf(record_name, "R_%d", current_type->unique_record_ID); + get_field_descriptor(new_type, field_descriptor); + lowercase(YYTEXT_STRING); + fieldref_index = cp_add_fieldref(record_name, YYTEXT_STRING, field_descriptor); + + bytecode_append(get_bytecode, getfield$); + bytecode_append_short_int(get_bytecode, fieldref_index); + + bytecode_append(put_bytecode, putfield$); + bytecode_append_short_int(put_bytecode, fieldref_index); + + + type_destroy(current_type); + current_type = new_type; + } + + + if (current_type == NULL) + { + add_error_message(425, YYTEXT_STRING, ""); + + /* Error-recovery */ + while ((current_token != SEMI_COLON) + && (current_token != KWD_END) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + type_destroy(current_type); + bytecode_destroy(get_bytecode); + bytecode_destroy(put_bytecode); + return; + } + + current_token = yylex(); + } + else if (current_token == OPEN_SQ_BR) + { + type_list *array_elements; + bytecode *tmp_code; + tmp_code = bytecode_create(); + + // ako je [, a zadnji je array, procitaj listu, usporedi, vrati slijedeci, skoci gore + if (current_type->type_class != array_type) + { + add_error_message(426, "", ""); + + /* Error-recovery */ + while ((current_token != SEMI_COLON) + && (current_token != KWD_END) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + type_destroy(current_type); + bytecode_destroy(get_bytecode); + bytecode_destroy(put_bytecode); + return; + } + + current_token = yylex(); + + array_elements = RD_expression_list_array(current_block, tmp_code, current_type); + + bytecode_append_bytecode(get_bytecode, tmp_code); + //bytecode_append_bytecode(put_bytecode, tmp_code); + bytecode_destroy(put_bytecode); + put_bytecode = bytecode_duplicate(get_bytecode); + + replace_aaload_instruction(get_bytecode, current_type->element_type); + + /* remove the last aaload from put bytecode, adjust the stack and create the + put bytecode */ + put_bytecode->bytecode_pos --; + bytecode_append(put_bytecode, dup2_x1$); + bytecode_append(put_bytecode, pop2$); + + switch(current_type->element_type->type_class) + { + case integer_type: + case boolean_type: + case char_type: + bytecode_append(put_bytecode, iastore$); + break; + + case real_type: + if (mathType == 1) + bytecode_append(put_bytecode, iastore$); + else + bytecode_append(put_bytecode, aastore$); + break; + + + case image_type: + case string_type: + case record_type: + case command_type: + case record_store_type: + case http_type: + case alert_type: + case stream_type: + bytecode_append(put_bytecode, aastore$); + break; + + } + + bytecode_destroy(tmp_code); + + if (type_list_different_parameter_array(array_elements, current_type->dimensions_list) != 0) + { + char num1[6], num2[6]; + + sprintf(num1, "%d", type_list_length(current_type->dimensions_list)); + sprintf(num2, "%d", type_list_length(array_elements)); + add_error_message(427, num1, num2); + + /* Error-recovery */ + while ((current_token != SEMI_COLON) + && (current_token != KWD_END) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + type_destroy(current_type); + bytecode_destroy(get_bytecode); + bytecode_destroy(put_bytecode); + return; + } + + if (current_token != CLOSE_SQ_BR) + { + add_error_message(200, "]", YYTEXT_STRING); + + /* Error-recovery */ + while ((current_token != SEMI_COLON) + && (current_token != KWD_END) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + type_destroy(current_type); + bytecode_destroy(get_bytecode); + bytecode_destroy(put_bytecode); + return; + } + + current_token = yylex(); + + new_type = type_duplicate(current_type->element_type); + type_destroy(current_type); + + current_type = new_type; + + type_list_destroy(array_elements); + } + else + { + add_error_message(204, YYTEXT_STRING, ""); + + /* Error-recovery */ + while ((current_token != SEMI_COLON) + && (current_token != KWD_END) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + bytecode_destroy(get_bytecode); + bytecode_destroy(put_bytecode); + return; + } + } + + assign_linenum = linenum; + + current_token = yylex(); + + expression_type = RD_expression(current_block); + + if ((type_equal_cast(current_type, expression_type) != 1) + && (current_type->type_class == real_type)) + { + usesFloat = 1; + + if (mathType == 1) + { + bytecode_append(current_block->code, invokestatic$); + bytecode_append_short_int(current_block->code, cp_add_methodref("F", "fI", "(I)I")); + } + else + { + bytecode_append(current_block->code, new$); + bytecode_append_short_int(current_block->code, cp_add_class("Real")); + bytecode_append(current_block->code, dup_x1$); + bytecode_append(current_block->code, swap$); + bytecode_append(current_block->code, invokespecial$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "", "(I)V")); + } + } + + if ((type_equal_cast(current_type, expression_type) == 2) + && (current_type->type_class == string_type)) + { + int method_index = cp_add_methodref("java/lang/String", "valueOf", "(C)Ljava/lang/String;"); + + /* string cast */ + bytecode_append(current_block->code, invokestatic$); + bytecode_append_short_int(current_block->code, method_index); + } + + bytecode_append_bytecode(current_block->code, put_bytecode); + + if ((type_equal_cast(current_type, expression_type) != 1) + && (type_equal_cast(current_type, expression_type) != 2)) + { + new_linenum=assign_linenum; + add_error_message(423, "", ""); + } + else + if (current_type->type_class == array_type) + { + new_linenum=assign_linenum; + add_error_message(443, "", ""); + } + + + + type_destroy(expression_type); + type_destroy(current_type); + bytecode_destroy(get_bytecode); + bytecode_destroy(put_bytecode); + } + + if (name != NULL) + identifier_destroy(name); + + if (element_name != NULL) + string_destroy(element_name); +} + + +/* + The list of expressions, used when calling the function + or procedure. + + -> (, )* +*/ +type_list* RD_expression_list(block *current_block) +{ + type_list *return_list; + type *expression_type; + + return_list = type_list_create(); + + expression_type = RD_expression(current_block); + + type_list_append(return_list, expression_type); + + type_destroy(expression_type); + + while (current_token == COMMA) + { + current_token = yylex(); + + expression_type = RD_expression(current_block); + + type_list_append(return_list, expression_type); + + type_destroy(expression_type); + } + + return return_list; +} + +/* + Same as the above, only the types are casted according to the second parameter +*/ +type_list* RD_expression_list_cast(block *current_block, type_list *formal_params) +{ + type_list *return_list; + type *expression_type; + type_list *it; + + it = formal_params; + + return_list = type_list_create(); + + expression_type = RD_expression(current_block); + + if ((it != NULL) && (it->data != NULL)) + { + int cast; + + cast = type_equal_cast(it->data, expression_type); + + if ((cast == 2) && (it->data->type_class == string_type)) + { + int method_index = cp_add_methodref("java/lang/String", "valueOf", "(C)Ljava/lang/String;"); + + bytecode_append(current_block->code, invokestatic$); + bytecode_append_short_int(current_block->code, method_index); + } + + if ((cast == 2) && (it->data->type_class == real_type)) + { + usesFloat = 1; + + if (mathType == 1) + { + bytecode_append(current_block->code, invokestatic$); + bytecode_append_short_int(current_block->code, cp_add_methodref("F", "fI", "(I)I")); + } + else + { + bytecode_append(current_block->code, new$); + bytecode_append_short_int(current_block->code, cp_add_class("Real")); + bytecode_append(current_block->code, dup_x1$); + bytecode_append(current_block->code, swap$); + bytecode_append(current_block->code, invokespecial$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "", "(I)V")); + } + } + + it = it->next; + } + + type_list_append(return_list, expression_type); + + type_destroy(expression_type); + + while (current_token == COMMA) + { + current_token = yylex(); + + expression_type = RD_expression(current_block); + + if ((it != NULL) && (it->data != NULL)) + { + int cast; + + cast = type_equal_cast(it->data, expression_type); + + if ((cast == 2) && (it->data->type_class == string_type)) + { + int method_index = cp_add_methodref("java/lang/String", "valueOf", "(C)Ljava/lang/String;"); + + bytecode_append(current_block->code, invokestatic$); + bytecode_append_short_int(current_block->code, method_index); + } + + if ((cast == 2) && (it->data->type_class == real_type)) + { + usesFloat = 1; + + if (mathType == 1) + { + bytecode_append(current_block->code, invokestatic$); + bytecode_append_short_int(current_block->code, cp_add_methodref("F", "fI", "(I)I")); + } + else + { + bytecode_append(current_block->code, new$); + bytecode_append_short_int(current_block->code, cp_add_class("Real")); + bytecode_append(current_block->code, dup_x1$); + bytecode_append(current_block->code, swap$); + bytecode_append(current_block->code, invokespecial$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "", "(I)V")); + } + } + + it = it->next; + } + + type_list_append(return_list, expression_type); + + type_destroy(expression_type); + } + + return return_list; +} + +/* + Same as RD_expression_list, only aaload is generated after each element and the indices + are adjusted.For example, if array is [a..b], the a value must be substracted from the index +*/ +type_list* RD_expression_list_array(block *current_block, bytecode *code, type *array_type) +{ + type_list *return_list; + type *expression_type; + bytecode *oldBytecode; + + type_list *it; + it = array_type->dimensions_list; + + oldBytecode = current_block->code; + current_block->code = code; + + return_list = type_list_create(); + + expression_type = RD_expression(current_block); + adjust_indices(code, it->data); + + if(it != NULL) + it = it->next; + + bytecode_append(code, aaload$); + + type_list_append(return_list, expression_type); + + type_destroy(expression_type); + + while (current_token == COMMA) + { + current_token = yylex(); + + expression_type = RD_expression(current_block); + adjust_indices(code, it->data); + + if(it != NULL) + it = it->next; + bytecode_append(code, aaload$); + + type_list_append(return_list, expression_type); + + type_destroy(expression_type); + } + + current_block->code = oldBytecode; + + return return_list; +} + + +/* + The with statement, currently not supported. This + function is used as an error recovery function. + + -> IDN (. IDN)* do +*/ +void RD_with_statement(block *current_block) +{ + /* simplified parsing */ + while (current_token != KWD_DO) + { + if (current_token == END_OF_INPUT) + return; + + current_token = yylex(); + } + + current_token = yylex(); + + RD_statement(current_block); +} + + +/* + Anything that has value: constant, identifier, identifier inside + a record or a function call. + + -> CONST + | IDN [ "[" "]" ] ( . IDN [ "[" "]" ])* + | IDN [ "(" ")"] + | "(" ")" +*/ +type* RD_value(block *current_block) +{ + type *return_type; + return_type = type_create(); + + return_type->type_class = error_type; + + if (current_token == CST_INTEGER) + { + switch(integer_constant) + { + case -1: + bytecode_append(current_block->code, iconst_m1$); + break; + case 0: + bytecode_append(current_block->code, iconst_0$); + break; + case 1: + bytecode_append(current_block->code, iconst_1$); + break; + case 2: + bytecode_append(current_block->code, iconst_2$); + break; + case 3: + bytecode_append(current_block->code, iconst_3$); + break; + case 4: + bytecode_append(current_block->code, iconst_4$); + break; + case 5: + bytecode_append(current_block->code, iconst_5$); + break; + default: + { + if (abs(integer_constant) < 127) + { + bytecode_append(current_block->code, bipush$); + bytecode_append(current_block->code, (char)(integer_constant)); + } + else if (abs(integer_constant) < 16000) + { + bytecode_append(current_block->code, sipush$); + bytecode_append_short_int(current_block->code, (short)(integer_constant)); + } + else + { + int cp_index; + cp_index = cp_add_integer(integer_constant); + if (cp_index <= 255) + { + bytecode_append(current_block->code, ldc$); + bytecode_append(current_block->code, (char) cp_index); + } + else + { + bytecode_append(current_block->code, ldc_w$); + bytecode_append_short_int(current_block->code, (short) cp_index); + } + } + break; + } + } + + current_token = yylex(); + return_type->type_class = integer_type; + return return_type; + } + + if (current_token == CST_REAL) + { + float cst; + int csti; /* the integer part */ + int cstf; /* the fraction part */ + + /* calculate the exponent and the integer part */ + cst = real_constant; + + csti = (int)cst; + cstf = (cst - (int)cst)*100000; + + usesFloat = 1; + + if (mathType == 1) + { + /* put the integer part on the stack */ + if (abs(csti) < 127) + { + bytecode_append(current_block->code, bipush$); + bytecode_append(current_block->code, csti); + } + else if (abs(csti) < 15000) + { + bytecode_append(current_block->code, sipush$); + bytecode_append_short_int(current_block->code, csti); + } + else + { + bytecode_append(current_block->code, ldc_w$); + bytecode_append_short_int(current_block->code, cp_add_integer(csti)); + } + + /* put the fraction part to the stack */ + if (abs(cstf) < 127) + { + bytecode_append(current_block->code, bipush$); + bytecode_append(current_block->code, cstf); + } + else if (abs(cstf) < 15000) + { + bytecode_append(current_block->code, sipush$); + bytecode_append_short_int(current_block->code, cstf); + } + else + { + bytecode_append(current_block->code, ldc_w$); + bytecode_append_short_int(current_block->code, cp_add_integer(cstf)); + } + + bytecode_append(current_block->code, invokestatic$); + bytecode_append_short_int(current_block->code, cp_add_methodref("F", "fI", "(II)I")); + } + else + { + char number[64]; + + bytecode_append(current_block->code, new$); + bytecode_append_short_int(current_block->code, cp_add_class("Real")); + bytecode_append(current_block->code, dup$); + + sprintf(number, "%f", real_constant); + bytecode_append(current_block->code, ldc_w$); + bytecode_append_short_int(current_block->code, cp_add_string(number)); + + bytecode_append(current_block->code, invokespecial$); + bytecode_append_short_int(current_block->code, cp_add_methodref("Real", "", "(Ljava/lang/String;)V")); + } + + current_token = yylex(); + return_type->type_class = real_type; + return return_type; + } + + if (current_token == CST_BOOLEAN) + { + if (boolean_constant) + { + bytecode_append(current_block->code, iconst_m1$); + } + else + { + bytecode_append(current_block->code, iconst_0$); + } + + current_token = yylex(); + return_type->type_class = boolean_type; + return return_type; + } + + if (current_token == CST_CHAR) + { + bytecode_append(current_block->code, bipush$); + bytecode_append(current_block->code, char_constant); + + current_token = yylex(); + return_type->type_class = char_type; + return return_type; + } + + if (current_token == CST_STRING) + { + int cp_index; + cp_index = cp_add_string(string_constant->cstr); + if (cp_index <= 255) + { + bytecode_append(current_block->code, ldc$); + bytecode_append(current_block->code, (char) cp_index); + } + else + { + bytecode_append(current_block->code, ldc_w$); + bytecode_append_short_int(current_block->code, (short) cp_index); + } + + current_token = yylex(); + return_type->type_class = string_type; + return return_type; + } + + if (current_token == IDENTIFIER) + { + identifier *name; + char *identifier_text; + identifier_text = (char*) mem_alloc(strlen(YYTEXT_STRING) + 1); + strcpy(identifier_text, YYTEXT_STRING); + lowercase(identifier_text); + + name = get_identifier(current_block, identifier_text); + + if ((name->identifier_class == none) + || (name->identifier_class == program_name) + || (name->identifier_class == type_name) + || (name->identifier_class == procedure_name)) + { + add_error_message(429, YYTEXT_STRING, ""); + current_token = yylex(); + identifier_destroy(name); + mem_free(identifier_text); + return return_type; + } + + + current_token = yylex(); + + if (name->identifier_class == constant_name) + { +constant_value: + create_constant_bytecode(name, current_block->code); + type_destroy(return_type); + return_type = type_duplicate(name->constant_type); + identifier_destroy(name); + mem_free(identifier_text); + return return_type; + } + + /* + Parse the unit functions. + */ + if (name->identifier_class == unit_name) + { + identifier *unit_name; + + if (current_token != DOT) + { + add_error_message(200, ".", YYTEXT_STRING); + while (current_token != SEMI_COLON) + current_token = yylex(); + return return_type; + } + + current_token = yylex(); + unit_name = name_table_find(name->unit_block->names, string_from_cstr(YYTEXT_STRING)); + identifier_text = malloc(strlen(YYTEXT_STRING) + 1); + strcpy(identifier_text, YYTEXT_STRING); + + if (unit_name == NULL) + { + add_error_message(453, YYTEXT_STRING, ""); + add_error_message(200, ".", YYTEXT_STRING); + while (current_token != SEMI_COLON) + current_token = yylex(); + return return_type; + } + + name = identifier_duplicate(unit_name); + current_token = yylex(); + + if (name->identifier_class == function_name) + goto function_call; + + if (name->identifier_class == constant_name) + goto constant_value; + + if (name->identifier_class == variable_name) + goto variable_value; + + add_error_message(458, YYTEXT_STRING, ""); + } + + if ((name->identifier_class == variable_name) + || (name->identifier_class == parameter_name)) + { + type *current_type; + type *new_type; + int is_field; +variable_value: + is_field = name->belongs_to_program_block; + + if (name->identifier_class == variable_name) + { + create_variable_bytecode(name, current_block->code, identifier_text, is_field); + current_type = type_duplicate(name->variable_type); + } + + + if(name->identifier_class == parameter_name) + { + create_variable_bytecode(name, current_block->code, identifier_text, is_field); + current_type = type_duplicate(name->parameter_type); + } + + mem_free(identifier_text); + + identifier_destroy(name); + + name = NULL; + + while ((current_token == DOT) + || (current_token == OPEN_SQ_BR)) + { + /* get an element from the record */ + if (current_token == DOT) + { + char record_name[5]; + char field_descriptor[128]; + int fieldref_index; + + if (current_type->type_class != record_type) + { + add_error_message(424, "", ""); + + /* Error-recovery */ + while ((current_token != SEMI_COLON) + && (current_token != KWD_END) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + type_destroy(current_type); + return return_type; + } + + current_token = yylex(); + + new_type = type_find_record_element(current_type, YYTEXT_STRING); + sprintf(record_name, "R_%d", current_type->unique_record_ID); + type_destroy(current_type); + current_type = new_type; + + if (current_type == NULL) + { + add_error_message(425, YYTEXT_STRING, ""); + + /* Error-recovery */ + while ((current_token != SEMI_COLON) + && (current_token != KWD_END) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + type_destroy(current_type); + return return_type; + } + + lowercase(YYTEXT_STRING); + get_field_descriptor(new_type, field_descriptor); + fieldref_index = cp_add_fieldref(record_name, YYTEXT_STRING, field_descriptor); + + bytecode_append(current_block->code, getfield$); + bytecode_append_short_int(current_block->code, fieldref_index); + + current_token = yylex(); + } + /* get an element from an array */ + else if (current_token == OPEN_SQ_BR) + { + type_list *array_elements; + + if (current_type->type_class != array_type) + { + add_error_message(426, "", ""); + + /* Error-recovery */ + while ((current_token != SEMI_COLON) + && (current_token != KWD_END) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + type_destroy(current_type); + return return_type; + } + + current_token = yylex(); + + array_elements = RD_expression_list_array(current_block, current_block->code, current_type); + + /* replace the last aaload in the bytecode with the proper loading instruction */ + replace_aaload_instruction(current_block->code, current_type->element_type); + + if (type_list_different_parameter_array(array_elements, current_type->dimensions_list) != 0) + { + char num1[6], num2[6]; + + sprintf(num1, "%d", type_list_length(current_type->dimensions_list)); + sprintf(num2, "%d", type_list_length(array_elements)); + add_error_message(427, num1, num2); + + /* Error-recovery */ + while ((current_token != SEMI_COLON) + && (current_token != KWD_END) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + type_destroy(current_type); + return return_type; + } + + if (current_token != CLOSE_SQ_BR) + { + add_error_message(200, "]", YYTEXT_STRING); + + /* Error-recovery */ + while ((current_token != SEMI_COLON) + && (current_token != KWD_END) + && (current_token != END_OF_INPUT)) + { + current_token = yylex(); + } + + type_destroy(current_type); + return return_type; + } + + current_token = yylex(); + + new_type = type_duplicate(current_type->element_type); + type_destroy(current_type); + + current_type = new_type; + + type_list_destroy(array_elements); + } + + } + + type_destroy(return_type); + + return_type = current_type; + + return return_type; + } + +function_call: + + /* a function call */ + if (name->identifier_class == function_name) + { + int methodref_index; + char *method_type; + int method_index; + method_type = (char*) mem_alloc(1024*5); + + if (name->standard_function) + { + create_std_function_prefix(current_block->code, identifier_text); + } + + if (type_list_length(name->parameters) == 0) + { + int br_depth = 0; + if (current_token == OPEN_BR) + { + add_error_message(419, "", ""); + br_depth = 1; + while (br_depth > 0) + { + if ((current_token == END_OF_INPUT) + || (current_token == KWD_END)) + { + identifier_destroy(name); + return return_type; + } + + current_token = yylex(); + + if (current_token == OPEN_BR) + br_depth ++; + + if (current_token == CLOSE_BR) + br_depth --; + } + + current_token = yylex(); + } + + /* create the bytecode */ + if (name->unit_function) + { + string *full_unit_name; + if (name->container_unit->is_library == 1) + full_unit_name = string_from_cstr("Lib_"); + else + full_unit_name = string_create(); + string_append(full_unit_name, name->container_unit->unit_name); + + lowercase(identifier_text); + strcpy(method_type, "()"); + get_field_descriptor(name->return_type, method_type + 2); + method_index = cp_add_methodref(full_unit_name->cstr, + identifier_text, method_type); + bytecode_append(current_block->code, invokestatic$); + bytecode_append_short_int(current_block->code, method_index); + string_destroy(full_unit_name); + } + else if (!name->standard_function) + { + /* the function is user-defined */ + strcpy(method_type, "()"); + get_field_descriptor(name->return_type, method_type + 2); + if (compiling_unit == 0) + methodref_index = cp_add_methodref("M", identifier_text, method_type); + else + methodref_index = cp_add_methodref(string_get_cstr(str_program_name), identifier_text, method_type); + bytecode_append(current_block->code, invokestatic$); /* call */ + bytecode_append_short_int(current_block->code, methodref_index); + } + else + { + /* handle standard functions and procedures */ + create_std_function_code(current_block->code, identifier_text); + } + + type_destroy(return_type); + + mem_free(identifier_text); + mem_free(method_type); + + return_type = type_duplicate(name->return_type); + + identifier_destroy(name); + + return return_type; + } + else + { + int compare_result; + int old_linenum; + type_list *parameter_list; + + if (current_token != OPEN_BR) + { + add_error_message(200, "(", YYTEXT_STRING); + } + + current_token = yylex(); + + old_linenum = linenum; + + parameter_list = RD_expression_list_cast(current_block, name->parameters); + + compare_result = type_list_different_parameter_cast(parameter_list, name->parameters); + + if (compare_result == -1){ + new_linenum=old_linenum; + add_error_message(421, "", ""); + } + + if (compare_result > 0) + { + char par_num[4]; + sprintf(par_num, "%d", compare_result); + new_linenum=old_linenum; + add_error_message(422, par_num, ""); + } + + type_list_destroy(parameter_list); + + if (current_token != CLOSE_BR) + { + add_error_message(200, ")", YYTEXT_STRING); + } + else + current_token = yylex(); + + type_destroy(return_type); + + /* create the bytecode */ + if (!name->standard_function) + { + { + int pos = 1; + type_list *it; + + it = name->parameters; + + method_type[0] = '('; + + while (it != NULL) + { + if (it->data == NULL) + break; + + + get_field_descriptor(it->data, method_type + pos); + pos = strlen(method_type); + + it = it->next; + } + + strcat(method_type, ")"); + } + + + get_field_descriptor(name->return_type, method_type + strlen(method_type)); + + if (name->unit_function) + { + string *full_unit_name; + if (name->container_unit->is_library == 1) + full_unit_name = string_from_cstr("Lib_"); + else + full_unit_name = string_create(); + string_append(full_unit_name, name->container_unit->unit_name); + lowercase(identifier_text); + methodref_index = cp_add_methodref(full_unit_name->cstr, identifier_text, method_type); + string_destroy(full_unit_name); + } + else + { + if (compiling_unit == 0) + methodref_index = cp_add_methodref("M", identifier_text, method_type); + else + methodref_index = cp_add_methodref(string_get_cstr(str_program_name), identifier_text, method_type); + } + + bytecode_append(current_block->code, invokestatic$); /* call */ + bytecode_append_short_int(current_block->code, methodref_index); + } + else + { + /* handle standard functions and procedures */ + create_std_function_code(current_block->code, identifier_text); + } + /* END create the bytecode */ + + return_type = type_duplicate(name->return_type); + + mem_free(identifier_text); + mem_free(method_type); + + identifier_destroy(name); + + return return_type; + } + } + + mem_free(identifier_text); + + return return_type; + } + + /* brackets, priority change, no code generated in here */ + if (current_token == OPEN_BR) + { + current_token = yylex(); + + type_destroy(return_type); + return_type = RD_expression(current_block); + + if (current_token != CLOSE_BR) + { + add_error_message(200, ")", YYTEXT_STRING); + } + + current_token = yylex(); + + return return_type; + } + + add_error_message(204, YYTEXT_STRING, ""); + + return return_type; +} + + +/* + Create the bytecode that loads the given constant +*/ +void create_constant_bytecode(identifier *item, bytecode *code) +{ + int cp_index; + + switch(item->constant_type->type_class) + { + case integer_type: + cp_index = cp_add_integer(item->constant_int_value); + if (cp_index <= 255) + { + bytecode_append(code, ldc$); + bytecode_append(code, (char) cp_index); + } + else + { + bytecode_append(code, ldc_w$); + bytecode_append_short_int(code, (short) cp_index); + } + break; + + case real_type: + { + float cst; + int csti; /* the integer part */ + int cstf; /* the fraction part */ + + /* calculate the exponent and the integer part */ + cst = item->constant_real_value; + + csti = (int)cst; + cstf = (cst - (int)cst)*100000; + + usesFloat = 1; + + if (mathType == 1) + { + /* put the integer part on the stack */ + if (abs(csti) < 127) + { + bytecode_append(code, bipush$); + bytecode_append(code, csti); + } + else if (abs(csti) < 15000) + { + bytecode_append(code, sipush$); + bytecode_append_short_int(code, csti); + } + else + { + bytecode_append(code, ldc_w$); + bytecode_append_short_int(code, cp_add_integer(csti)); + } + + /* put the fraction part to the stack */ + if (abs(cstf) < 127) + { + bytecode_append(code, bipush$); + bytecode_append(code, cstf); + } + else if (abs(cstf) < 15000) + { + bytecode_append(code, sipush$); + bytecode_append_short_int(code, cstf); + } + else + { + bytecode_append(code, ldc_w$); + bytecode_append_short_int(code, cp_add_integer(cstf)); + } + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("F", "fI", "(II)I")); + } + else + { + char number[64]; + + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup$); + + sprintf(number, "%f", real_constant); + bytecode_append(code, ldc_w$); + bytecode_append_short_int(code, cp_add_string(number)); + + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(Ljava/lang/String;)V")); + + } + + + + } + break; + + case char_type: + cp_index = cp_add_integer(item->constant_int_value); + if (cp_index <= 255) + { + bytecode_append(code, ldc$); + bytecode_append(code, (char) cp_index); + } + else + { + bytecode_append(code, ldc_w$); + bytecode_append_short_int(code, (short) cp_index); + } + break; + + case boolean_type: + if (item->constant_int_value) + { + bytecode_append(code, iconst_m1$); + } + else + { + bytecode_append(code, iconst_0$); + } + break; + + case string_type: + cp_index = cp_add_string(item->constant_string_value->cstr); + if (cp_index <= 255) + { + bytecode_append(code, ldc$); + bytecode_append(code, (char) cp_index); + } + else + { + bytecode_append(code, ldc_w$); + bytecode_append_short_int(code, (short) cp_index); + } + break; + } +} + + +/* + Creates the code that loads the variable or parameter value to the stack +*/ +void create_variable_bytecode(identifier *item, bytecode *code, char *name, int is_field) +{ + int index; + type *item_type; + + /* if the block is program block, load field instead of variable */ + if ((is_field) || (item->unit_function == 1)) + { + if (item->identifier_class == variable_name) + { + char type_descriptor[128]; + + lowercase(name); + bytecode_append(code, getstatic$); + get_field_descriptor(item->variable_type, type_descriptor); + + if (item->unit_function == 0) + { + if (compiling_unit == 0) + bytecode_append_short_int(code, cp_add_fieldref("M", name, type_descriptor)); + else + bytecode_append_short_int(code, cp_add_fieldref(string_get_cstr(str_program_name), name, type_descriptor)); + } + else + { + string *unit_name; + + if (item->container_unit->is_library == 0) + unit_name = string_create(); + else + unit_name = string_from_cstr("Lib_"); + + lowercase(string_get_cstr(item->container_unit->unit_name)); + + string_append(unit_name, item->container_unit->unit_name); + + bytecode_append_short_int(code, cp_add_fieldref(string_get_cstr(unit_name), name, type_descriptor)); + + string_destroy(unit_name); + } + } + + return; + } + + if (item->identifier_class == variable_name) + { + index = item->variable_index; + item_type = item->variable_type; + } + else if (item->identifier_class == function_name) + { + /* this is used for error recovery and returning values form functions */ + index = type_list_length(item->parameters); + item_type = item->return_type; + } + else if (item->identifier_class == parameter_name) + { + index = item->parameter_index; + item_type = item->parameter_type; + } + else + { + add_error_message(444, "", ""); + return 0; + } + + switch (item_type->type_class) + { + case integer_type: + case char_type: + case boolean_type: + switch(index) + { + case 0: + bytecode_append(code, iload_0$); + break; + case 1: + bytecode_append(code, iload_1$); + break; + case 2: + bytecode_append(code, iload_2$); + break; + case 3: + bytecode_append(code, iload_3$); + break; + default: + bytecode_append(code, iload$); + bytecode_append(code, index); + break; + } + + break; + + case real_type: + if (mathType == 1) + { + switch(index) + { + case 0: + bytecode_append(code, iload_0$); + break; + case 1: + bytecode_append(code, iload_1$); + break; + case 2: + bytecode_append(code, iload_2$); + break; + case 3: + bytecode_append(code, iload_3$); + break; + default: + bytecode_append(code, iload$); + bytecode_append(code, index); + break; + } + } + else + { + switch(index) + { + case 0: + bytecode_append(code, aload_0$); + break; + case 1: + bytecode_append(code, aload_1$); + break; + case 2: + bytecode_append(code, aload_2$); + break; + case 3: + bytecode_append(code, aload_3$); + break; + default: + bytecode_append(code, aload$); + bytecode_append(code, index); + break; + } + } + break; + + case string_type: + case record_type: + case array_type: + case image_type: + case command_type: + case stream_type: + case record_store_type: + case http_type: + case alert_type: + switch(index) + { + case 0: + bytecode_append(code, aload_0$); + break; + case 1: + bytecode_append(code, aload_1$); + break; + case 2: + bytecode_append(code, aload_2$); + break; + case 3: + bytecode_append(code, aload_3$); + break; + default: + bytecode_append(code, aload$); + bytecode_append(code, index); + break; + } + + break; + + default: + die(15); + } +} + +/* + Creates the code that puts the variable or parameter value from the stack into memory +*/ +void create_put_variable_bytecode(identifier *item, bytecode *code, char *name, int is_field) +{ + int index; + type *item_type; + + if (item->identifier_class == variable_name) + { + index = item->variable_index; + item_type = item->variable_type; + } + else if (item->identifier_class == parameter_name) + { + index = item->parameter_index; + item_type = item->parameter_type; + } + else if (item->identifier_class == function_name)/* function name, it is return value variable */ + { + index = type_list_length(item->parameters); + is_field = 0; + item_type = item->return_type; + } + else + { + add_error_message(444, "", ""); + return; + } + + /* if the value on the top of the stack is string, copy it */ + if (item_type->type_class == string_type) + { + int class_index; + int method_index; + + class_index = cp_add_class("java/lang/String"); + method_index = cp_add_methodref("java/lang/String", "", "(Ljava/lang/String;)V"); + + bytecode_append(code, new$); + bytecode_append_short_int(code, class_index); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, method_index); + } + + if ((item_type->type_class == real_type) && (mathType != 1)) + { + int class_index; + int method_index; + + usesFloat = 1; + + class_index = cp_add_class("Real"); + method_index = cp_add_methodref("Real", "", "(LReal;)V"); + + bytecode_append(code, new$); + bytecode_append_short_int(code, class_index); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, method_index); + } + + /* if the value on the top of the stack is record type, copy it */ + if (item_type->type_class == record_type) + { + int class_index; + int constructor_index; + int copy_index; + + char type_name[16]; + char copy_sig[64]; + + sprintf(type_name, "R_%d", item_type->unique_record_ID); + sprintf(copy_sig, "(L%s;)L%s;", type_name, type_name); + + class_index = cp_add_class(type_name); + constructor_index = cp_add_methodref(type_name, "", "()V"); + copy_index = cp_add_methodref(type_name, "Copy", copy_sig); + + bytecode_append(code, new$); + bytecode_append_short_int(code, class_index); + bytecode_append(code, dup_x1$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, constructor_index); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, copy_index); + } + + /* if the block is program block, load field instead of variable */ + if ((is_field) || (item->unit_function == 1)) + { + if (item->identifier_class == variable_name) + { + char type_descriptor[128]; + + lowercase(name); + bytecode_append(code, putstatic$); + get_field_descriptor(item->variable_type, type_descriptor); + + if (item->unit_function == 0) + { + if (compiling_unit == 0) + bytecode_append_short_int(code, cp_add_fieldref("M", name, type_descriptor)); + else + bytecode_append_short_int(code, cp_add_fieldref(string_get_cstr(str_program_name), name, type_descriptor)); + } + else + { + string *unit_name; + + if (item->container_unit->is_library == 0) + unit_name = string_create(); + else + unit_name = string_from_cstr("Lib_"); + + lowercase(string_get_cstr(item->container_unit->unit_name)); + + string_append(unit_name, item->container_unit->unit_name); + + bytecode_append_short_int(code, cp_add_fieldref(string_get_cstr(unit_name), name, type_descriptor)); + + string_destroy(unit_name); + } + } + + return; + } + + switch (item_type->type_class) + { + case integer_type: + case char_type: + case boolean_type: + switch(index) + { + case 0: + bytecode_append(code, istore_0$); + break; + case 1: + bytecode_append(code, istore_1$); + break; + case 2: + bytecode_append(code, istore_2$); + break; + case 3: + bytecode_append(code, istore_3$); + break; + default: + bytecode_append(code, istore$); + bytecode_append(code, index); + break; + } + + break; + + case real_type: + if (mathType == 1) + { + switch(index) + { + case 0: + bytecode_append(code, istore_0$); + break; + case 1: + bytecode_append(code, istore_1$); + break; + case 2: + bytecode_append(code, istore_2$); + break; + case 3: + bytecode_append(code, istore_3$); + break; + default: + bytecode_append(code, istore$); + bytecode_append(code, index); + break; + } + } + else + { + switch(index) + { + case 0: + bytecode_append(code, astore_0$); + break; + case 1: + bytecode_append(code, astore_1$); + break; + case 2: + bytecode_append(code, astore_2$); + break; + case 3: + bytecode_append(code, astore_3$); + break; + default: + bytecode_append(code, astore$); + bytecode_append(code, index); + break; + } + } + break; + + case string_type: + case record_type: + case array_type: + case image_type: + case command_type: + case stream_type: + case record_store_type: + case http_type: + case alert_type: + switch(index) + { + case 0: + bytecode_append(code, astore_0$); + break; + case 1: + bytecode_append(code, astore_1$); + break; + case 2: + bytecode_append(code, astore_2$); + break; + case 3: + bytecode_append(code, astore_3$); + break; + default: + bytecode_append(code, astore$); + bytecode_append(code, index); + break; + } + + break; + + default: + die(15); + } +} + +/* + The last instruction in the bytecode is aaload; it should be replaced with + the iaload, faload, aload or something like that. +*/ +void replace_aaload_instruction(bytecode *code, type *element_type) +{ + /* delete the last instruction */ + code->bytecode_pos --; + + /* create the new instruction */ + switch(element_type->type_class) + { + case integer_type: + case boolean_type: + case char_type: + bytecode_append(code, iaload$); + break; + + case real_type: + if (mathType == 1) + { + bytecode_append(code, iaload$); + } + else + { + bytecode_append(code, aaload$); + } + break; + + case record_type: + case string_type: + case image_type: + case command_type: + case stream_type: + case record_store_type: + case http_type: + case alert_type: + bytecode_append(code, aaload$); + break; + + default: + die(24); + } +} + +/* + Creates the code that adjustes array indices +*/ +void adjust_indices(bytecode *code, type *dimension) +{ + if (dimension == NULL) + return; + + switch(dimension->first_element) + { + case -1: + bytecode_append(code, iconst_m1$); + break; + case 0: + //bytecode_append(code, iconst_0$); + break; + case 1: + bytecode_append(code, iconst_1$); break; + case 2: + bytecode_append(code, iconst_2$); break; + case 3: + bytecode_append(code, iconst_3$); break; + case 4: + bytecode_append(code, iconst_4$); break; + case 5: + bytecode_append(code, iconst_5$); break; + default: + if (dimension->first_element < 128) + { + bytecode_append(code, bipush$); + bytecode_append(code, dimension->first_element); + } + else + { + bytecode_append(code, sipush$); + bytecode_append_short_int(code, dimension->first_element); + } + } + if (dimension->first_element != 0) + bytecode_append(code, isub$); + +} diff --git a/MPC.3.5.LINUX/parser/parser.h b/MPC.3.5.LINUX/parser/parser.h new file mode 100644 index 0000000..1464249 --- /dev/null +++ b/MPC.3.5.LINUX/parser/parser.h @@ -0,0 +1,59 @@ +/******************************************************************** + + parser.h - recursive-descent parser declarations + + Niksa Orlic, 2004-04-19 + +********************************************************************/ + + +void parser_start(); +string* RD_program_header(); +void RD_uses_list(); +block* RD_block(block*); +void RD_const_declaration(); +void RD_var_declaration(block*); +string_list* RD_identifier_list(block*, int); +void RD_type_declaration(block*); +void RD_procedure_declaration(block*); +void RD_function_declaration(block*); +int RD_proc_block(block*, type*, type_list*); +type_list* RD_param_list(block*); +void RD_block_body(block*); +void RD_inline_body(block*); +void RD_statement(block *); +void RD_if_statement(block *); +void RD_case_statement(block *); +void RD_case_list(block*, type*); +void RD_while_statement(block*); +void RD_repeat_statement(block*); +void RD_for_statement(block*); +type* RD_type(block*); +type* RD_basic_type(block*); +type* RD_array_declaration(block*); +type* RD_record_declaration(block*); +type* RD_file_declaration(block*); +void RD_set_declaration(block*); +type* RD_expression(block*); +type* RD_sum(block*); +type* RD_mult(block*); +type* RD_not(block*); +type* RD_neg(block*); +void RD_assignment_or_procedure_call(block*); +type_list* RD_expression_list(block*); +type_list* RD_expression_list_cast(block*, type_list*); +type_list* RD_expression_list_array(block*, bytecode*, type*); +void RD_with_statement(block*); +type* RD_value(block*); + +void RD_unit_interface(block*); +void RD_unit_implementation(block*); +void RD_unit_initialization(block*); +void RD_unit_finalization(block*); + +void create_constant_bytecode(identifier*, bytecode*); +void create_variable_bytecode(identifier*, bytecode*, char*, int); +void create_put_variable_bytecode(identifier*, bytecode*, char*, int); + +void replace_aaload_instruction(bytecode*, type*); +void adjust_indices(bytecode *code, type *dimension); diff --git a/MPC.3.5.LINUX/parser/stdpas.c b/MPC.3.5.LINUX/parser/stdpas.c new file mode 100644 index 0000000..24380f7 --- /dev/null +++ b/MPC.3.5.LINUX/parser/stdpas.c @@ -0,0 +1,3333 @@ +/******************************************************************** + + stdpas.c - initializes the parser/semantic checker with a + standard pascal types, constants etc. + + Niksa Orlic, 2004-04-29 + +********************************************************************/ + +#include "../util/strings.h" +#include "../util/error.h" +//#include "../util/message.h" +#include "../structures/type_list.h" +#include "../structures/string_list.h" +#include "../structures/type.h" +#include "../structures/identifier.h" +#include "../structures/name_table.h" +#include "../classgen/bytecode.h" +#include "../structures/block.h" +//#include "../main/static_entry.h" + +#include "../classgen/constant_pool.h" + +#include "stdpas.h" + +#include +#include +#include + +#pragma warning (disable:4305) +#pragma warning (disable:4761) + +int procedure_linenum; +extern char *source_file_name; +int usesForms = 0; /* set to 1 if FS.class should be added into the generated JAR file */ +int usesSupport = 0; /* set to 1 if S.class should be added into the generated JAR file */ +int usesFloat = 0; /* set to 1 if Float.class should be added into the generated JAR file */ +int usesRecordStore = 0; /* set to 1 if RS.class should be added into the generated JAR file */ +int usesHttp = 0; /* if H.class should be added */ +int usesPlayer = 0; /* if P.class should be used */ +int usesSMS = 0; /* if uses SM.class */ +extern int mathType; + +//int usesRegisteredFeature = 0; + +extern int canvasType; + + +/* + Creates and initializes the root block + with standard pascal types, constants etc. +*/ +block* initialize_root_block() +{ + block *root_block; + + root_block = block_create(NULL, NULL); + + add_std_types(root_block); + add_std_constants(root_block); + add_std_functions(root_block); + + return root_block; +} + + +/* + Adds the standard pascal types into the block. +*/ +void add_std_types(block *item) +{ + add_std_type(item, integer_type, "integer"); + add_std_type(item, real_type, "real"); + add_std_type(item, boolean_type, "boolean"); + add_std_type(item, char_type, "char"); + add_std_type(item, string_type, "string"); + add_std_type(item, image_type, "image"); + add_std_type(item, command_type, "command"); + add_std_type(item, stream_type, "resource"); + add_std_type(item, record_store_type, "recordstore"); + add_std_type(item, http_type, "http"); +} + +/* + Adds some constants into the block +*/ +void add_std_constants(block *item) +{ + add_real_constant(item, (float) 3.1415926535897932384626433832795, "pi"); + + /* key codes */ + add_integer_constant(item, 0, "KE_NONE"); + add_integer_constant(item, 0, "GA_NONE"); + + add_integer_constant(item, 1, "GA_UP"); + add_integer_constant(item, 6, "GA_DOWN"); + add_integer_constant(item, 2, "GA_LEFT"); + add_integer_constant(item, 5, "GA_RIGHT"); + add_integer_constant(item, 8, "GA_FIRE"); + add_integer_constant(item, 9, "GA_GAMEA"); + add_integer_constant(item, 10, "GA_GAMEB"); + add_integer_constant(item, 11, "GA_GAMEC"); + add_integer_constant(item, 12, "GA_GAMED"); + + add_integer_constant(item, 48, "KE_KEY0"); + add_integer_constant(item, 49, "KE_KEY1"); + add_integer_constant(item, 50, "KE_KEY2"); + add_integer_constant(item, 51, "KE_KEY3"); + add_integer_constant(item, 52, "KE_KEY4"); + add_integer_constant(item, 53, "KE_KEY5"); + add_integer_constant(item, 54, "KE_KEY6"); + add_integer_constant(item, 55, "KE_KEY7"); + add_integer_constant(item, 56, "KE_KEY8"); + add_integer_constant(item, 57, "KE_KEY9"); + add_integer_constant(item, 42, "KE_STAR"); + add_integer_constant(item, 35, "KE_POUND"); + + /* font constants */ + add_integer_constant(item, 0, "FONT_FACE_SYSTEM"); + add_integer_constant(item, 32, "FONT_FACE_MONOSPACE"); + add_integer_constant(item, 64, "FONT_FACE_PROPORTIONAL"); + + add_integer_constant(item, 8, "FONT_SIZE_SMALL"); + add_integer_constant(item, 0, "FONT_SIZE_MEDIUM"); + add_integer_constant(item, 16, "FONT_SIZE_LARGE"); + + add_integer_constant(item, 0, "FONT_STYLE_PLAIN"); + add_integer_constant(item, 1, "FONT_STYLE_BOLD"); + add_integer_constant(item, 2, "FONT_STYLE_ITALIC"); + add_integer_constant(item, 4, "FONT_STYLE_UNDERLINED"); + + /* command constants */ + add_integer_constant(item, 1, "CM_SCREEN"); + add_integer_constant(item, 2, "CM_BACK"); + add_integer_constant(item, 3, "CM_CANCEL"); + add_integer_constant(item, 4, "CM_OK"); + add_integer_constant(item, 5, "CM_HELP"); + add_integer_constant(item, 6, "CM_STOP"); + add_integer_constant(item, 7, "CM_EXIT"); + add_integer_constant(item, 8, "CM_ITEM"); + + /* text field constants */ + add_integer_constant(item, 0, "TF_ANY"); + add_integer_constant(item, 1, "TF_EMAIL"); + add_integer_constant(item, 2, "TF_NUMERIC"); + add_integer_constant(item, 3, "TF_PHONENUMBER"); + add_integer_constant(item, 4, "TF_URL"); + add_integer_constant(item, 0x10000, "TF_PASSWORD"); + + /* choice constants */ + add_integer_constant(item, 1, "CH_EXCLUSIVE"); + add_integer_constant(item, 2, "CH_MULTIPLE"); + add_integer_constant(item, 3, "CH_IMPLICIT"); + + /* http constants */ + add_string_constant(item, string_from_cstr("GET"), "GET"); + add_string_constant(item, string_from_cstr("HEAD"), "HEAD"); + add_string_constant(item, string_from_cstr("POST"), "POST"); + + /* date field constants */ + add_integer_constant(item, 1, "DF_DATE"); + add_integer_constant(item, 2, "DF_TIME"); + add_integer_constant(item, 3, "DF_DATE_TIME"); + + add_integer_constant(item, 1000, "EOF"); +} + + +/* + Adds standard functions and procedures +*/ +void add_std_functions(block *item) +{ + + add_special_function(item, real_type, real_type, "sqrt"); + add_special_function(item, real_type, integer_type, "trunc"); +// add_special_function(item, real_type, integer_type, "round"); + add_special_function(item, real_type, real_type, "sin"); + add_special_function(item, real_type, real_type, "cos"); + add_special_function(item, real_type, real_type, "atan"); + add_special_function(item, real_type, real_type, "log"); /* natural logarithm */ + add_special_function(item, real_type, real_type, "exp"); + add_special_function(item, real_type, real_type, "asin"); + add_special_function(item, real_type, real_type, "acos"); + add_special_function(item, real_type, real_type, "tan"); + add_special_function(item, real_type, real_type, "toDegrees"); + add_special_function(item, real_type, real_type, "toRadians"); + add_special_function(item, real_type, real_type, "frac"); + add_special_function2(item, real_type, real_type, real_type, "atan2"); + add_special_function(item, real_type, real_type, "log10"); + add_special_function2(item, real_type, real_type, real_type, "pow"); + add_special_function2(item, string_type, integer_type, real_type, "stringToReal"); + add_special_function(item, real_type, real_type, "rabs"); + + add_special_function(item, integer_type, integer_type, "sqr"); + add_special_function(item, integer_type, integer_type, "abs"); + + add_special_function(item, integer_type, boolean_type, "odd"); + add_special_function(item, integer_type, char_type, "chr"); + add_special_function(item, char_type, integer_type, "ord"); + + add_special_function(item, void_type, void_type, "halt"); + add_special_function(item, void_type, boolean_type, "isMidletPaused"); + + /* RNG functions */ + add_special_function(item, void_type, void_type, "randomize"); + add_special_function(item, integer_type, integer_type, "random"); + + /* string functions */ + add_special_function(item, string_type, string_type, "upcase"); + add_special_function(item, string_type, string_type, "locase"); + add_special_function(item, string_type, integer_type, "length"); + add_special_function3(item, string_type, integer_type, integer_type, string_type, "copy"); + add_special_function2(item, string_type, string_type, integer_type, "pos"); + add_special_function(item, string_type, integer_type, "stringToInteger"); + add_special_function(item, integer_type, string_type, "integerToString"); + add_special_function2(item, string_type, integer_type, char_type, "getChar"); + add_special_function3(item, string_type, char_type, integer_type, string_type, "setChar"); + + /* midlet functions */ + add_special_function(item, string_type, string_type, "getproperty"); + + + /* time functions */ + add_special_function(item, integer_type, void_type, "delay"); + add_special_function(item, void_type, integer_type, "getRelativeTimeMs"); + add_special_function(item, void_type, integer_type, "getCurrentTime"); + add_special_function(item, integer_type, integer_type, "getDay"); + add_special_function(item, integer_type, integer_type, "getMonth"); + add_special_function(item, integer_type, integer_type, "getYear"); + add_special_function(item, integer_type, integer_type, "getSecond"); + add_special_function(item, integer_type, integer_type, "getMinute"); + add_special_function(item, integer_type, integer_type, "getHour"); + add_special_function(item, integer_type, integer_type, "getWeekDay"); + add_special_function(item, integer_type, integer_type, "getYearDay"); + + + /* music functions */ + add_special_function3(item, integer_type, integer_type, integer_type, void_type, "playTone"); + + + /* action functions */ + add_special_function(item, void_type, integer_type, "getKeyPressed"); + add_special_function(item, void_type, integer_type, "getKeyClicked"); + add_special_function(item, integer_type, integer_type, "keyToAction"); + + + /* image functions */ + add_special_function(item, string_type, image_type, "loadImage"); + add_special_function(item, image_type, integer_type, "getImageWidth"); + add_special_function(item, image_type, integer_type, "getImageHeight"); + add_special_function5(item, image_type, integer_type, integer_type, integer_type, integer_type, image_type, "imageFromImage"); + add_special_function4(item, integer_type, integer_type, integer_type, integer_type, image_type, "imageFromCanvas"); + add_special_function2(item, string_type, integer_type, image_type, "imageFromBuffer"); + + /* drawing functions */ + add_special_function(item, void_type, void_type, "repaint"); + + add_special_function(item, void_type, integer_type, "getWidth"); + add_special_function(item, void_type, integer_type, "getHeight"); + add_special_function(item, void_type, boolean_type, "isColorDisplay"); + add_special_function(item, void_type, integer_type, "getColorsNum"); + + + add_special_function3(item, string_type, integer_type, integer_type, void_type, "drawText"); + add_special_function4(item, integer_type, integer_type, integer_type, integer_type, void_type, "setClip"); + add_special_function4(item, integer_type, integer_type, integer_type, integer_type, void_type, "drawLine"); + add_special_function3(item, integer_type, integer_type, integer_type, void_type, "setColor"); + add_special_function4(item, integer_type, integer_type, integer_type, integer_type, void_type, "drawEllipse"); + add_special_function4(item, integer_type, integer_type, integer_type, integer_type, void_type, "fillEllipse"); + add_special_function4(item, integer_type, integer_type, integer_type, integer_type, void_type, "drawRect"); + add_special_function4(item, integer_type, integer_type, integer_type, integer_type, void_type, "fillRect"); + add_special_function6(item, integer_type, integer_type, integer_type, integer_type, integer_type, integer_type, void_type, "drawArc"); + add_special_function2(item, integer_type, integer_type, void_type, "plot"); + add_special_function(item, void_type, integer_type, "getColorRed"); + add_special_function(item, void_type, integer_type, "getColorGreen"); + add_special_function(item, void_type, integer_type, "getColorBlue"); + add_special_function6(item, integer_type, integer_type, integer_type, integer_type, integer_type, integer_type, void_type, "drawRoundRect"); + add_special_function6(item, integer_type, integer_type, integer_type, integer_type, integer_type, integer_type, void_type, "fillRoundRect"); + + add_special_function3(item, integer_type, integer_type, integer_type, void_type, "setFont"); + add_special_function(item, void_type, void_type, "setDefaultFont"); + + add_special_function3(item, image_type, integer_type, integer_type, void_type, "drawImage"); + + add_special_function(item, string_type, integer_type, "getStringWidth"); + add_special_function(item, string_type, integer_type, "getStringHeight"); + + /* debug functions */ + add_special_function(item, string_type, void_type, "debug"); + add_special_function(item, boolean_type, void_type, "assert"); + + /* command & form functions */ + add_special_function3(item, string_type, integer_type, integer_type, command_type, "createCommand"); + add_special_function(item, void_type, command_type, "getClickedCommand"); + add_special_function(item, command_type, void_type, "addCommand"); + add_special_function(item, command_type, void_type, "removeCommand"); + add_special_function(item, void_type, command_type, "emptyCommand"); + + add_special_function(item, void_type, void_type, "showForm"); + add_special_function(item, void_type, void_type, "showCanvas"); + + add_special_function(item, string_type, void_type, "setTicker"); + + add_special_function(item, void_type, void_type, "clearForm"); + add_special_function(item, integer_type, void_type, "formRemove"); + add_special_function(item, string_type, integer_type, "formAddString"); + add_special_function(item, void_type, integer_type, "formAddSpace"); + add_special_function(item, image_type, integer_type, "formAddImage"); + add_special_function4(item, string_type, string_type, integer_type, integer_type, integer_type, "formAddTextField"); + add_special_function4(item, string_type, boolean_type, integer_type, integer_type, integer_type, "formAddGauge"); + add_special_function2(item, string_type, integer_type, integer_type, "formAddDateField"); + add_special_function2(item, integer_type, integer_type, void_type, "formSetDate"); + add_special_function(item, integer_type, integer_type, "formGetDate"); + + add_special_function2(item, string_type, integer_type, integer_type, "formAddChoice"); + + add_special_function(item, integer_type, integer_type, "formGetValue"); + add_special_function(item, integer_type, string_type, "formGetText"); + add_special_function2(item, integer_type, integer_type, void_type, "formSetValue"); + add_special_function2(item, integer_type, string_type, void_type, "formSetText"); + + add_special_function2(item, integer_type, string_type, integer_type, "choiceAppendString"); + add_special_function3(item, integer_type, string_type, image_type, integer_type, "choiceAppendStringImage"); + add_special_function2(item, integer_type, integer_type, boolean_type, "choiceIsSelected"); + add_special_function(item, integer_type, integer_type, "choiceGetSelectedIndex"); + + add_special_function(item, string_type, void_type, "setFormTitle"); + add_special_function(item, void_type, void_type, "removeFormTitle"); + add_special_function(item, void_type, string_type, "getFormTitle"); + + /* text box elements */ + add_special_function4(item, string_type, string_type, integer_type, integer_type, void_type, "showTextBox"); + add_special_function(item, void_type, string_type, "getTextBoxString"); + + /* alert elements */ + add_special_function4(item, string_type, string_type, image_type, alert_type, void_type, "showAlert"); + add_special_function(item, void_type, void_type, "playAlertSound"); + add_special_function(item, void_type, alert_type, "ALERT_INFO"); + add_special_function(item, void_type, alert_type, "ALERT_WARNING"); + add_special_function(item, void_type, alert_type, "ALERT_ERROR"); + add_special_function(item, void_type, alert_type, "ALERT_ALARM"); + add_special_function(item, void_type, alert_type, "ALERT_CONFIRMATION"); + + /* menu functions */ + add_special_function2(item, string_type, integer_type, void_type, "showMenu"); + add_special_function(item, string_type, integer_type, "menuAppendString"); + add_special_function2(item, string_type, image_type, integer_type, "menuAppendStringImage"); + add_special_function(item, integer_type, boolean_type, "menuIsSelected"); + add_special_function(item, void_type, integer_type, "menuGetSelectedIndex"); + + + /* record store functions */ + add_special_function(item, string_type, record_store_type, "openRecordStore"); + add_special_function(item, record_store_type, void_type, "closeRecordStore"); + add_special_function(item, string_type, void_type, "deleteRecordStore"); + add_special_function2(item, record_store_type, integer_type, void_type, "deleteRecordStoreEntry"); + add_special_function2(item, record_store_type, string_type, integer_type, "addRecordStoreEntry"); + add_special_function2(item, record_store_type, integer_type, string_type, "readRecordStoreEntry"); + add_special_function(item, record_store_type, integer_type, "getRecordStoreSize"); + add_special_function3(item, record_store_type, string_type, integer_type, void_type, "modifyRecordStoreEntry"); + add_special_function(item, record_store_type, integer_type, "getRecordStoreNextId"); + + /* http connectivity functions */ + add_special_function2(item, http_type, string_type, boolean_type, "openHttp"); + add_special_function(item, http_type, boolean_type, "isHttpOpen"); + add_special_function(item, http_type, void_type, "closeHttp"); + add_special_function3(item, http_type, string_type, string_type, void_type, "addHttpHeader"); + add_special_function2(item, http_type, string_type, void_type, "setHttpMethod"); + add_special_function(item, http_type, integer_type, "sendHttpMessage"); + add_special_function2(item, http_type, string_type, string_type, "getHttpHeader"); + add_special_function2(item, http_type, string_type, void_type, "addHttpBody"); + add_special_function(item, http_type, string_type, "getHttpResponse"); + + + /* resource-handling functions */ + add_special_function(item, string_type, stream_type, "openResource"); + add_special_function(item, stream_type, void_type, "closeResource"); + add_special_function(item, stream_type, integer_type, "readByte"); + add_special_function(item, stream_type, string_type, "readLine"); + add_special_function(item, stream_type, boolean_type, "resourceAvailable"); + + /* player functions */ + add_special_function2(item, string_type, string_type, boolean_type, "openPlayer"); + add_special_function(item, void_type, boolean_type, "startPlayer"); + add_special_function(item, void_type, void_type, "stopPlayer"); + add_special_function(item, integer_type, boolean_type, "setPlayerCount"); + add_special_function(item, void_type, integer_type, "getPlayerDuration"); + + + /* SMS functions */ + add_special_function2(item, string_type, string_type, boolean_type, "smsStartSend"); + add_special_function(item, void_type, boolean_type, "smsIsSending"); + add_special_function(item, void_type, boolean_type, "smsWasSuccessfull"); + +} + + +/* + Adds a single type into the block +*/ +void add_std_type(block *item, enum en_type_class type_class, char *cstr_name) +{ + string *name; + identifier *descriptor; + + name = string_from_cstr(cstr_name); + descriptor = identifier_create(); + descriptor->identifier_class = type_name; + descriptor->defined_type = type_create(); + descriptor->defined_type->type_class = type_class; + name_table_insert(item->names, name, descriptor); +} + + +/* + Add a standard function +*/ +void add_std_function(block *item, char *cstr_name, type_list *params, type *return_type) +{ + string *name; + identifier *descriptor; + + name = string_from_cstr(cstr_name); + descriptor = identifier_create(); + descriptor->identifier_class = function_name; + descriptor->return_type = return_type; + descriptor->parameters = params; + descriptor->variables = NULL; + descriptor->standard_function = 1; + name_table_insert(item->names, name, descriptor); +} + + +/* + Add a standard procedure +*/ +void add_std_procedure(block *item, char *cstr_name, type_list *params) +{ + string *name; + identifier *descriptor; + + name = string_from_cstr(cstr_name); + descriptor = identifier_create(); + descriptor->identifier_class = procedure_name; + descriptor->parameters = params; + descriptor->variables = NULL; + descriptor->standard_function = 1; + name_table_insert(item->names, name, descriptor); +} + + +/* + Creates the 'prefix' code, the code that is executed before the arguments are evaluated +*/ +void create_std_function_prefix(bytecode *code, char *name) +{ + lowercase(name); + + if ( (strcmp(name, "drawtext") == 0) + || (strcmp(name, "drawline") == 0) + || (strcmp(name, "setcolor") == 0) + || (strcmp(name, "drawellipse") == 0) + || (strcmp(name, "fillellipse") == 0) + || (strcmp(name, "drawrect") == 0) + || (strcmp(name, "fillrect") == 0) + || (strcmp(name, "drawarc") == 0) + || (strcmp(name, "plot") == 0) + || (strcmp(name, "getcolorred") == 0) + || (strcmp(name, "getcolorblue") == 0) + || (strcmp(name, "getcolorgreen") == 0) + || (strcmp(name, "drawroundrect") == 0) + || (strcmp(name, "fillroundrect") == 0) + || (strcmp(name, "setfont") == 0) + || (strcmp(name, "setdefaultfont") == 0) + || (strcmp(name, "drawimage") == 0) + || (strcmp(name, "getstringheight") == 0) + || (strcmp(name, "setclip") == 0) + ) + { + int field_index = cp_add_fieldref("M", "G", "Ljavax/microedition/lcdui/Graphics;"); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, field_index); + + return; + } + + if ( (strcmp(name, "getwidth") == 0) + || (strcmp(name, "getheight") == 0) + ) + { + int field_index = cp_add_fieldref("M", "I", "Ljavax/microedition/lcdui/Image;"); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, field_index); + + return; + } + + if ((strcmp(name, "getsecond") == 0) + || (strcmp(name, "getminute") == 0) + || (strcmp(name, "gethour") == 0) + || (strcmp(name, "getday") == 0) + || (strcmp(name, "getmonth") == 0) + || (strcmp(name, "getyear") == 0) + || (strcmp(name, "getweekday") == 0) + || (strcmp(name, "getyearday") == 0) + ) + { + int method1, class1; + method1 = cp_add_methodref("java/util/Calendar", "getInstance", "()Ljava/util/Calendar;"); + class1 = cp_add_class("java/util/Date"); + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, method1); + + bytecode_append(code, dup$); + + bytecode_append(code, new$); + bytecode_append_short_int(code, class1); + + bytecode_append(code, dup$); + + return; + } + + if (strcmp(name, "createcommand") == 0) + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("javax/microedition/lcdui/Command")); + bytecode_append(code, dup$); + + return; + } + + if ((strcmp(name, "vibrate") == 0) + || (strcmp(name, "iscolordisplay") == 0) + || (strcmp(name, "getcolorsnum") == 0)) + { + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "fw", "LFW;")); + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Display", + "getDisplay", "(Ljavax/microedition/midlet/MIDlet;)Ljavax/microedition/lcdui/Display;")); + return; + } + + if (strcmp(name, "showtextbox") == 0) + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("javax/microedition/lcdui/TextBox")); + bytecode_append(code, dup$); + return; + } + + if (strcmp(name, "showalert") == 0) + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("javax/microedition/lcdui/Alert")); + bytecode_append(code, dup$); + return; + } + + if (strcmp(name, "showmenu") == 0) + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("javax/microedition/lcdui/List")); + bytecode_append(code, dup$); + return; + } + + if ((strcmp(name, "menuappendstring") == 0) + || (strcmp(name, "menuappendstringimage") == 0) + || (strcmp(name, "menuisselected") == 0) + || (strcmp(name, "menugetselectedindex") == 0)) + { + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "L", "Ljavax/microedition/lcdui/List;")); + return; + } + + if (strcmp(name, "stringtoreal") == 0) + { + if (mathType != 1) + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup$); + } + } +} + + +/* + Create the bytecode for the standard function or procedure +*/ +void create_std_function_code(bytecode *code, char *name) +{ + int count = 0; + + lowercase(name); + + switch(name[0]) + { + case 'a': goto letter_a; + case 'b': goto letter_b; + case 'c': goto letter_c; + case 'd': goto letter_d; + case 'e': goto letter_e; + case 'f': goto letter_f; + case 'g': goto letter_g; + case 'h': goto letter_h; + case 'i': goto letter_i; + case 'j': goto letter_j; + case 'k': goto letter_k; + case 'l': goto letter_l; + case 'm': goto letter_m; + case 'n': goto letter_n; + case 'o': goto letter_o; + case 'p': goto letter_p; + case 'q': goto letter_q; + case 'r': goto letter_r; + case 's': goto letter_s; + case 't': goto letter_t; + case 'u': goto letter_u; + case 'v': goto letter_v; + case 'w': goto letter_w; + case 'x': goto letter_x; + case 'y': goto letter_y; + case 'z': goto letter_z; + } + +letter_a: + if (strcmp(name, "addhttpbody") == 0) + { + usesHttp = 1; + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("H", "o", "(Ljava/lang/String;)I")); + bytecode_append(code, pop$); + return; + } + + if (strcmp(name, "addcommand") == 0) + { + if (canvasType == FULL_NOKIA) + { + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "CD", "Ljavax/microedition/lcdui/Displayable;")); + + bytecode_append(code, dup$); + bytecode_append(code, instanceof$); + bytecode_append_short_int(code, cp_add_class("com/nokia/mid/ui/FullCanvas")); + + bytecode_append(code, ifne$); + bytecode_append_short_int(code, 10); + + bytecode_append(code, swap$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Displayable", "addCommand", "(Ljavax/microedition/lcdui/Command;)V")); + bytecode_append(code, goto$); + bytecode_append_short_int(code, 4); + + bytecode_append(code, pop2$); + } + else + { + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "CD", "Ljavax/microedition/lcdui/Displayable;")); + bytecode_append(code, swap$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Displayable", "addCommand", "(Ljavax/microedition/lcdui/Command;)V")); + } + + return; + } + + if (strcmp(name, "addrecordstoreentry") == 0) + { + usesRecordStore = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, + cp_add_methodref("RS", "L", "(Ljavax/microedition/rms/RecordStore;Ljava/lang/String;)I")); + return; + } + + if (strcmp(name, "assert") == 0) + { + char assert_text[128]; + sprintf(assert_text, "Assertion failed at: %s:%d", source_file_name ,procedure_linenum); + bytecode_append(code, ifne$); + bytecode_append_short_int(code, 12); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("java/lang/System", "out", "Ljava/io/PrintStream;")); + bytecode_append(code, ldc_w$); + bytecode_append_short_int(code, cp_add_string(assert_text)); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("java/io/PrintStream", "println", "(Ljava/lang/String;)V")); + return; + } + + if (strcmp(name, "abs") == 0) + { + int method_index; + + method_index = cp_add_methodref("java/lang/Math", "abs", "(I)I"); + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp(name, "atan") == 0) + { + usesFloat = 1; + if (mathType == 1) + { + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("F", "atan", "(I)I")); + } + else + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(LReal;)V")); + bytecode_append(code, dup$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("Real", "atan", "()V")); + } + + return; + } + + if (strcmp(name, "atan2") == 0) + { + usesFloat = 1; + if (mathType == 1) + { + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("F", "atan2", "(II)I")); + } + else + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(LReal;)V")); + + bytecode_append(code, swap$); + + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(LReal;)V")); + + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("Real", "atan2", "(LReal;)V")); + } + + return; + } + + if (strcmp(name, "asin") == 0) + { + usesFloat = 1; + if (mathType == 1) + { + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("F", "AS", "(I)I")); + } + else + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(LReal;)V")); + bytecode_append(code, dup$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("Real", "asin", "()V")); + } + + return; + } + + if (strcmp(name, "acos") == 0) + { + usesFloat = 1; + if (mathType == 1) + { + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("F", "AC", "(I)I")); + } + else + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(LReal;)V")); + bytecode_append(code, dup$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("Real", "acos", "()V")); + } + + return; + } + + if (strcmp(name, "addhttpheader") == 0) + { + usesHttp = 1; + //usesRegisteredFeature = 1; + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("H", "L", "(Ljava/lang/String;Ljava/lang/String;)V")); + return; + } + + if (strcmp(name, "alert_alarm") == 0) + { + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("javax/microedition/lcdui/AlertType", + "ALARM", "Ljavax/microedition/lcdui/AlertType;")); + return; + } + + if (strcmp(name, "alert_confirmation") == 0) + { + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("javax/microedition/lcdui/AlertType", + "CONFIRMATION", "Ljavax/microedition/lcdui/AlertType;")); + return; + } + + if (strcmp(name, "alert_error") == 0) + { + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("javax/microedition/lcdui/AlertType", + "ERROR", "Ljavax/microedition/lcdui/AlertType;")); + return; + } + + if (strcmp(name, "alert_info") == 0) + { + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("javax/microedition/lcdui/AlertType", + "INFO", "Ljavax/microedition/lcdui/AlertType;")); + return; + } + + if (strcmp(name, "alert_warning") == 0) + { + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("javax/microedition/lcdui/AlertType", + "WARNING", "Ljavax/microedition/lcdui/AlertType;")); + return; + } + +letter_b: +letter_c: + + if (strcmp(name, "closeresource") == 0) + { + usesSupport = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("S", "r", "(Ljava/io/InputStream;)V")); + return; + } + + if (strcmp(name, "createcommand") == 0) + { + int method_index = cp_add_methodref("javax/microedition/lcdui/Command", "", "(Ljava/lang/String;II)V"); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp(name, "cos") == 0) + { + usesFloat = 1; + if (mathType == 1) + { + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("F", "C", "(I)I")); + } + else + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(LReal;)V")); + bytecode_append(code, dup$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("Real", "cos", "()V")); + } + + return; + } + + if (strcmp(name, "chr") == 0) + { + /* do nothing since we represent chars and integers internally in the same way */ + return; + } + + if (strcmp(name, "copy") == 0) + { + int method_index; + + method_index = cp_add_methodref("java/lang/String", "substring", "(II)Ljava/lang/String;"); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + return; + } + + if (strcmp(name, "clearform") == 0) + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("javax/microedition/lcdui/Form")); + bytecode_append(code, dup$); + + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("java/lang/String")); + bytecode_append(code, dup$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("java/lang/String", "", "()V")); + + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Form", "", "(Ljava/lang/String;)V")); + + bytecode_append(code, dup$); + bytecode_append(code, putstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "F", "Ljavax/microedition/lcdui/Form;")); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "fw", "LFW;")); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Displayable", "setCommandListener", "(Ljavax/microedition/lcdui/CommandListener;)V")); + + goto show_form; + + return; + } + + if(strcmp(name, "choiceappendstring") == 0) + { + usesForms = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("FS", "I", "(ILjava/lang/String;)I")); + return; + } + + if(strcmp(name, "choiceappendstringimage") == 0) + { + usesForms = 1; + //usesRegisteredFeature = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("FS", "I", "(ILjava/lang/String;Ljavax/microedition/lcdui/Image;)I")); + return; + } + + if(strcmp(name, "choiceisselected") == 0) + { + usesForms = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("FS", "L", "(II)I")); + return; + } + + if (strcmp(name, "")) + + if(strcmp(name, "choicegetselectedindex") == 0) + { + usesForms = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("FS", "L", "(I)I")); + return; + } + + if (strcmp(name, "closerecordstore") == 0) + { + usesRecordStore = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("RS", "L", "(Ljavax/microedition/rms/RecordStore;)V")); + return; + } + + if (strcmp(name, "closehttp") == 0) + { + usesHttp = 1; + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("H", "c", "()V")); + return; + } + +letter_d: + if (strcmp(name, "deleterecordstore") == 0) + { + usesRecordStore = 1; + //usesRegisteredFeature = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("RS", "L", "(Ljava/lang/String;)V")); + return; + } + + if (strcmp(name, "deleterecordstoreentry") == 0) + { + usesRecordStore = 1; + //usesRegisteredFeature = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, + cp_add_methodref("RS", "L", "(Ljavax/microedition/rms/RecordStore;I)V")); + return; + } + + if (strcmp(name, "debug") == 0) + { + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("java/lang/System", "out", "Ljava/io/PrintStream;")); + bytecode_append(code, swap$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("java/io/PrintStream", "println", "(Ljava/lang/String;)V")); + return; + } + + if (strcmp(name, "delay") == 0) + { + int method_index; + + method_index = cp_add_methodref("java/lang/Thread", "sleep", "(J)V"); + + bytecode_append(code, i2l$); + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp(name, "drawtext") == 0) + { + int method_index; + + method_index = cp_add_methodref("javax/microedition/lcdui/Graphics", "drawString", "(Ljava/lang/String;III)V"); + + bytecode_append(code, bipush$); + bytecode_append(code, 20); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp(name, "drawline") == 0) + { + int method_index; + + method_index = cp_add_methodref("javax/microedition/lcdui/Graphics", "drawLine", "(IIII)V"); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp(name, "drawellipse") == 0) + { + int method_index; + + method_index = cp_add_methodref("javax/microedition/lcdui/Graphics", "drawArc", "(IIIIII)V"); + + bytecode_append(code, bipush$); + bytecode_append(code, 0); + bytecode_append(code, sipush$); + bytecode_append_short_int(code, 360); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp(name, "drawarc") == 0) + { + int method_index; + + method_index = cp_add_methodref("javax/microedition/lcdui/Graphics", "drawArc", "(IIIIII)V"); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp(name, "drawrect") == 0) + { + int method_index; + + method_index = cp_add_methodref("javax/microedition/lcdui/Graphics", "drawRect", "(IIII)V"); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp(name, "drawroundrect") == 0) + { + int method_index; + + method_index = cp_add_methodref("javax/microedition/lcdui/Graphics", "drawRoundRect", "(IIIIII)V"); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp(name, "drawimage") == 0) + { + int method_index = cp_add_methodref("javax/microedition/lcdui/Graphics", "drawImage", "(Ljavax/microedition/lcdui/Image;III)V"); + + bytecode_append(code, bipush$); + bytecode_append(code, 20); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + return; + } + +letter_e: + if (strcmp(name, "emptycommand") == 0) + { + bytecode_append(code, aconst_null$); + return; + } + + if (strcmp(name, "exp") == 0) + { + usesFloat = 1; + if (mathType == 1) + { + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("F", "e", "(I)I")); + } + else + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(LReal;)V")); + bytecode_append(code, dup$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("Real", "exp", "()V")); + } + + return; + } + +letter_f: + if (strcmp(name, "frac") == 0) + { + usesFloat = 1; + if (mathType == 1) + { + bytecode_append(code, sipush$); + bytecode_append_short_int(code, 0x0FFF); + bytecode_append(code, iand$); + } + else + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(LReal;)V")); + bytecode_append(code, dup$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("Real", "frac", "()V")); + } + + return; + } + + if (strcmp(name, "fillellipse") == 0) + { + int method_index; + + method_index = cp_add_methodref("javax/microedition/lcdui/Graphics", "fillArc", "(IIIIII)V"); + + bytecode_append(code, bipush$); + bytecode_append(code, 0); + bytecode_append(code, sipush$); + bytecode_append_short_int(code, 360); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp(name, "fillrect") == 0) + { + int method_index; + + method_index = cp_add_methodref("javax/microedition/lcdui/Graphics", "fillRect", "(IIII)V"); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + + + if (strcmp(name, "fillroundrect") == 0) + { + int method_index; + + method_index = cp_add_methodref("javax/microedition/lcdui/Graphics", "fillRoundRect", "(IIIIII)V"); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp(name, "formaddstring") == 0) + { + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "F", "Ljavax/microedition/lcdui/Form;")); + + bytecode_append(code, swap$); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Form", "append", "(Ljava/lang/String;)I")); + return; + } + + if (strcmp(name, "formaddimage") == 0) + { + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "F", "Ljavax/microedition/lcdui/Form;")); + + bytecode_append(code, swap$); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Form", "append", "(Ljavax/microedition/lcdui/Image;)I")); + return; + } + + if (strcmp(name, "formadddatefield") == 0) + { + usesForms = 1; + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("FS", "dd", "(Ljava/lang/String;I)I")); + return; + } + + if (strcmp(name, "formsetdate") == 0) + { + usesForms = 1; + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("FS", "dd", "(II)V")); + return; + } + + if (strcmp(name, "formgetdate") == 0) + { + usesForms = 1; + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("FS", "dd", "(I)I")); + return; + } + + if (strcmp(name, "formaddspace") == 0) + { + /* get Form */ + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "F", "Ljavax/microedition/lcdui/Form;")); + + /* new Spacer */ + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("javax/microedition/lcdui/Spacer")); + + bytecode_append(code, dup$); + + /* init spacer(10, 10)*/ + bytecode_append(code, bipush$); + bytecode_append(code, 10); + bytecode_append(code, dup$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Spacer", "", "(II)V")); + + /* form.append(Spacer)*/ + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Form", "append", "(Ljavax/microedition/lcdui/Item;)I")); + return; + } + + if (strcmp(name, "formaddtextfield") == 0) + { + usesForms = 1; + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("FS", "Lj", "(Ljava/lang/String;Ljava/lang/String;II)I")); + return; + } + + if (strcmp(name, "formaddgauge") == 0) + { + usesForms = 1; + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("FS", "Lj", "(Ljava/lang/String;III)I")); + return; + } + + if (strcmp(name, "formremove") == 0) + { + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "F", "Ljavax/microedition/lcdui/Form;")); + + bytecode_append(code, swap$); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Form", "delete", "(I)V")); + + return; + } + + if (strcmp(name, "formaddchoice") == 0) + { + usesForms = 1; + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("FS", "Lj", "(Ljava/lang/String;I)I")); + return; + } + + if (strcmp(name, "formgetvalue") == 0) + { + usesForms = 1; + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("FS", "Lja", "(I)I")); + return; + } + + if (strcmp(name, "formsetvalue") == 0) + { + usesForms = 1; + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("FS", "Lja", "(II)V")); + return; + } + + if (strcmp(name, "formgettext") == 0) + { + usesForms = 1; + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("FS", "ja", "(I)Ljava/lang/String;")); + return; + } + + if (strcmp(name, "formsettext") == 0) + { + usesForms = 1; + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("FS", "ja", "(ILjava/lang/String;)V")); + return; + } + +letter_g: + if (strcmp(name, "getformtitle") == 0) + { + usesForms = 1; + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("FS", "gft", "()Ljava/lang/String;")); + return; + } + + if (strcmp(name, "getrecordstorenextid") == 0) + { + usesRecordStore = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, + cp_add_methodref("RS", "Lja", "(Ljavax/microedition/rms/RecordStore;)I")); + return; + } + + if (strcmp(name, "getplayerduration") == 0) + { + usesPlayer = 1; + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("P", "c", "()I")); + return; + } + + if (strcmp(name, "getchar") == 0) + { + usesSupport = 1; + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("S", "gc", "(Ljava/lang/String;I)I")); + return; + } + + if (strcmp(name, "getrecordstoresize") == 0) + { + usesRecordStore = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("RS", "j", "(Ljavax/microedition/rms/RecordStore;)I")); + return; + } + + if (strcmp(name, "getclickedcommand") == 0) + { + /* return LC */ + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "LC", "Ljavax/microedition/lcdui/Command;")); + + /* set LC = null */ + bytecode_append(code, aconst_null$); + bytecode_append(code, putstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "LC", "Ljavax/microedition/lcdui/Command;")); + return; + } + + if (strcmp(name, "gettextboxstring") == 0) + { + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "TB", "Ljavax/microedition/lcdui/TextBox;")); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/TextBox", "getString", "()Ljava/lang/String;")); + return; + } + + if (strcmp(name, "getrelativetimems") == 0) + { + int method_index; + + method_index = cp_add_methodref("java/lang/System", "currentTimeMillis", "()J"); + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, method_index); + bytecode_append(code, l2i$); + return; + } + + if (strcmp(name, "getcurrenttime") == 0) + { + int method_index; + + method_index = cp_add_methodref("java/lang/System", "currentTimeMillis", "()J"); + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, method_index); + bytecode_append(code, sipush$); + bytecode_append_short_int(code, 1000); + bytecode_append(code, i2l$); + bytecode_append(code, ldiv$); + bytecode_append(code, l2i$); + return; + } + + if (strcmp(name, "getday") == 0) + { + int method1, method2, method3, method4; + method1 = cp_add_methodref("java/util/Calendar", "getInstance", "()Ljava/util/Calendar;"); + method2 = cp_add_methodref("java/util/Calendar", "setTime", "(Ljava/util/Date;)V"); + method3 = cp_add_methodref("java/util/Calendar", "get", "(I)I"); + method4 = cp_add_methodref("java/util/Date", "", "(J)V"); + + /* time as int-seconds traslate into millis-long */ + bytecode_append(code, i2l$); + bytecode_append(code, sipush$); + bytecode_append_short_int(code, 1000); + bytecode_append(code, i2l$); + bytecode_append(code, lmul$); + + /* the stack is now: ..., Calendar, Calendar, Date, Date, Millis */ + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, method4); + + /* stack is now Calendar, Calendar, Date*/ + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method2); + + bytecode_append(code, bipush$); + bytecode_append(code, 5); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method3); + + return; + } + + if (strcmp(name, "getweekday") == 0) + { + int method1, method2, method3, method4; + method1 = cp_add_methodref("java/util/Calendar", "getInstance", "()Ljava/util/Calendar;"); + method2 = cp_add_methodref("java/util/Calendar", "setTime", "(Ljava/util/Date;)V"); + method3 = cp_add_methodref("java/util/Calendar", "get", "(I)I"); + method4 = cp_add_methodref("java/util/Date", "", "(J)V"); + + /* time as int-seconds traslate into millis-long */ + bytecode_append(code, i2l$); + bytecode_append(code, sipush$); + bytecode_append_short_int(code, 1000); + bytecode_append(code, i2l$); + bytecode_append(code, lmul$); + + /* the stack is now: ..., Calendar, Calendar, Date, Date, Millis */ + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, method4); + + /* stack is now Calendar, Calendar, Date*/ + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method2); + + bytecode_append(code, bipush$); + bytecode_append(code, 7); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method3); + + return; + } + + if (strcmp(name, "getyearday") == 0) + { + int method1, method2, method3, method4; + method1 = cp_add_methodref("java/util/Calendar", "getInstance", "()Ljava/util/Calendar;"); + method2 = cp_add_methodref("java/util/Calendar", "setTime", "(Ljava/util/Date;)V"); + method3 = cp_add_methodref("java/util/Calendar", "get", "(I)I"); + method4 = cp_add_methodref("java/util/Date", "", "(J)V"); + + /* time as int-seconds traslate into millis-long */ + bytecode_append(code, i2l$); + bytecode_append(code, sipush$); + bytecode_append_short_int(code, 1000); + bytecode_append(code, i2l$); + bytecode_append(code, lmul$); + + /* the stack is now: ..., Calendar, Calendar, Date, Date, Millis */ + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, method4); + + /* stack is now Calendar, Calendar, Date*/ + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method2); + + bytecode_append(code, bipush$); + bytecode_append(code, 6); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method3); + + return; + } + + if (strcmp(name, "getmonth") == 0) + { + int method1, method2, method3, method4; + method1 = cp_add_methodref("java/util/Calendar", "getInstance", "()Ljava/util/Calendar;"); + method2 = cp_add_methodref("java/util/Calendar", "setTime", "(Ljava/util/Date;)V"); + method3 = cp_add_methodref("java/util/Calendar", "get", "(I)I"); + method4 = cp_add_methodref("java/util/Date", "", "(J)V"); + + /* time as int-seconds traslate into millis-long */ + bytecode_append(code, i2l$); + bytecode_append(code, sipush$); + bytecode_append_short_int(code, 1000); + bytecode_append(code, i2l$); + bytecode_append(code, lmul$); + + /* the stack is now: ..., Calendar, Calendar, Date, Date, Millis */ + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, method4); + + /* stack is now Calendar, Calendar, Date*/ + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method2); + + bytecode_append(code, bipush$); + bytecode_append(code, 2); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method3); + + bytecode_append(code, iconst_0$); + bytecode_append(code, iadd$); + + return; + } + + if (strcmp(name, "getyear") == 0) + { + int method1, method2, method3, method4; + method1 = cp_add_methodref("java/util/Calendar", "getInstance", "()Ljava/util/Calendar;"); + method2 = cp_add_methodref("java/util/Calendar", "setTime", "(Ljava/util/Date;)V"); + method3 = cp_add_methodref("java/util/Calendar", "get", "(I)I"); + method4 = cp_add_methodref("java/util/Date", "", "(J)V"); + + /* time as int-seconds traslate into millis-long */ + bytecode_append(code, i2l$); + bytecode_append(code, sipush$); + bytecode_append_short_int(code, 1000); + bytecode_append(code, i2l$); + bytecode_append(code, lmul$); + + /* the stack is now: ..., Calendar, Calendar, Date, Date, Millis */ + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, method4); + + /* stack is now Calendar, Calendar, Date*/ + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method2); + + bytecode_append(code, bipush$); + bytecode_append(code, 1); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method3); + + return; + } + + if (strcmp(name, "getsecond") == 0) + { + int method1, method2, method3, method4; + method1 = cp_add_methodref("java/util/Calendar", "getInstance", "()Ljava/util/Calendar;"); + method2 = cp_add_methodref("java/util/Calendar", "setTime", "(Ljava/util/Date;)V"); + method3 = cp_add_methodref("java/util/Calendar", "get", "(I)I"); + method4 = cp_add_methodref("java/util/Date", "", "(J)V"); + + /* time as int-seconds traslate into millis-long */ + bytecode_append(code, i2l$); + bytecode_append(code, sipush$); + bytecode_append_short_int(code, 1000); + bytecode_append(code, i2l$); + bytecode_append(code, lmul$); + + /* the stack is now: ..., Calendar, Calendar, Date, Date, Millis */ + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, method4); + + /* stack is now Calendar, Calendar, Date*/ + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method2); + + bytecode_append(code, bipush$); + bytecode_append(code, 13); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method3); + + return; + } + + if (strcmp(name, "getminute") == 0) + { + int method1, method2, method3, method4; + method1 = cp_add_methodref("java/util/Calendar", "getInstance", "()Ljava/util/Calendar;"); + method2 = cp_add_methodref("java/util/Calendar", "setTime", "(Ljava/util/Date;)V"); + method3 = cp_add_methodref("java/util/Calendar", "get", "(I)I"); + method4 = cp_add_methodref("java/util/Date", "", "(J)V"); + + /* time as int-seconds traslate into millis-long */ + bytecode_append(code, i2l$); + bytecode_append(code, sipush$); + bytecode_append_short_int(code, 1000); + bytecode_append(code, i2l$); + bytecode_append(code, lmul$); + + /* the stack is now: ..., Calendar, Calendar, Date, Date, Millis */ + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, method4); + + /* stack is now Calendar, Calendar, Date*/ + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method2); + + bytecode_append(code, bipush$); + bytecode_append(code, 12); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method3); + + return; + } + + if (strcmp(name, "gethour") == 0) + { + int method1, method2, method3, method4; + method1 = cp_add_methodref("java/util/Calendar", "getInstance", "()Ljava/util/Calendar;"); + method2 = cp_add_methodref("java/util/Calendar", "setTime", "(Ljava/util/Date;)V"); + method3 = cp_add_methodref("java/util/Calendar", "get", "(I)I"); + method4 = cp_add_methodref("java/util/Date", "", "(J)V"); + + /* time as int-seconds traslate into millis-long */ + bytecode_append(code, i2l$); + bytecode_append(code, sipush$); + bytecode_append_short_int(code, 1000); + bytecode_append(code, i2l$); + bytecode_append(code, lmul$); + + /* the stack is now: ..., Calendar, Calendar, Date, Date, Millis */ + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, method4); + + /* stack is now Calendar, Calendar, Date*/ + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method2); + + bytecode_append(code, bipush$); + bytecode_append(code, 11); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method3); + + return; + } + + if (strcmp(name, "getkeypressed") == 0) + { + int field_index = cp_add_fieldref("M", "KP", "I"); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, field_index); + + return; + } + + if (strcmp(name, "getkeyclicked") == 0) + { + int field_index = cp_add_fieldref("M", "KC", "I"); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, field_index); + bytecode_append(code, iconst_0$); + bytecode_append(code, putstatic$); + bytecode_append_short_int(code, field_index); + + return; + } + + if (strcmp(name, "getcolorred") == 0) + { + int method_index; + + method_index = cp_add_methodref("javax/microedition/lcdui/Graphics", "getRedComponent", "()I"); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp(name, "getcolorgreen") == 0) + { + int method_index; + + method_index = cp_add_methodref("javax/microedition/lcdui/Graphics", "getGreenComponent", "()I"); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp(name, "getcolorblue") == 0) + { + int method_index; + + method_index = cp_add_methodref("javax/microedition/lcdui/Graphics", "getBlueComponent", "()I"); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp(name, "getwidth") == 0) + { + int method_index; + + method_index = cp_add_methodref("javax/microedition/lcdui/Image", "getWidth", "()I"); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp(name, "getheight") == 0) + { + int method_index; + + method_index = cp_add_methodref("javax/microedition/lcdui/Image", "getHeight", "()I"); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp(name, "getimagewidth") == 0) + { + int method_index = cp_add_methodref("javax/microedition/lcdui/Image", "getWidth", "()I"); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + return; + } + + if (strcmp(name, "getimageheight") == 0) + { + int method_index = cp_add_methodref("javax/microedition/lcdui/Image", "getHeight", "()I"); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + return; + } + + if (strcmp(name, "getstringheight") == 0) + { + int method_index; + method_index = cp_add_methodref("javax/microedition/lcdui/Graphics", "getFont", "()Ljavax/microedition/lcdui/Font;"); + bytecode_append(code, pop$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + method_index = cp_add_methodref("javax/microedition/lcdui/Font", "getHeight", "()I"); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + return; + } + + if (strcmp(name, "getstringwidth") == 0) + { + int method_index; + int field_index = cp_add_fieldref("M", "G", "Ljavax/microedition/lcdui/Graphics;"); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, field_index); + + method_index = cp_add_methodref("javax/microedition/lcdui/Graphics", "getFont", "()Ljavax/microedition/lcdui/Font;"); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + bytecode_append(code, swap$); + method_index = cp_add_methodref("javax/microedition/lcdui/Font", "stringWidth", "(Ljava/lang/String;)I"); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp(name, "getproperty") == 0) + { + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("java/lang/System", "getProperty", "(Ljava/lang/String;)Ljava/lang/String;")); + bytecode_append(code, dup$); + bytecode_append(code, ifnonnull$); + bytecode_append_short_int(code, 11); + + /* if the returned string is null, create an empty string */ + bytecode_append(code, pop$); + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("java/lang/String")); + bytecode_append(code, dup$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("java/lang/String", "", "()V")); + return; + } + + if (strcmp(name, "getcolorsnum") == 0) + { + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Display", "numColors", "()I")); + return; + } + + if (strcmp(name, "gethttpheader") == 0) + { + usesHttp = 1; + //usesRegisteredFeature = 1; + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("H", "i", "(Ljava/lang/String;)Ljava/lang/String;")); + return; + } + + if (strcmp(name, "gethttpresponse") == 0) + { + usesHttp = 1; + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("H", "j", "()Ljava/lang/String;")); + return; + } + +letter_h: + if (strcmp(name, "halt") == 0) + { + int field_index; + int method_index; + + field_index = cp_add_fieldref("FW", "fw", "LFW;"); + method_index = cp_add_methodref("FW", "destroyApp", "(Z)V"); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, field_index); + bytecode_append(code, iconst_1$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("java/lang/Thread", "currentThread", "()Ljava/lang/Thread;")); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("java/lang/Thread", "join", "()V")); + + bytecode_append(code, sipush$); + bytecode_append_short_int(code, 1000); + bytecode_append(code, i2l$); + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("java/lang/Thread", "sleep", "(J)V")); + + return; + } + +letter_i: + if (strcmp(name, "imagefromimage") == 0) + { + usesSupport = 1; + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("S", "ii", "(Ljavax/microedition/lcdui/Image;IIII)Ljavax/microedition/lcdui/Image;")); + return; + } + + if (strcmp(name, "imagefromcanvas") == 0) + { + usesSupport = 1; + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("S", "ii", "(IIII)Ljavax/microedition/lcdui/Image;")); + return; + } + + if (strcmp(name, "imagefrombuffer") == 0) + { + usesSupport = 1; + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("S", "ii", "(Ljava/lang/String;I)Ljavax/microedition/lcdui/Image;")); + return; + } + + if (strcmp(name, "integertostring") == 0) + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("java/lang/StringBuffer")); + bytecode_append(code, dup$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("java/lang/StringBuffer", "", "()V")); + + bytecode_append(code, swap$); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("java/lang/StringBuffer", "append", "(I)Ljava/lang/StringBuffer;")); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("java/lang/StringBuffer", "toString", "()Ljava/lang/String;")); + return; + } + + if (strcmp(name, "ismidletpaused") == 0) + { + int field_index = cp_add_fieldref("FW", "MP", "I"); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, field_index); + + return; + } + + if (strcmp(name, "ishttpopen") == 0) + { + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("H", "L", "()I")); + return; + } + + if (strcmp(name, "iscolordisplay") == 0) + { + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Display", "isColor", "()Z")); + + bytecode_append(code, ifeq$); + bytecode_append_short_int(code, 7); + + bytecode_append(code, iconst_m1$); + bytecode_append(code, goto$); + bytecode_append_short_int(code, 4); + + bytecode_append(code, iconst_0$); + + return; + } + +letter_j: +letter_k: + if (strcmp(name, "keytoaction") == 0) + { + int field_index = cp_add_fieldref("M", "T", "LM;"); + + /* check if the argument is zero, goto (1)*/ + bytecode_append(code, dup$); + bytecode_append(code, ifeq$); + bytecode_append_short_int(code, 13); + + /* otherwise call the getGameAction*/ + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, field_index); + bytecode_append(code, swap$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("M", "getGameAction", "(I)I")); + + /* goto (2) */ + bytecode_append(code, goto$); + bytecode_append_short_int(code, 5); + + /* (1): pop the operands, push 0 to the stack */ + bytecode_append(code, pop$); + bytecode_append(code, iconst_0$); + + /* (2): continue */ + + return; + } + +letter_l: + if (strcmp(name, "log") == 0) + { + usesFloat = 1; + if (mathType == 1) + { + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("F", "log", "(I)I")); + } + else + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(LReal;)V")); + bytecode_append(code, dup$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("Real", "ln", "()V")); + } + + return; + } + + if (strcmp(name, "log10") == 0) + { + usesFloat = 1; + if (mathType == 1) + { + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("F", "log10", "(I)I")); + } + else + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(LReal;)V")); + bytecode_append(code, dup$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("Real", "log10", "()V")); + } + + return; + } + + if (strcmp(name, "length") == 0) + { + int method_index = cp_add_methodref("java/lang/String", "length", "()I"); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + return; + } + + if (strcmp(name, "locase") == 0) + { + int init_index; + int class_index; + int method_index; + + class_index = cp_add_class("java/lang/String"); + init_index = cp_add_methodref("java/lang/String", "", "(Ljava/lang/String;)V"); + method_index = cp_add_methodref("java/lang/String", "toLowerCase", "()Ljava/lang/String;"); + + bytecode_append(code, new$); + bytecode_append_short_int(code, class_index); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, init_index); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + return; + } + + if (strcmp(name, "loadimage") == 0) + { + int method_index = cp_add_methodref("javax/microedition/lcdui/Image", "createImage", "(Ljava/lang/String;)Ljavax/microedition/lcdui/Image;"); + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, method_index); + return; + } + +letter_m: + if (strcmp(name, "modifyrecordstoreentry") == 0) + { + usesRecordStore = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, + cp_add_methodref("RS", "L", "(Ljavax/microedition/rms/RecordStore;Ljava/lang/String;I)V")); + return; + } + + + if (strcmp(name, "menuappendstring") == 0) + { + bytecode_append(code, aconst_null$); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/List", + "append", + "(Ljava/lang/String;Ljavax/microedition/lcdui/Image;)I")); + return; + } + + if (strcmp(name, "menuappendstringimage") == 0) + { + //usesRegisteredFeature = 1; + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/List", + "append", + "(Ljava/lang/String;Ljavax/microedition/lcdui/Image;)I")); + return; + } + + if (strcmp(name, "menuisselected") == 0) + { + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/List", + "isSelected", + "(I)Z")); + + bytecode_append(code, ifeq$); + bytecode_append_short_int(code, 7); + bytecode_append(code, iconst_m1$); + bytecode_append(code, goto$); + bytecode_append_short_int(code, 4); + bytecode_append(code, iconst_0$); + + return; + } + + if (strcmp(name, "menugetselectedindex") == 0) + { + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/List", + "getSelectedIndex", + "()I")); + return; + } + + + +letter_n: +letter_o: + + if (strcmp(name, "openplayer") == 0) + { + usesPlayer = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("P", "a", "(Ljava/lang/String;Ljava/lang/String;)I")); + return; + } + + if (strcmp(name, "openresource") == 0) + { + usesSupport = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("S", "r", "(Ljava/lang/String;)Ljava/io/InputStream;")); + return; + } + + if (strcmp(name, "ord") == 0) + { + /* do nothing, opposite of chr */ + return; + } + + if (strcmp(name, "openhttp") == 0) + { + usesHttp = 1; + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("H", "L", "(Ljava/lang/String;)I")); + return; + } + + if (strcmp(name, "odd") == 0) + { + /* just leave the last bit: if it is zero, the number is even and the 0 (false) + will be on the stack */ + bytecode_append(code, iconst_1$); + bytecode_append(code, iand$); + bytecode_append(code, iconst_m1$); + bytecode_append(code, imul$); + + return; + } + + if (strcmp(name, "openrecordstore") == 0) + { + usesRecordStore = 1; + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("RS", "j", "(Ljava/lang/String;)Ljavax/microedition/rms/RecordStore;")); + return; + } + +letter_p: + if (strcmp(name, "playtone") == 0) + { + int method_index = cp_add_methodref("javax/microedition/media/Manager", "playTone", "(III)V"); + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp(name, "playalertsound") == 0) + { + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "A", "Ljavax/microedition/lcdui/Alert;")); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Alert", "getType", "()Ljavax/microedition/lcdui/AlertType;")); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "fw", "LFW;")); + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Display", "getDisplay", "(Ljavax/microedition/midlet/MIDlet;)Ljavax/microedition/lcdui/Display;")); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref( + "javax/microedition/lcdui/AlertType", + "playSound", + "(Ljavax/microedition/lcdui/Display;)Z")); + + bytecode_append(code, pop$); + return; + } + + if (strcmp(name, "pow") == 0) + { + usesFloat = 1; + if (mathType == 1) + { + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("F", "p", "(II)I")); + } + else + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(LReal;)V")); + + bytecode_append(code, swap$); + + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(LReal;)V")); + + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("Real", "pow", "(LReal;)V")); + } + + return; + } + + if (strcmp(name, "pos") == 0) + { + int method_index; + + method_index = cp_add_methodref("java/lang/String", "indexOf", "(Ljava/lang/String;)I"); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + return; + } + + if (strcmp(name, "plot") == 0) + { + int method_index; + + method_index = cp_add_methodref("javax/microedition/lcdui/Graphics", "fillRect", "(IIII)V"); + + bytecode_append(code, iconst_1$); + bytecode_append(code, dup$); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + +letter_q: +letter_r: + if (strcmp(name, "removeformtitle") == 0) + { + /* get Form */ + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "F", "Ljavax/microedition/lcdui/Form;")); + + /* set the form's title to null */ + bytecode_append(code, aconst_null$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Form", "setTitle", "(Ljava/lang/String;)V")); + + return; + } + + if (strcmp(name, "resourceavailable") == 0) + { + bytecode_append(code, aconst_null$); + bytecode_append(code, if_acmpeq$); + bytecode_append_short_int(code, 7); + + bytecode_append(code, iconst_m1$); + bytecode_append(code, goto$); + bytecode_append_short_int(code, 4); + + bytecode_append(code, iconst_0$); + return; + } + + if (strcmp(name, "readbyte") == 0) + { + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("S", "rb", "(Ljava/io/InputStream;)I")); + return; + } + + if (strcmp(name, "readline") == 0) + { + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("S", "nl", "(Ljava/io/InputStream;)Ljava/lang/String;")); + return; + } + + if (strcmp(name, "readrecordstoreentry") == 0) + { + usesRecordStore = 1; + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("RS", "j", "(Ljavax/microedition/rms/RecordStore;I)Ljava/lang/String;")); + return; + } + + if (strcmp(name, "round") == 0) + { + int method_index; + + method_index = cp_add_methodref("java/lang/Math", "round", "(F)I"); + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp(name, "rabs") == 0) + { + usesFloat = 1; + if (mathType == 1) + { + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("F", "A", "(I)I")); + } + else + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(LReal;)V")); + bytecode_append(code, dup$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("Real", "abs", "()V")); + } + + return; + } + + if (strcmp(name, "randomize") == 0) + { + /* re-initialize the random number generator */ + int random_field_index; + int random_class_index; + int random_method_index; + + random_field_index = cp_add_fieldref("M", "RNG", "Ljava/util/Random;"); + random_class_index = cp_add_class("java/util/Random"); + random_method_index = cp_add_methodref("java/util/Random", "", "()V"); + + bytecode_append(code, new$); + bytecode_append_short_int(code, random_class_index); + + bytecode_append(code, dup$); + + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, random_method_index); + + bytecode_append(code, putstatic$); + bytecode_append_short_int(code, random_field_index); + return; + } + + if (strcmp(name, "random") == 0) + { + int rng_index; + int method_index; + + rng_index = cp_add_fieldref("M", "RNG", "Ljava/util/Random;"); + method_index = cp_add_methodref("java/util/Random", "nextInt", "()I"); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, rng_index); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + // do abs + bytecode_append(code, iconst_m1$); + bytecode_append(code, iconst_1$); + bytecode_append(code, iushr$); + bytecode_append(code, iand$); + + bytecode_append(code, swap$); + bytecode_append(code, irem$); + + return; + } + + if (strcmp(name, "removecommand") == 0) + { + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "CD", "Ljavax/microedition/lcdui/Displayable;")); + bytecode_append(code, swap$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Displayable", "removeCommand", "(Ljavax/microedition/lcdui/Command;)V")); + return; + } + + + if (strcmp(name, "repaint") == 0) + { + int method_index; + int field_index; + + method_index = cp_add_methodref("M", "repaint", "()V"); + field_index = cp_add_fieldref("M", "T", "LM;"); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, field_index); + + bytecode_append(code, dup$); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + method_index = cp_add_methodref("M", "serviceRepaints", "()V"); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + +letter_s: + if (strcmp(name, "setformtitle") == 0) + { + /* get Form */ + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "F", "Ljavax/microedition/lcdui/Form;")); + + /* set the form's title */ + bytecode_append(code, swap$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Form", "setTitle", "(Ljava/lang/String;)V")); + + return; + } + + if (strcmp(name, "setclip") == 0) + { + int method_index; + + method_index = cp_add_methodref("javax/microedition/lcdui/Graphics", "setClip", "(IIII)V"); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp("smsstartsend", name) == 0) + { + usesSMS = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("SM", "send", "(Ljava/lang/String;Ljava/lang/String;)I")); + return; + } + + if (strcmp("smsissending", name) == 0) + { + usesSMS = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("SM", "IS", "()I")); + return; + } + + if (strcmp("smswassuccessfull", name) == 0) + { + usesSMS = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("SM", "GS", "()I")); + return; + } + + if (strcmp("startplayer", name) == 0) + { + usesPlayer = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("P", "a", "()I")); + return; + } + + if (strcmp("stopplayer", name) == 0) + { + usesPlayer = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("P", "b", "()V")); + return; + } + + if (strcmp("setplayercount", name) == 0) + { + usesPlayer = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("P", "a", "(I)I")); + return; + } + + if (strcmp(name, "setchar") == 0) + { + usesSupport = 1; + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("S", "gc", "(Ljava/lang/String;II)Ljava/lang/String;")); + return; + } + + if (strcmp(name, "sqr") == 0) + { + bytecode_append(code, dup$); + bytecode_append(code, imul$); + + return; + } + + if (strcmp(name, "setticker") == 0) + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("javax/microedition/lcdui/Ticker")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Ticker", "", "(Ljava/lang/String;)V")); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "F", "Ljavax/microedition/lcdui/Form;")); + + bytecode_append(code, swap$); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Form", "setTicker", "(Ljavax/microedition/lcdui/Ticker;)V")); + return; + } + + if (strcmp(name, "stringtointeger") == 0) + { + usesSupport = 1; + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("S", "parseInt", "(Ljava/lang/String;)I")); + return; + } + + if (strcmp(name, "stringtoreal") == 0) + { + usesFloat = 1; + //usesRegisteredFeature = 1; + if (mathType == 1) + { + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("F", "fI", "(Ljava/lang/String;I)I")); + } + else + { + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(Ljava/lang/String;I)V")); + } + + return; + } + + + if (strcmp(name, "sqrt") == 0) + { + usesFloat = 1; + if (mathType == 1) + { + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("F", "S", "(I)I")); + } + else + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(LReal;)V")); + bytecode_append(code, dup$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("Real", "sqrt", "()V")); + } + + return; + } + + if (strcmp(name, "sin") == 0) + { + usesFloat = 1; + if (mathType == 1) + { + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("F", "s", "(I)I")); + } + else + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(LReal;)V")); + bytecode_append(code, dup$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("Real", "sin", "()V")); + } + + return; + } + + if (strcmp(name, "setcolor") == 0) + { + int method_index; + + method_index = cp_add_methodref("javax/microedition/lcdui/Graphics", "setColor", "(III)V"); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + + + + if (strcmp(name, "setfont") == 0) + { + int method_index = cp_add_methodref("javax/microedition/lcdui/Font", "getFont", "(III)Ljavax/microedition/lcdui/Font;"); + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, method_index); + + method_index = cp_add_methodref("javax/microedition/lcdui/Graphics", "setFont", "(Ljavax/microedition/lcdui/Font;)V"); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + + + if (strcmp(name, "setdefaultfont") == 0) + { + int method_index = cp_add_methodref("javax/microedition/lcdui/Font", "getDefaultFont", "()Ljavax/microedition/lcdui/Font;"); + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, method_index); + + method_index = cp_add_methodref("javax/microedition/lcdui/Graphics", "setFont", "(Ljavax/microedition/lcdui/Font;)V"); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + + return; + } + + if (strcmp(name, "sethttpmethod") == 0) + { + usesHttp = 1; + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("H", "c", "(Ljava/lang/String;)V")); + return; + } + + if (strcmp(name, "sendhttpmessage") == 0) + { + usesHttp = 1; + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("H", "o", "()I")); + return; + } + + if (strcmp(name, "showform") == 0) + { +show_form: + /* + Display.getDisplay(FW.fw).setCurrent(FW.F); + */ + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "fw", "LFW;")); + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Display", "getDisplay", "(Ljavax/microedition/midlet/MIDlet;)Ljavax/microedition/lcdui/Display;")); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "F", "Ljavax/microedition/lcdui/Form;")); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Display", "setCurrent", "(Ljavax/microedition/lcdui/Displayable;)V")); + + /* + FW.CD = FW.F; + */ + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "F", "Ljavax/microedition/lcdui/Form;")); + + bytecode_append(code, putstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "CD", "Ljavax/microedition/lcdui/Displayable;")); + + return; + } + + if (strcmp(name, "showcanvas") == 0) + { + /* + Display.getDisplay(FW.fw).setCurrent(M.T); + */ + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "fw", "LFW;")); + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Display", "getDisplay", "(Ljavax/microedition/midlet/MIDlet;)Ljavax/microedition/lcdui/Display;")); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("M", "T", "LM;")); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Display", "setCurrent", "(Ljavax/microedition/lcdui/Displayable;)V")); + + /* + FW.CD = M.T; + */ + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("M", "T", "LM;")); + + bytecode_append(code, putstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "CD", "Ljavax/microedition/lcdui/Displayable;")); + + return; + } + + + if (strcmp(name, "showtextbox") == 0) + { + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/TextBox", "", "(Ljava/lang/String;Ljava/lang/String;II)V")); + + bytecode_append(code, putstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "TB", "Ljavax/microedition/lcdui/TextBox;")); + + /* + Display.getDisplay(FW.fw).setCurrent(FW.TB); + */ + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "fw", "LFW;")); + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Display", "getDisplay", "(Ljavax/microedition/midlet/MIDlet;)Ljavax/microedition/lcdui/Display;")); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "TB", "Ljavax/microedition/lcdui/TextBox;")); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Display", "setCurrent", "(Ljavax/microedition/lcdui/Displayable;)V")); + + /* + FW.CD = FW.TB; + */ + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "TB", "Ljavax/microedition/lcdui/TextBox;")); + + bytecode_append(code, putstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "CD", "Ljavax/microedition/lcdui/Displayable;")); + + + /* + FW.TB.setCommandListener(FW.fw); + */ + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "TB", "Ljavax/microedition/lcdui/TextBox;")); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "fw", "LFW;")); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Displayable", "setCommandListener", "(Ljavax/microedition/lcdui/CommandListener;)V")); + + return; + } + + if (strcmp(name, "showmenu") == 0) + { + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/List", "", "(Ljava/lang/String;I)V")); + + bytecode_append(code, putstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "L", "Ljavax/microedition/lcdui/List;")); + + /* + Display.getDisplay(FW.fw).setCurrent(FW.L); + */ + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "fw", "LFW;")); + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Display", "getDisplay", "(Ljavax/microedition/midlet/MIDlet;)Ljavax/microedition/lcdui/Display;")); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "L", "Ljavax/microedition/lcdui/List;")); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Display", "setCurrent", "(Ljavax/microedition/lcdui/Displayable;)V")); + + /* + FW.CD = FW.L; + */ + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "L", "Ljavax/microedition/lcdui/List;")); + + bytecode_append(code, putstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "CD", "Ljavax/microedition/lcdui/Displayable;")); + + + /* + FW.L.setCommandListener(FW.fw); + */ + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "L", "Ljavax/microedition/lcdui/List;")); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "fw", "LFW;")); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Displayable", "setCommandListener", "(Ljavax/microedition/lcdui/CommandListener;)V")); + + + return; + } + + + if (strcmp(name, "showalert") == 0) + { + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Alert", "", "(Ljava/lang/String;Ljava/lang/String;Ljavax/microedition/lcdui/Image;Ljavax/microedition/lcdui/AlertType;)V")); + + bytecode_append(code, putstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "A", "Ljavax/microedition/lcdui/Alert;")); + + /* + Display.getDisplay(FW.fw).setCurrent(FW.A); + */ + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "fw", "LFW;")); + + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Display", "getDisplay", "(Ljavax/microedition/midlet/MIDlet;)Ljavax/microedition/lcdui/Display;")); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "A", "Ljavax/microedition/lcdui/Alert;")); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Display", "setCurrent", "(Ljavax/microedition/lcdui/Displayable;)V")); + + /* + FW.CD = FW.A; + */ + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "A", "Ljavax/microedition/lcdui/Alert;")); + + bytecode_append(code, putstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "CD", "Ljavax/microedition/lcdui/Displayable;")); + + /* + FW.A.setCommandListener(FW.fw); + */ + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "A", "Ljavax/microedition/lcdui/Alert;")); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("FW", "fw", "LFW;")); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Alert", "setCommandListener", "(Ljavax/microedition/lcdui/CommandListener;)V")); + + + return; + } + +letter_t: + if (strcmp(name, "trunc") == 0) + { + usesFloat = 1; + if (mathType == 1) + { + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("F", "tI", "(I)I")); + } + else + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(LReal;)V")); + bytecode_append(code, dup$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("Real", "trunc", "()V")); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("Real", "toInteger", "()I")); + } + + return; + } + + + if (strcmp(name, "tan") == 0) + { + usesFloat = 1; + if (mathType == 1) + { + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("F", "tan", "(I)I")); + } + else + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(LReal;)V")); + bytecode_append(code, dup$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("Real", "tan", "()V")); + } + + return; + } + + + + if (strcmp(name, "todegrees") == 0) + { + usesFloat = 1; + if (mathType == 1) + { + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("F", "tD", "(I)I")); + } + else + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(LReal;)V")); + + bytecode_append(code, dup$); + bytecode_append(code, dup$); + + bytecode_append(code, sipush$); + bytecode_append_short_int(code, 180); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("Real", "mul", "(I)V")); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("Real", "PI", "LReal;")); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("Real", "div", "(LReal;)V")); + } + + return; + } + + if (strcmp(name, "toradians") == 0) + { + usesFloat = 1; + if (mathType == 1) + { + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("F", "tR", "(I)I")); + } + else + { + bytecode_append(code, new$); + bytecode_append_short_int(code, cp_add_class("Real")); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("Real", "", "(LReal;)V")); + + bytecode_append(code, dup$); + bytecode_append(code, dup$); + + bytecode_append(code, sipush$); + bytecode_append_short_int(code, 180); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("Real", "div", "(I)V")); + + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("Real", "PI", "LReal;")); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("Real", "mul", "(LReal;)V")); + } + + return; + } +letter_u: + if (strcmp(name, "upcase") == 0) + { + int init_index; + int class_index; + int method_index; + + class_index = cp_add_class("java/lang/String"); + init_index = cp_add_methodref("java/lang/String", "", "(Ljava/lang/String;)V"); + method_index = cp_add_methodref("java/lang/String", "toUpperCase", "()Ljava/lang/String;"); + + bytecode_append(code, new$); + bytecode_append_short_int(code, class_index); + bytecode_append(code, dup_x1$); + bytecode_append(code, swap$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, init_index); + + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, method_index); + return; + } + +letter_v: + if (strcmp(name, "vibrate") == 0) + { + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Display", "vibrate", "(I)Z")); + + bytecode_append(code, pop$); + return; + } +letter_w: +letter_x: +letter_y: +letter_z: + + if (count == 0) + { + count ++; + goto letter_a; + } + + die(25); +} + + +/* + Adds a function with 0 or 1 parameter +*/ +void add_special_function(block *item, enum en_type_class parameter_en, enum en_type_class return_type_en, char *name) +{ + type_list *params; + type *param; + type *return_type; + + params = type_list_create(); + param = type_create(); + return_type = type_create(); + param->type_class = parameter_en; + return_type->type_class = return_type_en; + if (parameter_en != void_type) + type_list_append(params, param); + type_destroy(param); + if (return_type_en == void_type) + add_std_procedure(item, name, params); + else + add_std_function(item, name, params, return_type); +} + +/* + Adds a function with 2 parameters +*/ +void add_special_function2(block *item, enum en_type_class parameter_en1, enum en_type_class parameter_en2, enum en_type_class return_type_en, char *name) +{ + type_list *params; + type *param; + type *return_type; + + params = type_list_create(); + param = type_create(); + return_type = type_create(); + param->type_class = parameter_en1; + return_type->type_class = return_type_en; + type_list_append(params, param); + param->type_class = parameter_en2; + type_list_append(params, param); + type_destroy(param); + + if (return_type_en == void_type) + add_std_procedure(item, name, params); + else + add_std_function(item, name, params, return_type); +} + +/* + Adds a function with 3 parameters +*/ +void add_special_function3(block *item, enum en_type_class parameter_en1, enum en_type_class parameter_en2, enum en_type_class parameter_en3, enum en_type_class return_type_en, char *name) +{ + type_list *params; + type *param; + type *return_type; + + params = type_list_create(); + param = type_create(); + return_type = type_create(); + param->type_class = parameter_en1; + return_type->type_class = return_type_en; + type_list_append(params, param); + param->type_class = parameter_en2; + type_list_append(params, param); + param->type_class = parameter_en3; + type_list_append(params, param); + type_destroy(param); + + if (return_type_en == void_type) + add_std_procedure(item, name, params); + else + add_std_function(item, name, params, return_type); +} + +/* + Adds a function with 4 parameters +*/ +void add_special_function4(block *item, enum en_type_class parameter_en1, enum en_type_class parameter_en2, enum en_type_class parameter_en3, enum en_type_class parameter_en4, enum en_type_class return_type_en, char *name) +{ + type_list *params; + type *param; + type *return_type; + + params = type_list_create(); + param = type_create(); + return_type = type_create(); + param->type_class = parameter_en1; + return_type->type_class = return_type_en; + type_list_append(params, param); + param->type_class = parameter_en2; + type_list_append(params, param); + param->type_class = parameter_en3; + type_list_append(params, param); + param->type_class = parameter_en4; + type_list_append(params, param); + type_destroy(param); + + if (return_type_en == void_type) + add_std_procedure(item, name, params); + else + add_std_function(item, name, params, return_type); +} + +/* + Adds a function with 5 parameters +*/ +void add_special_function5(block *item, enum en_type_class parameter_en1, enum en_type_class parameter_en2, enum en_type_class parameter_en3, enum en_type_class parameter_en4, enum en_type_class parameter_en5, enum en_type_class return_type_en, char *name) +{ + type_list *params; + type *param; + type *return_type; + + params = type_list_create(); + param = type_create(); + return_type = type_create(); + param->type_class = parameter_en1; + return_type->type_class = return_type_en; + type_list_append(params, param); + param->type_class = parameter_en2; + type_list_append(params, param); + param->type_class = parameter_en3; + type_list_append(params, param); + param->type_class = parameter_en4; + type_list_append(params, param); + param->type_class = parameter_en5; + type_list_append(params, param); + type_destroy(param); + + if (return_type_en == void_type) + add_std_procedure(item, name, params); + else + add_std_function(item, name, params, return_type); +} + +/* + Adds a function with 6 parameters +*/ +void add_special_function6(block *item, enum en_type_class parameter_en1, enum en_type_class parameter_en2, enum en_type_class parameter_en3, enum en_type_class parameter_en4, enum en_type_class parameter_en5, enum en_type_class parameter_en6, enum en_type_class return_type_en, char *name) +{ + type_list *params; + type *param; + type *return_type; + + params = type_list_create(); + param = type_create(); + return_type = type_create(); + param->type_class = parameter_en1; + return_type->type_class = return_type_en; + type_list_append(params, param); + param->type_class = parameter_en2; + type_list_append(params, param); + param->type_class = parameter_en3; + type_list_append(params, param); + param->type_class = parameter_en4; + type_list_append(params, param); + param->type_class = parameter_en5; + type_list_append(params, param); + param->type_class = parameter_en6; + type_list_append(params, param); + type_destroy(param); + + if (return_type_en == void_type) + add_std_procedure(item, name, params); + else + add_std_function(item, name, params, return_type); +} diff --git a/MPC.3.5.LINUX/parser/stdpas.h b/MPC.3.5.LINUX/parser/stdpas.h new file mode 100644 index 0000000..0603f20 --- /dev/null +++ b/MPC.3.5.LINUX/parser/stdpas.h @@ -0,0 +1,27 @@ +/******************************************************************** + + stdpas.h - initializes the parser/semantic checker with a + standard pascal types, constants etc. + + Niksa Orlic, 2004-04-29 + +********************************************************************/ + +block* initialize_root_block(); + +void add_std_types(block*); +void add_std_constants(block*); +void add_std_functions(block*); +void add_std_type(block*, enum en_type_class , char*); +void add_std_function(block*, char*, type_list*, type*); +void add_std_procedure(block*, char*, type_list*); + +void create_std_function_code(bytecode*, char*); +void create_std_function_prefix(bytecode*, char*); + +void add_special_function(block*, enum en_type_class, enum en_type_class, char*); +void add_special_function2(block*, enum en_type_class, enum en_type_class, enum en_type_class, char*); +void add_special_function3(block*, enum en_type_class, enum en_type_class, enum en_type_class, enum en_type_class, char*); +void add_special_function4(block*, enum en_type_class, enum en_type_class, enum en_type_class, enum en_type_class, enum en_type_class, char*); +void add_special_function5(block*, enum en_type_class, enum en_type_class, enum en_type_class, enum en_type_class, enum en_type_class, enum en_type_class, char*); +void add_special_function6(block*, enum en_type_class, enum en_type_class, enum en_type_class, enum en_type_class, enum en_type_class, enum en_type_class, enum en_type_class, char*); diff --git a/MPC.3.5.LINUX/preverifier/README.TXT b/MPC.3.5.LINUX/preverifier/README.TXT new file mode 100644 index 0000000..90d6e5e --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/README.TXT @@ -0,0 +1,15 @@ +PREVERIFIER TOOL + +This directory contains the source code of the +preverifier tool that is used for preprocessing +Java class files for the KVM. The preprocessed +class files are regular Java class files, but +they contain some additional/modified information +that will help speed up runtime verification. + +The preverifier implementation is derived from +the J2SE class file verifier that was written +originally for the "Classic" Java Virtual Machine. +Therefore, the implementation style is quite +different from the rest of the KVM codebase. + diff --git a/MPC.3.5.LINUX/preverifier/check_class.c b/MPC.3.5.LINUX/preverifier/check_class.c new file mode 100644 index 0000000..8d23460 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/check_class.c @@ -0,0 +1,844 @@ +/* + * @(#)check_class.c 1.6 02/09/27 + * + * Copyright 1995-1998 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +/*========================================================================= + * SYSTEM: Verifier + * SUBSYSTEM: Verifies ClassClass structure. + * FILE: check_class.c + * OVERVIEW: Code for verifying the ClassClass structure for internal + * consistency. + * AUTHOR: Sheng Liang, Consumer & Embedded + * Initial implementation based on the Classic VM Verifier. + * Edited by Tasneem Sayeed, Java Consumer Technologies + *=======================================================================*/ + +/*========================================================================= + * Include files + *=======================================================================*/ + +#include + +#include "oobj.h" +#include "utf.h" +#include "tree.h" +#include "sys_api.h" + +/*========================================================================= + * Globals and extern declarations + *=======================================================================*/ + +extern bool_t verify_class_codes(ClassClass *cb); + +//static bool_t verify_constant_pool(ClassClass *cb); + +//static bool_t is_legal_fieldname(ClassClass *cb, char *name, int type); +//static bool_t is_legal_method_signature(ClassClass *cb, char *name, char *signature); +//static bool_t is_legal_field_signature(ClassClass *cb, char *name, char *signature); + +//static char *skip_over_fieldname(char *name, bool_t slash_okay); +//static char *skip_over_field_signature(char *name, bool_t void_okay); + +//static void CCerror (ClassClass *cb, char *format, ...); + + +/* Argument for is_legal_fieldname */ +enum { LegalClass, LegalField, LegalMethod }; + + +/*========================================================================= + * FUNCTION: VerifyClass + * OVERVIEW: Verifies a class given a pointer to the ClassClass struct. + * Returns true if the class is ok. + * INTERFACE: + * parameters: pointer to the ClassClass structure. + * + * returns: boolean type + *=======================================================================*/ +bool_t +VerifyClass(ClassClass *cb) +{ + verify_class_codes(cb); + return TRUE; + /* + bool_t result = TRUE; + struct methodblock *mb; + struct fieldblock *fb; + int i; + if (!verify_constant_pool(cb)) + return FALSE; + /* Make sure all the method names and signatures are okay + for (i = cbMethodsCount(cb), mb = cbMethods(cb); --i >= 0; mb++) { + char *name = mb->fb.name; + char *signature = mb->fb.signature; + if (! (is_legal_fieldname(cb, name, LegalMethod) && + is_legal_method_signature(cb, name, signature))) + result = FALSE; + } + /* Make sure all the field names and signatures are okay + for (i = cbFieldsCount(cb), fb = cbFields(cb); --i >= 0; fb++) { + if (! (is_legal_fieldname(cb, fb->name, LegalField) && + is_legal_field_signature(cb, fb->name, fb->signature))) + result = FALSE; + } + /* Make sure we are not overriding any final methods or classes + if (cbIsInterface(cb)) { + struct methodblock *mb; + if ((cbSuperclass(cb) == NULL) || + (cbSuperclass(cb) != classJavaLangObject)) { + // CCerror(cb, "Interface %s has bad superclass", cbName(cb)); + result = FALSE; + } + for (i = cbMethodsCount(cb), mb = cbMethods(cb); --i >= 0; mb++) { + if (mb->fb.access & ACC_STATIC) { + if (mb->fb.name[0] != '<') { + /* Only internal methods can be static + // CCerror(cb, "Illegal static method %s in interface %s", +// mb->fb.name, cbName(cb)); + result = FALSE; + } + } + } + } else if (cbSuperclass(cb)) { + ClassClass *super_cb; + unsigned bitvector_size = (unsigned)(cbMethodTableSize(cb) + 31) >> 5; + long *bitvector = sysCalloc(bitvector_size, sizeof(long)); + for (super_cb = cbSuperclass(cb); ; super_cb = cbSuperclass(super_cb)) { + if (cbAccess(super_cb) & ACC_FINAL) { + // CCerror(cb, "Class %s is subclass of final class %s", +// cbName(cb), cbName(super_cb)); + result = FALSE; + } + mb = cbMethods(super_cb); + for (i = cbMethodsCount(super_cb); --i >= 0; mb++) { + if (mb->fb.access & ACC_FINAL) { + unsigned offset = mb->fb.u.offset; + bitvector[offset >> 5] |= (1 << (offset & 0x1F)); + } + } + if (cbSuperclass(super_cb) == NULL) break; + } + for (i = cbMethodsCount(cb), mb = cbMethods(cb); --i >= 0; mb++) { + unsigned offset = mb->fb.u.offset; + if ((offset > 0) + && bitvector[offset >> 5] & (1 << (offset & 0x1F))) { +// CCerror(cb, "Class %s overrides final method %s.%s", +// cbName(cb), mb->fb.name, mb->fb.signature); + result = FALSE; + } + } + sysFree(bitvector); + } else if (cb != classJavaLangObject) { +// CCerror(cb, "Class %s does not have superclass", cbName(cb)); + result = FALSE; + } + + if (result) + result = verify_class_codes(cb); + return result;*/ +} + + +/*========================================================================= + * FUNCTION: verify_constant_pool + * OVERVIEW: Verifies the constant pool given a pointer to the + * ClassClass structure. + * Makes two quick passes over the constant pool. The first + * pass ensures that everything is of the right type. + * Returns true if the constant pool is ok. + * INTERFACE: + * parameters: pointer to the ClassClass structure. + * + * returns: boolean type + *=======================================================================*/ +/* +static bool_t +verify_constant_pool(ClassClass *cb) +{ + union cp_item_type *cp = cbConstantPool(cb); + long cp_count = cbConstantPoolCount(cb); + unsigned char *type_table; + int i, type; + + const int utf8_resolved = (CONSTANT_Utf8 | CONSTANT_POOL_ENTRY_RESOLVED); + + if (cp_count == 0) /* Primitive classes + return TRUE; + type_table = cp[CONSTANT_POOL_TYPE_TABLE_INDEX].type; + /* Let's make two quick passes over the constant pool. The first one + * checks that everything is of the right type. + for (i = 1; i < cp_count; i++) { + switch(type = type_table[i]) { + case CONSTANT_String: + case CONSTANT_Class: { + int index = cp[i].i; + if ( (index < 1) + || (index >= cp_count) + || (type_table[index] != utf8_resolved)) { + // CCerror(cb, "Bad index in constant pool #%d", i); + return FALSE; + } + break; + } + + case CONSTANT_String | CONSTANT_POOL_ENTRY_RESOLVED: + /* This can only happen if a string is the "initial" value of + * some final static String. We assume that the checking has + * already been done. + + break; + + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + case CONSTANT_NameAndType: { + unsigned index = (unsigned)(cp[i].i); + int key1 = index >> 16; + int key2 = index & 0xFFFF; + if (key1 < 1 || key1 >= cp_count + || key2 < 1 || key2 >= cp_count) { + // CCerror(cb, "Bad index in constant pool #%d", i); + return FALSE; + } + if (type == CONSTANT_NameAndType) { + if ( (type_table[key1] != utf8_resolved) + || (type_table[key2] != utf8_resolved)) { +// CCerror(cb, "Bad index in constant pool."); + return FALSE; + } + } else { + if ( ((type_table[key1] & CONSTANT_POOL_ENTRY_TYPEMASK) + != CONSTANT_Class) + || ((type_table[key2] != CONSTANT_NameAndType))) { +// CCerror(cb, "Bad index in constant pool #%d", i); + return FALSE; + } + } + break; + } + + case CONSTANT_Fieldref | CONSTANT_POOL_ENTRY_RESOLVED: + case CONSTANT_Methodref | CONSTANT_POOL_ENTRY_RESOLVED: + case CONSTANT_InterfaceMethodref | CONSTANT_POOL_ENTRY_RESOLVED: + case CONSTANT_NameAndType | CONSTANT_POOL_ENTRY_RESOLVED: +// CCerror(cb, "Improperly resolved constant pool #%d", i); + return FALSE; + + + case CONSTANT_Class | CONSTANT_POOL_ENTRY_RESOLVED: + case CONSTANT_Utf8 | CONSTANT_POOL_ENTRY_RESOLVED: + case CONSTANT_Integer | CONSTANT_POOL_ENTRY_RESOLVED: + case CONSTANT_Float | CONSTANT_POOL_ENTRY_RESOLVED: + break; + + case CONSTANT_Long | CONSTANT_POOL_ENTRY_RESOLVED: + case CONSTANT_Double | CONSTANT_POOL_ENTRY_RESOLVED: + if ((i + 1 >= cp_count) || + (type_table[i + 1] != CONSTANT_POOL_ENTRY_RESOLVED)) { +// CCerror(cb, "Improper constant pool long/double #%d", i); + return FALSE; + } else { + i++; + break; + } + + case CONSTANT_Integer: + case CONSTANT_Float: + case CONSTANT_Long: + case CONSTANT_Double: + case CONSTANT_Utf8: +// CCerror(cb, "Improperly unresolved constant pool #%d", i); + return FALSE; + + + default: +// CCerror(cb, "Illegal constant pool type at #%d", i); + return FALSE; + + + } + } + for (i = 1; i < cp_count; i++) { + switch(type = type_table[i]) { + case CONSTANT_Class: { + int index = cp[i].i; + if (!is_legal_fieldname(cb, cp[index].cp, LegalClass)) + return FALSE; + break; + } + + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: { + unsigned index = (unsigned)(cp[i].i); + int name_type_index = index & 0xFFFF; + int name_type_key = cp[name_type_index].i; + int name_index = name_type_key >> 16; + int signature_index = name_type_key & 0xFFFF; + char *name = cp[name_index].cp; + char *signature = cp[signature_index].cp; + + if (type == CONSTANT_Fieldref) { + if (! (is_legal_fieldname(cb, name, LegalField) && + is_legal_field_signature(cb, name, signature))) + return FALSE; + } else { + if (! (is_legal_fieldname(cb, name, LegalMethod) && + is_legal_method_signature(cb, name, signature))) + return FALSE; + } + break; + } + } + } + return TRUE; +} + */ + +/*========================================================================= + * FUNCTION: is_legal_fieldname + * OVERVIEW: Returns true if the given name within the given ClassClass + * structure consists of a legal fieldname or a classname + * if the third argument is LegalClass. + * INTERFACE: + * parameters: pointer to the ClassClass structure. + * char*: legal field name or a classname + * int: type of name (class or field name) + * + * returns: boolean type + *=======================================================================*/ +#if 0 +static bool_t +is_legal_fieldname(ClassClass *cb, char *name, int type) +{ + bool_t result; + if (name[0] == '<') { + result = (type == LegalMethod) && + ((strcmp(name, "") == 0) || + (strcmp(name, "") == 0)); + } else { + char *p; + if (type == LegalClass && name[0] == SIGNATURE_ARRAY) { + p = skip_over_field_signature(name, FALSE); + } else { + p = skip_over_fieldname(name, type == LegalClass); + } + result = (p != 0 && p[0] == '\0'); + } + if (!result) { + char *thing = (type == LegalField) ? "Field" + : (type == LegalMethod) ? "Method" : "Class"; + +// CCerror(cb, "Illegal %s name \"%s\"", thing, name); + return FALSE; + } else { + return TRUE; + + } +} + + +/*========================================================================= + * FUNCTION: is_legal_field_signature + * OVERVIEW: Returns true if the entire given string within the given + * ClassClass structure consists of a legal field signature. + * INTERFACE: + * parameters: pointer to the ClassClass structure. + * char*: field name + * char*: field signature + * + * returns: boolean type + *=======================================================================*/ +static bool_t +is_legal_field_signature(ClassClass *cb, char *fieldname, char *signature) +{ + char *p = skip_over_field_signature(signature, FALSE); + if (p != 0 && p[0] == '\0') { + return TRUE; + } else { +// CCerror(cb, "Field \"%s\" has illegal signature \"%s\"", +// fieldname, signature); + return FALSE; + } +} + + +/*========================================================================= + * FUNCTION: is_legal_method_signature + * OVERVIEW: Returns true if the entire given string within the given + * ClassClass structure consists of a legal method signature. + * INTERFACE: + * parameters: pointer to the ClassClass structure. + * char*: method name + * char*: method signature + * + * returns: boolean type + *=======================================================================*/ +static bool_t +is_legal_method_signature(ClassClass *cb, char *methodname, char *signature) +{ + char *p = signature; + char *next_p; + /* The first character must be a '(' */ + if (*p++ == SIGNATURE_FUNC) { + /* Skip over however many legal field signatures there are */ + while ((next_p = skip_over_field_signature(p, FALSE)) != 0) + p = next_p; + /* The first non-signature thing better be a ')' */ + if (*p++ == SIGNATURE_ENDFUNC) { + if (methodname[0] == '<') { + /* All internal methods must return void */ + if ((p[0] == SIGNATURE_VOID) && (p[1] == '\0')) + return TRUE; + } else { + /* Now, we better just have a return value. */ + next_p = skip_over_field_signature(p, TRUE); + if (next_p && next_p[0] == '\0') + return TRUE; + } + } + } + // CCerror(cb, "Method \"%s\" has illegal signature \"%s\"", +// methodname, signature); + return FALSE; +} + +#endif + +#if 0 + +/*========================================================================= + * Automatic code generation tables + *=======================================================================*/ + /* The following tables and code generated using: */ + /* java GenerateCharacter -verbose -c -identifiers -spec UnicodeData-2.1.2.txt -template check_class.c.template -o check_class.c 8 4 4 */ + /* The X table has 256 entries for a total of 256 bytes. */ + + static unsigned char X[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, /* 0x0000 */ + 7, 8, 9, 10, 11, 12, 13, 14, /* 0x0800 */ + 15, 16, 7, 7, 7, 7, 7, 7, /* 0x1000 */ + 7, 7, 7, 7, 7, 7, 17, 18, /* 0x1800 */ + 19, 20, 7, 7, 7, 7, 7, 7, /* 0x2000 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 0x2800 */ + 21, 22, 7, 7, 7, 7, 7, 7, /* 0x3000 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 0x3800 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 0x4000 */ + 7, 7, 7, 7, 7, 7, 23, 23, /* 0x4800 */ + 23, 23, 23, 23, 23, 23, 23, 23, /* 0x5000 */ + 23, 23, 23, 23, 23, 23, 23, 23, /* 0x5800 */ + 23, 23, 23, 23, 23, 23, 23, 23, /* 0x6000 */ + 23, 23, 23, 23, 23, 23, 23, 23, /* 0x6800 */ + 23, 23, 23, 23, 23, 23, 23, 23, /* 0x7000 */ + 23, 23, 23, 23, 23, 23, 23, 23, /* 0x7800 */ + 23, 23, 23, 23, 23, 23, 23, 23, /* 0x8000 */ + 23, 23, 23, 23, 23, 23, 23, 23, /* 0x8800 */ + 23, 23, 23, 23, 23, 23, 23, 23, /* 0x9000 */ + 23, 23, 23, 23, 23, 23, 23, 24, /* 0x9800 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 0xA000 */ + 7, 7, 7, 7, 23, 23, 23, 23, /* 0xA800 */ + 23, 23, 23, 23, 23, 23, 23, 23, /* 0xB000 */ + 23, 23, 23, 23, 23, 23, 23, 23, /* 0xB800 */ + 23, 23, 23, 23, 23, 23, 23, 23, /* 0xC000 */ + 23, 23, 23, 23, 23, 23, 23, 23, /* 0xC800 */ + 23, 23, 23, 23, 23, 23, 23, 25, /* 0xD000 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 0xD800 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 0xE000 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 0xE800 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 0xF000 */ + 7, 23, 26, 27, 23, 28, 29, 30 /* 0xF800 */ + }; + + /* The Y table has 496 entries for a total of 496 bytes. */ + + static unsigned char Y[496] = { + 0, 0, 1, 2, 3, 4, 3, 5, /* 0 */ + 0, 0, 6, 7, 8, 9, 8, 9, /* 0 */ + 8, 8, 8, 8, 8, 8, 8, 8, /* 1 */ + 8, 8, 8, 8, 8, 8, 8, 10, /* 1 */ + 8, 11, 0, 0, 0, 8, 8, 8, /* 2 */ + 8, 8, 12, 13, 14, 14, 15, 0, /* 2 */ + 16, 16, 16, 16, 17, 0, 18, 19, /* 3 */ + 20, 8, 21, 8, 22, 23, 24, 25, /* 3 */ + 26, 8, 8, 8, 8, 26, 8, 8, /* 4 */ + 27, 8, 8, 8, 28, 8, 29, 30, /* 4 */ + 0, 0, 0, 3, 8, 31, 3, 8, /* 5 */ + 11, 32, 33, 34, 35, 8, 5, 36, /* 5 */ + 0, 0, 3, 5, 37, 38, 2, 39, /* 6 */ + 8, 8, 8, 40, 22, 41, 42, 2, /* 6 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */ + 43, 8, 8, 44, 45, 46, 47, 0, /* 8 */ + 48, 49, 50, 51, 52, 53, 47, 25, /* 8 */ + 54, 49, 50, 55, 56, 57, 58, 59, /* 9 */ + 60, 21, 50, 61, 62, 0, 63, 0, /* 9 */ + 48, 49, 50, 64, 65, 66, 67, 0, /* 10 */ + 68, 69, 70, 71, 72, 73, 74, 0, /* 10 */ + 75, 24, 50, 76, 77, 78, 67, 0, /* 11 */ + 79, 24, 50, 76, 77, 80, 67, 0, /* 11 */ + 79, 24, 50, 81, 82, 73, 67, 0, /* 12 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 12 */ + 3, 8, 22, 83, 84, 2, 0, 0, /* 13 */ + 85, 86, 87, 88, 89, 90, 0, 0, /* 13 */ + 0, 91, 2, 92, 93, 8, 94, 32, /* 14 */ + 95, 96, 45, 97, 0, 0, 0, 0, /* 14 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 15 */ + 0, 0, 8, 8, 98, 8, 8, 99, /* 15 */ + 8, 8, 8, 8, 8, 100, 8, 8, /* 16 */ + 8, 8, 101, 8, 8, 8, 8, 94, /* 16 */ + 8, 8, 8, 8, 8, 8, 8, 8, /* 17 */ + 8, 102, 8, 8, 8, 8, 8, 94, /* 17 */ + 8, 103, 8, 8, 103, 104, 8, 105, /* 18 */ + 8, 8, 8, 106, 107, 108, 109, 107, /* 18 */ + 0, 0, 0, 110, 111, 0, 0, 110, /* 19 */ + 0, 0, 109, 0, 0, 112, 113, 0, /* 19 */ + 114, 115, 116, 117, 0, 0, 8, 8, /* 20 */ + 36, 0, 0, 0, 0, 0, 0, 0, /* 20 */ + 118, 0, 119, 120, 3, 8, 8, 8, /* 21 */ + 8, 121, 3, 8, 8, 8, 8, 122, /* 21 */ + 123, 8, 109, 3, 8, 8, 8, 8, /* 22 */ + 22, 0, 0, 0, 0, 0, 0, 0, /* 22 */ + 8, 8, 8, 8, 8, 8, 8, 8, /* 23 */ + 8, 8, 8, 8, 8, 8, 8, 8, /* 23 */ + 8, 8, 8, 8, 8, 8, 8, 8, /* 24 */ + 8, 8, 98, 0, 0, 0, 0, 0, /* 24 */ + 8, 8, 8, 8, 8, 8, 8, 8, /* 25 */ + 8, 8, 25, 0, 0, 0, 0, 0, /* 25 */ + 8, 8, 105, 0, 0, 0, 0, 0, /* 26 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 26 */ + 99, 124, 50, 125, 126, 8, 8, 8, /* 27 */ + 8, 8, 8, 14, 0, 127, 8, 8, /* 27 */ + 8, 8, 8, 105, 0, 8, 8, 8, /* 28 */ + 8, 128, 8, 8, 11, 0, 0, 102, /* 28 */ + 0, 0, 129, 130, 131, 0, 132, 133, /* 29 */ + 8, 8, 8, 8, 8, 8, 8, 109, /* 29 */ + 1, 2, 3, 4, 3, 5, 134, 8, /* 30 */ + 8, 8, 8, 22, 135, 136, 137, 0 /* 30 */ + }; + + /* The A table has 2208 entries for a total of 552 bytes. */ + + static unsigned long A[138] = { + 0x00000000, /* 0 */ + 0x00000300, /* 1 */ + 0x00055555, /* 2 */ + 0xFFFFFFFC, /* 3 */ + 0xC03FFFFF, /* 4 */ + 0x003FFFFF, /* 5 */ + 0x00300FF0, /* 6 */ + 0x00300C00, /* 7 */ + 0xFFFFFFFF, /* 8 */ + 0xFFFF3FFF, /* 9 */ + 0xFFF00FFF, /* 10 */ + 0x0000FFFF, /* 11 */ + 0x0003FFFF, /* 12 */ + 0xFFC3FFFF, /* 13 */ + 0x0000000F, /* 14 */ + 0x000003FF, /* 15 */ + 0x55555555, /* 16 */ + 0x00000555, /* 17 */ + 0x00000005, /* 18 */ + 0x00300000, /* 19 */ + 0xF33F3000, /* 20 */ + 0xFFFFFFCF, /* 21 */ + 0x3FFFFFFF, /* 22 */ + 0x33303FFF, /* 23 */ + 0xFFFFFFF3, /* 24 */ + 0x000000FF, /* 25 */ + 0xF3FFFFFC, /* 26 */ + 0x0000154F, /* 27 */ + 0x03C3C3FF, /* 28 */ + 0xF0FFFFFF, /* 29 */ + 0x000F0FFF, /* 30 */ + 0x000C3FFF, /* 31 */ + 0x55555554, /* 32 */ + 0x55555545, /* 33 */ + 0x45455555, /* 34 */ + 0x00000114, /* 35 */ + 0x0000003F, /* 36 */ + 0x557FFFFF, /* 37 */ + 0x00000015, /* 38 */ + 0xFFFFFFFD, /* 39 */ + 0x3FF0FFFF, /* 40 */ + 0x41555CFF, /* 41 */ + 0x05517D55, /* 42 */ + 0xFFFFFC54, /* 43 */ + 0x5D0FFFFF, /* 44 */ + 0x05555555, /* 45 */ + 0xFFFF0154, /* 46 */ + 0x5555505F, /* 47 */ + 0xC3FFFC54, /* 48 */ + 0xFFFFFFC3, /* 49 */ + 0xFFF3FFFF, /* 50 */ + 0x510FF033, /* 51 */ + 0x05414155, /* 52 */ + 0xCF004000, /* 53 */ + 0xC03FFC10, /* 54 */ + 0x510F3CF3, /* 55 */ + 0x05414015, /* 56 */ + 0x33FC0000, /* 57 */ + 0x55555000, /* 58 */ + 0x000003F5, /* 59 */ + 0xCCFFFC54, /* 60 */ + 0x5D0FFCF3, /* 61 */ + 0x05454555, /* 62 */ + 0x55555003, /* 63 */ + 0x5D0FF0F3, /* 64 */ + 0x05414055, /* 65 */ + 0xCF005000, /* 66 */ + 0x5555500F, /* 67 */ + 0xF03FFC50, /* 68 */ + 0xF33C0FF3, /* 69 */ + 0xF03F03C0, /* 70 */ + 0x500FCFFF, /* 71 */ + 0x05515015, /* 72 */ + 0x00004000, /* 73 */ + 0x55554000, /* 74 */ + 0xF3FFFC54, /* 75 */ + 0x500FFCFF, /* 76 */ + 0x05515155, /* 77 */ + 0x00001400, /* 78 */ + 0xF3FFFC50, /* 79 */ + 0x30001400, /* 80 */ + 0x500FFFFF, /* 81 */ + 0x05515055, /* 82 */ + 0xC01555F7, /* 83 */ + 0x15557FFF, /* 84 */ + 0x0C33C33C, /* 85 */ + 0xFFFCFF00, /* 86 */ + 0x3CF0CCFC, /* 87 */ + 0x0D4555F7, /* 88 */ + 0x055533FF, /* 89 */ + 0x0F055555, /* 90 */ + 0x00050000, /* 91 */ + 0x50044400, /* 92 */ + 0xFFFCFFFF, /* 93 */ + 0x000FFFFF, /* 94 */ + 0x00555155, /* 95 */ + 0x55544555, /* 96 */ + 0x00045554, /* 97 */ + 0x00000FFF, /* 98 */ + 0x00003FFF, /* 99 */ + 0xC00FFFFF, /* 100 */ + 0xFFFF003F, /* 101 */ + 0x00FFFFFF, /* 102 */ + 0x0FFF0FFF, /* 103 */ + 0xCCCCFFFF, /* 104 */ + 0x0FFFFFFF, /* 105 */ + 0x33FFF3FF, /* 106 */ + 0x03FFF3F0, /* 107 */ + 0x00FFF0FF, /* 108 */ + 0x03FFFFFF, /* 109 */ + 0xC0000000, /* 110 */ + 0x00000003, /* 111 */ + 0x01555555, /* 112 */ + 0x00000004, /* 113 */ + 0xFFF0C030, /* 114 */ + 0x0FFF0CFF, /* 115 */ + 0xFFF33300, /* 116 */ + 0x0003FFCF, /* 117 */ + 0x0000CC00, /* 118 */ + 0x555FFFFC, /* 119 */ + 0x00000FFC, /* 120 */ + 0x3FD403FF, /* 121 */ + 0x3F3FFFFF, /* 122 */ + 0xFFFFFC00, /* 123 */ + 0xD000FFC0, /* 124 */ + 0x33FF3FFF, /* 125 */ + 0xFFFFF3CF, /* 126 */ + 0xFFFFFFC0, /* 127 */ + 0xFFFFFFF0, /* 128 */ + 0x00000055, /* 129 */ + 0x000003C0, /* 130 */ + 0xFC000000, /* 131 */ + 0x000C0000, /* 132 */ + 0xFFFFF33F, /* 133 */ + 0xFFFFF000, /* 134 */ + 0xFFF0FFF0, /* 135 */ + 0x03F0FFF0, /* 136 */ + 0x00003C0F /* 137 */ + }; + + /* In all, the character property tables require 1304 bytes. */ + +/* + * This code mirrors Character.isJavaIdentifierStart. It determines whether + * the specified character is a legal start of a Java identifier as per JLS. + * + * The parameter ch is the character to be tested; return 1 if the + * character is a letter, 0 otherwise. + */ +#define isJavaIdentifierStart(ch) (((A[Y[(X[ch>>8]<<4)|((ch>>4)&0xF)]]>>((ch&0xF)<<1))&3) & 0x2) + +/* + * This code mirrors Character.isJavaIdentifierPart. It determines whether + * the specified character is a legal part of a Java identifier as per JLS. + * + * The parameter ch is the character to be tested; return 1 if the + * character is a digit, 0 otherwise. + */ +#define isJavaIdentifierPart(ch) (((A[Y[(X[ch>>8]<<4)|((ch>>4)&0xF)]]>>((ch&0xF)<<1))&3) & 0x1) + + +/*========================================================================= + * FUNCTION: skip_over_fieldname + * OVERVIEW: Skips over the longest part of the string that could be + * taken as a fieldname given a pointer to a string. + * Allows '/' if slash_okay parameter is true. + * Returns a pointer to just past the fieldname. + * Returns NULL if no fieldname is found, or in the case of + * slash_okay being TRUE, we may see consecutive slashes + * (meaning that we were looking for a qualified path, but + * found something that was badly-formed.) + * INTERFACE: + * parameters: char*: name + * boolean: slash_okay + * + * returns: char* field name or NULL + *=======================================================================*/ +static char * +skip_over_fieldname(char *name, bool_t slash_okay) +{ + bool_t first; + char *p; + unicode last_ch = 0; + for (p = name, first = TRUE; ; first = FALSE) { + char *old_p = p; + unicode ch = next_utf2unicode(&p); + if (isJavaIdentifierStart(ch) || (!first && isJavaIdentifierPart(ch)) + || (slash_okay && ch == '/' && !first) + || ch == '_' || ch == '$') { + if (ch == '/' && last_ch == '/') { + return 0; /* Don't permit consecutive slashes */ + } else { + last_ch = ch; + } + } else { + return first ? 0 : old_p; + } + } +} + + +/*========================================================================= + * FUNCTION: skip_over_field_signature + * OVERVIEW: Skips over the longest part of the string that could be + * taken as a field signature given a pointer to a string. + * Allows "void" if void_okay parameter is true. + * Returns a pointer to just past the signature. + * Returns NULL if no legal signature is found. + * INTERFACE: + * parameters: char*: name + * boolean: void_okay + * + * returns: char* field signature or NULL + *=======================================================================*/ +static char * +skip_over_field_signature(char *name, bool_t void_okay) +{ + for (;;) { + switch (name[0]) { + case SIGNATURE_VOID: + if (!void_okay) return 0; + /* FALL THROUGH */ + case SIGNATURE_BOOLEAN: + case SIGNATURE_BYTE: + case SIGNATURE_CHAR: + case SIGNATURE_SHORT: + case SIGNATURE_INT: + case SIGNATURE_LONG: + return name + 1; + + case SIGNATURE_FLOAT: + case SIGNATURE_DOUBLE: + return no_floating_point ? NULL : name + 1; + + case SIGNATURE_CLASS: { + /* Skip over the classname, if one is there. */ + char *p = skip_over_fieldname(name + 1, TRUE); + /* The next character better be a semicolon. */ + if (p && p[0] == ';') { + return p + 1; + } + return NULL; + } + + case SIGNATURE_ARRAY: + /* The rest of what's there better be a legal signature. */ + name++; + void_okay = FALSE; + break; + + default: + return NULL; + } + } +} + + +/*========================================================================= + * FUNCTION: CCerror + * OVERVIEW: Handles formating errors found during class file + * verification. + * INTERFACE: + * parameters: pointer to the ClassClass structure. + * char *: format + * + * returns: nothing + *=======================================================================*/ +static void +CCerror (ClassClass *cb, char *format, ...) +{ + if (verbose) { + va_list args; +// jio_fprintf(stderr, "VERIFIER CLASS ERROR %s:\n", cbName(cb)); + va_start(args, format); + jio_vfprintf(stderr, format, args); + va_end(args); +// jio_fprintf(stderr, "\n"); + } +} + + +/*========================================================================= + * FUNCTION: IsLegalClassname + * OVERVIEW: Determines if the specified name is a legal UTF name for + * a class name. + * Note that this routine is intended for external use and + * expects the internal form of qualified classes + * (i.e. the dots should have been replaced by slashes.) + * INTERFACE: + * parameters: char*: name + * boolean: allowArrayClass + * + * returns: boolean type + *=======================================================================*/ +bool_t IsLegalClassname(char *name, bool_t allowArrayClass) +{ + char *p; + if (name[0] == SIGNATURE_ARRAY) { + if (!allowArrayClass) { + return FALSE; + } else { + /* Everything that's left better be a field signature */ + p = skip_over_field_signature(name, FALSE); + } + } else { + /* skip over the fieldname. Slashes are okay */ + p = skip_over_fieldname(name, TRUE); + } + return (p != 0 && p[0] == '\0'); +} + +#endif diff --git a/MPC.3.5.LINUX/preverifier/check_code.c b/MPC.3.5.LINUX/preverifier/check_code.c new file mode 100644 index 0000000..96f535a --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/check_code.c @@ -0,0 +1,3970 @@ +/* + * @(#)check_code.c 1.26 02/09/27 + * + * Copyright 1995-1999 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + + +/*========================================================================= + * SYSTEM: Verifier + * SUBSYSTEM: Verifies codes within a method block. + * FILE: check_code.c + * OVERVIEW: Verifies that the code within a method block does not + * exploit any security holes. + * AUTHOR: Sheng Liang, Consumer & Embedded + * Initial implementation based on the Classic VM Verifier. + * Edited by Tasneem Sayeed, Java Consumer Technologies + *=======================================================================*/ + + +/*========================================================================= + * Include files + *=======================================================================*/ + +#include "check_code.h" + +#include "opcodes.length" +#include "opcodes.in_out" + +//#include "winsock2.h" +#define ntohl(x) (x) + +/*========================================================================= + * Globals and extern declarations + *=======================================================================*/ + +#ifdef DEBUG_VERIFIER + int verify_verbose = 0; + static struct context_type *GlobalContext; +#endif + +void rewriteCode(context_type *vcontext, struct methodblock *mb); +static void verify_method(context_type *context, struct methodblock *mb); +static void verify_field(context_type *context, struct fieldblock *fb); + +static void verify_opcode_operands (context_type *, int inumber, int offset); +static void set_protected(context_type *, int inumber, int key, opcode_type); +static bool_t isSuperClass(context_type *, fullinfo_type); + +static void initialize_exception_table(context_type *); +static int instruction_length(unsigned char *iptr); +static bool_t isLegalTarget(context_type *, int offset); +static void verify_constant_pool_type(context_type *, int, unsigned); + +static void initialize_dataflow(context_type *); +static void run_dataflow(context_type *context); +static void check_register_values(context_type *context, int inumber); +static void check_flags(context_type *context, int inumber); +static void pop_stack(context_type *, int inumber, stack_info_type *); +static void update_registers(context_type *, int inumber, register_info_type *); +static void update_flags(context_type *, int inumber, + flag_type *new_and_flags, flag_type *new_or_flags); +static void push_stack(context_type *, int inumber, stack_info_type *stack); + +static void merge_into_successors(context_type *, int inumber, + register_info_type *register_info, + stack_info_type *stack_info, + flag_type and_flags, flag_type or_flags); +static void merge_into_one_successor(context_type *context, + int from_inumber, int inumber, + register_info_type *register_info, + stack_info_type *stack_info, + flag_type and_flags, flag_type or_flags, + bool_t isException); +static void merge_stack(context_type *, int inumber, int to_inumber, + stack_info_type *); +static void merge_registers(context_type *, int inumber, int to_inumber, + register_info_type *); +static void merge_flags(context_type *context, int from_inumber, int to_inumber, + flag_type new_and_flags, flag_type new_or_flags); + +static stack_item_type *copy_stack(context_type *, stack_item_type *); +static mask_type *copy_masks(context_type *, mask_type *masks, int mask_count); +static mask_type *add_to_masks(context_type *, mask_type *, int , int); + +static fullinfo_type decrement_indirection(fullinfo_type); + +static fullinfo_type merge_fullinfo_types(context_type *context, + fullinfo_type a, fullinfo_type b, + bool_t assignment); +static bool_t isAssignableTo(context_type *,fullinfo_type a, fullinfo_type b); + +static ClassClass *object_fullinfo_to_classclass(context_type *, fullinfo_type); + + +#define NEW(type, count) \ + ((type *)CCalloc(context, (count)*(sizeof(type)), FALSE)) +#define ZNEW(type, count) \ + ((type *)CCalloc(context, (count)*(sizeof(type)), TRUE)) + +static void CCinit(context_type *context); +static void CCreinit(context_type *context); +static void CCdestroy(context_type *context); +static void *CCalloc(context_type *context, int size, bool_t zero); + +static char *cp_index_to_fieldname(context_type *context, int cp_index); +static char *cp_index_to_signature(context_type *context, int cp_index); +static fullinfo_type cp_index_to_class_fullinfo(context_type *, int, bool_t); + +static char signature_to_fieldtype(context_type *context, + char **signature_p, fullinfo_type *info); + +static void CCerror (context_type *, char *format, ...); + +#ifdef DEBUG_VERIFIER +static void print_stack (context_type *, stack_info_type *stack_info); +static void print_registers(context_type *, register_info_type *register_info); +static void print_flags(context_type *, flag_type, flag_type); +static void print_formatted_fieldname(context_type *context, int index); +#endif + + +/* + * Access local hash tables without locking. This extra level + * of naming is intended to emphasize the fact that locks are + * not held and also to do error handling. Although it is not + * strictly necessary, one should always use the "_Local" + * versions of these functions on the verifier's local hash + * tables. + */ +#define Str2IDFree_Local(localHashRoot) Str2IDFree(localHashRoot) + + +/*========================================================================= + * FUNCTION: Str2ID_Local + * OVERVIEW: Access local hash tables without locking + * This extra level of naming is intended to emphasize the + * fact that locks are not held and also to do error handling. + * These functions could all be macros like Str2IDFree_Local(), + * except that Str2ID() and ID2Str() can run out of memory, + * and the code in this file makes it inconvenient to check + * for that. As an expedient, rather than throwing exceptions, + * Str2ID_Local() is a function that calls CCerror() if + * necessary. + * Returns the index given the string which corresponds to the + * hash table entry. + * INTERFACE: + * parameters: context_type *: context + * struct StrIDhash **: hash_ptr + * char *: s + * void ***: param + * int: Copy + * + * returns: unsigned short + *=======================================================================*/ +unsigned short +Str2ID_Local(context_type *context, struct StrIDhash **hash_ptr, char *s, + void ***param, int Copy) { + unsigned short ret; + if ((ret = Str2ID(hash_ptr, s, param, Copy)) == 0) { +// CCerror(context, "Out of memory"); + } + + return ret; +} + + +/*========================================================================= + * FUNCTION: ID2Str_Local + * OVERVIEW: Access local hash tables without locking + * This extra level of naming is intended to emphasize the + * fact that locks are not held and also to do error handling. + * These functions could all be macros like Str2IDFree_Local(), + * except that Str2ID() and ID2Str() can run out of memory, + * and the code in this file makes it inconvenient to check + * for that. As an expedient, rather than throwing exceptions, + * ID2Str_Local() is a function that calls CCerror() if + * necessary. + * Returns the string given the index which corresponds to the + * hash table entry. + * INTERFACE: + * parameters: context_type *: context + * struct StrIDhash *: h + * unsigned short: ID + * void ***: param + * + * returns: char * + *=======================================================================*/ +char * +ID2Str_Local(context_type *context, struct StrIDhash *h, unsigned short ID, + void ***param) { + char *ret; + if ((ret = ID2Str(h, ID, param)) == 0) { +// CCerror(context, "Out of memory"); + } + + return ret; +} + + +/*========================================================================= + * FUNCTION: verify_class_codes + * OVERVIEW: Verifies the code for each of the methods in a class. + * Invoked by verify_class(). + * Returns true if the class codes are ok. + * INTERFACE: + * parameters: pointer to the ClassClass structure. + * + * returns: boolean type + *=======================================================================*/ +bool_t verify_class_codes(ClassClass *cb) { + context_type context_structure; + context_type *context = &context_structure; + bool_t result = TRUE; + void **addr; + int i; + +#ifdef DEBUG_VERIFIER + GlobalContext = context; +#endif + + /* Initialize the class-wide fields of the context. */ + context->class = cb; + + context->classHash = 0; + /* Zero method block field of the context, in case anyone calls CCerrror */ + context->mb = 0; + context->superClasses = NULL; /* filled in later */ + + /* Don't call CCerror or anything that can call it above the setjmp! */ + if (!setjmp(context->jump_buffer)) { + struct methodblock *mb; + struct fieldblock *fb; + + CCinit(context); /* initialize heap; may throw */ + + context->object_info = + MAKE_CLASSNAME_INFO(context, JAVAPKG "Object", &addr); + *addr = classJavaLangObject; + context->string_info = + MAKE_CLASSNAME_INFO(context, JAVAPKG "String", &addr); + *addr = classJavaLangString; + context->throwable_info = + MAKE_CLASSNAME_INFO(context, JAVAPKG "Throwable", &addr); + *addr = classJavaLangThrowable; + context->currentclass_info = + MAKE_CLASSNAME_INFO_WITH_COPY(context, cbName(cb), &addr); + *addr = cb; + if (cbSuperclass(cb) != 0) { + ClassClass *super = cbSuperclass(cb); + context->superclass_info = + MAKE_CLASSNAME_INFO_WITH_COPY(context, cbName(super), &addr); + *addr = super; + } else { + context->superclass_info = 0; + } + + /* Look at each method */ + for (i = cbFieldsCount(cb), fb = cbFields(cb); --i >= 0; fb++) + verify_field(context, fb); + + unhand(context->class)->new_class_entries = + (char **)malloc((cbConstantPoolCount(context->class) * 3 + 100) * sizeof(char *)); + unhand(context->class)->n_new_class_entries = 0; + + for (i = cbMethodsCount(cb), mb = cbMethods(cb); --i >= 0; mb++) + verify_method(context, mb); + + unhand(context->class)->new_class_entries = + (char **)realloc(unhand(context->class)->new_class_entries, + unhand(context->class)->n_new_class_entries * sizeof(char *)); + + result = TRUE; + } else { + result = FALSE; + } + + /* Cleanup */ + Str2IDFree_Local(&context->classHash); + +#ifdef DEBUG_VERIFIER + GlobalContext = 0; +#endif + + if (context->superClasses != NULL) { + sysFree(context->superClasses); + } + CCdestroy(context); /* destroy heap */ + return result; +} + + +/*========================================================================= + * FUNCTION: verify_field + * OVERVIEW: Verifies the field block within each method of a class + * file. + * Invoked by verify_class_codes(). + * Returns true if the field block is ok. + * INTERFACE: + * parameters: pointer to the context_type structure. + * pointer to the field block + * + * returns: boolean type + *=======================================================================*/ +static void +verify_field(context_type *context, struct fieldblock *fb) +{ + int access_bits = fb->access; + + if ( ((access_bits & ACC_PUBLIC) != 0) && + ((access_bits & (ACC_PRIVATE | ACC_PROTECTED)) != 0)) { + if (verbose) { + // jio_fprintf(stderr, "VERIFIER ERROR %s.%s:\n", + // cbName(fieldclass(fb)), fb->name); + // jio_fprintf(stderr, "Inconsistent access bits."); + } + longjmp(context->jump_buffer, 1); + } +} + + +/*========================================================================= + * FUNCTION: get_type_name + * OVERVIEW: Retrieves the type name information given the item type. + * Used by get_type_code() which is invoked by verify_method() + * to retrieve the type code for the stack map entries. + * INTERFACE: + * parameters: pointer to the context_type structure. + * fullinfo_type: type + * char *: buf + * + * returns: nothing + *=======================================================================*/ +static void +get_type_name(context_type *context, fullinfo_type type, char *buf) +{ + int i; + int indirection = GET_INDIRECTION(type); + for (i = indirection; i-- > 0; ) + *buf++ = '['; + switch (GET_ITEM_TYPE(type)) { + case ITEM_Integer: + *buf++ = 'I'; break; + case ITEM_Float: + *buf++ = 'F'; break; + case ITEM_Double: + *buf++ = 'D'; break; + case ITEM_Long: + *buf++ = 'J'; break; + case ITEM_Char: + *buf++ = 'C'; break; + case ITEM_Short: + *buf++ = 'S'; break; + case ITEM_Byte: + *buf++ = 'B'; break; + case ITEM_Boolean: + *buf++ = 'Z'; break; + case ITEM_Object: { + unsigned short extra = GET_EXTRA_INFO(type); + if (indirection) *buf++ = 'L'; + if (extra == 0) { +// panic("unexpected"); + } else { + char *name = ID2Str_Local(context, context->classHash, + extra, 0); + strcpy(buf, name); + if (indirection) strcat(buf, ";"); + } + return; + } + // default: + // panic("bad type"); + } + *buf = '\0'; +} + + +/*========================================================================= + * FUNCTION: check_class_constant + * OVERVIEW: Checks and returns the index corresponding to the given + * UTF8 constant entry within the constant pool. + * Returns -1 if none was found. + * Invoked by get_type_code(). + * INTERFACE: + * parameters: pointer to the ClassClass structure. + * char *: utf8 + * + * returns: long type + *=======================================================================*/ +long check_class_constant(ClassClass *cb, char *utf8) +{ + int i; + cp_item_type *constant_pool = cbConstantPool(cb); + unsigned char *type_table = + constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type; + for (i = 0; i < cbConstantPoolCount(cb); i++) { + if (type_table[i] == (CONSTANT_Class | CONSTANT_POOL_ENTRY_RESOLVED) && + strcmp(utf8, cbName(constant_pool[i].clazz)) == 0) { + return i; + } + if (type_table[i] == CONSTANT_Class && + strcmp(utf8, constant_pool[constant_pool[i].i].cp) == 0) { + return i; + } + } + return -1; +} + + +/*========================================================================= + * FUNCTION: get_type_code + * OVERVIEW: Retrieves the type code entry given the item type. + * Invoked by verify_method() to retrieve the type code + * for the stack map entries. + * INTERFACE: + * parameters: pointer to the context_type structure. + * fullinfo_type: type + * + * returns: struct map_entry + *=======================================================================*/ +struct map_entry get_type_code(context_type *context, fullinfo_type type) +{ + struct map_entry result = {0,0}; + switch (type) { + case ITEM_Double_2: + case ITEM_Long_2: + case ITEM_Bogus: + result.type = CF_ITEM_Bogus; + return result; + case ITEM_Integer: + result.type = CF_ITEM_Integer; + return result; + case ITEM_Float: + result.type = CF_ITEM_Float; + return result; + case ITEM_Double: + result.type = CF_ITEM_Double; + return result; + case ITEM_Long: + result.type = CF_ITEM_Long; + return result; + case ITEM_InitObject: + result.type = CF_ITEM_InitObject; + return result; + default: + if (GET_ITEM_TYPE(type) == ITEM_NewObject) { + int inum = GET_EXTRA_INFO(type); + result.type = CF_ITEM_NewObject; + result.info = context->instruction_data[inum].offset; + return result; + } else if (GET_ITEM_TYPE(type) == ITEM_Object && GET_EXTRA_INFO(type) == 0) { + result.type = CF_ITEM_Null; + return result; + } else if (GET_ITEM_TYPE(type) == ITEM_Object || GET_INDIRECTION(type) > 0) { + char type_name[1024]; + int i; + result.type = CF_ITEM_Object; + get_type_name(context, type, type_name); + i = check_class_constant(context->class, type_name); + if (i >= 0) { + result.info = i; + return result; + } + for (i = 0; i < unhand(context->class)->n_new_class_entries; i++) { + if (strcmp(type_name, unhand(context->class)->new_class_entries[i]) == 0) { + result.info = ~i; + return result; + } + } + { + int entries = unhand(context->class)->n_new_class_entries; + unhand(context->class)->new_class_entries[entries] = strdup(type_name); + result.info = ~entries; + unhand(context->class)->n_new_class_entries = entries + 1; + return result; + } + } else { + // panic("bad type code"); + return result; /* not reached */ + } + } +} + + +/*========================================================================= + * FUNCTION: verify_method + * OVERVIEW: Verifies the code for one method within a class file. + * Invoked by verify_class_codes(). + * INTERFACE: + * parameters: pointer to the context_type structure. + * struct methodblock*: mb + * + * returns: nothing + *=======================================================================*/ +static void +verify_method(context_type *context, struct methodblock *mb) +{ + int access_bits = mb->fb.access; + unsigned char *code; + int code_length; + short *code_data; + instruction_data_type *idata = 0; + int instruction_count; + int i, offset, inumber; + int exception_count; + int n_stack_maps, dead_count, jsr_count; + + again: + code = mb->code; + code_length = mb->code_length; + + /* CCerror can give method-specific info once this is set */ + context->mb = mb; + + CCreinit(context); /* initial heap */ + code_data = NEW(short, code_length); + +#ifdef DEBUG_VERIFIER +// if (verify_verbose) { +// jio_fprintf(stdout, "Looking at %s.%s%s 0x%x\n", +// cbName(fieldclass(&mb->fb)), mb->fb.name, mb->fb.signature, +// (long)mb); +// } +#endif + + if (((access_bits & ACC_PUBLIC) != 0) && + ((access_bits & (ACC_PRIVATE | ACC_PROTECTED)) != 0)) { +// CCerror(context, "Inconsistent access bits."); + } + + if ((access_bits & (ACC_ABSTRACT | ACC_NATIVE)) != 0) { + /* not much to do for abstract or native methods */ + return; + } + + if (code_length >= 65535) { +// CCerror(context, "Code of a method longer than 65535 bytes"); + } + + /* Run through the code. Mark the start of each instruction, and give + * the instruction a number */ + for (i = 0, offset = 0; offset < code_length; i++) { + int length = instruction_length(&code[offset]); + int next_offset = offset + length; +// if (length <= 0) +// CCerror(context, "Illegal instruction found at offset %d", offset); +// if (next_offset > code_length) +// CCerror(context, "Code stops in the middle of instruction " +// " starting at offset %d", offset); + code_data[offset] = i; + while (++offset < next_offset) + code_data[offset] = -1; /* illegal location */ + } + instruction_count = i; /* number of instructions in code */ + + /* Allocate a structure to hold info about each instruction. */ + idata = NEW(instruction_data_type, instruction_count); + + /* Initialize the heap, and other info in the context structure. */ + context->code = code; + context->instruction_data = idata; + context->code_data = code_data; + context->instruction_count = instruction_count; + context->handler_info = NEW(struct handler_info_type, + mb->exception_table_length); + context->bitmask_size = (mb->nlocals + (BITS_PER_INT - 1))/BITS_PER_INT; + +// if (instruction_count == 0) +// CCerror(context, "Empty code"); + + for (inumber = 0, offset = 0; offset < code_length; inumber++) { + int length = instruction_length(&code[offset]); + instruction_data_type *this_idata = &idata[inumber]; + this_idata->opcode = code[offset]; + this_idata->offset = offset; + this_idata->length = length; + this_idata->stack_info.stack = NULL; + this_idata->stack_info.stack_size = UNKNOWN_STACK_SIZE; + this_idata->register_info.register_count = UNKNOWN_REGISTER_COUNT; + this_idata->changed = FALSE; /* no need to look at it yet. */ + this_idata->protected = FALSE; /* no need to look at it yet. */ + /* Added for inlinejsr */ + this_idata->is_target = FALSE; /* no need to look at it yet. */ + this_idata->and_flags = (flag_type) -1; /* "bottom" and value */ + this_idata->or_flags = 0; /* "bottom" or value*/ + + /* This also sets up this_data->operand. It also makes the + * xload_x and xstore_x instructions look like the generic form. */ + verify_opcode_operands(context, inumber, offset); + offset += length; + } + + + /* make sure exception table is reasonable. */ + initialize_exception_table(context); + /* Set up first instruction, and start of exception handlers. */ + initialize_dataflow(context); + /* Run data flow analysis on the instructions. */ + context->redoJsr = FALSE; + run_dataflow(context); + + for (inumber = 0; inumber < instruction_count; inumber++) { + instruction_data_type *this_idata = &idata[inumber]; + if ( (this_idata->or_flags & FLAG_REACHED) && + ((this_idata->opcode == opc_jsr) || + (this_idata->opcode == opc_jsr_w)) && + (this_idata->operand2.i == UNKNOWN_RET_INSTRUCTION)) { + this_idata->changed = TRUE; + context->redoJsr = TRUE; + } + } + if (context->redoJsr) { + run_dataflow(context); + } + + + /* verify checked exceptions, if any */ + if ((exception_count = mb->nexceptions) > 0) { + unsigned short *exceptions = mb->exceptions; + for (i = 0; i < (int)exception_count; i++) { + /* Make sure the constant pool item is CONSTANT_Class */ + verify_constant_pool_type(context, (int)exceptions[i], + 1 << CONSTANT_Class); + } + } + + + dead_count = jsr_count = 0; + for (inumber = 0; inumber < instruction_count; inumber++) { + instruction_data_type *this_idata = &idata[inumber]; + if ((this_idata->or_flags & FLAG_REACHED) == 0) { + dead_count++; + } else if (this_idata->opcode == opc_jsr || + this_idata->opcode == opc_jsr_w) { + jsr_count++; + } + } + if (dead_count > 0 || jsr_count > 0) { + rewriteCode(context, mb); + goto again; + } + + n_stack_maps = 0; + for (inumber = 0; inumber < instruction_count; inumber++) { + instruction_data_type *this_idata = &idata[inumber]; + if (this_idata->is_target) { + n_stack_maps++; + } + } + + mb->n_stack_maps = n_stack_maps; + mb->stack_maps = + (struct stack_map *)malloc(n_stack_maps * sizeof(struct stack_map)); + + n_stack_maps = 0; + for (inumber = 0; inumber < instruction_count; inumber++) { + instruction_data_type *this_idata = &idata[inumber]; + if (this_idata->is_target) { + struct stack_info_type *stack_info = &this_idata->stack_info; + struct register_info_type *register_info = &this_idata->register_info; + int register_count = register_info->register_count; + struct stack_item_type *stack; + struct map_entry *new_entries; + int index, index2; + + + /* We may be allocating too big a structure if there are longs + * or doubles on the stack, but that's okay */ + new_entries = (struct map_entry *)malloc(register_count * sizeof(struct map_entry)); + + for (index2 = 0, index = 0; index < register_count; index++) { + fullinfo_type info = register_info->registers[index]; + if (info == ITEM_Double || info == ITEM_Long) { + if (index + 1 < register_count && + register_info->registers[index + 1] == info+1) { + new_entries[index2++] = get_type_code(context, info); + index++; + } else { + new_entries[index2++] = get_type_code(context, ITEM_Bogus); + } + } else { + new_entries[index2++] = get_type_code(context, info); + } + } + mb->stack_maps[n_stack_maps].offset = this_idata->offset; + mb->stack_maps[n_stack_maps].locals = new_entries; + mb->stack_maps[n_stack_maps].nlocals = index2; + + + mb->stack_maps[n_stack_maps].nstacks = 0; + for (stack = stack_info->stack; stack; stack = stack->next) { + mb->stack_maps[n_stack_maps].nstacks++; + } + new_entries = (struct map_entry *)malloc(mb->stack_maps[n_stack_maps].nstacks * sizeof(struct map_entry)); + index = 0; + for (stack = stack_info->stack; stack; stack = stack->next) { + new_entries[mb->stack_maps[n_stack_maps].nstacks - (++index)] = + get_type_code(context, stack->item); + } + mb->stack_maps[n_stack_maps].stacks = new_entries; + + unhand(context->class)->has_stack_maps = 1; + n_stack_maps++; + } + } +} + + +/*========================================================================= + * FUNCTION: verify_opcode_operands + * OVERVIEW: Verifies the operands of a single instruction given an + * instruction number and an offset. + * Also, for simplicity, move the operand into the ->operand + * field. + * Make sure that branches do not go into the middle + * of nowhere. + * Invoked by verify_method(). + * INTERFACE: + * parameters: context_type *: context + * int: inumber + * int: offset + * + * returns: nothing + *=======================================================================*/ +static void +verify_opcode_operands(context_type *context, int inumber, int offset) +{ + instruction_data_type *idata = context->instruction_data; + instruction_data_type *this_idata = &idata[inumber]; + short *code_data = context->code_data; + struct methodblock *mb = context->mb; + unsigned char *code = context->code; + opcode_type opcode = this_idata->opcode; + int var; + + this_idata->operand.i = 0; + this_idata->operand2.i = 0; + + switch (opcode) { + + case opc_jsr: + /* instruction of ret statement */ + this_idata->operand2.i = UNKNOWN_RET_INSTRUCTION; + /* FALLTHROUGH */ + case opc_ifeq: case opc_ifne: case opc_iflt: + case opc_ifge: case opc_ifgt: case opc_ifle: + case opc_ifnull: case opc_ifnonnull: + case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmplt: + case opc_if_icmpge: case opc_if_icmpgt: case opc_if_icmple: + case opc_if_acmpeq: case opc_if_acmpne: + case opc_goto: { + /* Set the ->operand to be the instruction number of the target. */ + int jump = (((signed char)(code[offset+1])) << 8) + code[offset+2]; + int target = offset + jump; +// if (!isLegalTarget(context, target)) +// CCerror(context, "Illegal target of jump or branch"); + this_idata->operand.i = code_data[target]; + break; + } + + case opc_jsr_w: + /* instruction of ret statement */ + this_idata->operand2.i = UNKNOWN_RET_INSTRUCTION; + /* FALLTHROUGH */ + case opc_goto_w: { + /* Set the ->operand to be the instruction number of the target. */ + int jump = (((signed char)(code[offset+1])) << 24) + + (code[offset+2] << 16) + (code[offset+3] << 8) + + (code[offset + 4]); + int target = offset + jump; +// if (!isLegalTarget(context, target)) +// CCerror(context, "Illegal target of jump or branch"); + this_idata->operand.i = code_data[target]; + break; + } + + case opc_tableswitch: + case opc_lookupswitch: { + /* Set the ->operand to be a table of possible instruction targets. */ + long *lpc = (long *) UCALIGN(code + offset + 1); + long *lptr; + int *saved_operand; + int keys; + int k, delta; + if (opcode == opc_tableswitch) { + keys = ntohl(lpc[2]) - ntohl(lpc[1]) + 1; + delta = 1; + } else { + keys = ntohl(lpc[1]); /* number of pairs */ + delta = 2; + /* Make sure that the tableswitch items are sorted */ + for (k = keys - 1, lptr = &lpc[2]; --k >= 0; lptr += 2) { + long this_key = ntohl(lptr[0]); /* NB: ntohl may be unsigned */ + long next_key = ntohl(lptr[2]); +// if (this_key >= next_key) { +// CCerror(context, "Unsorted lookup switch"); +// } + } + } + /* This code has been changed for inlining. We know have the keys + * in the same order that they occur in the code, with the default + * key being the first one. + */ + saved_operand = NEW(int, keys + 2); +// if (!isLegalTarget(context, offset + ntohl(lpc[0]))) +// CCerror(context, "Illegal default target in switch"); + + saved_operand[0] = keys + 1; /* number of successors */ + saved_operand[1] = code_data[offset + ntohl(lpc[0])]; /* default */ + + for (k = 0, lptr = &lpc[3]; k < keys; lptr += delta, k++) { + int target = offset + ntohl(lptr[0]); + // if (!isLegalTarget(context, target)) + // CCerror(context, "Illegal branch in opc_tableswitch"); + saved_operand[k + 2] = code_data[target]; + } + this_idata->operand.ip = saved_operand; + break; + } + + case opc_ldc: { + /* Make sure the constant pool item is the right type. */ + int key = code[offset + 1]; + int types = (1 << CONSTANT_Integer) | (1 << CONSTANT_Float) | + (1 << CONSTANT_String); + this_idata->operand.i = key; + verify_constant_pool_type(context, key, types); + break; + } + + case opc_ldc_w: { + /* Make sure the constant pool item is the right type. */ + int key = (code[offset + 1] << 8) + code[offset + 2]; + int types = (1 << CONSTANT_Integer) | (1 << CONSTANT_Float) | + (1 << CONSTANT_String); + this_idata->operand.i = key; + verify_constant_pool_type(context, key, types); + break; + } + + case opc_ldc2_w: { + /* Make sure the constant pool item is the right type. */ + int key = (code[offset + 1] << 8) + code[offset + 2]; + int types = (1 << CONSTANT_Double) | (1 << CONSTANT_Long); + this_idata->operand.i = key; + verify_constant_pool_type(context, key, types); + break; + } + + case opc_getfield: case opc_putfield: + case opc_getstatic: case opc_putstatic: { + /* Make sure the constant pool item is the right type. */ + int key = (code[offset + 1] << 8) + code[offset + 2]; + this_idata->operand.i = key; + verify_constant_pool_type(context, key, 1 << CONSTANT_Fieldref); + if (opcode == opc_getfield || opcode == opc_putfield) + set_protected(context, inumber, key, opcode); + break; + } + + case opc_invokevirtual: + case opc_invokespecial: + case opc_invokestatic: + case opc_invokeinterface: { + /* Make sure the constant pool item is the right type. */ + int key = (code[offset + 1] << 8) + code[offset + 2]; + char *methodname; + fullinfo_type clazz_info; + int kind = (opcode == opc_invokeinterface + ? 1 << CONSTANT_InterfaceMethodref + : 1 << CONSTANT_Methodref); + /* Make sure the constant pool item is the right type. */ + verify_constant_pool_type(context, key, kind); + methodname = cp_index_to_fieldname(context, key); + clazz_info = cp_index_to_class_fullinfo(context, key, TRUE); + this_idata->operand.i = key; + this_idata->operand2.fi = clazz_info; + if (strcmp(methodname, "") == 0) { +// if (opcode != opc_invokespecial) +// CCerror(context, +// "Must call initializers using invokespecial"); + this_idata->opcode = opc_invokeinit; + } else { +// if (methodname[0] == '<') +// CCerror(context, "Illegal call to internal method"); + if (opcode == opc_invokespecial + && clazz_info != context->currentclass_info + && clazz_info != context->superclass_info) { + ClassClass *cb = context->class; + for (; ; cb = cbSuperclass(cb)) { + if (clazz_info == MAKE_CLASSNAME_INFO_WITH_COPY(context, cbName(cb), 0)) + break; + /* The optimizer make cause this to happen on local code */ + if (cbSuperclass(cb) == 0) { + /* optimizer make cause this to happen on local code */ + // if (cbLoader(cb) != 0) + // CCerror(context, + // "Illegal use of nonvirtual function call"); + break; + } + } + } + } + if (opcode == opc_invokeinterface) { + char *signature = cp_index_to_signature(context, key); + unsigned int args1 = Signature2ArgsSize(signature) + 1; + unsigned int args2 = code[offset + 3]; + if (args1 != args2) { + // CCerror(context, + // "Inconsistent args_size for opc_invokeinterface"); + } + if (code[offset + 4] != 0) { + // CCerror(context, + // "Fourth operand byte of invokeinterface must be zero"); + } + } else if (opcode == opc_invokevirtual + || opcode == opc_invokespecial) + set_protected(context, inumber, key, opcode); + break; + } + + + case opc_instanceof: + case opc_checkcast: + case opc_new: + case opc_anewarray: + case opc_multianewarray: { + /* Make sure the constant pool item is a class */ + int key = (code[offset + 1] << 8) + code[offset + 2]; + fullinfo_type target; + verify_constant_pool_type(context, key, 1 << CONSTANT_Class); + target = cp_index_to_class_fullinfo(context, key, FALSE); +// if (GET_ITEM_TYPE(target) == ITEM_Bogus) +// CCerror(context, "Illegal type"); + switch(opcode) { + case opc_anewarray: + if ((GET_INDIRECTION(target)) >= MAX_ARRAY_DIMENSIONS) + CCerror(context, "Array with too many dimensions"); + this_idata->operand.fi = MAKE_FULLINFO(GET_ITEM_TYPE(target), + GET_INDIRECTION(target) + 1, + GET_EXTRA_INFO(target)); + break; + case opc_new: +// if (WITH_ZERO_EXTRA_INFO(target) != +// MAKE_FULLINFO(ITEM_Object, 0, 0)) +// CCerror(context, "Illegal creation of multi-dimensional array"); + /* operand gets set to the "unitialized object". operand2 gets + * set to what the value will be after it's initialized. */ + this_idata->operand.fi = MAKE_FULLINFO(ITEM_NewObject, 0, inumber); + this_idata->operand2.fi = target; + break; + case opc_multianewarray: + this_idata->operand.fi = target; + this_idata->operand2.i = code[offset + 3]; + // if ( (this_idata->operand2.i > (int)GET_INDIRECTION(target)) + // || (this_idata->operand2.i == 0)) + // CCerror(context, "Illegal dimension argument"); + break; + default: + this_idata->operand.fi = target; + } + break; + } + + case opc_newarray: { + /* Cache the result of the opc_newarray into the operand slot */ + fullinfo_type full_info; + switch (code[offset + 1]) { + case T_INT: + full_info = MAKE_FULLINFO(ITEM_Integer, 1, 0); break; + case T_LONG: + full_info = MAKE_FULLINFO(ITEM_Long, 1, 0); break; + case T_FLOAT: + full_info = MAKE_FULLINFO(ITEM_Float, 1, 0); break; + case T_DOUBLE: + full_info = MAKE_FULLINFO(ITEM_Double, 1, 0); break; + case T_BYTE: + full_info = MAKE_FULLINFO(ITEM_Byte, 1, 0); break; + case T_BOOLEAN: + full_info = MAKE_FULLINFO(ITEM_Boolean, 1, 0); break; + case T_CHAR: + full_info = MAKE_FULLINFO(ITEM_Char, 1, 0); break; + case T_SHORT: + full_info = MAKE_FULLINFO(ITEM_Short, 1, 0); break; + default: + full_info = 0; /* make GCC happy */ + // CCerror(context, "Bad type passed to opc_newarray"); + } + this_idata->operand.fi = full_info; + break; + } + + /* Fudge iload_x, aload_x, etc to look like their generic cousin. */ + case opc_iload_0: case opc_iload_1: case opc_iload_2: case opc_iload_3: + this_idata->opcode = opc_iload; + var = opcode - opc_iload_0; + goto check_local_variable; + + case opc_fload_0: case opc_fload_1: case opc_fload_2: case opc_fload_3: + this_idata->opcode = opc_fload; + var = opcode - opc_fload_0; + goto check_local_variable; + + case opc_aload_0: case opc_aload_1: case opc_aload_2: case opc_aload_3: + this_idata->opcode = opc_aload; + var = opcode - opc_aload_0; + goto check_local_variable; + + case opc_lload_0: case opc_lload_1: case opc_lload_2: case opc_lload_3: + this_idata->opcode = opc_lload; + var = opcode - opc_lload_0; + goto check_local_variable2; + + case opc_dload_0: case opc_dload_1: case opc_dload_2: case opc_dload_3: + this_idata->opcode = opc_dload; + var = opcode - opc_dload_0; + goto check_local_variable2; + + case opc_istore_0: case opc_istore_1: case opc_istore_2: case opc_istore_3: + this_idata->opcode = opc_istore; + var = opcode - opc_istore_0; + goto check_local_variable; + + case opc_fstore_0: case opc_fstore_1: case opc_fstore_2: case opc_fstore_3: + this_idata->opcode = opc_fstore; + var = opcode - opc_fstore_0; + goto check_local_variable; + + case opc_astore_0: case opc_astore_1: case opc_astore_2: case opc_astore_3: + this_idata->opcode = opc_astore; + var = opcode - opc_astore_0; + goto check_local_variable; + + case opc_lstore_0: case opc_lstore_1: case opc_lstore_2: case opc_lstore_3: + this_idata->opcode = opc_lstore; + var = opcode - opc_lstore_0; + goto check_local_variable2; + + case opc_dstore_0: case opc_dstore_1: case opc_dstore_2: case opc_dstore_3: + this_idata->opcode = opc_dstore; + var = opcode - opc_dstore_0; + goto check_local_variable2; + + case opc_wide: + this_idata->opcode = code[offset + 1]; + var = (code[offset + 2] << 8) + code[offset + 3]; + switch(this_idata->opcode) { + case opc_lload: case opc_dload: + case opc_lstore: case opc_dstore: + goto check_local_variable2; + default: + goto check_local_variable; + } + + case opc_iinc: /* the increment amount doesn't matter */ + case opc_ret: + case opc_aload: case opc_iload: case opc_fload: + case opc_astore: case opc_istore: case opc_fstore: + var = code[offset + 1]; + check_local_variable: + /* Make sure that the variable number isn't illegal. */ + this_idata->operand.i = var; +// if (var >= (int)mb->nlocals) +// CCerror(context, "Illegal local variable number"); + break; + + case opc_lload: case opc_dload: case opc_lstore: case opc_dstore: + var = code[offset + 1]; + check_local_variable2: + /* Make sure that the variable number isn't illegal. */ + this_idata->operand.i = var; +// if ((var + 1) >= (int)mb->nlocals) +// CCerror(context, "Illegal local variable number"); + break; + + // default: +// if (opcode >= opc_breakpoint) +// CCerror(context, "Quick instructions shouldn't appear yet."); + break; + } /* of switch */ +} + + +/*========================================================================= + * FUNCTION: set_protected + * OVERVIEW: Checks the field access to see if the instruction is + * protected, is private and is in the same class package, + * then the protected bit for the given instruction is set. + * Invoked by verify_operands_opcodes() to set protected bit + * for instructions of the following opcode types: + * opc_getfield, opc_putfield, and opc_invokevirtual. + * INTERFACE: + * parameters: context_type *: context + * int: instruction number + * int: key + * opcode_type: opcode + * + * returns: nothing + *=======================================================================*/ +static void +set_protected(context_type *context, int inumber, int key, opcode_type opcode) +{ + /* fullinfo_type clazz_info = cp_index_to_class_fullinfo(context, key, TRUE); + if (isSuperClass(context, clazz_info)) { + char *name = cp_index_to_fieldname(context, key); + char *signature = cp_index_to_signature(context, key); + unsigned ID = NameAndTypeToHash(name, signature); + ClassClass *calledClass = + object_fullinfo_to_classclass(context, clazz_info); + struct fieldblock *fb; + + if (ID == 0) { // NameAndTypeToHash returns 0 if out of memory + // CCerror(context, "Out of memory"); + return; + } + if (opcode != opc_invokevirtual && opcode != opc_invokespecial) { + int n = cbFieldsCount(calledClass); + fb = cbFields(calledClass); + for (; --n >= 0; fb++) { + if (fb->ID == ID) { + goto haveIt; + } + } + return; + } else { + struct methodblock *mb = cbMethods(calledClass); + int n = cbMethodsCount(calledClass); + for (; --n >= 0; mb++) { + if (mb->fb.ID == ID) { + fb = &mb->fb; + goto haveIt; + } + } + return; + } + haveIt: + if (IsProtected(fb->access)) { + if (IsPrivate(fb->access) || + !IsSameClassPackage(calledClass, context->class)) + context->instruction_data[inumber].protected = TRUE; + } + }*/ +} + + +/*========================================================================= + * FUNCTION: isSuperClass + * OVERVIEW: Determines which of the classes are superclasses. + * Returns true if the given clazz_info corresponds to a + * a superclass. + * INTERFACE: + * parameters: context_type* : context + * fullinfo_type: clazz_info + * + * returns: boolean type + *=======================================================================*/ +static bool_t +isSuperClass(context_type *context, fullinfo_type clazz_info) { + + //return TRUE; + + fullinfo_type *fptr = context->superClasses; + if (fptr == NULL) { + ClassClass *cb; + fullinfo_type *gptr; + int i; + /* Count the number of superclasses. By counting ourselves, and + * not counting Object, we get the same number. */ + for (i = 0, cb = context->class; + cb != classJavaLangObject; + i++, cb = cbSuperclass(cb)); + /* Can't go on context heap since it survives more than one method */ + context->superClasses = fptr + = sysMalloc(sizeof(fullinfo_type)*(i + 1)); + if (fptr == 0) { + // CCerror(context, "Out of memory"); + } + for (gptr = fptr, cb = context->class; cb != classJavaLangObject; ) { + void **addr; + cb = cbSuperclass(cb); + *gptr++ = MAKE_CLASSNAME_INFO_WITH_COPY(context, cbName(cb), &addr); + *addr = cb; + } + *gptr = 0; + } + for (; *fptr != 0; fptr++) { + if (*fptr == clazz_info) + return TRUE; + } + return FALSE; +} + + +/*========================================================================= + * FUNCTION: initialize_exception_table + * OVERVIEW: Initializes the exception table. + * Looks through each item on the exception table and ensures + * that each of the fields refers to a legal instruction. + * INTERFACE: + * parameters: pointer to the context_type structure. + * + * returns: nothing + *=======================================================================*/ +static void +initialize_exception_table(context_type *context) +{ + struct methodblock *mb = context->mb; + struct CatchFrame *exception_table = mb->exception_table; + struct handler_info_type *handler_info = context->handler_info; + short *code_data = context->code_data; + unsigned long code_length = mb->code_length; + + int i; + for (i = mb->exception_table_length; + --i >= 0; exception_table++, handler_info++) { + unsigned long start = exception_table->start_pc; + unsigned long end = exception_table->end_pc; + unsigned long handler = exception_table->handler_pc; + unsigned catchType = exception_table->catchType; + stack_item_type *stack_item = NEW(stack_item_type, 1); + if (!( start < end && start >= 0 + && isLegalTarget(context, start) + && (end == code_length || isLegalTarget(context, end)))) { + // CCerror(context, "Illegal exception table range"); + } + if (!((handler > 0) && isLegalTarget(context, handler))) { + // CCerror(context, "Illegal exception table handler"); + } + + handler_info->start = code_data[start]; + /* end may point to one byte beyond the end of bytecodes. */ + handler_info->end = (end == context->mb->code_length) ? + context->instruction_count : code_data[end]; + handler_info->handler = code_data[handler]; + handler_info->stack_info.stack = stack_item; + handler_info->stack_info.stack_size = 1; + + stack_item->next = NULL; + if (catchType != 0) { + union cp_item_type *cp = cbConstantPool(context->class); + char *classname; + verify_constant_pool_type(context, catchType, 1 << CONSTANT_Class); + classname = GetClassConstantClassName(cp, catchType); + stack_item->item = MAKE_CLASSNAME_INFO_WITH_COPY(context, classname, 0); + } else { + stack_item->item = context->throwable_info; + } + } +} + + +/*========================================================================= + * FUNCTION: instruction_length + * OVERVIEW: Given a pointer to an instruction, return its length. + * Use the table opcode_length[] which is automatically built. + * INTERFACE: + * parameters: pointer to the instruction + * + * returns: int type + *=======================================================================*/ +static int instruction_length(unsigned char *iptr) +{ + int instruction = *iptr; + switch (instruction) { + case opc_tableswitch: { + long *lpc = (long *) UCALIGN(iptr + 1); + int index = ntohl(lpc[2]) - ntohl(lpc[1]); + if ((index < 0) || (index > 65535)) { + return -1; /* illegal */ + } else { + return (unsigned char *)(&lpc[index + 4]) - iptr; + } + } + + case opc_lookupswitch: { + long *lpc = (long *) UCALIGN(iptr + 1); + int npairs = ntohl(lpc[1]); + if (npairs < 0 || npairs >= 8192) + return -1; + else + return (unsigned char *)(&lpc[2 * (npairs + 1)]) - iptr; + } + + case opc_wide: + switch(iptr[1]) { + case opc_ret: + case opc_iload: case opc_istore: + case opc_fload: case opc_fstore: + case opc_aload: case opc_astore: + case opc_lload: case opc_lstore: + case opc_dload: case opc_dstore: + return 4; + case opc_iinc: + return 6; + default: + return -1; + } + + default: { + /* A length of 0 indicates an error. */ + int length = opcode_length[instruction]; + return (length <= 0) ? -1 : length; + } + } +} + + +/*========================================================================= + * FUNCTION: isLegalTarget + * OVERVIEW: Given the target of a branch, make sure that it is a legal + * target. Returns true if it is a legal target of a branch. + * INTERFACE: + * parameters: pointer to the context_type + * int: offset + * + * returns: boolean type + *=======================================================================*/ +static bool_t +isLegalTarget(context_type *context, int offset) +{ + struct methodblock *mb = context->mb; + int code_length = mb->code_length; + short *code_data = context->code_data; + return (offset >= 0 && offset < code_length && code_data[offset] >= 0); +} + + +/*========================================================================= + * FUNCTION: verify_constant_pool_type + * OVERVIEW: Make sure that an element of the constant pool is really + * of the indicated type. + * INTERFACE: + * parameters: pointer to the context_type + * int: index + * unsigned: mask + * returns: nothing + *=======================================================================*/ +static void +verify_constant_pool_type(context_type *context, int index, unsigned mask) +{ + ClassClass *cb = context->class; + union cp_item_type *constant_pool = cbConstantPool(cb); + int nconstants = cbConstantPoolCount(cb); + unsigned char *type_table = + constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type; + unsigned type; + + // if ((index <= 0) || (index >= nconstants)) +// CCerror(context, "Illegal constant pool index"); + + type = CONSTANT_POOL_TYPE_TABLE_GET_TYPE(type_table, index); +// if ((mask & (1 << type)) == 0) +// CCerror(context, "Illegal type in constant pool"); +} + + +/*========================================================================= + * Functions for Data Flow Analysis + *=======================================================================*/ + +/*========================================================================= + * FUNCTION: initialize_dataflow + * OVERVIEW: Initialize for data flow analysis. + * INTERFACE: + * parameters: pointer to the context_type + * returns: nothing + *=======================================================================*/ +static void +initialize_dataflow(context_type *context) +{ + instruction_data_type *idata = context->instruction_data; + struct methodblock *mb = context->mb; + fullinfo_type *reg_ptr; + fullinfo_type full_info; + char *p; + + /* Initialize the function entry, since we know everything about it. */ + idata[0].stack_info.stack_size = 0; + idata[0].stack_info.stack = NULL; + idata[0].register_info.register_count = mb->args_size; + idata[0].register_info.registers = NEW(fullinfo_type, mb->args_size); + idata[0].register_info.mask_count = 0; + idata[0].register_info.masks = NULL; + idata[0].and_flags = 0; /* nothing needed */ + idata[0].or_flags = FLAG_REACHED; /* instruction reached */ + reg_ptr = idata[0].register_info.registers; + + if ((mb->fb.access & ACC_STATIC) == 0) { + /* A non static method. If this is an method, the first + * argument is an uninitialized object. Otherwise it is an object of + * the given class type. java.lang.Object. is special since + * we don't call its superclass method. + */ + if (strcmp(mb->fb.name, "") == 0 + && context->currentclass_info != context->object_info) { + *reg_ptr++ = MAKE_FULLINFO(ITEM_InitObject, 0, 0); + idata[0].or_flags |= FLAG_NEED_CONSTRUCTOR; + } else { + *reg_ptr++ = context->currentclass_info; + } + } + /* Fill in each of the arguments into the registers. */ + for (p = mb->fb.signature + 1; *p != SIGNATURE_ENDFUNC; ) { + char fieldchar = signature_to_fieldtype(context, &p, &full_info); + // if (no_floating_point && (fieldchar == 'D' || fieldchar == 'F')) { + // CCerror(context, "Floating point arguments not allowed"); + // } + switch (fieldchar) { + case 'D': case 'L': + *reg_ptr++ = full_info; + *reg_ptr++ = full_info + 1; + break; + default: + *reg_ptr++ = full_info; + break; + } + } + p++; /* skip over right parenthesis */ + if (*p == 'V') { + context->return_type = MAKE_FULLINFO(ITEM_Void, 0, 0); + } else { + signature_to_fieldtype(context, &p, &full_info); + context->return_type = full_info; + } + + /* Indicate that we need to look at the first instruction. */ + idata[0].changed = TRUE; +} + + +/*========================================================================= + * FUNCTION: run_dataflow + * OVERVIEW: Execute the data flow analysis as long as there are things + * to change. + * INTERFACE: + * parameters: pointer to the context_type + * returns: nothing + *=======================================================================*/ +static void +run_dataflow(context_type *context) { + struct methodblock *mb = context->mb; + int max_stack_size = mb->maxstack; + instruction_data_type *idata = context->instruction_data; + int icount = context->instruction_count; + bool_t work_to_do = TRUE; + int inumber; + + /* Run through the loop, until there is nothing left to do. */ + while (work_to_do) { + work_to_do = FALSE; + for (inumber = 0; inumber < icount; inumber++) { + instruction_data_type *this_idata = &idata[inumber]; + if (this_idata->changed) { + register_info_type new_register_info; + stack_info_type new_stack_info; + flag_type new_and_flags, new_or_flags; + + this_idata->changed = FALSE; + work_to_do = TRUE; + /* Make sure the registers and flags are appropriate */ + check_register_values(context, inumber); + check_flags(context, inumber); + + /* Make sure the stack can deal with this instruction */ + pop_stack(context, inumber, &new_stack_info); + + /* Update the registers and flags */ + update_registers(context, inumber, &new_register_info); + update_flags(context, inumber, &new_and_flags, &new_or_flags); + + /* Update the stack. */ + push_stack(context, inumber, &new_stack_info); + +// if (new_stack_info.stack_size > max_stack_size) +// CCerror(context, "Stack size too large"); + + /* Add the new stack and register information to any + * instructions that can follow this instruction. */ + merge_into_successors(context, inumber, + &new_register_info, &new_stack_info, + new_and_flags, new_or_flags); + } + } + } +} + + +/*========================================================================= + * FUNCTION: check_register_values + * OVERVIEW: Make sure that the registers contain a legitimate value + * for the given instruction. + * INTERFACE: + * parameters: pointer to the context_type + * int inumber + * returns: nothing + *=======================================================================*/ +static void +check_register_values(context_type *context, int inumber) +{ + instruction_data_type *idata = context->instruction_data; + instruction_data_type *this_idata = &idata[inumber]; + opcode_type opcode = this_idata->opcode; + int operand = this_idata->operand.i; + int register_count = this_idata->register_info.register_count; + fullinfo_type *registers = this_idata->register_info.registers; + bool_t double_word = FALSE; /* default value */ + int type; + + switch (opcode) { + default: + return; + case opc_iload: case opc_iinc: + type = ITEM_Integer; break; + case opc_fload: + type = ITEM_Float; break; + case opc_aload: + type = ITEM_Object; break; + case opc_ret: + type = ITEM_ReturnAddress; break; + case opc_lload: + type = ITEM_Long; double_word = TRUE; break; + case opc_dload: + type = ITEM_Double; double_word = TRUE; break; + } + if (!double_word) { + fullinfo_type reg = registers[operand]; + /* Make sure we don't have an illegal register or one with wrong type */ + if (operand >= register_count) { + CCerror(context, + "Accessing value from uninitialized register %d", operand); + } else if (WITH_ZERO_EXTRA_INFO(reg) == MAKE_FULLINFO(type, 0, 0)) { + /* the register is obviously of the given type */ + return; + } else if (GET_INDIRECTION(reg) > 0 && type == ITEM_Object) { + /* address type stuff be used on all arrays */ + return; + } else if (GET_ITEM_TYPE(reg) == ITEM_ReturnAddress) { +// CCerror(context, "Cannot load return address from register %d", +// operand); + /* alternatively + (GET_ITEM_TYPE(reg) == ITEM_ReturnAddress) + && (opcode == opc_iload) + && (type == ITEM_Object || type == ITEM_Integer) + but this never occurs + */ + } else if (reg == ITEM_InitObject && type == ITEM_Object) { + return; + } else if (WITH_ZERO_EXTRA_INFO(reg) == + MAKE_FULLINFO(ITEM_NewObject, 0, 0) && + type == ITEM_Object) { + return; + } else { +// CCerror(context, "Register %d contains wrong type", operand); + } + } else { + /* Make sure we don't have an illegal register or one with wrong type */ + if ((operand + 1) >= register_count) { +// CCerror(context, +// "Accessing value from uninitialized register pair %d/%d", +// operand, operand+1); + } else { + if ((registers[operand] == MAKE_FULLINFO(type, 0, 0)) && + (registers[operand + 1] == MAKE_FULLINFO(type + 1, 0, 0))) { + return; + } else { +// CCerror(context, "Register pair %d/%d contains wrong type", +// operand, operand+1); + } + } + } +} + + +/*========================================================================= + * FUNCTION: check_flags + * OVERVIEW: Make sure that the flags contain legitimate values for this + * instruction. + * INTERFACE: + * parameters: pointer to the context_type + * int: instruction number + * returns: nothing + *=======================================================================*/ +static void +check_flags(context_type *context, int inumber) +{ + instruction_data_type *idata = context->instruction_data; + instruction_data_type *this_idata = &idata[inumber]; + opcode_type opcode = this_idata->opcode; +} + + +/*========================================================================= + * FUNCTION: pop_stack + * OVERVIEW: Make sure that the top of the stack contains reasonable + * values for the given instruction. The post-pop values of + * the stack and its size are returned in *new_stack_info. + * INTERFACE: + * parameters: pointer to the context_type + * int: instruction number + * stack_info_type: *new_stack_info + * returns: nothing + *=======================================================================*/ +static void +pop_stack(context_type *context, int inumber, stack_info_type *new_stack_info) +{ + instruction_data_type *idata = context->instruction_data; + instruction_data_type *this_idata = &idata[inumber]; + opcode_type opcode = this_idata->opcode; + stack_item_type *stack = this_idata->stack_info.stack; + int stack_size = this_idata->stack_info.stack_size; + char *stack_operands, *p; + char buffer[257]; /* for holding manufactured argument lists */ + fullinfo_type stack_extra_info_buffer[256]; /* save info popped off stack */ + fullinfo_type *stack_extra_info = &stack_extra_info_buffer[256]; + fullinfo_type full_info, put_full_info; + + switch(opcode) { + default: + /* For most instructions, we just use a built-in table */ + stack_operands = opcode_in_out[opcode][0]; + break; + + case opc_putstatic: case opc_putfield: { + /* The top thing on the stack depends on the signature of + * the object. */ + int operand = this_idata->operand.i; + char *signature = cp_index_to_signature(context, operand); + char *ip = buffer; + + if (opcode == opc_putfield) + *ip++ = 'A'; /* object for putfield */ + *ip++ = signature_to_fieldtype(context, &signature, &put_full_info); + *ip = '\0'; + stack_operands = buffer; + break; + } + + case opc_invokevirtual: case opc_invokespecial: + case opc_invokeinit: /* invokespecial call to */ + case opc_invokestatic: case opc_invokeinterface: { + /* The top stuff on the stack depends on the method signature */ + int operand = this_idata->operand.i; + char *signature = cp_index_to_signature(context, operand); + char *ip = buffer; + char *p; + + if (opcode != opc_invokestatic) + /* First, push the object */ + *ip++ = (opcode == opc_invokeinit ? '@' : 'A'); + for (p = signature + 1; *p != SIGNATURE_ENDFUNC; ) { + *ip++ = signature_to_fieldtype(context, &p, &full_info); + // if (ip >= buffer + sizeof(buffer) - 1) + // CCerror(context, "Signature %s has too many arguments", + // signature); + } + *ip = 0; + stack_operands = buffer; + break; + } + + case opc_multianewarray: { + /* Count can't be larger than 255. So can't overflow buffer */ + int count = this_idata->operand2.i; /* number of ints on stack */ + memset(buffer, 'I', count); + buffer[count] = '\0'; + stack_operands = buffer; + break; + } + + } /* of switch */ + + /* Run through the list of operands >>backwards<< */ + for ( p = stack_operands + strlen(stack_operands); + p > stack_operands; + stack = stack->next) { + int type = *--p; + fullinfo_type top_type = stack ? stack->item : 0; + int size = (type == 'D' || type == 'L') ? 2 : 1; + *--stack_extra_info = top_type; +// if (stack == NULL) +// CCerror(context, "Unable to pop operand off an empty stack"); + switch (type) { + case 'I': + // if (top_type != MAKE_FULLINFO(ITEM_Integer, 0, 0)) + // CCerror(context, "Expecting to find integer on stack"); + break; + + case 'F': + // if (top_type != MAKE_FULLINFO(ITEM_Float, 0, 0)) + // CCerror(context, "Expecting to find float on stack"); + break; + + case 'A': /* object or array */ + if ( (GET_ITEM_TYPE(top_type) != ITEM_Object) + && (GET_INDIRECTION(top_type) == 0)) { + /* The thing isn't an object or an array. Let's see if it's + * one of the special cases */ + if ( (WITH_ZERO_EXTRA_INFO(top_type) == + MAKE_FULLINFO(ITEM_ReturnAddress, 0, 0)) + && (opcode == opc_astore)) + break; + if ( (GET_ITEM_TYPE(top_type) == ITEM_NewObject + || (GET_ITEM_TYPE(top_type) == ITEM_InitObject)) + && ((opcode == opc_astore) || (opcode == opc_aload))) + break; + + /* The 2nd edition VM of the specification allows field + * initializations before the superclass initializer, + * if the field is defined within the current class. + */ + if ( (GET_ITEM_TYPE(top_type) == ITEM_InitObject) + && (opcode == opc_putfield)) { + + int num_fields; + int key = this_idata->operand.i; + fullinfo_type clazz_info = cp_index_to_class_fullinfo( + context, key, TRUE); + char *name = cp_index_to_fieldname(context, key); + char *signature = cp_index_to_signature(context, key); + unsigned ID = NameAndTypeToHash(name, signature); + + ClassClass *calledClass = + object_fullinfo_to_classclass(context, clazz_info); + struct fieldblock *fb; + if (ID == 0) { + /* NameAndTypeToHash returns 0 + * if out of memory + */ + // CCerror(context, "Out of memory"); + break; + } + num_fields = cbFieldsCount(calledClass); + fb = cbFields(calledClass); + for (; --num_fields >= 0; fb++) { + if (fb->ID == ID) { + break; + } + } + + if (num_fields != -1) { + top_type = context->currentclass_info; + *stack_extra_info = top_type; + break; + } + } + // CCerror(context, "Expecting to find object/array on stack"); + } + break; + + case '@': { /* unitialized object, for call to */ + int item_type = GET_ITEM_TYPE(top_type); + // if (item_type != ITEM_NewObject && item_type != ITEM_InitObject) + // CCerror(context, + // "Expecting to find unitialized object on stack"); + break; + } + + case 'O': /* object, not array */ + // if (WITH_ZERO_EXTRA_INFO(top_type) != + // MAKE_FULLINFO(ITEM_Object, 0, 0)) + // CCerror(context, "Expecting to find object on stack"); + break; + + case 'a': /* integer, object, or array */ + // if ( (top_type != MAKE_FULLINFO(ITEM_Integer, 0, 0)) + // && (GET_ITEM_TYPE(top_type) != ITEM_Object) + // && (GET_INDIRECTION(top_type) == 0)) + // CCerror(context, + // "Expecting to find object, array, or int on stack"); + break; + + case 'D': /* double */ + // if (top_type != MAKE_FULLINFO(ITEM_Double, 0, 0)) + // CCerror(context, "Expecting to find double on stack"); + break; + + case 'L': /* long */ + // if (top_type != MAKE_FULLINFO(ITEM_Long, 0, 0)) + // CCerror(context, "Expecting to find long on stack"); + break; + + case ']': /* array of some type */ + if (top_type == NULL_FULLINFO) { + /* do nothing */ + } else switch(p[-1]) { + case 'I': /* array of integers */ + // if (top_type != MAKE_FULLINFO(ITEM_Integer, 1, 0) && + // top_type != NULL_FULLINFO) + // CCerror(context, + // "Expecting to find array of ints on stack"); + break; + + case 'L': /* array of longs */ + // if (top_type != MAKE_FULLINFO(ITEM_Long, 1, 0)) + // CCerror(context, + // "Expecting to find array of longs on stack"); + break; + + case 'F': /* array of floats */ + // if (top_type != MAKE_FULLINFO(ITEM_Float, 1, 0)) + // CCerror(context, + // "Expecting to find array of floats on stack"); + break; + + case 'D': /* array of doubles */ + // if (top_type != MAKE_FULLINFO(ITEM_Double, 1, 0)) + // CCerror(context, + // "Expecting to find array of doubles on stack"); + break; + + case 'A': { /* array of addresses (arrays or objects) */ + // int indirection = GET_INDIRECTION(top_type); + // if ((indirection == 0) || + // ((indirection == 1) && + // (GET_ITEM_TYPE(top_type) != ITEM_Object))) + // CCerror(context, + // "Expecting to find array of objects or arrays " + // "on stack"); + break; + } + + case 'b': /* array of bytes or boolean */ + // if (top_type != MAKE_FULLINFO(ITEM_Byte, 1, 0) && + // top_type != MAKE_FULLINFO(ITEM_Boolean, 1, 0)) + // CCerror(context, + // "Expecting to find array of bytes or booleans on stack"); + break; + + case 'B': /* array of bytes */ + // if (top_type != MAKE_FULLINFO(ITEM_Byte, 1, 0)) + // CCerror(context, + // "Expecting to find array of bytes on stack"); + break; + + case 'Z': /* array of boolean */ + // if (top_type != MAKE_FULLINFO(ITEM_Boolean, 1, 0)) + // CCerror(context, + // "Expecting to find array of bytes on stack"); + break; + + case 'C': /* array of characters */ + // if (top_type != MAKE_FULLINFO(ITEM_Char, 1, 0)) + // CCerror(context, + // "Expecting to find array of chars on stack"); + break; + + case 'S': /* array of shorts */ + // if (top_type != MAKE_FULLINFO(ITEM_Short, 1, 0)) + // CCerror(context, + // "Expecting to find array of shorts on stack"); + break; + + case '?': /* any type of array is okay */ + // if (GET_INDIRECTION(top_type) == 0) + // CCerror(context, + // "Expecting to find array on stack"); + break; + + default: + // CCerror(context, "Internal error #1"); + sysAssert(FALSE); + break; + } + p -= 2; /* skip over [ */ + break; + + case '1': case '2': case '3': case '4': /* stack swapping */ + if (top_type == MAKE_FULLINFO(ITEM_Double, 0, 0) + || top_type == MAKE_FULLINFO(ITEM_Long, 0, 0)) { + if ((p > stack_operands) && (p[-1] == '+')) { + context->swap_table[type - '1'] = top_type + 1; + context->swap_table[p[-2] - '1'] = top_type; + size = 2; + p -= 2; + } else { + // CCerror(context, + // "Attempt to split long or double on the stack"); + } + } else { + context->swap_table[type - '1'] = stack->item; + if ((p > stack_operands) && (p[-1] == '+')) + p--; /* ignore */ + } + break; + case '+': /* these should have been caught. */ + default: + // CCerror(context, "Internal error #2"); + sysAssert(FALSE); + } + stack_size -= size; + } + + /* For many of the opcodes that had an "A" in their field, we really + * need to go back and do a little bit more accurate testing. We can, of + * course, assume that the minimal type checking has already been done. + */ + switch (opcode) { + default: break; + case opc_aastore: { /* array index object */ + fullinfo_type array_type = stack_extra_info[0]; + fullinfo_type object_type = stack_extra_info[2]; + fullinfo_type target_type = decrement_indirection(array_type); + if (array_type == NULL_FULLINFO) { + break; + } + if ((WITH_ZERO_EXTRA_INFO(target_type) == + MAKE_FULLINFO(ITEM_Object, 0, 0)) && + (WITH_ZERO_EXTRA_INFO(object_type) == + MAKE_FULLINFO(ITEM_Object, 0, 0))) { + /* I disagree. But other's seem to think that we should allow + * an assignment of any Object to any array of any Object type. + * There will be an runtime error if the types are wrong. + */ + break; + } + // if (!isAssignableTo(context, object_type, target_type)) + // CCerror(context, "Incompatible types for storing into array of " + // "arrays or objects"); + break; + } + + case opc_putfield: + case opc_getfield: + case opc_putstatic: { + int operand = this_idata->operand.i; + fullinfo_type stack_object = stack_extra_info[0]; + if (opcode == opc_putfield || opcode == opc_getfield) { + if (!isAssignableTo(context, + stack_object, + cp_index_to_class_fullinfo(context, operand, + TRUE))) { + // CCerror(context, + // "Incompatible type for getting or setting field"); + } + /* FY: Why is this commented out?? */ + /* + if (this_idata->protected && + !isAssignableTo(context, stack_object, + context->currentclass_info)) { + CCerror(context, "Bad access to protected data"); + }*/ + } + if (opcode == opc_putfield || opcode == opc_putstatic) { + int item = (opcode == opc_putfield ? 1 : 0); + if (!isAssignableTo(context, + stack_extra_info[item], put_full_info)) { + // CCerror(context, "Bad type in putfield/putstatic"); + } + } + break; + } + + case opc_athrow: +// if (!isAssignableTo(context, stack_extra_info[0], +// context->throwable_info)) { +// CCerror(context, "Can only throw Throwable objects"); +// } + break; + + case opc_aaload: { /* array index */ + /* We need to pass the information to the stack updater */ + fullinfo_type array_type = stack_extra_info[0]; + context->swap_table[0] = decrement_indirection(array_type); + break; + } + + case opc_invokevirtual: case opc_invokespecial: + case opc_invokeinit: + case opc_invokeinterface: case opc_invokestatic: { + int operand = this_idata->operand.i; + char *signature = cp_index_to_signature(context, operand); + int item; + char *p; + if (opcode == opc_invokestatic) { + item = 0; + } else if (opcode == opc_invokeinit) { + fullinfo_type init_type = this_idata->operand2.fi; + fullinfo_type object_type = stack_extra_info[0]; + context->swap_table[0] = object_type; /* save value */ + if (GET_ITEM_TYPE(stack_extra_info[0]) == ITEM_NewObject) { + /* We better be calling the appropriate init. Find the + * inumber of the "opc_new" instruction", and figure + * out what the type really is. + */ + int new_inumber = GET_EXTRA_INFO(stack_extra_info[0]); + fullinfo_type target_type = idata[new_inumber].operand2.fi; + context->swap_table[1] = target_type; + // if (target_type != init_type) { + // CCerror(context, "Call to wrong initialization method"); + // } + } else { + /* We better be calling super() or this(). */ + if (init_type != context->superclass_info && + init_type != context->currentclass_info) { + // CCerror(context, "Call to wrong initialization method"); + } + context->swap_table[1] = context->currentclass_info; + } + item = 1; + } else { + fullinfo_type target_type = this_idata->operand2.fi; + fullinfo_type object_type = stack_extra_info[0]; + if (!isAssignableTo(context, object_type, target_type)){ + // CCerror(context, + // "Incompatible object argument for function call"); + } + /* The specification of the structural constraints for + * invokespecial needs to be more stringent. + * + * If invokespecial is used to invoke an instance method + * that is not an instance initialization method, then the + * type of the class instance, which is the target of method + * invocation, must be assignment compatible with the + * current class. + */ + if (opcode == opc_invokespecial + && !isAssignableTo(context, object_type, + context->currentclass_info)) { + /* Make sure object argument is assignment compatible + * to current class + */ + // CCerror(context, + // "Incompatible object argument for invokespecial"); + } + + if (this_idata->protected + && !isAssignableTo(context, object_type, + context->currentclass_info)) { + /* This is ugly. Special dispensation. Arrays pretend to + implement public Object clone() even though they don't */ + if ((target_type == context->object_info) && + (GET_INDIRECTION(object_type) > 0) && + (strcmp(cp_index_to_fieldname(context, this_idata->operand.i), + "clone") == 0)) { + } else { + // CCerror(context, "Bad access to protected data"); + } + } + item = 1; + } + for (p = signature + 1; *p != SIGNATURE_ENDFUNC; item++) + if (signature_to_fieldtype(context, &p, &full_info) == 'A') { + if (!isAssignableTo(context, + stack_extra_info[item], full_info)) { + // CCerror(context, "Incompatible argument to function"); + } + } + + break; + } + + case opc_return: +// if (context->return_type != MAKE_FULLINFO(ITEM_Void, 0, 0)) +// CCerror(context, "Wrong return type in function"); + break; + + case opc_ireturn: case opc_lreturn: case opc_freturn: + case opc_dreturn: case opc_areturn: { + fullinfo_type target_type = context->return_type; + fullinfo_type object_type = stack_extra_info[0]; + if (!isAssignableTo(context, object_type, target_type)) { +// CCerror(context, "Wrong return type in function"); + } + break; + } + + case opc_new: { + /* Make sure that nothing on the stack already looks like what + * we want to create. I can't image how this could possibly happen + * but we should test for it anyway, since if it could happen, the + * result would be an unitialized object being able to masquerade + * as an initialized one. + */ + stack_item_type *item; + for (item = stack; item != NULL; item = item->next) { + // if (item->item == this_idata->operand.fi) { + // CCerror(context, + // "Uninitialized object on stack at creating point"); + // } + } + /* Info for update_registers */ + context->swap_table[0] = this_idata->operand.fi; + context->swap_table[1] = MAKE_FULLINFO(ITEM_Bogus, 0, 0); + + break; + } + } + new_stack_info->stack = stack; + new_stack_info->stack_size = stack_size; +} + + +/*========================================================================= + * FUNCTION: update_registers + * OVERVIEW: Perform the operation on the registers, and return the + * updated results in new_register_count_p and new_registers. + * Note that the instruction has already been determined + * to be legal. + * INTERFACE: + * parameters: pointer to the context_type + * int: instruction number + * register_info_type: pointer to new register info + * + * returns: nothing + *=======================================================================*/ +static void +update_registers(context_type *context, int inumber, + register_info_type *new_register_info) +{ + instruction_data_type *idata = context->instruction_data; + instruction_data_type *this_idata = &idata[inumber]; + opcode_type opcode = this_idata->opcode; + int operand = this_idata->operand.i; + int register_count = this_idata->register_info.register_count; + fullinfo_type *registers = this_idata->register_info.registers; + stack_item_type *stack = this_idata->stack_info.stack; + int mask_count = this_idata->register_info.mask_count; + mask_type *masks = this_idata->register_info.masks; + + /* Use these as default new values. */ + int new_register_count = register_count; + int new_mask_count = mask_count; + fullinfo_type *new_registers = registers; + mask_type *new_masks = masks; + + enum { NONE, SINGLE, DOUBLE } access = NONE; + int i; + + /* Remember, we've already verified the type at the top of the stack. */ + switch (opcode) { + default: break; + case opc_istore: case opc_fstore: case opc_astore: + access = SINGLE; + goto continue_store; + + case opc_lstore: case opc_dstore: + access = DOUBLE; + goto continue_store; + + continue_store: { + /* We have a modification to the registers. Copy them if needed. */ + fullinfo_type stack_top_type = stack->item; + int max_operand = operand + ((access == DOUBLE) ? 1 : 0); + + if ( max_operand < register_count + && registers[operand] == stack_top_type + && ((access == SINGLE) || + (registers[operand + 1]== stack_top_type + 1))) + /* No changes have been made to the registers. */ + break; + new_register_count = MAX(max_operand + 1, register_count); + new_registers = NEW(fullinfo_type, new_register_count); + for (i = 0; i < register_count; i++) + new_registers[i] = registers[i]; + for (i = register_count; i < new_register_count; i++) + new_registers[i] = MAKE_FULLINFO(ITEM_Bogus, 0, 0); + new_registers[operand] = stack_top_type; + if (access == DOUBLE) + new_registers[operand + 1] = stack_top_type + 1; + break; + } + + case opc_iload: case opc_fload: case opc_aload: + case opc_iinc: case opc_ret: + access = SINGLE; + break; + + case opc_lload: case opc_dload: + access = DOUBLE; + break; + + case opc_jsr: case opc_jsr_w: + for (i = 0; i < new_mask_count; i++) + if (new_masks[i].entry == operand) + CCerror(context, "Recursive call to jsr entry"); + if (context->redoJsr + && this_idata->operand2.i == UNKNOWN_RET_INSTRUCTION) { + /* Do nothing */ + } else { + new_masks = add_to_masks(context, masks, mask_count, operand); + new_mask_count++; + } + break; + + case opc_invokeinit: + case opc_new: { + /* For invokeinit, an uninitialized object has been initialized. + * For new, all previous occurrences of an uninitialized object + * from the same instruction must be made bogus. + * We find all occurrences of swap_table[0] in the registers, and + * replace them with swap_table[1]; + */ + fullinfo_type from = context->swap_table[0]; + fullinfo_type to = context->swap_table[1]; + + int i; + for (i = 0; i < register_count; i++) { + if (new_registers[i] == from) { + /* Found a match */ + break; + } + } + if (i < register_count) { /* We broke out loop for match */ + /* We have to change registers, and possibly a mask */ + bool_t copied_mask = FALSE; + int k; + new_registers = NEW(fullinfo_type, register_count); + memcpy(new_registers, registers, + register_count * sizeof(registers[0])); + for ( ; i < register_count; i++) { + if (new_registers[i] == from) { + new_registers[i] = to; + for (k = 0; k < new_mask_count; k++) { + if (!IS_BIT_SET(new_masks[k].modifies, i)) { + if (!copied_mask) { + new_masks = copy_masks(context, new_masks, + mask_count); + copied_mask = TRUE; + } + SET_BIT(new_masks[k].modifies, i); + } + } + } + } + } + break; + } + } /* of switch */ + + if ((access != NONE) && (new_mask_count > 0)) { + int i, j; + for (i = 0; i < new_mask_count; i++) { + int *mask = new_masks[i].modifies; + if ((!IS_BIT_SET(mask, operand)) || + ((access == DOUBLE) && !IS_BIT_SET(mask, operand + 1))) { + new_masks = copy_masks(context, new_masks, mask_count); + for (j = i; j < new_mask_count; j++) { + SET_BIT(new_masks[j].modifies, operand); + if (access == DOUBLE) + SET_BIT(new_masks[j].modifies, operand + 1); + } + break; + } + } + } + + new_register_info->register_count = new_register_count; + new_register_info->registers = new_registers; + new_register_info->masks = new_masks; + new_register_info->mask_count = new_mask_count; +} + + +/*========================================================================= + * FUNCTION: update_flags + * OVERVIEW: Update the flags now that we have already determined + * the instruction to be legal and have already updated the + * registers. + * INTERFACE: + * parameters: pointer to the context_type + * int: instruction number + * flag_type: pointer to new_and_flags + * flag_type: pointer to new_or_flags + * + * returns: nothing + *=======================================================================*/ +static void +update_flags(context_type *context, int inumber, + flag_type *new_and_flags, flag_type *new_or_flags) + +{ + instruction_data_type *idata = context->instruction_data; + instruction_data_type *this_idata = &idata[inumber]; + flag_type and_flags = this_idata->and_flags; + flag_type or_flags = this_idata->or_flags; + + /* Set the "we've done a constructor" flag */ + if (this_idata->opcode == opc_invokeinit) { + fullinfo_type from = context->swap_table[0]; + if (from == MAKE_FULLINFO(ITEM_InitObject, 0, 0)) + and_flags |= FLAG_CONSTRUCTED; + } + *new_and_flags = and_flags; + *new_or_flags = or_flags; +} + + +/*========================================================================= + * FUNCTION: push_stack + * OVERVIEW: Perform the operation on the stack. + * Note that the instruction has already been determined + * to be legal. + * new_stack_size_p and new_stack_p point to the results after + * the pops have already been done. Do the pushes, and then + * put the results back there. + * INTERFACE: + * parameters: pointer to the context_type + * int: instruction number + * stack_info_type: pointer to new stack info + * + * returns: nothing + *=======================================================================*/ +static void +push_stack(context_type *context, int inumber, stack_info_type *new_stack_info) +{ + instruction_data_type *idata = context->instruction_data; + instruction_data_type *this_idata = &idata[inumber]; + opcode_type opcode = this_idata->opcode; + int operand = this_idata->operand.i; + + int stack_size = new_stack_info->stack_size; + stack_item_type *stack = new_stack_info->stack; + char *stack_results; + + fullinfo_type full_info = 0; + char buffer[5], *p; /* actually [2] is big enough */ + + /* We need to look at all those opcodes in which either we can't tell the + * value pushed onto the stack from the opcode, or in which the value + * pushed onto the stack is an object or array. For the latter, we need + * to make sure that full_info is set to the right value. + */ + switch(opcode) { + default: + stack_results = opcode_in_out[opcode][1]; + break; + + case opc_ldc: case opc_ldc_w: case opc_ldc2_w: { + /* Look to constant pool to determine correct result. */ + union cp_item_type *cp = cbConstantPool(context->class); + unsigned char *type_table = cp[CONSTANT_POOL_TYPE_TABLE_INDEX].type; + switch (CONSTANT_POOL_TYPE_TABLE_GET_TYPE(type_table, operand)) { + case CONSTANT_Integer: + stack_results = "I"; break; + case CONSTANT_Float: + stack_results = "F"; break; + case CONSTANT_Double: + stack_results = "D"; break; + case CONSTANT_Long: + stack_results = "L"; break; + case CONSTANT_String: + stack_results = "A"; + full_info = context->string_info; + break; + default: + // CCerror(context, "Internal error #3"); + sysAssert(FALSE); + } + break; + } + + case opc_getstatic: case opc_getfield: { + /* Look to signature to determine correct result. */ + int operand = this_idata->operand.i; + char *signature = cp_index_to_signature(context, operand); +#ifdef DEBUG_VERIFIER + if (verify_verbose) { + print_formatted_fieldname(context, operand); + } +#endif + buffer[0] = signature_to_fieldtype(context, &signature, &full_info); + buffer[1] = '\0'; + stack_results = buffer; + break; + } + + case opc_invokevirtual: case opc_invokespecial: + case opc_invokeinit: + case opc_invokestatic: case opc_invokeinterface: { + /* Look to signature to determine correct result. */ + int operand = this_idata->operand.i; + char *signature = cp_index_to_signature(context, operand); + char *result_signature = strchr(signature, SIGNATURE_ENDFUNC) + 1; + if (result_signature[0] == SIGNATURE_VOID) { + stack_results = ""; + } else { + buffer[0] = signature_to_fieldtype(context, &result_signature, + &full_info); + buffer[1] = '\0'; + stack_results = buffer; + } + break; + } + + case opc_aconst_null: + stack_results = opcode_in_out[opcode][1]; + full_info = NULL_FULLINFO; /* special NULL */ + break; + + case opc_new: + case opc_checkcast: + case opc_newarray: + case opc_anewarray: + case opc_multianewarray: + stack_results = opcode_in_out[opcode][1]; + /* Conventionally, this result type is stored here */ + full_info = this_idata->operand.fi; + if (no_floating_point && (opcode == opc_newarray) + && (full_info == MAKE_FULLINFO(ITEM_Float, 1, 0) || + full_info == MAKE_FULLINFO(ITEM_Double, 1, 0))) { + // CCerror(context, "Cannot create floating point array"); + } + break; + + case opc_aaload: + stack_results = opcode_in_out[opcode][1]; + /* pop_stack() saved value for us. */ + full_info = context->swap_table[0]; + break; + + case opc_aload: + stack_results = opcode_in_out[opcode][1]; + /* The register hasn't been modified, so we can use its value. */ + full_info = this_idata->register_info.registers[operand]; + break; + } /* of switch */ + + for (p = stack_results; *p != 0; p++) { + int type = *p; + stack_item_type *new_item = NEW(stack_item_type, 1); + new_item->next = stack; + stack = new_item; + switch (type) { + case 'I': + stack->item = MAKE_FULLINFO(ITEM_Integer, 0, 0); break; + case 'F': + // if (no_floating_point) { + // CCerror(context, "Floating point result not allowed"); + // } + stack->item = MAKE_FULLINFO(ITEM_Float, 0, 0); + break; + case 'D': + // if (no_floating_point) { + // CCerror(context, "Floating point result not allowed"); + // } + stack->item = MAKE_FULLINFO(ITEM_Double, 0, 0); + stack_size++; + break; + case 'L': + stack->item = MAKE_FULLINFO(ITEM_Long, 0, 0); + stack_size++; break; + case 'R': + stack->item = MAKE_FULLINFO(ITEM_ReturnAddress, 0, operand); + break; + case '1': case '2': case '3': case '4': { + /* Get the info saved in the swap_table */ + fullinfo_type stype = context->swap_table[type - '1']; + stack->item = stype; + if (stype == MAKE_FULLINFO(ITEM_Long, 0, 0) || + stype == MAKE_FULLINFO(ITEM_Double, 0, 0)) { + stack_size++; p++; + } + break; + } + case 'A': + /* full_info should have the appropriate value. */ + sysAssert(full_info != 0); + stack->item = full_info; + break; + default: + // CCerror(context, "Internal error #4"); + sysAssert(FALSE); + + } /* switch type */ + stack_size++; + } /* outer for loop */ + + if (opcode == opc_invokeinit) { + /* If there are any instances of "from" on the stack, we need to + * replace it with "to", since calling initializes all versions + * of the object, obviously. */ + fullinfo_type from = context->swap_table[0]; + stack_item_type *ptr; + for (ptr = stack; ptr != NULL; ptr = ptr->next) { + if (ptr->item == from) { + fullinfo_type to = context->swap_table[1]; + stack = copy_stack(context, stack); + for (ptr = stack; ptr != NULL; ptr = ptr->next) + if (ptr->item == from) ptr->item = to; + break; + } + } + } + + new_stack_info->stack_size = stack_size; + new_stack_info->stack = stack; +} + + +/*========================================================================= + * FUNCTION: merge_into_successors + * OVERVIEW: Executed an instruction, and have determined the new + * registers and stack values. Look at all of the possibly + * subsequent instructions, and merge this stack value into + * theirs. + * INTERFACE: + * parameters: pointer to the context_type + * int: instruction number + * stack_info_type: pointer to stack_info + * flag_type: and_flags + * flag_type: or_flags + * + * returns: nothing + *=======================================================================*/ +static void +merge_into_successors(context_type *context, int inumber, + register_info_type *register_info, + stack_info_type *stack_info, + flag_type and_flags, flag_type or_flags) +{ + instruction_data_type *idata = context->instruction_data; + instruction_data_type *this_idata = &idata[inumber]; + opcode_type opcode = this_idata->opcode; + int operand = this_idata->operand.i; + struct handler_info_type *handler_info = context->handler_info; + int handler_info_length = context->mb->exception_table_length; + + + int buffer[2]; /* default value for successors */ + int *successors = buffer; /* table of successors */ + int successors_count; + int i; + + switch (opcode) { + default: + successors_count = 1; + buffer[0] = inumber + 1; + break; + + case opc_ifeq: case opc_ifne: case opc_ifgt: + case opc_ifge: case opc_iflt: case opc_ifle: + case opc_ifnull: case opc_ifnonnull: + case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpgt: + case opc_if_icmpge: case opc_if_icmplt: case opc_if_icmple: + case opc_if_acmpeq: case opc_if_acmpne: + successors_count = 2; + buffer[0] = inumber + 1; + buffer[1] = operand; + idata[operand].is_target = TRUE; /* inlinejsr */ + break; + + case opc_jsr: case opc_jsr_w: + if (this_idata->operand2.i != UNKNOWN_RET_INSTRUCTION) + idata[this_idata->operand2.i].changed = TRUE; + /* FALLTHROUGH */ + case opc_goto: case opc_goto_w: + successors_count = 1; + buffer[0] = operand; + idata[operand].is_target = TRUE; /* inlinejsr */ + break; + + + case opc_ireturn: case opc_lreturn: case opc_return: + case opc_freturn: case opc_dreturn: case opc_areturn: + case opc_athrow: + /* The testing for the returns is handled in pop_stack() */ + successors_count = 0; + break; + + case opc_ret: { + /* This is slightly slow, but good enough for a seldom used instruction. + * The EXTRA_ITEM_INFO of the ITEM_ReturnAddress indicates the + * address of the first instruction of the subroutine. We can return + * to 1 after any instruction that jsr's to that instruction. + */ + if (this_idata->operand2.ip == NULL) { + fullinfo_type *registers = this_idata->register_info.registers; + int called_instruction = GET_EXTRA_INFO(registers[operand]); + int i, count, *ptr;; + for (i = context->instruction_count, count = 0; --i >= 0; ) { + if (((idata[i].opcode == opc_jsr) || + (idata[i].opcode == opc_jsr_w)) && + (idata[i].operand.i == called_instruction)) + count++; + } + this_idata->operand2.ip = ptr = NEW(int, count + 1); + *ptr++ = count; + for (i = context->instruction_count, count = 0; --i >= 0; ) { + if (((idata[i].opcode == opc_jsr) || + (idata[i].opcode == opc_jsr_w)) && + (idata[i].operand.i == called_instruction)) { + *ptr++ = i + 1; + idata[i + 1].is_target = TRUE; /* inlinejsr */ + } + } + } + successors = this_idata->operand2.ip; /* use this instead */ + successors_count = *successors++; + break; + + } + + case opc_tableswitch: + case opc_lookupswitch: { + int i; + successors = this_idata->operand.ip; /* use this instead */ + successors_count = *successors++; + for (i = 0; i < successors_count; i++) { + idata[successors[i]].is_target = TRUE; /* inlinejsr */ + } + break; + } + + } + + + + handler_info = context->handler_info; + for (i = handler_info_length; --i >= 0; handler_info++) { + if (handler_info->start <= inumber && handler_info->end > inumber) { + int handler = handler_info->handler; + idata[handler].is_target = TRUE; /* inlinejsr */ + if (opcode != opc_invokeinit) { + merge_into_one_successor(context, inumber, handler, + &this_idata->register_info, /* old */ + &handler_info->stack_info, + (flag_type) (and_flags + & this_idata->and_flags), + (flag_type) (or_flags + | this_idata->or_flags), + TRUE); + } else { + /* We need to be a little bit more careful with this + * instruction. Things could either be in the state before + * the instruction or in the state afterwards */ + fullinfo_type from = context->swap_table[0]; + flag_type temp_or_flags = or_flags; + if (from == MAKE_FULLINFO(ITEM_InitObject, 0, 0)) + temp_or_flags |= FLAG_NO_RETURN; + merge_into_one_successor(context, inumber, handler, + &this_idata->register_info, /* old */ + &handler_info->stack_info, + this_idata->and_flags, + this_idata->or_flags, + TRUE); + merge_into_one_successor(context, inumber, handler, + register_info, + &handler_info->stack_info, + and_flags, temp_or_flags, TRUE); + } + } + } + for (i = 0; i < successors_count; i++) { + int target = successors[i]; +// if (target >= context->instruction_count) +/// CCerror(context, "Falling off the end of the code"); + merge_into_one_successor(context, inumber, target, + register_info, stack_info, and_flags, or_flags, + FALSE); + } +} + + +/*========================================================================= + * FUNCTION: merge_into_one_successor + * OVERVIEW: Executed an instruction, and have determined a new + * set of registers and stack values for a given instruction. + * Merge this new set into the values that are already there. + * INTERFACE: + * parameters: pointer to the context_type + * int: instruction number + * stack_info_type: pointer to stack_info + * flag_type: new_and_flags + * flag_type: new_or_flags + * boolean type: isException + * + * returns: nothing + *=======================================================================*/ +static void +merge_into_one_successor(context_type *context, + int from_inumber, int to_inumber, + register_info_type *new_register_info, + stack_info_type *new_stack_info, + flag_type new_and_flags, flag_type new_or_flags, + bool_t isException) +{ + instruction_data_type *idata = context->instruction_data; + register_info_type register_info_buf; + stack_info_type stack_info_buf; + instruction_data_type *this_idata = &idata[to_inumber]; + + + /* All uninitialized objects are set to "bogus" when jsr and + * ret are executed. Thus uninitialized objects can't propagate + * into or out of a subroutine. + */ + if (idata[from_inumber].opcode == opc_ret || + idata[from_inumber].opcode == opc_jsr || + idata[from_inumber].opcode == opc_jsr_w) { + int new_register_count = new_register_info->register_count; + fullinfo_type *new_registers = new_register_info->registers; + int i; + stack_item_type *item; + + for (item = new_stack_info->stack; item != NULL; item = item->next) { + if (GET_ITEM_TYPE(item->item) == ITEM_NewObject) { + /* This check only succeeds for hand-contrived code. + * Efficiency is not an issue. + */ + stack_info_buf.stack = copy_stack(context, + new_stack_info->stack); + stack_info_buf.stack_size = new_stack_info->stack_size; + new_stack_info = &stack_info_buf; + for (item = new_stack_info->stack; item != NULL; + item = item->next) { + if (GET_ITEM_TYPE(item->item) == ITEM_NewObject) { + item->item = MAKE_FULLINFO(ITEM_Bogus, 0, 0); + } + } + break; + } + } + for (i = 0; i < new_register_count; i++) { + if (GET_ITEM_TYPE(new_registers[i]) == ITEM_NewObject) { + /* This check only succeeds for hand-contrived code. + * Efficiency is not an issue. + */ + fullinfo_type *new_set = NEW(fullinfo_type, + new_register_count); + for (i = 0; i < new_register_count; i++) { + fullinfo_type t = new_registers[i]; + new_set[i] = GET_ITEM_TYPE(t) != ITEM_NewObject ? + t : MAKE_FULLINFO(ITEM_Bogus, 0, 0); + } + register_info_buf.register_count = new_register_count; + register_info_buf.registers = new_set; + register_info_buf.mask_count = new_register_info->mask_count; + register_info_buf.masks = new_register_info->masks; + new_register_info = ®ister_info_buf; + break; + } + } + } + + /* Returning from a subroutine is somewhat ugly. The actual thing + * that needs to get merged into the new instruction is a joining + * of info from the ret instruction with stuff in the jsr instruction + */ + if (idata[from_inumber].opcode == opc_ret && !isException) { + int new_register_count = new_register_info->register_count; + fullinfo_type *new_registers = new_register_info->registers; + int new_mask_count = new_register_info->mask_count; + mask_type *new_masks = new_register_info->masks; + int operand = idata[from_inumber].operand.i; + int called_instruction = GET_EXTRA_INFO(new_registers[operand]); + instruction_data_type *jsr_idata = &idata[to_inumber - 1]; + register_info_type *jsr_reginfo = &jsr_idata->register_info; + if (jsr_idata->operand2.i != from_inumber) { + // if (jsr_idata->operand2.i != UNKNOWN_RET_INSTRUCTION) + // CCerror(context, "Multiple returns to single jsr"); + jsr_idata->operand2.i = from_inumber; + } + if (jsr_reginfo->register_count == UNKNOWN_REGISTER_COUNT) { + /* We don't want to handle the returned-to instruction until + * we've dealt with the jsr instruction. When we get to the + * jsr instruction (if ever), we'll re-mark the ret instruction + */ + ; + } else { + int register_count = jsr_reginfo->register_count; + fullinfo_type *registers = jsr_reginfo->registers; + int max_registers = MAX(register_count, new_register_count); + fullinfo_type *new_set = NEW(fullinfo_type, max_registers); + int *return_mask; + struct register_info_type new_new_register_info; + int i; + /* Make sure the place we're returning from is legal! */ + for (i = new_mask_count; --i >= 0; ) + if (new_masks[i].entry == called_instruction) + break; + // if (i < 0) + // CCerror(context, "Illegal return from subroutine"); + /* pop the masks down to the indicated one. Remember the mask + * we're popping off. */ + return_mask = new_masks[i].modifies; + new_mask_count = i; + for (i = 0; i < max_registers; i++) { + if (IS_BIT_SET(return_mask, i)) + new_set[i] = i < new_register_count ? + new_registers[i] : MAKE_FULLINFO(ITEM_Bogus, 0, 0); + else + new_set[i] = i < register_count ? + registers[i] : MAKE_FULLINFO(ITEM_Bogus, 0, 0); + } + new_new_register_info.register_count = max_registers; + new_new_register_info.registers = new_set; + new_new_register_info.mask_count = new_mask_count; + new_new_register_info.masks = new_masks; + + merge_stack(context, to_inumber - 1, to_inumber, new_stack_info); + merge_registers(context, to_inumber - 1, to_inumber, + &new_new_register_info); + /* ADDED FOR JSR_INFO. Is this correct?? */ + merge_flags(context, from_inumber, to_inumber, + new_and_flags, new_or_flags); + } + } else { + merge_stack(context, from_inumber, to_inumber, new_stack_info); + merge_registers(context, from_inumber, to_inumber, new_register_info); + merge_flags(context, from_inumber, to_inumber, + new_and_flags, new_or_flags); + } + + +} + + +/*========================================================================= + * FUNCTION: merge_stack + * OVERVIEW: Used by merge_into_one_successor() for merging stack values + * from a given instruction to another specified instruction. + * INTERFACE: + * parameters: pointer to the context_type + * int: from instruction number + * int: to instruction number + * stack_info_type: pointer to new_stack_info + * + * returns: nothing + *=======================================================================*/ +static void +merge_stack(context_type *context, int from_inumber, int to_inumber, + stack_info_type *new_stack_info) +{ + instruction_data_type *idata = context->instruction_data; + instruction_data_type *this_idata = &idata[to_inumber]; + + int new_stack_size = new_stack_info->stack_size; + stack_item_type *new_stack = new_stack_info->stack; + + int stack_size = this_idata->stack_info.stack_size; + + if (stack_size == UNKNOWN_STACK_SIZE) { + /* First time at this instruction. Just copy. */ + this_idata->stack_info.stack_size = new_stack_size; + this_idata->stack_info.stack = new_stack; + this_idata->changed = TRUE; + } else if (new_stack_size != stack_size) { +// CCerror(context, "Inconsistent stack height %d != %d", +// new_stack_size, stack_size); + } else { + stack_item_type *stack = this_idata->stack_info.stack; + stack_item_type *old, *new; + bool_t change = FALSE; + for (old = stack, new = new_stack; old != NULL; + old = old->next, new = new->next) { + if (!isAssignableTo(context, new->item, old->item)) { + change = TRUE; + break; + } + } + if (change) { + stack = copy_stack(context, stack); + for (old = stack, new = new_stack; old != NULL; + old = old->next, new = new->next) { + if (new == NULL) { + break; + } + old->item = merge_fullinfo_types(context, old->item, new->item, + FALSE); + if (GET_ITEM_TYPE(old->item) == ITEM_Bogus) { + // CCerror(context, "Mismatched stack types"); + } + } + if (old != NULL || new != NULL) { + // CCerror(context, "Mismatched stack types"); + } + this_idata->stack_info.stack = stack; + this_idata->changed = TRUE; + } + } +} + + +/*========================================================================= + * FUNCTION: merge_registers + * OVERVIEW: Used by merge_into_one_successor() for merging registers + * from a given instruction to another specified instruction. + * INTERFACE: + * parameters: pointer to the context_type + * int: from instruction number + * int: to instruction number + * stack_info_type: pointer to new_stack_info + * + * returns: nothing + *=======================================================================*/ +static void +merge_registers(context_type *context, int from_inumber, int to_inumber, + register_info_type *new_register_info) +{ + instruction_data_type *idata = context->instruction_data; + instruction_data_type *this_idata = &idata[to_inumber]; + register_info_type *this_reginfo = &this_idata->register_info; + + int new_register_count = new_register_info->register_count; + fullinfo_type *new_registers = new_register_info->registers; + int new_mask_count = new_register_info->mask_count; + mask_type *new_masks = new_register_info->masks; + + + if (this_reginfo->register_count == UNKNOWN_REGISTER_COUNT) { + this_reginfo->register_count = new_register_count; + this_reginfo->registers = new_registers; + this_reginfo->mask_count = new_mask_count; + this_reginfo->masks = new_masks; + this_idata->changed = TRUE; + } else { + /* See if we've got new information on the register set. */ + int register_count = this_reginfo->register_count; + fullinfo_type *registers = this_reginfo->registers; + int mask_count = this_reginfo->mask_count; + mask_type *masks = this_reginfo->masks; + + bool_t copy = FALSE; + int i, j; + if (register_count > new_register_count) { + /* Any register larger than new_register_count is now bogus */ + this_reginfo->register_count = new_register_count; + register_count = new_register_count; + this_idata->changed = TRUE; + } + for (i = 0; i < register_count; i++) { + fullinfo_type prev_value = registers[i]; + if ((i < new_register_count) + ? (!isAssignableTo(context, new_registers[i], prev_value)) + : (prev_value != MAKE_FULLINFO(ITEM_Bogus, 0, 0))) { + copy = TRUE; + break; + } + } + + if (copy) { + /* We need a copy. So do it. */ + fullinfo_type *new_set = NEW(fullinfo_type, register_count); + for (j = 0; j < i; j++) + new_set[j] = registers[j]; + for (j = i; j < register_count; j++) { + if (i >= new_register_count) + new_set[j] = MAKE_FULLINFO(ITEM_Bogus, 0, 0); + else + new_set[j] = merge_fullinfo_types(context, + new_registers[j], + registers[j], FALSE); + } + /* Some of the end items might now be bogus. This step isn't + * necessary, but it may save work later. */ + while ( register_count > 0 + && GET_ITEM_TYPE(new_set[register_count-1]) == ITEM_Bogus) + register_count--; + this_reginfo->register_count = register_count; + this_reginfo->registers = new_set; + this_idata->changed = TRUE; + } + if (mask_count > 0) { + /* If the target instruction already has a sequence of masks, then + * we need to merge new_masks into it. We want the entries on + * the mask to be the longest common substring of the two. + * (e.g. a->b->d merged with a->c->d should give a->d) + * The bits set in the mask should be the or of the corresponding + * entries in each of the original masks. + */ + int i, j, k; + int matches = 0; + int last_match = -1; + bool_t copy_needed = FALSE; + for (i = 0; i < mask_count; i++) { + int entry = masks[i].entry; + for (j = last_match + 1; j < new_mask_count; j++) { + if (new_masks[j].entry == entry) { + /* We have a match */ + int *prev = masks[i].modifies; + int *new = new_masks[j].modifies; + matches++; + /* See if new_mask has bits set for "entry" that + * weren't set for mask. If so, need to copy. */ + for (k = context->bitmask_size - 1; + !copy_needed && k >= 0; + k--) + if (~prev[k] & new[k]) + copy_needed = TRUE; + last_match = j; + break; + } + } + } + if ((matches < mask_count) || copy_needed) { + /* We need to make a copy for the new item, since either the + * size has decreased, or new bits are set. */ + mask_type *copy = NEW(mask_type, matches); + for (i = 0; i < matches; i++) { + copy[i].modifies = NEW(int, context->bitmask_size); + } + this_reginfo->masks = copy; + this_reginfo->mask_count = matches; + this_idata->changed = TRUE; + matches = 0; + last_match = -1; + for (i = 0; i < mask_count; i++) { + int entry = masks[i].entry; + for (j = last_match + 1; j < new_mask_count; j++) { + if (new_masks[j].entry == entry) { + int *prev1 = masks[i].modifies; + int *prev2 = new_masks[j].modifies; + int *new = copy[matches].modifies; + copy[matches].entry = entry; + for (k = context->bitmask_size - 1; k >= 0; k--) + new[k] = prev1[k] | prev2[k]; + matches++; + last_match = j; + break; + } + } + } + } + } + } +} + + +/*========================================================================= + * FUNCTION: merge_flags + * OVERVIEW: Used by merge_into_one_successor() for merging flags + * from a given instruction to a specified instruction. + * INTERFACE: + * parameters: pointer to the context_type + * int: from instruction number + * int: to instruction number + * flag_type: new_and_flags + * flag_type: new_or_flags + * + * returns: nothing + *=======================================================================*/ +static void +merge_flags(context_type *context, int from_inumber, int to_inumber, + flag_type new_and_flags, flag_type new_or_flags) +{ + /* Set this_idata->and_flags &= new_and_flags + this_idata->or_flags |= new_or_flags + */ + instruction_data_type *idata = context->instruction_data; + instruction_data_type *this_idata = &idata[to_inumber]; + flag_type this_and_flags = this_idata->and_flags; + flag_type this_or_flags = this_idata->or_flags; + flag_type merged_and = this_and_flags & new_and_flags; + flag_type merged_or = this_or_flags | new_or_flags; + + if ((merged_and != this_and_flags) || (merged_or != this_or_flags)) { + this_idata->and_flags = merged_and; + this_idata->or_flags = merged_or; + this_idata->changed = TRUE; + } +} + + +/*========================================================================= + * FUNCTION: copy_stack + * OVERVIEW: Make a copy of a stack. + * INTERFACE: + * parameters: pointer to the context_type + * stack_item_type: pointer to stack + * + * returns: pointer to stack_item_type + *=======================================================================*/ +static stack_item_type * +copy_stack(context_type *context, stack_item_type *stack) +{ + int length; + stack_item_type *ptr; + + /* Find the length */ + for (ptr = stack, length = 0; ptr != NULL; ptr = ptr->next, length++); + + if (length > 0) { + stack_item_type *new_stack = NEW(stack_item_type, length); + stack_item_type *new_ptr; + for ( ptr = stack, new_ptr = new_stack; + ptr != NULL; + ptr = ptr->next, new_ptr++) { + new_ptr->item = ptr->item; + new_ptr->next = new_ptr + 1; + } + new_stack[length - 1].next = NULL; + return new_stack; + } else { + return NULL; + } +} + + +/*========================================================================= + * FUNCTION: copy_masks + * OVERVIEW: Make a copy of the masks. + * INTERFACE: + * parameters: pointer to the context_type + * mask_type: pointer to masks + * int: mask count + * + * returns: pointer to mask_type + *=======================================================================*/ +static mask_type * +copy_masks(context_type *context, mask_type *masks, int mask_count) +{ + mask_type *result = NEW(mask_type, mask_count); + int bitmask_size = context->bitmask_size; + int *bitmaps = NEW(int, mask_count * bitmask_size); + int i; + for (i = 0; i < mask_count; i++) { + result[i].entry = masks[i].entry; + result[i].modifies = &bitmaps[i * bitmask_size]; + memcpy(result[i].modifies, masks[i].modifies, bitmask_size * sizeof(int)); + } + return result; +} + + +/*========================================================================= + * FUNCTION: add_to_masks + * OVERVIEW: Used by Update_registers for adding entries to masks for + * JSR instructions. + * INTERFACE: + * parameters: pointer to the context_type + * mask_type: pointer to masks + * int: mask count + * int: d + * + * returns: pointer to mask_type + *=======================================================================*/ +static mask_type * +add_to_masks(context_type *context, mask_type *masks, int mask_count, int d) +{ + mask_type *result = NEW(mask_type, mask_count + 1); + int bitmask_size = context->bitmask_size; + int *bitmaps = NEW(int, (mask_count + 1) * bitmask_size); + int i; + for (i = 0; i < mask_count; i++) { + result[i].entry = masks[i].entry; + result[i].modifies = &bitmaps[i * bitmask_size]; + memcpy(result[i].modifies, masks[i].modifies, bitmask_size * sizeof(int)); + } + result[mask_count].entry = d; + result[mask_count].modifies = &bitmaps[mask_count * bitmask_size]; + memset(result[mask_count].modifies, 0, bitmask_size * sizeof(int)); + return result; +} + + +/*========================================================================= + * Storage Management Operations + *=======================================================================*/ + +/* We create our own storage manager, since we malloc lots of little items, + * and we do not want to keep track of them when they become free. + * It would have been nice if we had heaps, which could all be freed when + * done. + */ + +#define CCSegSize 2000 + +struct CCpool { /* a segment of allocated memory in the pool */ + struct CCpool *next; + int segSize; /* almost always CCSegSize */ + char space[CCSegSize]; +}; + + +/*========================================================================= + * FUNCTION: CCinit + * OVERVIEW: Initialize the context's heap. + * INTERFACE: + * parameters: pointer to the context_type + * + * returns: nothing + *=======================================================================*/ +static void CCinit(context_type *context) +{ + struct CCpool *new = (struct CCpool *) sysMalloc(sizeof(struct CCpool)); + /* Set context->CCroot to 0 if new == 0 to tell CCdestroy to lay off */ + context->CCroot = context->CCcurrent = new; + if (new == 0) { + CCerror(context, "Out of memory"); + } + new->next = NULL; + new->segSize = CCSegSize; + context->CCfree_size = CCSegSize; + context->CCfree_ptr = &new->space[0]; +} + + +/*========================================================================= + * FUNCTION: CCreinit + * OVERVIEW: Reuse all the space that we have in the context's heap. + * INTERFACE: + * parameters: pointer to the context_type + * + * returns: nothing + *=======================================================================*/ +static void CCreinit(context_type *context) +{ + struct CCpool *first = context->CCroot; + context->CCcurrent = first; + context->CCfree_size = CCSegSize; + context->CCfree_ptr = &first->space[0]; +} + + +/*========================================================================= + * FUNCTION: CCdestroy + * OVERVIEW: Destroy the context's heap. + * INTERFACE: + * parameters: pointer to the context_type + * + * returns: nothing + *=======================================================================*/ +static void CCdestroy(context_type *context) +{ + struct CCpool *this = context->CCroot; + while (this) { + struct CCpool *next = this->next; + sysFree(this); + this = next; + } + /* These two aren't necessary. But can't hurt either */ + context->CCroot = context->CCcurrent = NULL; + context->CCfree_ptr = 0; +} + + +/*========================================================================= + * FUNCTION: CCalloc + * OVERVIEW: Allocate an object of the given size from the context's heap. + * INTERFACE: + * parameters: pointer to the context_type + * int: size + * bool_t: zero + * + * returns: pointer to void + *=======================================================================*/ +static void * +CCalloc(context_type *context, int size, bool_t zero) +{ + + register char *p; + /* Round CC to the size of a pointer */ + size = (size + (sizeof(void *) - 1)) & ~(sizeof(void *) - 1); + + if (context->CCfree_size < size) { + struct CCpool *current = context->CCcurrent; + struct CCpool *new; + if (size > CCSegSize) { /* we need to allocate a special block */ + new = (struct CCpool *)sysMalloc(sizeof(struct CCpool) + + (size - CCSegSize)); + if (new == 0) { + CCerror(context, "Out of memory"); + } + new->next = current->next; + new->segSize = size; + current->next = new; + } else { + new = current->next; + if (new == NULL) { + new = (struct CCpool *) sysMalloc(sizeof(struct CCpool)); + if (new == 0) { + CCerror(context, "Out of memory"); + } + current->next = new; + new->next = NULL; + new->segSize = CCSegSize; + } + } + context->CCcurrent = new; + context->CCfree_ptr = &new->space[0]; + context->CCfree_size = new->segSize; + } + p = context->CCfree_ptr; + context->CCfree_ptr += size; + context->CCfree_size -= size; + if (zero) + memset(p, 0, size); + return p; +} + + +/*========================================================================= + * FUNCTION: cp_index_to_signature + * OVERVIEW: Get the signature associated with a particular field or + * method in the constant pool. + * INTERFACE: + * parameters: pointer to the context_type + * int: constant pool index + * + * returns: char * type + *=======================================================================*/ +static char * +cp_index_to_signature(context_type *context, int cp_index) +{ + union cp_item_type *cp = cbConstantPool(context->class); + int index = cp[cp_index].i; /* value of Fieldref field */ + int key2 = index & 0xFFFF; /* index to NameAndType */ + int signature_index = cp[key2].i & 0xFFFF; + char *signature = cp[signature_index].cp; + return signature; +} + + +/*========================================================================= + * FUNCTION: cp_index_to_fieldname + * OVERVIEW: Get the fieldname for the specific index within the + * constant pool. + * INTERFACE: + * parameters: pointer to the context_type + * int: constant pool index + * + * returns: char * type + *=======================================================================*/ +static char * +cp_index_to_fieldname(context_type *context, int cp_index) +{ + union cp_item_type *cp = cbConstantPool(context->class); + int index = cp[cp_index].i; /* value of Fieldref field */ + int key2 = index & 0xFFFF; /* index to NameAndType */ + int name_index = cp[key2].i >> 16; + return cp[name_index].cp; +} + + +/*========================================================================= + * FUNCTION: cp_index_to_class_fullinfo + * OVERVIEW: Get the class associated with a particular field or + * method or class in the constant pool. If is_field is true, + * then it is a field or method. Otherwise, if false, it is a + * class. + * INTERFACE: + * parameters: pointer to the context_type + * int: constant pool index + * bool_t: is_field + * + * returns: fullinfo_type + *=======================================================================*/ +static fullinfo_type +cp_index_to_class_fullinfo(context_type *context, int cp_index, bool_t is_field) +{ + union cp_item_type *cp = cbConstantPool(context->class); + unsigned classkey = is_field ? (cp[cp_index].i >> 16) : cp_index; + char *classname = GetClassConstantClassName(cp, classkey); + if (classname[0] == SIGNATURE_ARRAY) { + fullinfo_type result; + /* This make recursively call us, in case of a class array */ + signature_to_fieldtype(context, &classname, &result); + return result; + } else { + return MAKE_CLASSNAME_INFO_WITH_COPY(context, classname, 0); + } +} + + +/*========================================================================= + * FUNCTION: CCerror + * OVERVIEW: Error handling + * INTERFACE: + * parameters: pointer to the context_type + * char: pointer to format + * + * returns: nothing + *=======================================================================*/ +static void +CCerror (context_type *context, char *format, ...) +{ +/* va_list args; + struct methodblock *mb = context->mb; + printCurrentClassName(); + if (mb != 0) { + jio_fprintf(stderr, "VERIFIER ERROR %s.%s%s:\n", + cbName(fieldclass(&mb->fb)), mb->fb.name, mb->fb.signature); + } else { + jio_fprintf(stderr, "VERIFIER ERROR class %s (mb uninitialized):\n", + cbName(context->class)); + } + va_start(args, format); + jio_vfprintf(stderr, format, args); + va_end(args); + jio_fprintf(stderr, "\n"); + exit(1);*/ +} + + +/*========================================================================= + * FUNCTION: signature_to_fieldtype + * OVERVIEW: Given the full info type for a field, returns the field type + * which corresponds to this signature. + * INTERFACE: + * parameters: pointer to the context_type + * char: **signature_p + * fullinfo_type: *full_info_p + * + * returns: char + *=======================================================================*/ +static char +signature_to_fieldtype(context_type *context, + char **signature_p, fullinfo_type *full_info_p) +{ + char *p = *signature_p; + fullinfo_type full_info = MAKE_FULLINFO(0, 0, 0); + char result; + int array_depth = 0; + + for (;;) { + switch(*p++) { + default: + full_info = MAKE_FULLINFO(ITEM_Bogus, 0, 0); + result = 0; + break; + + case SIGNATURE_BYTE: + full_info = (array_depth > 0) + ? MAKE_FULLINFO(ITEM_Byte, 0, 0) + : MAKE_FULLINFO(ITEM_Integer, 0, 0); + result = 'I'; + break; + + case SIGNATURE_BOOLEAN: + full_info = (array_depth > 0) + ? MAKE_FULLINFO(ITEM_Boolean, 0, 0) + : MAKE_FULLINFO(ITEM_Integer, 0, 0); + result = 'I'; + break; + + case SIGNATURE_CHAR: + full_info = (array_depth > 0) + ? MAKE_FULLINFO(ITEM_Char, 0, 0) + : MAKE_FULLINFO(ITEM_Integer, 0, 0); + result = 'I'; + break; + + case SIGNATURE_SHORT: + full_info = (array_depth > 0) + ? MAKE_FULLINFO(ITEM_Short, 0, 0) + : MAKE_FULLINFO(ITEM_Integer, 0, 0); + result = 'I'; + break; + + case SIGNATURE_INT: + full_info = MAKE_FULLINFO(ITEM_Integer, 0, 0); + result = 'I'; + break; + + case SIGNATURE_FLOAT: + full_info = MAKE_FULLINFO(ITEM_Float, 0, 0); + result = 'F'; + break; + + case SIGNATURE_DOUBLE: + full_info = MAKE_FULLINFO(ITEM_Double, 0, 0); + result = 'D'; + break; + + case SIGNATURE_LONG: + full_info = MAKE_FULLINFO(ITEM_Long, 0, 0); + result = 'L'; + break; + + case SIGNATURE_ARRAY: + array_depth++; + continue; /* only time we ever do the loop > 1 */ + + case SIGNATURE_CLASS: { + char buffer_space[256]; + char *buffer = buffer_space; + char *finish = strchr(p, SIGNATURE_ENDCLASS); + int length = finish - p; + if (length + 1 > sizeof(buffer_space)) { + buffer = sysMalloc(length + 1); + if (buffer == 0) { + // CCerror(context, "Out of memory"); + } + } + memcpy(buffer, p, length); + buffer[length] = '\0'; + full_info = MAKE_CLASSNAME_INFO_WITH_COPY(context, buffer, 0); + result = 'A'; + p = finish + 1; + if (buffer != buffer_space) + sysFree(buffer); + break; + } + } /* end of switch */ + break; + } + *signature_p = p; + if (array_depth == 0 || result == 0) { + /* either not an array, or result is bogus */ + *full_info_p = full_info; + return result; + } else { +// if (array_depth > MAX_ARRAY_DIMENSIONS) +// CCerror(context, "Array with too many dimensions"); + *full_info_p = MAKE_FULLINFO(GET_ITEM_TYPE(full_info), + array_depth, + GET_EXTRA_INFO(full_info)); + return 'A'; + } +} + + +/*========================================================================= + * FUNCTION: decrement_indirection + * OVERVIEW: Given an array type, create the type that has one less + * level of indirection. + * INTERFACE: + * parameters: fullinfo_type array_info + * + * returns: fullinfo_type + *=======================================================================*/ +static fullinfo_type +decrement_indirection(fullinfo_type array_info) +{ + if (array_info == NULL_FULLINFO) { + return NULL_FULLINFO; + } else { + int type = GET_ITEM_TYPE(array_info); + int indirection = GET_INDIRECTION(array_info) - 1; + int extra_info = GET_EXTRA_INFO(array_info); + if ( (indirection == 0) + && ((type == ITEM_Short || type == ITEM_Byte || type == ITEM_Boolean || type == ITEM_Char))) + type = ITEM_Integer; + return MAKE_FULLINFO(type, indirection, extra_info); + } +} + + +/*========================================================================= + * FUNCTION: isAssignableTo + * OVERVIEW: Given an object of the "from" type, determine if it can be + * assigned to an object of the "to" type. + * INTERFACE: + * parameters: pointer to the context_type + * fullinfo_type: from + * fullinfo_type: to + * + * returns: boolean type + *=======================================================================*/ +static bool_t isAssignableTo(context_type *context, + fullinfo_type from, fullinfo_type to) +{ + return (merge_fullinfo_types(context, from, to, TRUE) == to); +} + + +/*========================================================================= + * FUNCTION: merge_fullinfo_types + * OVERVIEW: Given two fullinfo_types, find their lowest common deno- + * minator. If the assignable_p argument is non-null, we are + * really just calling to find out if " := " + * is a legitimate assignment. + * We treat all interfaces as if they were of type ' + * java/lang/Object, since the runtime will do the full + * checking. + * + * INTERFACE: + * parameters: pointer to the context_type + * fullinfo_type: value + * fullinfo_type: target + * bool_t for_assignment + * + * returns: fullinfo_type + *=======================================================================*/ +static fullinfo_type +merge_fullinfo_types(context_type *context, + fullinfo_type value, fullinfo_type target, + bool_t for_assignment) +{ + if (value == target) { + /* If they're identical, clearly just return what we've got */ + return value; + } + + /* Both must be either arrays or objects to go further */ + if (GET_INDIRECTION(value) == 0 && GET_ITEM_TYPE(value) != ITEM_Object) + return MAKE_FULLINFO(ITEM_Bogus, 0, 0); + if (GET_INDIRECTION(target) == 0 && GET_ITEM_TYPE(target) != ITEM_Object) + return MAKE_FULLINFO(ITEM_Bogus, 0, 0); + + /* If either is NULL, return the other. */ + if (value == NULL_FULLINFO) + return target; + else if (target == NULL_FULLINFO) + return value; + + /* If either is java/lang/Object, that's the result. */ + if (target == context->object_info) + return target; + else if (value == context->object_info) { + /* Minor hack. For assignments, Interface := Object, return Interface + * rather than Object, so that isAssignableTo() will get the right + * result. */ + if (for_assignment && (WITH_ZERO_EXTRA_INFO(target) == + MAKE_FULLINFO(ITEM_Object, 0, 0))) { + ClassClass *cb = object_fullinfo_to_classclass(context, target); + if (cb && cbIsInterface(cb)) + return target; + } + return value; + } + if (GET_INDIRECTION(value) > 0 || GET_INDIRECTION(target) > 0) { + /* At least one is an array. Neither is java/lang/Object or NULL. + * Moreover, the types are not identical. + * The result must either be Object, or an array of some object type. + */ + int dimen_value = GET_INDIRECTION(value); + int dimen_target = GET_INDIRECTION(target); + + /* First, if either item's base type isn't ITEM_Object, promote it up + * to an object or array of object. If either is elemental, we can + * punt. + */ + if (GET_ITEM_TYPE(value) != ITEM_Object) { + if (dimen_value == 0) + return MAKE_FULLINFO(ITEM_Bogus, 0, 0); + dimen_value--; + value = MAKE_Object_ARRAY(dimen_value); + + } + if (GET_ITEM_TYPE(target) != ITEM_Object) { + if (dimen_target == 0) + return MAKE_FULLINFO(ITEM_Bogus, 0, 0); + dimen_target--; + target = MAKE_Object_ARRAY(dimen_target); + } + /* Both are now objects or arrays of some sort of object type */ + if (dimen_value == dimen_target) { + /* Arrays of the same dimension. Merge their base types. */ + fullinfo_type value_base = WITH_ZERO_INDIRECTION(value); + fullinfo_type target_base = WITH_ZERO_INDIRECTION(target); + fullinfo_type result_base = + merge_fullinfo_types(context, value_base, target_base, + for_assignment); + if (result_base == MAKE_FULLINFO(ITEM_Bogus, 0, 0)) + /* bogus in, bogus out */ + return result_base; + return MAKE_FULLINFO(ITEM_Object, dimen_value, + GET_EXTRA_INFO(result_base)); + } else { + /* Arrays of different sizes. Return Object, with a dimension + * of the smaller of the two. + */ + int dimen = dimen_value < dimen_target ? dimen_value : dimen_target; + return MAKE_Object_ARRAY(dimen); + } + } else { + /* Both are non-array objects. Neither is java/lang/Object or NULL */ + ClassClass *cb_value, *cb_target, *cb_super_value, *cb_super_target; + void **addr; + int value_info; + + /* Let's get the classes corresponding to each of these. Treat + * interfaces as if they were java/lang/Object. See hack note above. */ + cb_target = object_fullinfo_to_classclass(context, target); + if (cb_target == 0) + return MAKE_FULLINFO(ITEM_Bogus, 0, 0); + if (cbIsInterface(cb_target)) + return for_assignment ? target : context->object_info; + cb_value = object_fullinfo_to_classclass(context, value); + if (cb_value == 0) + return MAKE_FULLINFO(ITEM_Bogus, 0, 0); + if (cbIsInterface(cb_value)) + return context->object_info; + + /* If this is for assignment of target := value, we just need to see if + * cb_target is a superclass of cb_value. Save ourselves a lot of + * work. + */ + if (for_assignment) { + for (cb_super_value = cb_value; + cbSuperclass(cb_super_value) != NULL; + cb_super_value = cbSuperclass(cb_super_value)) { + if (cb_super_value == cb_target) { + return target; + } + } + return context->object_info; + } + + /* Find out whether cb_value or cb_target is deeper in the class + * tree by moving both toward the root, and seeing who gets there + * first. */ + for (cb_super_value = cb_value, cb_super_target = cb_target; + cbSuperclass(cb_super_value) && cbSuperclass(cb_super_target); ) { + /* Optimization. If either hits the other when going up looking + * for a parent, then might as well return the parent immediately */ + if (cb_super_value == cb_target) + return target; + if (cb_super_target == cb_value) + return value; + cb_super_value= cbSuperclass(cb_super_value); + cb_super_target = cbSuperclass(cb_super_target); + } + /* At most one of the following two while clauses will be executed. + * Bring the deeper of cb_target and cb_value to the depth of the + * shallower one. + */ + while (cbSuperclass(cb_super_value)) { /* cb_value is deeper */ + cb_super_value= cbSuperclass(cb_super_value); + cb_value= cbSuperclass(cb_value); + } + while (cbSuperclass(cb_super_target)) { /* cb_target is deeper */ + cb_super_target= cbSuperclass(cb_super_target); + cb_target = cbSuperclass(cb_target); + } + + /* Walk both up, maintaining equal depth, until a join is found. We + * know that we will find one. */ + while (cb_value != cb_target) { + cb_value = cbSuperclass(cb_value); + cb_target = cbSuperclass(cb_target); + } + /* Get the info for this guy. We know its cb_value, so we should + * fill that in, while we're at it. */ + value_info = Str2ID_Local(context, &context->classHash, + cbName(cb_value), &addr, TRUE); + *addr = cb_value; + return MAKE_FULLINFO(ITEM_Object, 0, value_info); + } /* both items are classes */ +} + + +/*========================================================================= + * FUNCTION: object_fullinfo_to_classclass + * OVERVIEW: Given a fullinfo_type corresponding to an Object, return the + * pointer to the ClassClass structure of that type. + * Returns 0 for an illegal class. + * INTERFACE: + * parameters: pointer to the context_type + * fullinfo_type: classinfo + * + * returns: pointer to the ClassClass type + *=======================================================================*/ +static ClassClass * +object_fullinfo_to_classclass(context_type *context, fullinfo_type classinfo) +{ + void **addr; + ClassClass *cb; + + unsigned short info = GET_EXTRA_INFO(classinfo); + char *classname = ID2Str_Local(context, context->classHash, info, &addr); + if ((cb = *addr) != 0) { + return cb; + } else { + *addr = cb = FindClassFromClass(0, classname, FALSE, context->class); +// if (cb == 0) +// CCerror(context, "Cannot find class %s", classname); + return cb; + } +} + + +/*========================================================================= + * The functions below are for debugging the preverifier + *=======================================================================*/ + +#ifdef DEBUG_VERIFIER + +static void print_fullinfo_type(context_type *, fullinfo_type, bool_t); + + +/*========================================================================= + * FUNCTION: print_stack + * OVERVIEW: Prints stack information. + * + * INTERFACE: + * parameters: pointer to the context_type + * stack_info: pointer to stack_info + * + * returns: nothing + *=======================================================================*/ +static void +print_stack(context_type *context, stack_info_type *stack_info) +{ + stack_item_type *stack = stack_info->stack; + if (stack_info->stack_size == UNKNOWN_STACK_SIZE) { + jio_fprintf(stdout, "x"); + } else { + jio_fprintf(stdout, "("); + for ( ; stack != 0; stack = stack->next) + print_fullinfo_type(context, stack->item, verify_verbose > 1); + jio_fprintf(stdout, ")"); + } +} + + +/*========================================================================= + * FUNCTION: print_registers + * OVERVIEW: Prints registers. + * + * INTERFACE: + * parameters: pointer to the context_type + * register_info_type: pointer to register_info + * + * returns: nothing + *=======================================================================*/ +static void +print_registers(context_type *context, register_info_type *register_info) +{ + int register_count = register_info->register_count; + if (register_count == UNKNOWN_REGISTER_COUNT) { + jio_fprintf(stdout, "x"); + } else { + fullinfo_type *registers = register_info->registers; + int mask_count = register_info->mask_count; + mask_type *masks = register_info->masks; + int i, j; + + jio_fprintf(stdout, "{"); + for (i = 0; i < register_count; i++) + print_fullinfo_type(context, registers[i], verify_verbose > 1); + jio_fprintf(stdout, "}"); + for (i = 0; i < mask_count; i++) { + char *separator = ""; + int *modifies = masks[i].modifies; + jio_fprintf(stdout, "<%d: ", masks[i].entry); + for (j = 0; j < context->mb->nlocals; j++) + if (IS_BIT_SET(modifies, j)) { + jio_fprintf(stdout, "%s%d", separator, j); + separator = ","; + } + jio_fprintf(stdout, ">"); + } + } +} + + +/*========================================================================= + * FUNCTION: print_flags + * OVERVIEW: Prints flags. + * + * INTERFACE: + * parameters: pointer to the context_type + * flag_type: and_flags + * flag_type: or_flags + * + * returns: nothing + *=======================================================================*/ +static void +print_flags(context_type *context, flag_type and_flags, flag_type or_flags) +{ + if (and_flags != ((flag_type)-1) || or_flags != 0) { + jio_fprintf(stdout, "<%x %x>", and_flags, or_flags); + } +} + + +/*========================================================================= + * FUNCTION: print_fullinfo_type + * OVERVIEW: Prints fullinfo_type information. + * + * INTERFACE: + * parameters: pointer to the context_type + * fullinfo_type: type + * bool_t verbose + * + * returns: nothing + *=======================================================================*/ +static void +print_fullinfo_type(context_type *context, fullinfo_type type, bool_t verbose) +{ + int i; + int indirection = GET_INDIRECTION(type); + for (i = indirection; i-- > 0; ) + jio_fprintf(stdout, "["); + switch (GET_ITEM_TYPE(type)) { + case ITEM_Integer: + jio_fprintf(stdout, "I"); break; + case ITEM_Float: + jio_fprintf(stdout, "F"); break; + case ITEM_Double: + jio_fprintf(stdout, "D"); break; + case ITEM_Double_2: + jio_fprintf(stdout, "d"); break; + case ITEM_Long: + jio_fprintf(stdout, "L"); break; + case ITEM_Long_2: + jio_fprintf(stdout, "l"); break; + case ITEM_ReturnAddress: + jio_fprintf(stdout, "a"); break; + case ITEM_Object: + if (!verbose) { + jio_fprintf(stdout, "A"); + } else { + unsigned short extra = GET_EXTRA_INFO(type); + if (extra == 0) { + jio_fprintf(stdout, "/Null/"); + } else { + char *name = ID2Str_Local(context, context->classHash, + extra, 0); + char *name2 = strrchr(name, '/'); + jio_fprintf(stdout, "/%s/", name2 ? name2 + 1 : name); + } + } + break; + case ITEM_Char: + jio_fprintf(stdout, "C"); break; + case ITEM_Short: + jio_fprintf(stdout, "S"); break; + case ITEM_Byte: + jio_fprintf(stdout, "B"); break; + case ITEM_Boolean: + jio_fprintf(stdout, "Z"); break; + case ITEM_NewObject: + if (!verbose) { + jio_fprintf(stdout, "@"); + } else { + int inum = GET_EXTRA_INFO(type); + fullinfo_type real_type = + context->instruction_data[inum].operand2.fi; + jio_fprintf(stdout, ">"); + print_fullinfo_type(context, real_type, TRUE); + jio_fprintf(stdout, "<"); + } + break; + case ITEM_InitObject: + jio_fprintf(stdout, verbose ? ">/this/<" : "@"); + break; + + default: + jio_fprintf(stdout, "?"); break; + } + for (i = indirection; i-- > 0; ) + jio_fprintf(stdout, "]"); +} + + +/*========================================================================= + * FUNCTION: print_formatted_fieldname + * OVERVIEW: Prints formatted fieldname associated with the given + * index within the constant pool. + * + * INTERFACE: + * parameters: pointer to the context_type + * int: index + * + * returns: nothing + *=======================================================================*/ +static void +print_formatted_fieldname(context_type *context, int index) +{ + union cp_item_type *constant_pool = cbConstantPool(context->class); + unsigned char *type_table = + constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type; + unsigned type = CONSTANT_POOL_TYPE_TABLE_GET_TYPE(type_table, index); + + unsigned key = constant_pool[index].i; + unsigned classkey = key >> 16; + unsigned nametypekey = key & 0xFFFF; + unsigned nametypeindex = constant_pool[nametypekey].i; + unsigned fieldnameindex = nametypeindex >> 16; + unsigned fieldtypeindex = nametypeindex & 0xFFFF; + jio_fprintf(stdout, " <%s.%s%s%s>", + GetClassConstantClassName(constant_pool, classkey), + constant_pool[fieldnameindex].cp, + type == CONSTANT_Fieldref ? " " : "", + constant_pool[fieldtypeindex].cp); +} + +#endif /*DEBUG_VERIFIER*/ + diff --git a/MPC.3.5.LINUX/preverifier/check_code.h b/MPC.3.5.LINUX/preverifier/check_code.h new file mode 100644 index 0000000..ff9dd86 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/check_code.h @@ -0,0 +1,160 @@ +/* + * @(#)check_code.h 1.3 02/09/27 + * + * Copyright 1995-1999 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +#include + +#include "oobj.h" +#include "opcodes.h" +#include "tree.h" +#include "sys_api.h" + +#define MAX_ARRAY_DIMENSIONS 255 + + +#define UNKNOWN_STACK_SIZE -1 +#define UNKNOWN_REGISTER_COUNT -1 +#define UNKNOWN_RET_INSTRUCTION -1 + +#undef MAX +#undef MIN +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +#define BITS_PER_INT (CHAR_BIT * sizeof(int)/sizeof(char)) +#define SET_BIT(flags, i) (flags[(i)/BITS_PER_INT] |= \ + ((unsigned)1 << ((i) % BITS_PER_INT))) +#define IS_BIT_SET(flags, i) (flags[(i)/BITS_PER_INT] & \ + ((unsigned)1 << ((i) % BITS_PER_INT))) + +typedef unsigned long fullinfo_type; +typedef unsigned int *bitvector; + +#define GET_ITEM_TYPE(thing) ((thing) & 0x1F) +#define GET_INDIRECTION(thing) (((thing) & 0xFFFF) >> 5) +#define GET_EXTRA_INFO(thing) ((unsigned short)((thing) >> 16)) +#define WITH_ZERO_INDIRECTION(thing) ((thing) & ~(0xFFE0)) +#define WITH_ZERO_EXTRA_INFO(thing) ((thing) & 0xFFFF) + +#define MAKE_FULLINFO(type, indirect, extra) \ + ((fullinfo_type)((type) + ((indirect) << 5) + ((extra) << 16))) +#define MAKE_CLASSNAME_INFO(context, classname, addr) \ + MAKE_FULLINFO(ITEM_Object, 0, \ + Str2ID_Local(context, &context->classHash, (classname), (addr), FALSE)) +#define MAKE_CLASSNAME_INFO_WITH_COPY(context, classname, addr) \ + MAKE_FULLINFO(ITEM_Object, 0, \ + Str2ID_Local(context, &context->classHash, (classname), (addr), TRUE)) +#define MAKE_Object_ARRAY(indirect) \ + (context->object_info + ((indirect) << 5)) + +#define NULL_FULLINFO MAKE_FULLINFO(ITEM_Object, 0, 0) + +/* opc_invokespecial calls to need to be treated special */ +#define opc_invokeinit 0x100 + +struct context_type { + /* these fields are per class */ + ClassClass *class; /* current class */ + struct StrIDhash *classHash; + fullinfo_type object_info; /* fullinfo for java/lang/Object */ + fullinfo_type string_info; /* fullinfo for java/lang/String */ + fullinfo_type throwable_info; /* fullinfo for java/lang/Throwable */ + + fullinfo_type currentclass_info; /* fullinfo for context->class */ + fullinfo_type superclass_info; /* fullinfo for superclass */ + + /* these fields are per method */ + struct methodblock *mb; /* current method */ + unsigned char *code; /* current code object */ + short *code_data; /* offset to instruction number */ + struct instruction_data_type *instruction_data; /* info about each */ + struct handler_info_type *handler_info; + fullinfo_type *superClasses; /* null terminated superclasses */ + int instruction_count; /* number of instructions */ + fullinfo_type return_type; /* function return type */ + fullinfo_type swap_table[4]; /* used for passing information */ + int bitmask_size; /* words needed to hold bitmap of arguments */ + + /* Used by inliner */ + bool_t redoJsr; + + /* Used by the space allocator */ + struct CCpool *CCroot, *CCcurrent; + char *CCfree_ptr; + int CCfree_size; + + /* Jump here on any error. */ + jmp_buf jump_buffer; +}; + +struct stack_info_type { + struct stack_item_type *stack; + int stack_size; +}; + +struct register_info_type { + int register_count; /* number of registers used */ + fullinfo_type *registers; + int mask_count; /* number of masks in the following */ + struct mask_type *masks; +}; + +struct mask_type { + int entry; + int *modifies; +}; + +typedef unsigned short flag_type; + +struct instruction_data_type { + opcode_type opcode; /* may turn into "canonical" opcode */ + unsigned changed:1; /* has it changed */ + unsigned protected:1; /* must accessor be a subclass of "this" */ + unsigned is_target:1; + + union { + int i; /* operand to the opcode */ + int *ip; + fullinfo_type fi; + } operand, operand2; + fullinfo_type p; + struct stack_info_type stack_info; + struct register_info_type register_info; +#define FLAG_REACHED 0x01 /* instruction reached */ +#define FLAG_NEED_CONSTRUCTOR 0x02 /* must call this. or super. */ +#define FLAG_NO_RETURN 0x04 /* must throw out of method */ + flag_type or_flags; /* true for at least one path to this inst */ +#define FLAG_CONSTRUCTED 0x01 /* this. or super. called */ + flag_type and_flags; /* true for all paths to this instruction */ + unsigned short offset; + unsigned short length; +}; + +struct handler_info_type { + int start, end, handler; + struct stack_info_type stack_info; +}; + +struct stack_item_type { + fullinfo_type item; + struct stack_item_type *next; +}; + + +typedef struct context_type context_type; +typedef struct instruction_data_type instruction_data_type; +typedef struct stack_item_type stack_item_type; +typedef struct register_info_type register_info_type; +typedef struct stack_info_type stack_info_type; +typedef struct mask_type mask_type; diff --git a/MPC.3.5.LINUX/preverifier/classloader.c b/MPC.3.5.LINUX/preverifier/classloader.c new file mode 100644 index 0000000..5cb4f34 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/classloader.c @@ -0,0 +1,1783 @@ +/* + * @(#)classloader.c 1.37 02/09/27 + * + * Copyright 1995-1999 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +/*========================================================================= + * SYSTEM: Verifier + * SUBSYSTEM: class loader. + * FILE: classloader.c + * OVERVIEW: Routines for loading and resolving class definitions. + * These routines should not be depending upon the interpreter + * or the garbage collector. + * AUTHOR: Sheng Liang, Sun Microsystems, Inc. + * Modifications for JAR support and comments, + * Tasneem Sayeed, Sun Microsystems + *=======================================================================*/ + +/*========================================================================= + * Include files + *=======================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "jar.h" +#include "oobj.h" +#include "path.h" +#include "tree.h" +#include "signature.h" +#include "convert_md.h" + +#include "sys_api.h" + +#ifdef UNIX +#include +#endif + + +/*========================================================================= + * Globals and extern declarations + *=======================================================================*/ + +char *stat_source(ClassClass *cb, struct stat *s, char *pathbuf, int maxlen); + +extern ClassClass *allocClassClass(); + +extern bool_t JARfile; + +extern char * zipFileName; + +extern zip_t * getZipEntry(char *zipFile, int len); + +extern bool_t findJARDirectories(zip_t *entry, struct stat *statbuf); + +extern JAR_DataStreamPtr loadJARfile(zip_t *entry, const char* filename); + + +/*========================================================================= + * FUNCTION: AddBinClass + * OVERVIEW: Used by createInternalClass1() and createFakeArrayClass() + * to add a class in the class table. + * INTERFACE: + * parameters: ClassClass: cb + * + * returns: nothing + *=======================================================================*/ +void +AddBinClass(ClassClass * cb) +{ + register int left, right, middle, result, i; + char *name = cbName(cb); + struct Hjava_lang_ClassLoader *loader = cbLoader(cb); + + BINCLASS_LOCK(); + left = 0; + right = nbinclasses - 1; + result = 1; + while (left <= right) { + ClassClass *cb1; + middle = (left+right)/2; + cb1 = binclasses[middle]; + result = strcmp(name, cbName(cb1)); + if (result == 0) { + if (loader < cbLoader(cb1)) { + result = -1; + } else if (loader > cbLoader(cb1)) { + result = 1; + } else { + result = 0; + } + } + if (result < 0) { + right = middle-1; + } else if (result > 0) { + left = middle+1; + } else { + break; + } + } + if (result != 0) { + if (nbinclasses >= sizebinclasses) { + if (binclasses == 0) + binclasses = (ClassClass **) + sysMalloc(sizeof(ClassClass *) * (sizebinclasses = 50)); + else + binclasses = (ClassClass **) + sysRealloc(binclasses, sizeof(ClassClass *) + * (sizebinclasses = nbinclasses * 2)); + } + if (binclasses == 0) + goto unlock; + right++; + for (i = nbinclasses; i > right; i--) { + binclasses[i] = binclasses[i-1]; + } + binclasses[right] = cb; + nbinclasses++; + } + +unlock: + BINCLASS_UNLOCK(); +} + + +/*========================================================================= + * FUNCTION: DelBinClass + * OVERVIEW: Intended for allowing deletion of classes from the class + * table. + * + * INTERFACE: + * parameters: ClassClass: cb + * + * returns: nothing + *=======================================================================*/ +void +DelBinClass(ClassClass * cb) +{ + register int i, j; + BINCLASS_LOCK(); + for (i = nbinclasses; --i >= 0; ) + if (binclasses[i] == cb) { + nbinclasses--; + for (j = i; j < nbinclasses; j++) { + binclasses[j] = binclasses[j+1]; + } + break; + } + BINCLASS_UNLOCK(); +} + + +/*========================================================================= + * FUNCTION: MakeClassSticky + * OVERVIEW: Used to lock certain system classes into memory during + * initialization. + * + * INTERFACE: + * parameters: ClassClass: cb + * + * returns: nothing + *=======================================================================*/ +void +MakeClassSticky(ClassClass *cb) +{ + /* monitorEnter(obj_monitor(cb)); */ + CCSet(cb, Sticky); + /* monitorExit(obj_monitor(cb)); */ +} + + +/*========================================================================= + * FUNCTION: LoadClassFromFile + * OVERVIEW: Loads a .class file normally from disk or a null if it fails. + * When the interpreter requests for a file, it is actually + * looking for a classblock structure to be created, and the + * only way it can get one of those is by loading a compiled + * class. + * OpenCode() tries to open a .class file first. If it fails + * to open the file, it returns a non-zero status. If it + * returns a valid file descriptor, this usually means that + * this is a valid .class file. + * It then invokes createInternalClass() to actually create the + * internal representation of the class. + * + * INTERFACE: + * parameters: char*: file name + * char*: directory + * char*: class name + * + * returns: nothing + *=======================================================================*/ +ClassClass * +LoadClassFromFile(char *fn, char *dir, char *class_name) +{ + extern int OpenCode(char *, char *, char *, struct stat*); + struct stat st; + ClassClass *cb = 0; + int codefd = -1; + unsigned char *external_class; + char *detail; + + codefd = OpenCode(fn, NULL, dir, &st); + + if (codefd < 0) /* open failed */ + return 0; + + /* Snarf the file into memory. */ + external_class = (unsigned char *)sysMalloc(st.st_size); + if (external_class == 0) + goto failed; + if (sysRead(codefd, external_class, st.st_size) != st.st_size) + goto failed; + sysClose(codefd); + codefd = -1; + + /* Create the internal class */ + cb = allocClassClass(); + if (cb == NULL || + !createInternalClass(external_class, external_class + st.st_size, + cb, NULL, class_name, &detail)) { + sysFree(external_class); + goto failed; + } + sysFree(external_class); + + if (verbose) + jio_fprintf(stderr, "[Loaded %s]\n", fn); + + return cb; +failed: + if (codefd >= 0) + sysClose(codefd); + if (cb != 0) + FreeClass(cb); + return 0; +} + + +/*========================================================================= + * FUNCTION: LoadClassFromZip + * TYPE: load class from a JAR or Zip file + * OVERVIEW: Called by LoadClassLocally for loading classes from a Zip. + * + * This function loads a .class file normally from a Zip or + * JAR file. + * It returns the class when it succeeds or NULL if it fails. + * + * INTERFACE: + * parameters: zip_t: zip file entry + * char*: class file name to search for loading + * returns: Pointer to ClassClass when it succeeds, or NULL if it fails. + *=======================================================================*/ +static ClassClass * +LoadClassFromZip(zip_t *zipEntry, char *class_name) +{ + ClassClass *cb = 0; + JAR_DataStreamPtr jdstream = NULL; + unsigned char *external_class; + int data_length; + char *detail; + + jdstream = loadJARfile (zipEntry, class_name); + + if (jdstream == NULL) + goto failed; + + external_class = jdstream->data; + data_length = jdstream->dataLen; + + /* Create the internal class */ + cb = allocClassClass(); + if (cb == NULL || + !createInternalClass(external_class, external_class + data_length, + cb, NULL, class_name, &detail)) { + goto failed; + } + if (jdstream != NULL) { + freeBytes(jdstream); + } + + if (verbose) { + jio_fprintf(stderr, "[Loaded %s] from [%s]\n", class_name, + zipEntry->name); + } + return cb; +failed: + if (cb != 0) + FreeClass(cb); + if (jdstream != NULL) { + freeBytes(jdstream); + } + return 0; +} + + +/*========================================================================= + * FUNCTION: LoadClassLocally + * OVERVIEW: Find a class file that is somewhere local, and not from a + * class loader. + * It still needs to be searched using the classpath. + * + * INTERFACE: + * parameters: char* : class file name + * returns: Pointer to ClassClass when it succeeds, or NULL if it fails. + *=======================================================================*/ +ClassClass *LoadClassLocally(char *name) +{ + ClassClass *cb = 0; + cpe_t **cpp; + + if (name[0] == DIR_SEPARATOR || name[0] == SIGNATURE_ARRAY) + return 0; + + for (cpp = sysGetClassPath(); cpp && *cpp != 0; cpp++) { + cpe_t *cpe = *cpp; + char *path; + + if (cpe->type == CPE_DIR) { + path = (char *)sysMalloc(strlen(cpe->u.dir) + + sizeof(LOCAL_DIR_SEPARATOR) + + strlen(name) + + strlen(JAVAOBJEXT) + + 2); /* 2 is for the . and the \0 */ + if (sprintf(path, + "%s%c%s." JAVAOBJEXT, cpe->u.dir, + LOCAL_DIR_SEPARATOR, name) == -1) { + sysFree(path); + return 0; + } + if ((cb = LoadClassFromFile(sysNativePath(path), + cpe->u.dir, name))) { + sysFree(path); + return cb; + } + } else if (cpe->type == CPE_ZIP) { + // if (JAR_DEBUG && verbose) + // jio_fprintf(stderr, "Loading classes from a ZIP file... \n"); + if ((cb = LoadClassFromZip(cpe->u.zip, name))) { + return cb; + } + } + + } + return cb; +} + + +/*========================================================================= + * FUNCTION: stat_source + * OVERVIEW: Unused by the Verifier, but it is too late to remove it now. + * + * INTERFACE: + * parameters: ClassClass *: cb + * struct stat*: s + * char*: pathbuf + * int: maxlen + * returns: char *, or NULL if it fails. + *=======================================================================*/ +char * +stat_source(ClassClass *cb, struct stat *s, char *pathbuf, int maxlen) +{ +#define NAMEBUFLEN 255 + char nm[NAMEBUFLEN]; + char *p, *q, *lp; + cpe_t **cpp; + + /* don't bother searching if absolute */ + /* REMIND: only here for compatibility */ + if (sysIsAbsolute(cbSourceName(cb))) { + if (sysStat(cbSourceName(cb), s) == 0) { + if (jio_snprintf(pathbuf, maxlen, "%s", cbSourceName(cb)) == -1) { + return 0; + } + return pathbuf; + } else { + return 0; + } + } + + /* parse the package name */ + p = cbName(cb); + if (strlen(p) > NAMEBUFLEN - 1) { + return 0; + } + for (q = lp = nm ; *p ; p++) { + if (*p == DIR_SEPARATOR) { + *q++ = LOCAL_DIR_SEPARATOR; + lp = q; + } else { + *q++ = *p; + } + } + + /* append the source file name */ + p = cbSourceName(cb); + if (strlen(p) + (lp - nm) > NAMEBUFLEN - 1) { + return 0; + } + for (; *p ; p++) { + *lp++ = (*p == DIR_SEPARATOR ? LOCAL_DIR_SEPARATOR : *p); + } + *lp = '\0'; + + /* search the class path */ + for (cpp = sysGetClassPath() ; cpp && *cpp != 0 ; cpp++) { + cpe_t *cpe = *cpp; + if (cpe->type == CPE_DIR) { + if (jio_snprintf(pathbuf, maxlen, "%s%c%s", + cpe->u.dir, LOCAL_DIR_SEPARATOR, nm) == -1) { + return 0; + } + if (sysStat(pathbuf, s) == 0) { + return pathbuf; + } + } + } + return 0; +} + + +/*========================================================================= + * Globals and externs for Internal Class representation + *=======================================================================*/ +struct CICmallocs { + struct CICmallocs *next; + void * alignment_padding; + +/* Whatever follows will be 8-byte aligned, if the structure itself is + 8-byte aligned. */ +}; + +typedef struct CICmallocs CICmallocs; + +struct CICcontext { + unsigned char *ptr; + unsigned char *end_ptr; + ClassClass *cb; + jmp_buf jump_buffer; + char **detail; + + int pass; /* two passes, 1 or 2 */ + int malloc_size; /* space needed for everything other than */ + int clinit_size; /* space needed for the method */ + int in_clinit; /* indicates whether we are loading method */ + + struct { + CICmallocs *mallocs; /* list of memory blocks used in the first pass */ + + void * alignment_padding; + /* Whatever follows will be 8-byte aligned */ + } pass1; + + struct { + char *malloc_buffer; /* used to hold everything other than */ + char *malloc_ptr; /* current point of allocation */ + + char *clinit_buffer; /* used to hold the method */ + char *clinit_ptr; /* current point of allocation */ + } pass2; + +}; + +typedef struct CICcontext CICcontext; + +static char *getAsciz(CICcontext *, bool_t); +static char *getAscizFromClass(CICcontext *, int i); + +static unsigned char get1byte(CICcontext *); +static unsigned short get2bytes(CICcontext *); +static unsigned long get4bytes(CICcontext *); +static void getNbytes(CICcontext *, int count, char *buffer); +static void *allocNBytes(CICcontext *, int size); +static void freeBuffers(CICcontext *); + +static void LoadConstantPool(CICcontext *); +static void ReadInCode(CICcontext *, struct methodblock *); +static void ReadLineTable(CICcontext *, struct methodblock *mb); +static void ReadExceptions(CICcontext *, struct methodblock *); +static void ReadLocalVars(CICcontext *, struct methodblock *mb); + +static void +createInternalClass0(CICcontext *context, ClassClass *cb, + struct Hjava_lang_ClassLoader *loader, char *name); + +bool_t +createInternalClass1(unsigned char *ptr, unsigned char *end_ptr, + ClassClass *cb, struct Hjava_lang_ClassLoader *loader, + char *name, char **detail); + + +/*========================================================================= + * FUNCTION: createInternalClass + * OVERVIEW: Invoked by LoadClassFromFile() or LoadClassFromZip() to + * create an internal class. See createInternalClass1() for + * details. + * + * INTERFACE: + * parameters: unsigned char *: ptr + * unsigned char *: end_ptr + * ClassClass *: cb + * struct Hjava_lang_ClassLoader *: loader + * char *: name + * char **: detail + * + * returns: bool_t + *=======================================================================*/ +bool_t +createInternalClass(unsigned char *ptr, unsigned char *end_ptr, + ClassClass *cb, struct Hjava_lang_ClassLoader *loader, + char *name, char **detail) +{ + bool_t res; + res = createInternalClass1(ptr, end_ptr, cb, loader, name, detail); + + return res; +} + + +/*========================================================================= + * FUNCTION: JAVA_ERROR + * OVERVIEW: Verifier error processing function. + * + * INTERFACE: + * parameters: CICcontext *: context + * char * : name + * + * returns: nothing + *=======================================================================*/ +void JAVA_ERROR(CICcontext *context, char *name) { + printCurrentClassName(); + *(context->detail) = name; + EE()->class_loading_msg = name; + fprintf(stderr, "Class loading error: %s\n", name); + exit(1); +} + + +/*========================================================================= + * FUNCTION: createInternalClass1 + * OVERVIEW: Auxiliary function for creating an internal class. + * Invoked by createInternalClass(). + * + * Creates an internal class file from the indicated data. + * It should be in a buffer for which the first byte is at + * *ptr and the last byte is just before *end_ptr. + * The class's classloader is indicated by the classloader + * argument. + * + * We go through the buffer twice. In the first pass, we + * determine the amount of storage needed by the class. + * We then allocate a single chunk of memory, free the + * temporary storage, and load from the buffer for the second + * time. + * + * Since all storage needed by the class initialization method + * can be freed after the class is loaded, we count + * the space needs separately and store the + * method in a separate chunk of memory. + * + * INTERFACE: + * parameters: unsigned char *: ptr + * unsigned char *: end_ptr + * ClassClass *: cb + * struct Hjava_lang_ClassLoader *: loader + * char *: name + * char **: detail + * + * returns: bool_t + *=======================================================================*/ +bool_t +createInternalClass1(unsigned char *ptr, unsigned char *end_ptr, + ClassClass *cb, struct Hjava_lang_ClassLoader *loader, + char *name, char **detail) +{ + struct CICcontext context_block; + struct CICcontext *context = &context_block; + + /* Set up the context */ + context->ptr = ptr; + context->end_ptr = end_ptr; + context->cb = cb; + context->detail = detail; + + /* initialize the remaining fields of the context block */ + context->pass = 0; + context->malloc_size = 0; + context->clinit_size = 0; + context->in_clinit = 0; + context->pass1.mallocs = 0; + + context->pass2.malloc_buffer = NULL; + context->pass2.malloc_ptr = NULL; + context->pass2.clinit_buffer = NULL; + context->pass2.clinit_ptr = NULL; + + + if (setjmp(context->jump_buffer)) { + + /* We've gotten an error of some sort + * See comments below about zeroing these + * two fields before freeing the temporary + * buffer. + */ + + cbConstantPool(cb) = NULL; + cbFields(cb) = NULL; + + /* Zero out the method so that freeClass will + * not try to free the clinit method. + */ + + cbMethodsCount(cb) = 0; + freeBuffers(context); + return FALSE; + } + + /* The first pass allows us to uncover any class format + * errors and find out the size of the buffer needed. + */ + + context->pass = 1; + createInternalClass0(context, cb, loader, name); + + /* We must set the following two fields to zero before we free + * the temporary buffers, because markClassClass may scan a + * partially constructed class block in the second pass. + * If these two fields are set to zero, markClassClass will + * not scan the constant pool and field blocks, which may + * point to freed memory. + */ + + cbConstantPool(cb) = NULL; + cbFields(cb) = NULL; + + /* Zero out the method so that freeClass will not try + * to free the clinit method. + */ + + cbMethodsCount(cb) = 0; + freeBuffers(context); + + context->ptr = ptr; /* rewind the raw class data */ + + if (context->malloc_size > 0) { + context->pass2.malloc_buffer = + (char *)sysCalloc(1, context->malloc_size); + + if (context->pass2.malloc_buffer == 0) + JAVA_ERROR(context, "out of memory"); + } + + if (context->clinit_size > 0) { + context->pass2.clinit_buffer = + (char *)sysCalloc(1, context->clinit_size * sizeof(char)); + + if (context->pass2.clinit_buffer == 0) { + sysFree(context->pass2.malloc_buffer); + JAVA_ERROR(context, "out of memory"); + } + } + + context->pass2.malloc_ptr = context->pass2.malloc_buffer; + context->pass2.clinit_ptr = context->pass2.clinit_buffer; + + /* The second pass accomplishes the real task. */ + + context->pass = 2; + createInternalClass0(context, cb, loader, name); + + /* Valid class - let's put it in the class table. */ + AddBinClass(cb); + + return TRUE; +} + + +/*========================================================================= + * FUNCTION: createInternalClass0 + * OVERVIEW: Auxiliary function invoked by createInternalClass1() during + * the second pass to actually load the internal class file + * structures such as the constant pool, method blocks, field + * blocks and so on. + * + * INTERFACE: + * parameters: CICcontext *: ptr + * ClassClass *: cb + * struct Hjava_lang_ClassLoader *: loader + * char *: name + * + * returns: nothing + *=======================================================================*/ +static void +createInternalClass0(CICcontext *context, ClassClass *cb, + struct Hjava_lang_ClassLoader *loader, char *name) +{ + int i, j, len; + char buff[BUFSIZ]; + char *UTFname = &buff[0]; + union cp_item_type *constant_pool; + unsigned char *type_table; + int attribute_count; + unsigned fields_count; + struct methodblock *mb; + struct fieldblock *fb; + struct Classjava_lang_Class *ucb = unhand(cb); + + int32_t tmp = get4bytes(context); + if (tmp != JAVA_CLASSFILE_MAGIC) + JAVA_ERROR(context, "Bad magic number"); + + ucb->minor_version = get2bytes(context); + ucb->major_version = get2bytes(context); + ucb->loader = loader; + + /* Ignore version # so that the preverifier can work with JDK 1.4 onwards */ + /* + if (ucb->major_version != JAVA_VERSION) + JAVA_ERROR(context, "Bad major version number"); + */ + + LoadConstantPool(context); + constant_pool = ucb->constantpool; + type_table = constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type; + + ucb->access = get2bytes(context) & ACC_WRITTEN_FLAGS; + + /* Get the name of the class */ + i = get2bytes(context); /* index in constant pool of class */ + ucb->name = getAscizFromClass(context, i); + + /* Conversion for Japanese filenames */ + len = native2utf8(name, UTFname, BUFSIZ); + + if (name != NULL && strcmp(ucb->name, UTFname) != 0) + JAVA_ERROR(context, "Wrong name"); + constant_pool[i].clazz = cb; + CONSTANT_POOL_TYPE_TABLE_SET_RESOLVED(type_table, i); + + if (loader) { + /* We don't trust a classloader to do the right thing. . . */ + ClassClass **pcb, **end_pcb; + char *name = ucb->name; +// if (name == NULL || !IsLegalClassname(name, FALSE)) { +// JAVA_ERROR(context, "Bad name"); +// } + BINCLASS_LOCK(); + for (pcb = binclasses, end_pcb = pcb + nbinclasses; + pcb < end_pcb; pcb++) { + ClassClass *cb = *pcb; + if ((cbLoader(cb) == loader) && (strcmp(name, cbName(cb)) == 0)) + break; + } + BINCLASS_UNLOCK(); + if (pcb < end_pcb) + /* There's already a class with the same name and loader */ + JAVA_ERROR(context, "Duplicate name"); + } + + /* Get the super class name. */ + i = get2bytes(context); /* index in constant pool of class */ + if (i > 0) { + ucb->super_name = getAscizFromClass(context, i); + ucb->superclass_idx = i; +// if (!IsLegalClassname(ucb->super_name, FALSE)) { +// JAVA_ERROR(context, "Bad superclass name"); +// } + } + + i = ucb->implements_count = get2bytes(context); + if (i > 0) { + int j; + ucb->implements = allocNBytes(context, i * sizeof(short)); + for (j = 0; j < i; j++) { + ucb->implements[j] = get2bytes(context); + } + } + + fields_count = ucb->fields_count = get2bytes(context); + if (fields_count > 0) + ucb->fields = (struct fieldblock *) + allocNBytes(context, ucb->fields_count * sizeof(struct fieldblock)); + for (i = fields_count, fb = ucb->fields; --i >= 0; fb++) { + fieldclass(fb) = cb; + fb->access = get2bytes(context) & ACC_WRITTEN_FLAGS; + fb->name = getAsciz(context, FALSE); + fb->signature = getAsciz(context, FALSE); + attribute_count = get2bytes(context); + for (j = 0; j < (int)attribute_count; j++) { + char *attr_name = getAsciz(context, FALSE); + int length = get4bytes(context); + if (strcmp(attr_name, "ConstantValue") == 0) { + if (fb->access & ACC_STATIC) { + if (length != 2) { + JAVA_ERROR(context, "Wrong size for VALUE attribute"); + } + fb->access |= ACC_VALKNOWN; + /* we'll change this below */ + fb->u.offset = get2bytes(context); + } else { + getNbytes(context, length, NULL); + } + } else if (strcmp(attr_name, "Deprecated") == 0) { + if (length > 0) { + JAVA_ERROR(context, "Bad deprecated size"); + } + fb->deprecated = TRUE; + } else if (strcmp(attr_name, "Synthetic") == 0) { + if (length > 0) { + JAVA_ERROR(context, "Bad synthetic attribute size"); + } + fb->synthetic = TRUE; + } else { + getNbytes(context, length, NULL); + } + } + /* + if (fb->access & ACC_STATIC) { + InitializeStaticVar(fb, context); + } + */ + } + + if ((ucb->methods_count = get2bytes(context)) > 0) + ucb->methods = (struct methodblock *) + allocNBytes(context, ucb->methods_count * sizeof(struct methodblock)); + + for (i = cbMethodsCount(cb), mb = cbMethods(cb); --i >= 0; mb++) { + fieldclass(&mb->fb) = cb; + mb->fb.access = get2bytes(context) & ACC_WRITTEN_FLAGS; + mb->fb.name = getAsciz(context, FALSE); + mb->fb.signature = getAsciz(context, FALSE); + + if (strcmp(mb->fb.name, "") == 0 && + strcmp(mb->fb.signature, "()V") == 0) + context->in_clinit = TRUE; + + mb->args_size = Signature2ArgsSize(mb->fb.signature) + + ((mb->fb.access & ACC_STATIC) ? 0 : 1); + if (mb->args_size > 255) + JAVA_ERROR(context, "Too many arguments"); + + attribute_count = get2bytes(context); + for (j = 0; j < attribute_count; j++) { + char *attr_name = getAsciz(context, FALSE); + if ((strcmp(attr_name, "Code") == 0) + && ((mb->fb.access & (ACC_NATIVE | ACC_ABSTRACT))==0)) { + ReadInCode(context, mb); + } else if (strcmp(attr_name, "Exceptions") == 0) { + ReadExceptions(context, mb); + } else { + int length = get4bytes(context); + if (strcmp(attr_name, "Deprecated") == 0) { + if (length > 0) { + JAVA_ERROR(context, "Bad deprecated size"); + } + mb->fb.deprecated = TRUE; + } else if (strcmp(attr_name, "Synthetic") == 0) { + if (length > 0) { + JAVA_ERROR(context, "Bad synthetic attribute size"); + } + mb->fb.synthetic = TRUE; + } else { + getNbytes(context, length, NULL); + } + } + } + context->in_clinit = FALSE; + } + + /* See if there are class attributes */ + attribute_count = get2bytes(context); + for (j = 0; j < attribute_count; j++) { + char *attr_name = getAsciz(context, FALSE); + int length = get4bytes(context); + if (strcmp(attr_name, "SourceFile") == 0) { + if (length != 2) { + JAVA_ERROR(context, "Wrong size for VALUE attribute"); + } + ucb->source_name = getAsciz(context, FALSE); + } else if (strcmp(attr_name, "AbsoluteSourcePath") == 0) { + if (length == 2) { + ucb->absolute_source_name = getAsciz(context, FALSE); + } else + getNbytes(context, length, NULL); + } else if (strcmp(attr_name, "TimeStamp") == 0) { + if (length == 8) { + ucb->hasTimeStamp = TRUE; + ucb->timestamp.high = get4bytes(context); + ucb->timestamp.low = get4bytes(context); + } else { + getNbytes(context, length, NULL); + } + } else if (strcmp(attr_name, "Deprecated") == 0) { + if (length > 0) { + JAVA_ERROR(context, "Bad deprecated size"); + } + ucb->deprecated = TRUE; + } else if (strcmp(attr_name, "Synthetic") == 0) { + if (length > 0) { + JAVA_ERROR(context, "Bad synthetic attribute size"); + } + ucb->synthetic = TRUE; + } else if (strcmp(attr_name, "InnerClasses") == 0) { + int count = get2bytes(context); + struct innerClasses *thisInnerClass = (struct innerClasses *) + allocNBytes(context, count * sizeof(struct innerClasses)); + struct innerClasses *lastInnerClass = thisInnerClass + count; + + if (count * 8 + 2 != length) { + JAVA_ERROR(context, "Bad length of InnerClasses attribute"); + } + + ucb->inner_classes_count = count; + ucb->inner_classes = thisInnerClass; + + for ( ; thisInnerClass < lastInnerClass; thisInnerClass++) { + thisInnerClass->inner_class = get2bytes(context); + thisInnerClass->outer_class = get2bytes(context); + thisInnerClass->inner_name = getAsciz(context, TRUE); + thisInnerClass->access = get2bytes(context); + if (thisInnerClass->inner_class != 0) { + /* Make sure that inner_class really belongs to a CLASS */ + getAscizFromClass(context, thisInnerClass->inner_class); + } + if (thisInnerClass->outer_class != 0) { + /* Make sure that outer_class really belongs to a CLASS */ + getAscizFromClass(context, thisInnerClass->outer_class); + } + } + } else { + getNbytes(context, length, NULL); + } + } +} + + +/*========================================================================= + * FUNCTION: createFakeArrayClass + * OVERVIEW: Invoked by Locked_FindArrayClassFromClass() for creating + * a fake array class that has the specified fields. + * + * INTERFACE: + * parameters: char *: name + * int : base type + * int : depth (array dimension) + * ClassClass * : base type if T_CLASS + * struct Hjava_lang_ClassLoader *: class loader + * + * returns: ClassClass * + *=======================================================================*/ +ClassClass * +createFakeArrayClass(char *name, /* name */ + int base_type, /* base_type */ + int depth, /* array dimension */ + ClassClass *inner_cb, /* base type if T_CLASS */ + struct Hjava_lang_ClassLoader *loader) +{ + ClassClass *cb = allocClassClass(); + Classjava_lang_Class *ucb = unhand(cb); + cp_item_type *constant_pool = + sysCalloc(CONSTANT_POOL_ARRAY_LENGTH, + (sizeof(cp_item_type) + sizeof(unsigned char))); + unsigned char *type_table = (unsigned char *) + (constant_pool + CONSTANT_POOL_ARRAY_LENGTH); + sysAssert(name[0] == SIGNATURE_ARRAY); + ucb->major_version = JAVA_VERSION; + ucb->minor_version = JAVA_MINOR_VERSION; + ucb->name = strdup(name); + ucb->super_name = JAVAPKG "Object"; + ucb->constantpool = constant_pool; + ucb->constantpool_count = CONSTANT_POOL_ARRAY_LENGTH; + ucb->loader = loader; + + constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type = type_table; + constant_pool[CONSTANT_POOL_ARRAY_DEPTH_INDEX].i = depth; + constant_pool[CONSTANT_POOL_ARRAY_TYPE_INDEX].i = base_type; + type_table[CONSTANT_POOL_ARRAY_DEPTH_INDEX] = + CONSTANT_Integer | CONSTANT_POOL_ENTRY_RESOLVED; + type_table[CONSTANT_POOL_ARRAY_TYPE_INDEX] = + CONSTANT_Integer | CONSTANT_POOL_ENTRY_RESOLVED; + + if (base_type == T_CLASS) { + /* Initialize the appropriate fields of the constant pool */ + constant_pool[CONSTANT_POOL_ARRAY_CLASS_INDEX].clazz = inner_cb; + type_table[CONSTANT_POOL_ARRAY_CLASS_INDEX] = + CONSTANT_Class | CONSTANT_POOL_ENTRY_RESOLVED; + /* The class is public iff its base class is public */ + ucb->access = ACC_FINAL | ACC_ABSTRACT | + (cbAccess(inner_cb) & ACC_PUBLIC); + } else { + /* Set the class field to something innocuous */ + type_table[CONSTANT_POOL_ARRAY_CLASS_INDEX] = + CONSTANT_Integer | CONSTANT_POOL_ENTRY_RESOLVED; + ucb->access = ACC_FINAL | ACC_ABSTRACT | ACC_PUBLIC; + } + AddBinClass(cb); + return cb; +} + + +/*========================================================================= + * FUNCTION: createPrimitiveClass + * OVERVIEW: Creates a class block to represent a primitive type. + * NOTE: this is not added to the built-in class table, so + * it should only be called once per primitive type. + * See FindPrimitiveClass(). + * + * INTERFACE: + * parameters: char *: name + * char : sig + * unsigned char: typecode + * unsigned char: slotsize + * unsigned char: elementsize + * + * returns: ClassClass * + *=======================================================================*/ +ClassClass * +createPrimitiveClass(char *name, char sig, unsigned char typecode, + unsigned char slotsize, unsigned char elementsize) +{ + ClassClass *cb = allocClassClass(); + Classjava_lang_Class *ucb = unhand(cb); + + ucb->major_version = JAVA_VERSION; + ucb->minor_version = JAVA_MINOR_VERSION; + ucb->name = strdup(name); + ucb->super_name = JAVAPKG "Object"; + ucb->constantpool = NULL; + ucb->constantpool_count = 0; + ucb->loader = NULL; + ucb->access = ACC_FINAL | ACC_ABSTRACT | ACC_PUBLIC; + + CCSet(cb, Primitive); + cbTypeSig(cb) = sig; + cbTypeCode(cb) = typecode; + cbSlotSize(cb) = slotsize; + cbElementSize(cb) = elementsize; + MakeClassSticky(cb); + + return cb; +} + + +/*========================================================================= + * FUNCTION: LoadConstantPool + * OVERVIEW: Loads the constant pool given a pointer to the internal + * class file. + * + * INTERFACE: + * parameters: CICcontext *: ptr + * + * returns: nothing + *=======================================================================*/ +static void LoadConstantPool(CICcontext *context) +{ + ClassClass *cb = context->cb; + int nconstants = get2bytes(context); + cp_item_type *constant_pool; + unsigned char *type_table; + int i; + Java8 t1; + + if (nconstants > 16384) { + JAVA_ERROR(context, "Preverifier only " + "handles constant pool size up to 16K"); + } + + t1.x[0] = 0; /* shut off warning */ + if (nconstants < CONSTANT_POOL_UNUSED_INDEX) { + JAVA_ERROR(context, "Illegal constant pool size"); + } + + constant_pool = (cp_item_type *) + allocNBytes(context, nconstants * sizeof(cp_item_type)); + type_table = allocNBytes(context, nconstants * sizeof(char)); + + for (i = CONSTANT_POOL_UNUSED_INDEX; i < nconstants; i++) { + int type = get1byte(context); + CONSTANT_POOL_TYPE_TABLE_PUT(type_table, i, type); + switch (type) { + case CONSTANT_Utf8: { + int length = get2bytes(context); + char *result = allocNBytes(context, length + 1); + getNbytes(context, length, result); + result[length] = '\0'; + constant_pool[i].cp = result; + CONSTANT_POOL_TYPE_TABLE_SET_RESOLVED(type_table, i); + break; + } + + case CONSTANT_Class: + case CONSTANT_String: + constant_pool[i].i = get2bytes(context); + break; + + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + case CONSTANT_NameAndType: + constant_pool[i].i = get4bytes(context); + break; + + case CONSTANT_Float: + if (no_floating_point) { + panic("floating-point constants should not appear"); + } + + case CONSTANT_Integer: + constant_pool[i].i = get4bytes(context); + CONSTANT_POOL_TYPE_TABLE_SET_RESOLVED(type_table, i); + break; + + case CONSTANT_Double: + if (no_floating_point) { + panic("floating-point constants should not appear"); + } + case CONSTANT_Long: { + /* We ignore endian problems, and just load the two + * values. The verifier never actually cares what + * the actual value is. + */ + constant_pool[i].i = get4bytes(context); + CONSTANT_POOL_TYPE_TABLE_SET_RESOLVED(type_table, i); + i++; + if (i >= nconstants) { + JAVA_ERROR(context, "illegal constant pool entry"); + } + /* Indicate that the next object in the constant pool cannot + * be accessed independently. + */ + constant_pool[i].i = get4bytes(context); + CONSTANT_POOL_TYPE_TABLE_PUT(type_table, i, 0); + CONSTANT_POOL_TYPE_TABLE_SET_RESOLVED(type_table, i); + break; + } + + default: + JAVA_ERROR(context, "Illegal constant pool type"); + } + } + /* It is important to only set these after everything is setup, + so that the GC sees a consistent state.*/ + cbConstantPool(cb) = constant_pool; + cbConstantPoolCount(cb) = nconstants; + constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type = type_table; +} + + +/*========================================================================= + * FUNCTION: ReadInCode + * OVERVIEW: Reads the code attributes given a pointer to the internal + * class file and a pointer to the method block structure. + * This includes line number and local variable tables. + * + * INTERFACE: + * parameters: CICcontext *: ptr + * struct methodblock *: mb + * + * returns: nothing + *=======================================================================*/ +static void ReadInCode(CICcontext *context, struct methodblock *mb) +{ + int attribute_length = get4bytes(context); + unsigned char *end_ptr = context->ptr + attribute_length; + int attribute_count; + int code_length; + int i; + + if (cbMinorVersion(context->cb) == JAVA_VERSION && + cbMinorVersion(context->cb) <= 2) { + mb->maxstack = get1byte(context); + mb->nlocals = get1byte(context); + code_length = mb->code_length = get2bytes(context); + } else { + mb->maxstack = get2bytes(context); + mb->nlocals = get2bytes(context); + code_length = mb->code_length = get4bytes(context); + } + if (mb->nlocals < mb->args_size) + JAVA_ERROR(context, "Arguments can't fit into locals"); + + if (code_length > 65535) { + JAVA_ERROR(context, "Byte code size exceeds 65535 bytes"); + } + + mb->code = allocNBytes(context, code_length); + + getNbytes(context, code_length, (char *)mb->code); + if ((mb->exception_table_length = get2bytes(context)) > 0) { + unsigned exception_table_size = mb->exception_table_length + * sizeof(struct CatchFrame); + mb->exception_table = allocNBytes(context, exception_table_size); + for (i = 0; i < (int)mb->exception_table_length; i++) { + mb->exception_table[i].start_pc = get2bytes(context); + mb->exception_table[i].end_pc = get2bytes(context); + mb->exception_table[i].handler_pc = get2bytes(context); + mb->exception_table[i].catchType = get2bytes(context); + mb->exception_table[i].compiled_CatchFrame = NULL; + } + } + attribute_count = get2bytes(context); + for (i = 0; i < attribute_count; i++) { + char *name = getAsciz(context, FALSE); + if (strcmp(name, "LineNumberTable") == 0) { + ReadLineTable(context, mb); + } else if (strcmp(name, "LocalVariableTable") == 0) { + ReadLocalVars(context, mb); + } else { + int length = get4bytes(context); + getNbytes(context, length, NULL); + } + } + if (context->ptr != end_ptr) + JAVA_ERROR(context, "Code segment was wrong length"); +} + + +/*========================================================================= + * FUNCTION: ReadLineTable + * OVERVIEW: Reads the line number table given a pointer to the internal + * class file and a pointer to the method block structure. + * + * INTERFACE: + * parameters: CICcontext *: ptr + * struct methodblock *: mb + * + * returns: nothing + *=======================================================================*/ +static void ReadLineTable(CICcontext *context, struct methodblock *mb) +{ + int attribute_length = get4bytes(context); + unsigned char *end_ptr = context->ptr + attribute_length; + int i; + if ((mb->line_number_table_length = get2bytes(context)) > 0) { + struct lineno *ln = + allocNBytes(context, mb->line_number_table_length * + sizeof(struct lineno)); + mb->line_number_table = ln; + for (i = mb->line_number_table_length; --i >= 0; ln++) { + ln->pc = get2bytes(context); + ln->line_number = get2bytes(context); + } + } + if (context->ptr != end_ptr) + JAVA_ERROR(context, "Line number table was wrong length?"); +} + + + +/*========================================================================= + * FUNCTION: ReadLocalVars + * OVERVIEW: Reads the localvar table given a pointer to the internal + * class file and a pointer to the method block structure. + * + * INTERFACE: + * parameters: CICcontext *: ptr + * struct methodblock *: mb + * + * returns: nothing + *=======================================================================*/ +static void ReadLocalVars(CICcontext *context, struct methodblock *mb) +{ + int attribute_length = get4bytes(context); + unsigned char *end_ptr = context->ptr + attribute_length; + int i; + if ((mb->localvar_table_length = get2bytes(context)) > 0) { + struct localvar *lv = + allocNBytes(context, mb->localvar_table_length * + sizeof(struct localvar)); + mb->localvar_table = lv; + for (i = mb->localvar_table_length; --i >= 0; lv++) { + lv->pc0 = get2bytes(context); + lv->length = get2bytes(context); + lv->name = getAsciz(context, FALSE); + lv->signature = getAsciz(context, FALSE); + lv->slot = get2bytes(context); + } + } + if (context->ptr != end_ptr) + JAVA_ERROR(context, "Local variables table was wrong length?"); +} + + +/*========================================================================= + * FUNCTION: ReadExceptions + * OVERVIEW: Reads the Exception attribute given a pointer to the internal + * class file and a pointer to the method block structure. + * + * INTERFACE: + * parameters: CICcontext *: ptr + * struct methodblock *: mb + * + * returns: nothing + *=======================================================================*/ +static void +ReadExceptions(CICcontext *context, struct methodblock *mb) +{ + int attribute_length = get4bytes(context); + unsigned char *end_ptr = context->ptr + attribute_length; + unsigned short nexceptions = get2bytes(context); + + if ((mb->nexceptions = nexceptions) > 0) { + unsigned short *ep, *exceptions = + allocNBytes(context, nexceptions * sizeof (unsigned short)); + mb->exceptions = ep = exceptions; + while (nexceptions-- > 0) { + *ep++ = get2bytes(context); + } + } + if (context->ptr != end_ptr) + JAVA_ERROR(context, "Exceptions attribute has wrong length"); +} + + +/*========================================================================= + * FUNCTION: Signature2ArgsSize + * OVERVIEW: Returns the size of arguments given a pointer to a method + * signature. + * + * INTERFACE: + * parameters: char*: method_signature + * + * returns: unsigned + *=======================================================================*/ +unsigned Signature2ArgsSize(char *method_signature) +{ + char *p; + int args_size = 0; + for (p = method_signature; *p != SIGNATURE_ENDFUNC; p++) { + switch (*p) { + case SIGNATURE_FLOAT: + if (no_floating_point) { + panic("floating-point arguments should not appear"); + } + + case SIGNATURE_BOOLEAN: + case SIGNATURE_BYTE: + case SIGNATURE_CHAR: + case SIGNATURE_SHORT: + case SIGNATURE_INT: + args_size += 1; + break; + + case SIGNATURE_CLASS: + args_size += 1; + while (*p != SIGNATURE_ENDCLASS) p++; + break; + + case SIGNATURE_ARRAY: + args_size += 1; + while ((*p == SIGNATURE_ARRAY)) p++; + /* If an array of classes, skip over class name, too. */ + if (*p == SIGNATURE_CLASS) { + while (*p != SIGNATURE_ENDCLASS) + p++; + } + break; + + case SIGNATURE_DOUBLE: + if (no_floating_point) { + panic("floating-point arguments should not appear"); + } + + case SIGNATURE_LONG: + args_size += 2; + break; + + case SIGNATURE_FUNC: /* ignore initial (, if given */ + break; + + default: /* Indicates an error. */ + return 0; + } + } + return args_size; +} + + +/*========================================================================= + * FUNCTION: free_clinit_memory + * OVERVIEW: Frees clinit memory. + * + * INTERFACE: + * parameters: struct methodblock *: mb + * + * returns: nothing + *=======================================================================*/ +void free_clinit_memory(struct methodblock *mb) +{ + /* This function is somewhat a hack. It fixes the problem in 1.1.3 + * and before. sysFree may be called on the wrong memory block if + * the exception attribute comes before the code attribute. + */ + /* If there is no exceptions attribute, or if both have already + * been freed. + */ + if (mb->exceptions == NULL) { + if (mb->code) { + sysFree(mb->code); + mb->code = NULL; + } + return; + } + + /* If both attributes exist, free the one at the lower address */ + if ((char *)mb->code < (char *)mb->exceptions) + sysFree(mb->code); + else + sysFree(mb->exceptions); + + mb->code = NULL; + mb->exceptions = NULL; +} + + +/*========================================================================= + * FUNCTION: FreeClass + * OVERVIEW: Frees class. + * + * INTERFACE: + * parameters: ClassClass *: cb + * + * returns: nothing + *=======================================================================*/ +void FreeClass(ClassClass *cb) +{ + int i; + struct methodblock *mb; + + for (i = cbMethodsCount(cb), mb = cbMethods(cb); --i >= 0; mb++) { + if (strcmp(mb->fb.name, "") == 0 && + strcmp(mb->fb.signature, "()V") == 0 && + mb->code_length /* not external */ ) + free_clinit_memory(mb); + } + + sysFree(cbConstantPool(cb)); + + sysFree(cbMethodTableMem(cb)); + sysFree(cbSlotTable(cb)); + + /* Interface method tables can be shared between child and + * super classes. + */ + if (cbImplementsCount(cb) != 0 || cbIsInterface(cb)) + sysFree(cbIntfMethodTable(cb)); +} + + +/*========================================================================= + * FUNCTION: get1byte + * OVERVIEW: Gets one byte from the class file. + * + * INTERFACE: + * parameters: CICcontext *: context + * + * returns: value read or 0 if an error occurred. + *=======================================================================*/ +static unsigned char get1byte(CICcontext *context) +{ + unsigned char *ptr = context->ptr; + if (context->end_ptr - ptr < 1) { + JAVA_ERROR(context, "Truncated class file"); + return 0; + } else { + unsigned char *ptr = context->ptr; + unsigned char value = ptr[0]; + (context->ptr) += 1; + return value; + } +} + + +/*========================================================================= + * FUNCTION: get2bytes + * OVERVIEW: Gets two bytes from the class file. + * + * INTERFACE: + * parameters: CICcontext *: context + * + * returns: value read or 0 if an error occurred. + *=======================================================================*/ +static unsigned short get2bytes(CICcontext *context) +{ + unsigned char *ptr = context->ptr; + if (context->end_ptr - ptr < 2) { + JAVA_ERROR(context, "Truncated class file"); + return 0; + } else { + unsigned short value = (ptr[0] << 8) + ptr[1]; + (context->ptr) += 2; + return value; + } +} + + +/*========================================================================= + * FUNCTION: get4bytes + * OVERVIEW: Gets four bytes from the class file. + * + * INTERFACE: + * parameters: CICcontext *: context + * + * returns: value read or 0 if an error occurred. + *=======================================================================*/ +static unsigned long get4bytes(CICcontext *context) +{ + unsigned char *ptr = context->ptr; + if (context->end_ptr - ptr < 4) { + JAVA_ERROR(context, "Truncated class file"); + return 0; + } else { + unsigned long value = (ptr[0] << 24) + (ptr[1] << 16) + + (ptr[2] << 8) + ptr[3]; + (context->ptr) += 4; + return value; + } +} + + +/*========================================================================= + * FUNCTION: getNbytes + * OVERVIEW: Gets N bytes from the class file specified by the count + * parameter. If buffer is not null, it will also copy the + * count number of bytes read into the buffer as well. + * Note that this function seems to be always invoked with + * a NULL argument for the buffer, except when it loads the + * UTF8 entry from the constant pool and when the code + * attribute is loaded. + * + * INTERFACE: + * parameters: CICcontext *: context + * int: count + * char *: buffer + * + * returns: nothing + *=======================================================================*/ +static void getNbytes(CICcontext *context, int count, char *buffer) +{ + unsigned char *ptr = context->ptr; + if (context->end_ptr - ptr < count) + JAVA_ERROR(context, "Truncated class file"); + if (buffer != NULL) + memcpy(buffer, ptr, count); + (context->ptr) += count; +} + + +/*========================================================================= + * FUNCTION: getAsciz + * OVERVIEW: Reads the next two bytes and uses this value to look up for + * the corresponding constant pool entry. + * Returns null if the value is 0 and zeroOkay flag is set. + * + * INTERFACE: + * parameters: CICcontext *: context + * bool_t : zeroOkay + * + * returns: char * or NULL + *=======================================================================*/ +static char *getAsciz(CICcontext *context, bool_t zeroOkay) +{ + ClassClass *cb = context->cb; + union cp_item_type *constant_pool = cbConstantPool(cb); + int nconstants = cbConstantPoolCount(cb); + unsigned char *type_table = + constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type; + + int value = get2bytes(context); + if (value == 0 && zeroOkay) { + return NULL; + } else if ((value == 0) || (value >= nconstants) || + type_table[value] != (CONSTANT_Utf8 | CONSTANT_POOL_ENTRY_RESOLVED)) + JAVA_ERROR(context, "Illegal constant pool index"); + return constant_pool[value].cp; +} + + +/*========================================================================= + * FUNCTION: getAscizFromClass + * OVERVIEW: Given the constant pool index, returns the name of the class + * which corresponds to this constant pool entry. + * + * INTERFACE: + * parameters: CICcontext *: context + * int: value + * + * returns: char * or NULL + *=======================================================================*/ +static char *getAscizFromClass(CICcontext *context, int value) +{ + ClassClass *cb = context->cb; + union cp_item_type *constant_pool = cbConstantPool(cb); + int nconstants = cbConstantPoolCount(cb); + unsigned char *type_table = + constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type; + if ((value > 0) && (value < nconstants)) { + if (type_table[value] == CONSTANT_Class) { + value = constant_pool[value].i; + if ((value <= 0) || (value >= nconstants) || + (type_table[value] != (CONSTANT_Utf8 | + CONSTANT_POOL_ENTRY_RESOLVED))) + JAVA_ERROR(context, "Illegal constant pool index"); + return constant_pool[value].cp; + } else if (type_table[value] == (CONSTANT_Class | + CONSTANT_POOL_ENTRY_RESOLVED)) { + ClassClass *cb = constant_pool[value].clazz; + return cbName(cb); + } else { + JAVA_ERROR(context, "Illegal constant pool index"); + } + } else { + JAVA_ERROR(context, "Illegal constant pool index"); + } + return NULL; /* not reached */ +} + +/* In order to avoid possible alignment errors, round up all sizes to + * multiples of eight. + */ +#define ROUNDUP_SIZE(s) while ((s) % 8 != 0) (s)++ + + +/*========================================================================= + * FUNCTION: allocNBytes + * OVERVIEW: Memory allocation function for internal class file + * structures. + * It calculates the number of allocations needed for the + * two passes, and the allocations required for the clinit + * method. + * + * INTERFACE: + * parameters: CICcontext *: context + * int : size + * + * returns: void * + *=======================================================================*/ +static void *allocNBytes(CICcontext *context, int size) +{ + void *result; + if (context->pass == 1) { + /* The first pass + * A more sophisticated scheme could reduce the number of mallocs. + */ + CICmallocs *mallocs = + (CICmallocs *)sysCalloc(1, sizeof(CICmallocs) + size); + if (mallocs == 0) + JAVA_ERROR(context, "out of memory"); + result = (void *)(mallocs + 1); + mallocs->next = context->pass1.mallocs; + ROUNDUP_SIZE(size); + if (context->in_clinit) + context->clinit_size += size; + else + context->malloc_size += size; + context->pass1.mallocs = mallocs; + } else { + /* The second pass */ + + ROUNDUP_SIZE(size); + +#define ALLOC_BLOCK(ptr,buf,sizelimit) \ + result = (ptr); \ + (ptr) += (size); \ + sysAssert((ptr) <= (buf) + (sizelimit)) + + if (context->in_clinit) { + /* Make sure that this clinit pointer is not null */ + sysAssert(context->pass2.clinit_ptr != NULL); + + ALLOC_BLOCK(context->pass2.clinit_ptr, + context->pass2.clinit_buffer, + context->clinit_size*sizeof(char)); + + } else { + + /* Make sure that this malloc pointer is not null */ + sysAssert(context->pass2.malloc_ptr != NULL); + + ALLOC_BLOCK(context->pass2.malloc_ptr, + context->pass2.malloc_buffer, + context->malloc_size); + } + } + return result; +} + + +/*========================================================================= + * FUNCTION: freeBuffers + * OVERVIEW: Frees buffers allocated by allocNBytes(). + * + * INTERFACE: + * parameters: CICcontext *: context + * + * returns: nothing + *=======================================================================*/ +static void freeBuffers(CICcontext * context) +{ + if (context->pass == 1) { + CICmallocs *mallocs = context->pass1.mallocs; + + while (mallocs) { + CICmallocs *tmp = mallocs; + mallocs = mallocs->next; + if (tmp != NULL) { + sysFree(tmp); + } + } + context->pass1.mallocs = 0; + } else { /* context->pass = 2 */ + +/* Note: this code is here just for historical reasons. Actually, these + * buffers cannot really be freed here since the data in them is still + * pointed to by the class buffer (cb) and we are not yet done loading + * the class. If the class loading fails, FreeClass() will free the method + * blocks and the clinit memory. + */ + if (context->pass2.malloc_buffer != NULL) { + sysFree(context->pass2.malloc_buffer); + /* Reset only if buffer was freed */ + context->pass2.malloc_buffer = 0; + } + + if (context->pass2.clinit_buffer != NULL) { + sysFree(context->pass2.clinit_buffer); + /* Initialize only if buffer was freed */ + context->pass2.clinit_buffer = 0; + } + } +} + + +/*========================================================================= + * FUNCTION: GetClassConstantClassName + * OVERVIEW: Returns class name corresponding to the constant pool entry + * for the given cpIndex. This is desirable in cases when we + * may simply be interested in the name of the class, but may + * not necessarily want to resolve the class reference if it + * isn't already. + * + * INTERFACE: + * parameters: cp_item_type *: constant pool + * int : index + * + * returns: char *: class name + *=======================================================================*/ +char *GetClassConstantClassName(cp_item_type *constant_pool, int index) +{ + unsigned char *type_table = + constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type; + switch(type_table[index]) { + case CONSTANT_Class | CONSTANT_POOL_ENTRY_RESOLVED: { + ClassClass *cb = constant_pool[index].clazz; + return cbName(cb); + } + + case CONSTANT_Class: { + int name_index = constant_pool[index].i; + return constant_pool[name_index].cp; + } + + default: + return (char *)0; + } +} + diff --git a/MPC.3.5.LINUX/preverifier/classresolver.c b/MPC.3.5.LINUX/preverifier/classresolver.c new file mode 100644 index 0000000..64df7df --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/classresolver.c @@ -0,0 +1,1269 @@ +/* + * @(#)classresolver.c 1.19 02/09/27 + * + * Copyright 1995-1998 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +/*========================================================================= + * SYSTEM: Verifier + * SUBSYSTEM: class resolver.c. + * FILE: classresolver.c + * OVERVIEW: Routines for loading and resolving class definitions. + * These routines should not be depending upon the interpreter + * or the garbage collector. + * AUTHOR: Sheng Liang, Sun Microsystems, Inc. + * Modifications for CLDC compliance checks, + * Tasneem Sayeed, Sun Microsystems + * Frank Yellin, Sun Microsystems + *=======================================================================*/ + +/*========================================================================= + * Include files + *=======================================================================*/ + +#include +#include +#include +#include +#include +#include + +#include "oobj.h" +#include "tree.h" +#include "signature.h" +#include "path.h" +#include "sys_api.h" +#include "convert_md.h" + +/*========================================================================= + * Globals and extern declarations + *=======================================================================*/ + +ClassClass *classJavaLangObject; +ClassClass *classJavaLangClass = 0; +ClassClass *classJavaLangString; +ClassClass *classJavaLangThrowable; +ClassClass *classJavaLangError; +ClassClass *classJavaLangException; +ClassClass *classJavaLangRuntimeException; +ClassClass *classJavaLangThreadDeath; + +ClassClass *interfaceJavaLangCloneable; +ClassClass *interfaceJavaIoSerializable; + +bool_t inline_jsr_on = TRUE; + +static bool_t RunClinit(ClassClass * cb); + +static ClassClass *InitializeAndResolveClass(ClassClass *cb, bool_t resolve); +static char *Locked_InitializeClass(ClassClass * cb, char **detail); +static char *Locked_LinkClass(ClassClass * cb, char **detail); +char * LinkClass(ClassClass *cb, char **detail); +static ClassClass *FindLoadedClass(char *name, + struct Hjava_lang_ClassLoader *loader); +static ClassClass *Locked_FindArrayClassFromClass(struct execenv *ee, + char *name, + ClassClass *from); +static void InitPrimitiveClasses(); + +/* An Explanation of Class-related Locks + * + * There are two global locks related to class loading: + * + * LOADCLASS_LOCK: ensures that only one thread is loading a class at + * a given time. This eliminates the possibility of two threads loading + * classes with the same name and same loader. + * + * BINCLASS_LOCK: ensures that only one thread is updating the global + * class table (binclasses). This lock is also grabbed by the GC to ensure + * that the GC always sees a valid global class table state. + * + * In addition, each class may have its own associated locks that are + * created with monitorEnter(). ResolveClass, for example, need to + * first grab this lock to ensure that the class is resolved only by + * one thread, rather than simultaneously by multiple threads. + */ + +sys_mon_t *_loadclass_lock; +sys_mon_t *_binclass_lock; + +static struct fieldblock ** +addslots(struct fieldblock ** fb, ClassClass * cb) +{ + long n = cbFieldsCount(cb); + struct fieldblock *sfb = cbFields(cb); + if (cbSuperclass(cb)) + fb = addslots(fb, cbSuperclass(cb)); + while (--n >= 0) { + *fb++ = sfb; + sfb++; + } + return fb; +} + +int +Locked_makeslottable(ClassClass * clb) +{ + ClassClass *sclb; + int nslots = 0; + + if (cbSlotTable(clb)) { + return SYS_OK; + } + sclb = clb; + while (sclb) { + long n = cbFieldsCount(sclb); + struct fieldblock *fb = cbFields(sclb); + while (--n >= 0) { + nslots++; + fb++; + } + if (cbSuperclass(sclb) == 0) { + break; + } + sclb = cbSuperclass(sclb); + } + cbSlotTableSize(clb) = nslots; + if (nslots == 0) { + nslots++; + } + cbSlotTable(clb) = (struct fieldblock **) + sysMalloc(nslots * sizeof(struct fieldblock *)); + if (cbSlotTable(clb) == 0) { + return SYS_NOMEM; + } + addslots(cbSlotTable(clb), clb); + return SYS_OK; +} + +int +makeslottable(ClassClass * clb) +{ + int result; + LOADCLASS_LOCK(); + result = Locked_makeslottable(clb); + LOADCLASS_UNLOCK(); + return result; +} + +#if 0 +static char * +copyclassname(char *src, char *dst) +{ + sysAssert(*src == SIGNATURE_CLASS); + src++; + while (*src && *src != SIGNATURE_ENDCLASS) + *dst++ = *src++; + *dst = 0; + return src; +} +#endif + +static char * +ResolveFields(ClassClass *cb, unsigned slot) +{ + struct fieldblock *fb; + int size; + + fb = cbFields(cb); + for (size = 0; size < (int) cbFieldsCount(cb); size++, fb++) { + char *signature = fieldsig(fb); + int size = (((signature[0] == SIGNATURE_LONG || + signature[0] == SIGNATURE_DOUBLE)) ? 2 : 1); + fb->ID = NameAndTypeToHash(fb->name, signature); + if (fb->access & ACC_STATIC) { + /* Do nothing. Handled when the class is loaded. */ + } else { + fb->u.offset = slot; + slot += size * sizeof(OBJECT); + } +#ifdef UNUSED + if ((fb->access & (ACC_STATIC | ACC_TRANSIENT)) == 0) { + for (s = fieldname(fb); (c = *s++) != 0;) + thishash = thishash * 7 + c; + for (s = fieldsig(fb); (c = *s++) != 0;) + thishash = thishash * 7 + c; + } +#endif + } + if (slot > 65535) { + return "java/lang/InternalError"; + } + + cbInstanceSize(cb) = slot; +#ifdef UNUSED + cbThisHash(cb) = thishash; + if (cbSuperclass(cb)) + cbTotalHash(cb) = thishash - cbTotalHash(unhand(cbSuperclass(cb))); + else + cbTotalHash(cb) = thishash; + if (cbTotalHash(cb) < N_TYPECODES) + cbTotalHash(cb) += N_TYPECODES; +#endif + return NULL; +} + + +static char * +ResolveMethods(ClassClass *cb) +{ + struct methodblock *mb; + int size; + struct methodtable *new_table; + struct methodblock **super_methods; + int mslot, super_methods_count; + void *ptr; + static unsigned finalizerID = 0; + + if (finalizerID == 0) + finalizerID = NameAndTypeToHash(FINALIZER_METHOD_NAME, + FINALIZER_METHOD_SIGNATURE); + mb = cbMethods(cb); + for (size = 0; size < (int) cbMethodsCount(cb); size++, mb++) { + mb->fb.ID = NameAndTypeToHash(mb->fb.name, mb->fb.signature); + mb->fb.u.offset = 0; + mb->invoker = 0; + } + + if (cbIsInterface(cb)) { + /* We don't really need to built a method table for interfaces. */ + cbMethodTable(cb) = NULL; + cbMethodTableSize(cb) = 0; + mb = cbMethods(cb); + /* Each method's offset is its index in the interface */ + for (size = 0; size < (int) cbMethodsCount(cb); size++, mb++) { + mb->fb.u.offset = size; + } + return NULL; + } + + if (cbSuperclass(cb) != NULL) { + ClassClass *super = cbSuperclass(cb); + mslot = cbMethodTableSize(super); + super_methods = cbMethodTable(super)->methods; + super_methods_count = cbMethodTableSize(super); + /* Inherit one's parent's finalizer, if it has one */ + cbFinalizer(cb) = cbFinalizer(cbSuperclass(cb)); + } else { + mslot = 1; + super_methods = NULL; + super_methods_count = 0; + cbFinalizer(cb) = NULL; + } + + mb = cbMethods(cb); + for (size = 0; size < (int) cbMethodsCount(cb); size++, mb++) { + unsigned long ID = mb->fb.ID; + struct methodblock **super_methods_p; + int count; + + if ((mb->fb.access & ACC_STATIC) || (mb->fb.access & ACC_PRIVATE)) + continue; + if (strcmp(mb->fb.name, "") == 0) + continue; + + /* If this item has its own finalizer method, grab it */ + if (mb->fb.ID == finalizerID) { + if (no_finalizers) { + panic("finalize methods should not appear"); + } + cbFinalizer(cb) = mb; + } + + for (super_methods_p = super_methods, count = super_methods_count; + count > 0; + super_methods_p++, count--) { + if ((*super_methods_p != NULL) && ((*super_methods_p)->fb.ID == ID)) { + /* Private methods are not inherited outside of the class. */ + if ((*super_methods_p)->fb.access & ACC_PRIVATE) + continue; + /* Package-private methods are not inherited outside of the + package. */ + if (((*super_methods_p)->fb.access & ACC_PROTECTED) || + ((*super_methods_p)->fb.access & ACC_PUBLIC) || + IsSameClassPackage((*super_methods_p)->fb.clazz, cb)) { + mb->fb.u.offset = (*super_methods_p)->fb.u.offset; + break; + } + /* + jio_fprintf(stderr, "!!!%s.%s\n", cbName(cb), mb->fb.name); + */ + } + } + + if (mb->fb.u.offset == 0) { + mb->fb.u.offset = mslot; + mslot++; + } + } + + if (mslot > 65535) { + return "java/lang/InternalError"; + } + + /* + * This should be the only place that method tables are + * allocated. We allocate more than we need here and mask the + * resulting pointer because the methodtable pointer field in + * object handles is overloaded and sometimes hold array types + * and array lengths. We must ensure that method table pointers + * are allocated on an appropriate boundary so we don't lose any + * address bits when we mask off the type portion of the pointer. + */ + ptr = sysMalloc(sizeof(struct methodtable) + + (mslot - 1)* sizeof(struct methodblock *) + + FLAG_MASK); + if (ptr == NULL) { + CCSet(cb, Error); + return JAVAPKG "OutOfMemoryError"; + } + cbMethodTableMem(cb) = ptr; + new_table = (struct methodtable *)((((long)ptr) + FLAG_MASK) & LENGTH_MASK); + new_table->classdescriptor = cb; + memset((char *)new_table->methods, 0, mslot * sizeof(struct methodblock *)); + if (super_methods) + memcpy((char *) new_table->methods, + (char *) super_methods, + super_methods_count * sizeof(struct methodblock *)); + mb = cbMethods(cb); + for (size = 0; size < (int) cbMethodsCount(cb); size++, mb++) { + int offset = (int)mb->fb.u.offset; + if (offset > 0) { + sysAssert(offset < mslot); + mt_slot(new_table, offset) = mb; + } + } + cbMethodTable(cb) = new_table; + cbMethodTableSize(cb) = mslot; + + return NULL; +} + + +static char * +ResolveInterfaces(ClassClass *cb, char **detail) +{ + const int ITEM_SIZE = sizeof(cbIntfMethodTable(cb)->itable[0]); + bool_t isInterface = cbIsInterface(cb); + if (cbImplementsCount(cb) == 0 && !isInterface) { + /* classes that don't implement their own interfaces can just inherit + * their parents imethodtable. */ + if (cb == classJavaLangObject) { + /* We can preinitialize the imethodtable of java.lang.Object */ + static struct imethodtable t = { 0 }; + cbIntfMethodTable(cb) = &t; + } else { + ClassClass *super = cbSuperclass(cb); + cbIntfMethodTable(cb) = cbIntfMethodTable(super); + } + return NULL; + } else { + cp_item_type *constant_pool = cbConstantPool(cb); + ClassClass *super = cbSuperclass(cb); + unsigned char *mallocSpace, *mallocSpaceEnd; + ClassClass *icb; /* temporary */ + struct imethodtable *super_itable = cbIntfMethodTable(super); + struct imethodtable *this_itable = NULL; + int super_itable_count = super_itable->icount; + int i, j, k, icount, mcount; + + /* Resolve all the interfaces that this class implements, and + * make sure that they all really are interfaces + * + * icount will total all the interfaces that this class implements, + * (include interfaces implemented by our superclass, and by + * interfaces that we implement.) + * mcount will total the total amount of space (in sizeof(long)) for + * which we'll have to allocate space for in the offsets table. + */ + icount = super_itable_count + (isInterface ? 1 : 0); + mcount = 0; + for (i = 0; i < (int)(cbImplementsCount(cb)); i++) { + int interface_index = cbImplements(cb)[i]; + struct imethodtable *sub_itable; + + icb = constant_pool[interface_index].clazz; + if (!cbIsInterface(icb)) { + *detail = "Implementing class"; + return JAVAPKG "IncompatibleClassChangeError"; + } + sub_itable = cbIntfMethodTable(icb); + icount += sub_itable->icount; + if (!isInterface) + for (j = sub_itable->icount; --j >= 0; ) + mcount += cbMethodsCount(sub_itable->itable[j].classdescriptor); + } + + { + int this_itable_size = + offsetof(struct imethodtable, itable) + icount * ITEM_SIZE; + int offsets_size = mcount * sizeof(unsigned long); + mallocSpace = sysMalloc(this_itable_size + offsets_size); + if (mallocSpace == NULL) { + return JAVAPKG "OutOfMemoryError"; + } + mallocSpaceEnd = mallocSpace + this_itable_size + offsets_size; + this_itable = (struct imethodtable *)mallocSpace; + mallocSpace += this_itable_size; + sysAssert(mallocSpace <= mallocSpaceEnd); + } + + cbIntfMethodTable(cb) = this_itable; + + /* Start filling in the table. */ + icount = 0; + if (isInterface) { + this_itable->itable[icount].classdescriptor = cb; + this_itable->itable[icount].offsets = NULL; + icount++; + } + if (super_itable_count > 0) { + /* We can copy our superclass's offset table. The offsets + will stay the same. */ + memcpy(&this_itable->itable[icount], + &super_itable->itable[0], + super_itable_count * ITEM_SIZE); + icount += super_itable_count; + } + for (i = 0; i < (int)(cbImplementsCount(cb)); i++) { + /* Add the interfaces that we implement, either directly, or + * because those interfaces implement other interfaces. */ + int interface_index = cbImplements(cb)[i]; + icb = constant_pool[interface_index].clazz; + memcpy(&this_itable->itable[icount], + &cbIntfMethodTable(icb)->itable[0], + cbIntfMethodTable(icb)->icount * ITEM_SIZE); + icount += cbIntfMethodTable(icb)->icount; + } + sysAssert(!isInterface || super_itable_count == 0); + /* Delete duplicates from the table. This is very rare, so it can + * be quite inefficient. */ + for (i = (isInterface ? 1 : super_itable_count); i < icount; i++) { + icb = this_itable->itable[i].classdescriptor; + for (j = 0; j < i; j++) { + if (icb == this_itable->itable[j].classdescriptor) { + /* We have an overlap. Item i is a duplicate. Delete from + * the table */ + for (k = i + 1; k < icount; k++) + this_itable->itable[k - 1] = this_itable->itable[k]; + icount--; + i--; /* Reconsider this entry! */ + break; + } + } + } + this_itable->icount = icount; + if (isInterface || cbIsAbstract(cb)) { + /* Nothing more to do for interfaces or abstract classes */ + return NULL; + } + + /* For each additional interface . . . */ + for (i = super_itable_count; i < icount; i++) { + /* The table length is the number of interface methods */ + ClassClass *intfi = this_itable->itable[i].classdescriptor; + int intfi_count = cbMethodsCount(intfi); + unsigned long *offsets = (unsigned long *)mallocSpace; + mallocSpace += intfi_count * sizeof(unsigned long); + sysAssert(mallocSpace <= mallocSpaceEnd); + this_itable->itable[i].offsets = offsets; + /* Look at each interface method */ + for (j = 0; j < intfi_count; j++) { + struct methodblock *imb = cbMethods(intfi) + j; + if ((imb->fb.access & ACC_STATIC) != 0) { + sysAssert(!strcmp(imb->fb.name, "")); + offsets[j] = 0; + } else { + /* Find the class method that implements the interface + * method */ + unsigned ID = imb->fb.ID; + struct methodblock **mbt = cbMethodTable(cb)->methods; + for (k = cbMethodTableSize(cb) - 1; k >= 0; --k) { + struct methodblock *mb = mbt[k]; + if (mb != NULL + && mb->fb.ID == ID && IsPublic(mb->fb.access)) { + offsets[j] = mb->fb.u.offset; + break; + } + } + /* + if (k == -1) { + *detail = "Unimplemented interface method"; + return JAVAPKG "IncompatibleClassChangeError"; + } + */ + } + } + } + return NULL; + } +} + + +char * +InitializeClass(ClassClass * cb, char **detail) +{ + char *result; + monitorEnter(obj_monitor(cb)); + result = Locked_InitializeClass(cb, detail); + monitorExit(obj_monitor(cb)); + return result; +} + + +char * +ResolveClass(ClassClass *cb, char **detail) +{ + char *result; + if (CCIs(cb, Resolved)) + return 0; + result = LinkClass(cb, detail); + if (result == 0) { + if (!RunClinit(cb)) { + result = JAVAPKG "ExceptionInInitializerError"; + *detail = cbName(cb); + } + } + return result; +} + +char * +LinkClass(ClassClass *cb, char **detail) +{ + char *result; + if (CCIs(cb, Linked)) + return 0; + monitorEnter(obj_monitor(cb)); + result = Locked_LinkClass(cb, detail); + monitorExit(obj_monitor(cb)); + return result; +} + +/* + * Detect class circularities from InitializeClass() + */ + +static void +pushSeen(ExecEnv *ee, struct seenclass *seen) +{ + struct seenclass *prev = ee->seenclasses.next; + ee->seenclasses.next = seen; + seen->next = prev; +} + +static void +popSeen(ExecEnv *ee, struct seenclass *seen) +{ + if (seen != ee->seenclasses.next) /* paranoia */ + panic("popSeen: corrupt seen class stack"); + ee->seenclasses.next = ee->seenclasses.next->next; +} + +static bool_t +checkSeen(ExecEnv *ee, ClassClass *cb) +{ + struct seenclass *seen = ee->seenclasses.next; + while (seen) { + if (cb == seen->cb) + return TRUE; + seen = seen->next; + } + return FALSE; +} + +static char * +Locked_InitializeClass(ClassClass * cb, char **detail) +{ + ClassClass *super = 0; + char *ret = 0; + bool_t noLoader; + int i; + char buff[BUFSIZ]; + char *nativeName = &buff[0]; + + if (CCIs(cb, Initialized)) + return NULL; + +#ifndef TRIMMED + if (verbose) + jio_fprintf(stderr, "[Initializing %s]\n", cbName(cb)); +#endif + + noLoader = (cbLoader(cb) == 0); + if (cbFieldsCount(cb) > 2000) { + return JAVAPKG "ClassFormatError"; + } + if ((strcmp(cbName(cb), CLS_RESLV_INIT_CLASS) == 0) && noLoader) { + /* Temporarily disable class circularity checks */ + ExecEnv *ee = EE(); + struct seenclass *save = ee->seenclasses.next; + ee->seenclasses.next = NULL; + /* Note: don't bother restoring on (fatal) error during bootstrap */ + + classJavaLangClass = cb; + MakeClassSticky(cb); + classJavaLangString = + FindStickySystemClass(NULL, JAVAPKG "String", TRUE); + if (classJavaLangString == 0) { + *detail = JAVAPKG "String"; + return JAVAPKG "NoClassDefFoundError"; + } +/* classJavaLangThreadDeath = + FindStickySystemClass(NULL, JAVAPKG "ThreadDeath", TRUE); + if (classJavaLangThreadDeath == 0) { + *detail = JAVAPKG "ThreadDeath"; + return JAVAPKG "NoClassDefFoundError"; + } + */ + classJavaLangThrowable = + FindStickySystemClass(NULL, JAVAPKG "Throwable", TRUE); + if (classJavaLangThrowable == 0) { + *detail = JAVAPKG "Throwable"; + return JAVAPKG "NoClassDefFoundError"; + } + /* + classJavaLangException = + FindStickySystemClass(NULL, JAVAPKG "Exception", TRUE); + if (classJavaLangException == 0) { + *detail = JAVAPKG "Exception"; + return JAVAPKG "NoClassDefFoundError"; + } + classJavaLangError = + FindStickySystemClass(NULL, JAVAPKG "Error", TRUE); + if (classJavaLangError == 0) { + *detail = JAVAPKG "Error"; + return JAVAPKG "NoClassDefFoundError"; + } + classJavaLangRuntimeException = + FindStickySystemClass(NULL, JAVAPKG "RuntimeException", TRUE); + if (classJavaLangRuntimeException == 0) { + *detail = JAVAPKG "RuntimeException"; + return JAVAPKG "NoClassDefFoundError"; + } + interfaceJavaLangCloneable = + FindStickySystemClass(NULL, JAVAPKG "Cloneable", TRUE); + if (interfaceJavaLangCloneable == 0) { + *detail = JAVAPKG "Cloneable"; + return JAVAPKG "NoClassDefFoundError"; + } + interfaceJavaIoSerializable = + FindStickySystemClass(NULL, "java/io/Serializable", TRUE); + if (interfaceJavaIoSerializable == 0) { + *detail = "java/io/Serializable"; + return JAVAPKG "NoClassDefFoundError"; + } +*/ + /* Restore stack for class circularity checks */ + ee->seenclasses.next = save; + + } else if ((strcmp(cbName(cb), CLS_RESLV_INIT_OBJECT) == 0) && noLoader){ + classJavaLangObject = cb; + MakeClassSticky(classJavaLangObject); + } + + if (noLoader) { + char *name = cbName(cb); + if (strcmp(name, CLS_RESLV_INIT_REF) == 0) { + CCSet(cb, SoftRef); + } + if (strncmp(name, "java/", 5) || strncmp(name, "sun/", 4)) { + CCSet(cb, SysLock); + } + } + if (cbSuperclass(cb) == NULL) { + if (cbSuperName(cb)) { + /* Check for class definition circularities */ + ExecEnv *ee = EE(); + struct seenclass this[1]; + if (checkSeen(ee, cb)) { + *detail = cbName(cb); + CCSet(cb, Error); + return JAVAPKG "ClassCircularityError"; + } + this->cb = cb; + this->next = NULL; + pushSeen(ee, this); + + /* Conversion for Japanese file names */ + utf2native(cbSuperName(cb), nativeName, BUFSIZ); + + super = FindClassFromClass(ee, nativeName, FALSE, cb); + + popSeen(ee, this); + if (super != NULL) { + sysAssert(CCIs(super, Initialized)); + /* Don't allow a class to have a superclass it can't access */ + if (!VerifyClassAccess(cb, super, FALSE)) { + super = NULL; + } + } + if (super != NULL) { + cbSuperclass(cb) = cbHandle(super); + if (CCIs(super, SoftRef)) + CCSet(cb, SoftRef); + } else { + ret = JAVAPKG "NoClassDefFoundError"; + *detail = cbSuperName(cb); + cbSuperclass(cb) = NULL; + CCSet(cb, Error); + } + } else if (cb == classJavaLangObject) { + cbSuperclass(cb) = 0; + } else { + *detail = cbName(cb); + return JAVAPKG "ClassFormatException"; + } + } + + for (i = 0; i < (int)(cbImplementsCount(cb)); i++) { + /* Be very careful, since not verified yet. . . + */ + int interface_index = cbImplements(cb)[i]; + cp_item_type *constant_pool = cbConstantPool(cb); + unsigned char *type_table = + constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type; + ClassClass *icb; + int nconstants = cbConstantPoolCount(cb); + int iname_index; + char *iname; + + if (interface_index <= 0 || + interface_index >= nconstants || + type_table[interface_index] != CONSTANT_Class || + !(iname_index = constant_pool[interface_index].i) || + iname_index <= 0 || + iname_index >= nconstants || + type_table[iname_index] != + (CONSTANT_Utf8 | CONSTANT_POOL_ENTRY_RESOLVED)) { + *detail = "Bad interface index"; + return JAVAPKG "ClassFormatError"; + } + + iname = constant_pool[iname_index].cp; +// if (iname == NULL || !IsLegalClassname(iname, FALSE)) { +// *detail = "Bad interface name"; +// return JAVAPKG "ClassFormatError"; +// } + + { + ExecEnv *ee = EE(); + struct seenclass this[1]; + if (checkSeen(ee, cb)) { + *detail = cbName(cb); + CCSet(cb, Error); + return JAVAPKG "ClassCircularityError"; + } + this->cb = cb; + this->next = NULL; + pushSeen(ee, this); + icb = FindClassFromClass(ee, iname, FALSE, cb); + popSeen(ee, this); + if (icb) { + constant_pool[interface_index].clazz = icb; + type_table[interface_index] |= CONSTANT_POOL_ENTRY_RESOLVED; + } else { + *detail = iname; + CCSet(cb, Error); + return JAVAPKG "NoClassDefFoundError"; + } + } + } + + CCSet(cb, Initialized); + + /* Make sure we know what classJavaLangClass is, and that it's method table + * is filled in. + */ + if (classJavaLangClass == 0) { + classJavaLangClass = + FindClassFromClass(0, CLS_RESLV_INIT_CLASS, TRUE, cb); + if (classJavaLangClass == 0) { + return JAVAPKG "NoClassDefFoundError"; + } + } + + /* The following may not do anything useful if classJavaLangClass hasn't + * been completely resolved. But we clean up in ResolveClass + */ + + cbHandle(cb)->methods = cbMethodTable(classJavaLangClass); + return ret; +} + +static char * +Locked_LinkClass(ClassClass * cb, char **detail) +{ + ClassClass *super = 0; + unsigned slot = 0; + char *ret = 0; + int i; + + if (CCIs(cb, Error)) { + *detail = cbName(cb); + return JAVAPKG "NoClassDefFoundError"; + } + + sysAssert(CCIs(cb, Initialized)); + + if (CCIs(cb, Linked)) { + return NULL; + } + + if (cbSuperclass(cb)) { + /* If this object has a superclass. . . */ + super = cbSuperclass(cb); + if (!CCIs(super, Linked)) { + if ((ret = LinkClass(super, detail)) != 0) { + CCSet(cb, Error); + return ret; + } + } + sysAssert(CCIs(super, Linked)); + slot = cbInstanceSize(super); + } + + for (i = 0; i < (int)(cbImplementsCount(cb)); i++) { + int interface_index = cbImplements(cb)[i]; + cp_item_type *constant_pool = cbConstantPool(cb); + ClassClass *icb; + icb = constant_pool[interface_index].clazz; + if (!CCIs(icb, Linked)) { + if ((ret = LinkClass(icb, detail)) != 0) { + CCSet(cb, Error); + return ret; + } + } + } + + sysAssert(!CCIs(cb, Error)); + sysAssert(!CCIs(cb, Linked)); + +#ifndef TRIMMED + if (verbose) + jio_fprintf(stderr, "[Resolving %s]\n", cbName(cb)); +#endif + cbInstanceSize(cb) = -1; + if ((ret = ResolveFields(cb, slot))) { /* May return "InternalError" */ + *detail = cbName(cb); + CCSet(cb, Error); + return ret; + } + + if ((ret = ResolveMethods(cb))) { + /* May return "OutOfMemoryError" or "InternalError" */ + *detail = cbName(cb); + CCSet(cb, Error); + return ret; + } + + if ((ret = ResolveInterfaces(cb, detail))) { /* All sorts of errors */ + CCSet(cb, Error); + return ret; + } + + InitializeInvoker(cb); + + if ((verifyclasses == VERIFY_ALL) || + ((verifyclasses == VERIFY_REMOTE) && (cbLoader(cb) != NULL))) { + if (!VerifyClass(cb)) { + *detail = ""; + return JAVAPKG "VerifyError"; + } + } + + CCSet(cb, Linked); + + /* We need this for bootstrapping. We can't set the Handle's class block + * pointer in Object or Class until Class has been resolved. + */ + if (cb == classJavaLangClass) { + int j; + ClassClass **pcb; + BINCLASS_LOCK(); + for (j = nbinclasses, pcb = binclasses; --j >= 0; pcb++) { + cbHandle(*pcb)->methods = cbMethodTable(cb); + } + BINCLASS_UNLOCK(); + InitPrimitiveClasses(); + } + return NULL; +} + +static bool_t +RunClinit(ClassClass * cb) +{ + + if (CCIs(cb, Resolved)) + return TRUE; + + if ((cbName(cb)[0] != SIGNATURE_ARRAY) && !cbIsPrimitive(cb)) { + /* Don't need to initialize or verify array or primitive classes */ + return RunStaticInitializers(cb); + } else if (cbName(cb)[0] == SIGNATURE_ARRAY) { + ClassClass *inner_cb = + cbConstantPool(cb)[CONSTANT_POOL_ARRAY_CLASS_INDEX].clazz; + if (inner_cb) { + char *detail = 0; + char *ret = ResolveClass(inner_cb, &detail); + if (ret != NULL) { + if (!exceptionOccurred(EE())) { + SignalError(0, ret, detail); + } + CCSet(cb, Error); + return FALSE; + } else { + CCSet(cb, Resolved); + } + } else { + CCSet(cb, Resolved); + } + } else { + CCSet(cb, Resolved); + } + return TRUE; +} + + +/* Find an already loaded class with the given name. If no such class exists + * then return 0. + */ + +#ifdef DEBUG +void +PrintLoadedClasses() +{ + int j; + ClassClass **pcb, *cb; + BINCLASS_LOCK(); + pcb = binclasses; + for (j = nbinclasses; --j >= 0; pcb++) { + cb = *pcb; + jio_fprintf(stdout, "class=%s, 0x%x\n", cbName(cb), cbLoader(cb)); + } + BINCLASS_UNLOCK(); +} +#endif + +static ClassClass * +FindLoadedClass(char *name, struct Hjava_lang_ClassLoader *loader) +{ + int left, right, middle, result; + ClassClass *cb = NULL; + + BINCLASS_LOCK(); + left = 0; + right = nbinclasses - 1; + result = 1; + while (left <= right) { + middle = (left + right)/2; + cb = binclasses[middle]; + result = strcmp(name, cbName(cb)); + if (result == 0) { + if (loader < cbLoader(cb)) { + result = -1; + } else if (loader > cbLoader(cb)) { + result = 1; + } else { + result = 0; + } + } + if (result < 0) { + right = middle - 1; + } else if (result > 0) { + left = middle + 1; + } else { + break; + } + } + + BINCLASS_UNLOCK(); + if (result == 0) { + return cb; + } + return NULL; +} + +/* We attempt to resolve it, also, if the "resolve" argument is true. + * Otherwise, we only perform a minimal initialization on it, such that + * it points to its superclass, which points to its superclass. . . . + */ + +static ClassClass * +InitializeAndResolveClass(ClassClass *cb, bool_t resolve) +{ + char *err, *detail = NULL; + if ((err = InitializeClass(cb, &detail))) { + /* Check for underlying error already posted */ + if (!exceptionOccurred(EE())) + SignalError(0, err, detail); + return 0; + } + if (resolve) { + err = ResolveClass(cb, &detail); + if (err) { + /* Check for underlying error already posted */ + if (!exceptionOccurred(EE())) + SignalError(0, err, detail); + return 0; + } + } + return cb; +} + +/* Find the class with the given name. + * If "resolve" is true, then we completely resolve the class. Otherwise, + * we only make sure that it points to its superclass, which points to its + * superclass, . . . . + */ +ClassClass *(*class_loader_func)(HObject *loader, char *name, long resolve) = 0; + +ClassClass * +FindClass(struct execenv *ee, char *name, bool_t resolve) +{ + return FindClassFromClass(ee, name, resolve, 0); +} + + +/* + * lock_classes and unlock_classes are exported by the JIT interface, + * but no longer used anywhere else. It grabs both locks to ensure + * backward compatibility with 1.0.2. + */ +void +lock_classes() +{ + LOADCLASS_LOCK(); + BINCLASS_LOCK(); +} + +void +unlock_classes() +{ + BINCLASS_UNLOCK(); + LOADCLASS_UNLOCK(); +} + +extern char *output_path; + +extern ClassClass * +LoadClassFromFile(char *fn, char *dir, char *class_name); + +ClassClass * +FindClassFromClass(struct execenv *ee, char *name, bool_t resolve, + ClassClass *from) +{ + char fn[64]; + sprintf(fn, "%s.class", name); + return LoadClassFromFile(fn, output_path, name); +} + +/* + * FindStickySystemClass is a variant of FindClassFromClass that makes the + * class sticky (immune to class GC) if the class can be found. It is only + * used on system classes, i.e. classes with no class loader, so it's + * equivalent to FindClassFromClass with "from" argument 0. It returns 0 + * if the class can't be found, and like FindClass assumes that the caller + * will deal with that. Note that until the class has been made sticky it + * must be kept somewhere where GC will find it. + */ +ClassClass * +FindStickySystemClass(struct execenv *ee, char *name, bool_t resolve) +{ + ClassClass *cb; + if ((cb = FindClassFromClass(ee, name, resolve, 0)) != NULL) { + MakeClassSticky(cb); + } + return cb; +} + +/* Find the array class with the specified name. */ +static ClassClass * +Locked_FindArrayClassFromClass(struct execenv *ee, char *name, + ClassClass *from) { + struct Hjava_lang_ClassLoader *fromLoader = + (from == NULL) ? NULL : cbLoader(from); + char *name_p; + int depth, base_type; + ClassClass *cb; + struct Hjava_lang_ClassLoader *loader; + ClassClass *inner_cb; + + sysAssert(name[0] == SIGNATURE_ARRAY); + + if (fromLoader == NULL) { + /* quick optimization if we know that we don't need a class loader */ + cb = FindLoadedClass(name, NULL); + if (cb != NULL) + return cb; + } + + + + /* Strip off all the initial SIGNATURE_ARRAY's to determine the depth, + * and also what's left. When we're done, name_p points at the first + * non-character, and depth is the count of the array depth + */ + for (name_p = name, depth = 0; *name_p == SIGNATURE_ARRAY; + name_p++, depth++); + + /* Look at the character to determine what type of array we have. */ + switch(*name_p++) { + case SIGNATURE_INT: base_type = T_INT; break; + case SIGNATURE_LONG: base_type = T_LONG; break; + case SIGNATURE_FLOAT: base_type = T_FLOAT; break; + case SIGNATURE_DOUBLE: base_type = T_DOUBLE; break; + case SIGNATURE_BOOLEAN:base_type = T_BOOLEAN; break; + case SIGNATURE_BYTE: base_type = T_BYTE; break; + case SIGNATURE_CHAR: base_type = T_CHAR; break; + case SIGNATURE_SHORT: base_type = T_SHORT; break; + case SIGNATURE_CLASS: base_type = T_CLASS; break; + default: return NULL; /* bad signature */ + } + if (base_type == T_CLASS) { + char buffer_space[50]; + char *buffer = buffer_space; + char *endChar = strchr(name_p, SIGNATURE_ENDCLASS); + int nameLength = endChar - name_p; + if (endChar == NULL || endChar[1] != '\0') + return NULL; + if (nameLength >= sizeof(buffer_space)) /* need bigger buffer */ + buffer = sysMalloc(nameLength + 1); + memcpy(buffer, name_p, nameLength); + buffer[nameLength] = '\0'; + inner_cb = FindClassFromClass(ee, buffer, FALSE, from); + if (buffer != buffer_space) /* free buffer, if we malloc'ed it */ + sysFree(buffer); + if (inner_cb == NULL) + return NULL; + /* loader should either be fromLoader or NULL. */ + loader = cbLoader(inner_cb); + } else { + if (*name_p != '\0') /* bad signature */ + return NULL; + inner_cb = NULL; + loader = NULL; + } + + + LOADCLASS_LOCK(); + cb = FindLoadedClass(name, loader); + if (cb == NULL) { + /* Create the fake array class corresponding to this. + */ + cb = createFakeArrayClass(name, base_type, depth, inner_cb, loader); + } + LOADCLASS_UNLOCK(); + return cb; +} + +/* + * Convert a name and type to a hash code + * + * We make copies of all strings that go into the hash table + * in case the class that is the source of the strings being + * inserted is eventually unloaded. + */ +unsigned NameAndTypeToHash(char *name, char *type) +{ + extern struct StrIDhash *nameTypeHash; + + unsigned name_key; + unsigned type_key; + unsigned ret; + + NAMETYPEHASH_LOCK(); + if (((name_key = Str2ID(&nameTypeHash, name, 0, TRUE)) == 0) || + ((type_key = Str2ID(&nameTypeHash, type, 0, TRUE)) == 0)) { + SignalError(0, JAVAPKG "OutOfMemoryError", 0); + ret = 0; + } else { + ret = (name_key << 16) + type_key; + } + NAMETYPEHASH_UNLOCK(); + + return ret; +} + +/* + * Pseudo-classes to represent primitive Java types. + */ + +ClassClass *class_void; +ClassClass *class_boolean; +ClassClass *class_byte; +ClassClass *class_char; +ClassClass *class_short; +ClassClass *class_int; +ClassClass *class_long; +ClassClass *class_float; +ClassClass *class_double; + +struct primtype { + char *name; + char typesig; + unsigned char typecode; + unsigned char slotsize; + unsigned char elementsize; + ClassClass **cellp; +} const primitive_types[] = { + { "void", SIGNATURE_VOID, T_VOID, 0, 0, &class_void }, + { "boolean",SIGNATURE_BOOLEAN, T_BOOLEAN, 4, 1, &class_boolean }, + { "byte", SIGNATURE_BYTE, T_BYTE, 4, 1, &class_byte }, + { "char", SIGNATURE_CHAR, T_CHAR, 4, 2, &class_char }, + { "short", SIGNATURE_SHORT, T_SHORT, 4, 2, &class_short }, + { "int", SIGNATURE_INT, T_INT, 4, 4, &class_int }, + { "long", SIGNATURE_LONG, T_LONG, 8, 8, &class_long }, + { "float", SIGNATURE_FLOAT, T_FLOAT, 4, 4, &class_float }, + { "double", SIGNATURE_DOUBLE, T_DOUBLE, 8, 8, &class_double } +}; + +#define PRIMITIVE_TYPE_COUNT \ + (sizeof (primitive_types) / sizeof (primitive_types[0])) + +#define GET_PRIMITIVE_CLASS(nm) \ + (class_##nm ? class_##nm : FindPrimitiveClass(#nm)) + +ClassClass * +FindPrimitiveClass(char *name) +{ + int i; + ClassClass *cb; + const struct primtype *p; + + for (i = 0; i < PRIMITIVE_TYPE_COUNT; i++) { + p = &primitive_types[i]; + if (strcmp(name, p->name) == 0) { + cb = *p->cellp; + if (cb == NULL) { + char *err, *detail = NULL; + cb = createPrimitiveClass(p->name, p->typesig, p->typecode, + p->slotsize, p->elementsize); + sysAssert(cb != NULL); + if ((err = InitializeClass(cb, &detail)) != NULL) + return NULL; /* XXX */ + if ((err = ResolveClass(cb, &detail)) != NULL) + return NULL; /* XXX*/ + *p->cellp = cb; + } + return cb; + } + } + return NULL; +} + +static void +InitPrimitiveClasses() +{ + int i; + for (i = 0; i < PRIMITIVE_TYPE_COUNT; i++) + FindPrimitiveClass(primitive_types[i].name); +} diff --git a/MPC.3.5.LINUX/preverifier/convert_md.c b/MPC.3.5.LINUX/preverifier/convert_md.c new file mode 100644 index 0000000..a19a5a4 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/convert_md.c @@ -0,0 +1,155 @@ +/* + * @(#)convert_md.c 1.2 00/11/22 + * + * Copyright 1995-1998 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +#include +//#include +#include + +#ifdef UNIX +#include +#include +#include +#include + +#define UTF8 "UTF-8" + +static iconv_t +open_iconv(const char* to, const char* from) { + iconv_t ic = iconv_open(to, from); + if (ic == (iconv_t)-1) { +// if (errno == EINVAL) { + //if (0) + /* There is a bug in some versions of Solaris in which + * nl_langinfo() returns a string beginning with ISO, but you + * have to remove the ISO before calling open_iconv. + */ + // if (strncmp(from, "ISO", 3) == 0) { + // /* Try again, but with the ISO in front of the "from" */ + // return open_iconv(to, from + 3); + // } else if (strncmp(to, "ISO", 3) == 0) { + // /* Try again, but with the ISO in front of the "to" */ + // return open_iconv(to + 3, from); + // } else { + // fprintf(stderr, "%s to %s not supported on this platform\n", + // from, to); + // } + //} else { + // perror("iconv_open error: "); + //} + exit(1); + } + return ic; +} + +static char* +get_langinfo_codeset() +{ + static char *name = NULL; + + if (name == NULL) { + name = nl_langinfo(CODESET); + if (name == NULL || strlen(name) == 0) { + name = "ISO8859-1"; + } + } + return name; +} + +int native2utf8(const char* from, char* to, int buflen) { + int ret; + size_t ileft, oleft; + char *langinfo_codeset = get_langinfo_codeset(); + iconv_t ic; + if (strncmp(langinfo_codeset, UTF8, 5) == 0) { + /* don't invoke 'iconv' functions to do the + * conversion if it's already in UTF-8 encoding + */ + memcpy(to, from, buflen); + return 0; + } + + ic = open_iconv(UTF8, get_langinfo_codeset()); + memset(to, 0, buflen); + ileft = strlen(from); + oleft = buflen; + + ret = iconv(ic, &from, &ileft, &to, &oleft); + if (ret == (size_t)-1) { + fprintf(stderr, "native2utf8:Failed to convert (err=%d)\n", ret); + exit(1); + } + iconv_close(ic); + + return buflen-oleft; +} + +int utf2native(const char* from, char* to, int buflen) { + int ret; + size_t ileft, oleft; + + char *langinfo_codeset = get_langinfo_codeset(); + iconv_t ic; + + if (strncmp(langinfo_codeset, UTF8, 5) == 0) { + /* Don't do the conversion if it's + * already in UTF-8 encoding + * Copy over the 'from' to 'to'. + */ + memcpy(to, from, buflen); + return 0; + } + + ic = open_iconv(get_langinfo_codeset(), UTF8); + memset(to, 0, buflen); + ileft = strlen(from); + oleft = buflen; + + ret = iconv(ic, &from, &ileft, &to, &oleft); + if (ret == (size_t)-1) { + fprintf(stderr, "utf2native:Failed to convert (err=%d)\n", ret); + exit(1); + } + iconv_close(ic); + + return buflen-oleft; +} + + +#endif +#ifdef WIN32 + +#include + +#include "oobj.h" +#include "utf.h" + +int native2utf8(const char* from, char* to, int buflen) { + int len; + unsigned short unicode[BUFSIZ]; + len = MultiByteToWideChar(CP_ACP, 0, from, -1, &unicode[0], BUFSIZ); + unicode2utf(&unicode[0], len-1, to, buflen); + return utfstrlen(to); +} +int utf2native(const char* from, char* to, int buflen) { + int len, len2; + unsigned short unicode[BUFSIZ]; + utf2unicode((char*)from, &unicode[0], BUFSIZ, &len); + len2 = WideCharToMultiByte(CP_ACP, 0, &unicode[0], len, to, + buflen, NULL, NULL); + to[len2]=0; + return len2; +} +#endif + diff --git a/MPC.3.5.LINUX/preverifier/convert_md.h b/MPC.3.5.LINUX/preverifier/convert_md.h new file mode 100644 index 0000000..f341034 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/convert_md.h @@ -0,0 +1,22 @@ +/* + * @(#)convert_md.h 1.2 00/11/22 + * + * Copyright 1995-1998 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +#ifndef _CONVERT_MD_ +#define _CONVERT_MD_ + +extern int native2utf8(const char* from, char* to, int buflen); +extern int utf2native(const char* from, char* to, int buflen); + +#endif diff --git a/MPC.3.5.LINUX/preverifier/file.c b/MPC.3.5.LINUX/preverifier/file.c new file mode 100644 index 0000000..b53b648 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/file.c @@ -0,0 +1,787 @@ +/* + * @(#)file.c 1.40 02/09/27 + * + * Copyright 1995-1998 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +/*========================================================================= + * SYSTEM: Verifier + * SUBSYSTEM: Operations on class files. + * FILE: file.c + * OVERVIEW: Routines for outputing the internal class file. + * + * AUTHOR(s): Original implementation, + * Sheng Liang, Sun Microsystems, Inc. + * + * Modifications for JAR support, debug support, CLDC compliance, + * Tasneem Sayeed, Sun Microsystems + * + * Added support for inner classes, fixes for stack maps, etc. + * Frank Yellin, Sun Microsystems + *=======================================================================*/ + +/*========================================================================= + * Include files + *=======================================================================*/ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef UNIX +#include +#endif + +#include "oobj.h" +#include "jar.h" +#include "tree.h" +#include "sys_api.h" +#include "convert_md.h" + +#ifdef WIN32 +#include +#endif + +/* initialize opnames[256]; */ +#include "opcodes.init" + + +/*========================================================================= + * Globals and extern declarations + *=======================================================================*/ + +extern char *progname; +extern bool_t JARfile; +extern bool_t tmpDirExists; + +char *current_class_name = NULL; + +bool_t stack_map_on = TRUE; + +static char *PrintableClassname(char *classname); + +extern char tmp_dir[32]; + +char *output_dir = "output"; +unsigned char *class_buf; +int class_buf_size = 0; +int class_index; +int last_not_utf8_index; + +#define INIT_CLASS_BUF_SIZE 256 + +void ensure_capacity(int sz) +{ + if (class_index + sz >= class_buf_size) { + while (class_index + sz >= class_buf_size) { + class_buf_size *= 2; + } + } + class_buf = (unsigned char *)realloc(class_buf, class_buf_size); +} + +void write_u1(unsigned long u1) +{ + ensure_capacity(1); + class_buf[class_index++] = (unsigned char)u1; +} + +void write_u2(unsigned long u2) +{ + ensure_capacity(2); + class_buf[class_index++] = (unsigned char)(u2 >> 8); + class_buf[class_index++] = (unsigned char)u2; +} + +void write_u4(unsigned long u4) +{ + ensure_capacity(4); + class_buf[class_index++] = (unsigned char)(u4 >> 24); + class_buf[class_index++] = (unsigned char)(u4 >> 16); + class_buf[class_index++] = (unsigned char)(u4 >> 8); + class_buf[class_index++] = (unsigned char)u4; +} + +int new_utf8_index(ClassClass *cb, int index) +{ + if (index > last_not_utf8_index) { + return index + unhand(cb)->n_new_class_entries; + } else { + return index; + } +} + +unsigned long lookup_utf8(ClassClass *cb, char *utf8) +{ + int i; + cp_item_type *constant_pool = cbConstantPool(cb); + int cpEntries, newEntries; + unsigned char *type_table = + constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type; + cpEntries = cbConstantPoolCount(cb); + newEntries = unhand(cb)->n_new_utf8_entries; + for (i = 0; i < cpEntries; i++) { + if (type_table[i] == (CONSTANT_Utf8 | CONSTANT_POOL_ENTRY_RESOLVED) && + strcmp(utf8, constant_pool[i].cp) == 0) { + return new_utf8_index(cb, i); + } + } + for (i = 0; i < newEntries; i++) { + if (strcmp(unhand(cb)->new_utf8_entries[i], utf8) == 0) { + return i + cpEntries + unhand(cb)->n_new_class_entries; + } + } + unhand(cb)->new_utf8_entries[newEntries] = utf8; + unhand(cb)->n_new_utf8_entries = newEntries + 1; + return newEntries + cpEntries + unhand(cb)->n_new_class_entries; +} + + +unsigned long lookup_class(ClassClass *cb, char *name) +{ + int i; + cp_item_type *constant_pool = cbConstantPool(cb); + unsigned char *type_table = + constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type; + for (i = 0; i < cbConstantPoolCount(cb); i++) { + if (type_table[i] == (CONSTANT_Class | CONSTANT_POOL_ENTRY_RESOLVED) && + strcmp(name, cbName(constant_pool[i].clazz)) == 0) { + return i; + } + if (type_table[i] == CONSTANT_Class && + strcmp(name, constant_pool[constant_pool[i].i].cp) == 0) { + return i; + } + } +// panic("class expected to be in constant pool: %s", name); + return 0; +} + +int get_last_not_utf8_index(ClassClass *cb) +{ + int i; + int result; + cp_item_type *constant_pool = cbConstantPool(cb); + unsigned char *type_table = + constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type; + for (i = 0, result = -1; i < cbConstantPoolCount(cb); i++) { + if (type_table[i] != (CONSTANT_Utf8 | CONSTANT_POOL_ENTRY_RESOLVED)) { + result = i; + } + } + return result; +} + +void write_constant_pool_preverifier(ClassClass *cb) +{ + int i, j; + cp_item_type *constant_pool = cbConstantPool(cb); + unsigned char *type_table = + constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type; + unsigned int sealedValue; + + last_not_utf8_index = get_last_not_utf8_index(cb); + if (stack_map_on && unhand(cb)->has_stack_maps) { + /* The maximum number of new utf8 entries we'll need is one + * for "StackMap", plus one for each of the new class entries. + * However, we bump the number to 2 in case we need to add another + * entry for the SourceFile attribute. + */ + unhand(cb)->n_new_utf8_entries = 0; + unhand(cb)->new_utf8_entries = + (char **)malloc((unhand(cb)->n_new_class_entries + 2) * + sizeof(char *)); + /* Put sure we have all the Utf8 entries that we need, so that + * we'll know the final size of the constant pool. + */ + lookup_utf8(cb, "StackMap"); + for (i = 0; i < unhand(cb)->n_new_class_entries; i++) { + lookup_utf8(cb, unhand(cb)->new_class_entries[i]); + } + } else { + unhand(cb)->n_new_utf8_entries = 0; + unhand(cb)->new_utf8_entries = NULL; + unhand(cb)->n_new_class_entries = 0; + if (unhand(cb)->new_class_entries != NULL) { + free(unhand(cb)->new_class_entries); + unhand(cb)->new_class_entries = NULL; + } + } + /* At this, we should not add have to create any more utf8 entries. + * We find the value of unhand(cb)->n_new_utf8_entries, and complain + * later if this value has changed. + */ + sealedValue = unhand(cb)->n_new_utf8_entries; + + write_u2(cbConstantPoolCount(cb) + + unhand(cb)->n_new_class_entries + + unhand(cb)->n_new_utf8_entries); + + for (i = 1; i < cbConstantPoolCount(cb); i++) { + write_u1(type_table[i] & CONSTANT_POOL_ENTRY_TYPEMASK); + switch(type_table[i]) { + case CONSTANT_Utf8 | CONSTANT_POOL_ENTRY_RESOLVED: + write_u2(strlen(constant_pool[i].cp)); + for (j = 0; j < (int)strlen(constant_pool[i].cp); j++) { + write_u1(constant_pool[i].cp[j]); + } + break; + + case CONSTANT_Class: + case CONSTANT_String: + write_u2(new_utf8_index(cb, constant_pool[i].i)); + break; + + case CONSTANT_Class | CONSTANT_POOL_ENTRY_RESOLVED: + write_u2(lookup_utf8(cb, cbName(constant_pool[i].clazz))); + break; + + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + write_u2(constant_pool[i].i >> 16); + write_u2(constant_pool[i].i & 0xFFFF); + break; + + case CONSTANT_NameAndType: + write_u2(new_utf8_index(cb, constant_pool[i].i >> 16)); + write_u2(new_utf8_index(cb, constant_pool[i].i & 0xFFFF)); + break; + + case CONSTANT_Integer | CONSTANT_POOL_ENTRY_RESOLVED: + case CONSTANT_Float | CONSTANT_POOL_ENTRY_RESOLVED: + write_u4(constant_pool[i].i); + break; + + case CONSTANT_Long | CONSTANT_POOL_ENTRY_RESOLVED: + case CONSTANT_Double | CONSTANT_POOL_ENTRY_RESOLVED: + write_u4(constant_pool[i].i); + write_u4(constant_pool[i + 1].i); + i++; + break; + + // default: + // panic("bad constant pool entry type: %d", type_table[i]); + } + if (i == last_not_utf8_index) { + /* Write extra CONSTANT_Class entries created by the stackmaps */ + for (j = 0; j < unhand(cb)->n_new_class_entries; j++) { + char *classname = unhand(cb)->new_class_entries[j]; + write_u1(CONSTANT_Class); + write_u2(lookup_utf8(cb, classname)); + } + } + } + /* Write extra CONSTANT_Utf8 entries created by the stackmaps */ + for (i = 0; i < unhand(cb)->n_new_utf8_entries; i++) { + char *string = unhand(cb)->new_utf8_entries[i]; + int length = strlen(string); + write_u1(CONSTANT_Utf8); + write_u2(length); + for (j = 0; j < length; j++) { + write_u1(string[j]); + } + } + if (sealedValue != (unsigned int) unhand(cb)->n_new_utf8_entries) { + // panic("New utf8 entries have been added???"); + } + +} + +void write_interfaces(ClassClass *cb) +{ + int i; + write_u2(cbImplementsCount(cb)); + for (i = 0; i < cbImplementsCount(cb); i++) { + write_u2(cbImplements(cb)[i]); + } +} + +void write_fields(ClassClass *cb) +{ + int i; + write_u2(cbFieldsCount(cb)); + for (i = 0; i < cbFieldsCount(cb); i++) { + struct fieldblock *fb = &cbFields(cb)[i]; + write_u2(fb->access & ACC_WRITTEN_FLAGS); + write_u2(lookup_utf8(cb, fb->name)); + write_u2(lookup_utf8(cb, fb->signature)); + /* Number of attributes we're about to output. + * Each item in the following sum is a boolean that returns 1 or 0. + */ + write_u2( ((fb->access & ACC_VALKNOWN) != 0) + + (fb->synthetic != 0) + + (fb->deprecated != 0)); + if (fb->access & ACC_VALKNOWN) { + write_u2(lookup_utf8(cb, "ConstantValue")); /* Attribute name */ + write_u4(2); /* Length */ + write_u2(fb->u.offset); + } + if (fb->deprecated) { + write_u2(lookup_utf8(cb, "Deprecated")); /* Attribute name */ + write_u4(0); /* Length */ + } + if (fb->synthetic) { + write_u2(lookup_utf8(cb, "Synthetic")); /* Attribute name */ + write_u4(0); /* Length */ + } + } +} + +void write_stack_map(int nentries, struct map_entry *entries) +{ + int i; + for (i = 0; i < nentries; i++) { + struct map_entry *entry = entries + i; + write_u1(entry->type); + if (entry->type == CF_ITEM_NewObject) { + write_u2(entry->info); + } + if (entry->type == CF_ITEM_Object) { + /* This is ugly + * Non-negative entries refer to classes + * in the original constant pool. + * Negative entries, ~(entry->info) is the entry's index + * in the list of additional constant pool entries. + */ + if (entry->info >= 0) { + write_u2(entry->info); + } else { + write_u2(last_not_utf8_index + 1 + ~entry->info); + } + } + } +} + +int stack_map_size(int nentries, struct map_entry *entries) +{ + int i; + int result = 0; + for (i = 0; i < nentries; i++) { + struct map_entry *entry = entries + i; + result += 1; + if (entry->type == CF_ITEM_Object || entry->type == CF_ITEM_NewObject) { + result += 2; + } + } + return result; +} + +void write_methods(ClassClass *cb) +{ + int i; + write_u2(cbMethodsCount(cb)); + for (i = 0; i < cbMethodsCount(cb); i++) { + struct methodblock *mb = &cbMethods(cb)[i]; + write_u2(mb->fb.access & ACC_WRITTEN_FLAGS); + write_u2(lookup_utf8(cb, mb->fb.name)); + write_u2(lookup_utf8(cb, mb->fb.signature)); + + /* Attribute count + * Each item in the following sum is a boolean that returns 1 or 0. + */ + write_u2( (mb->code_length > 0) + + (mb->nexceptions > 0) + + (mb->fb.synthetic != 0) + + (mb->fb.deprecated != 0)); + + if (mb->code_length > 0) { + int j; + int stack_map_attr_length = 0; /* Stack Map attribute length */ + int line_no_attr_length = 0; /* line_number_table attr Length */ + int localvar_attr_length = 0; /* localVar_table attr Length */ + int code_attrs = 0; /* Attributes count for Code attribute */ + + if (stack_map_on && mb->n_stack_maps > 0) { + stack_map_attr_length = 8; + code_attrs++; /* increment code attributes */ + for (j = 0; j < mb->n_stack_maps; j++) { + stack_map_attr_length += 6 + + stack_map_size(mb->stack_maps[j].nlocals, + mb->stack_maps[j].locals) + + stack_map_size(mb->stack_maps[j].nstacks, + mb->stack_maps[j].stacks); + } + } + + /* attribute_name_index for "Code" attribute */ + write_u2(lookup_utf8(cb, "Code")); + if (mb->line_number_table_length > 0) { + /* calculate the size of the line_number_table attribute */ + /* Attribute length for line_number_table + * sizeof line_number_table(4) * no. of table entries + 8 + * 8 bytes = 2 bytes for attr_name_index + + * 4 bytes for attr_length + + * 2 bytes for line_number_table_length + */ + code_attrs++; /* increment code attributes */ + line_no_attr_length = 4 * mb->line_number_table_length + 8; + } + if (mb->localvar_table_length > 0) { + /* calculate the size of the localvar_table attribute */ + /* Attribute length for localvar_table + * sizeof localvar_table (10) * no. of table entries + 8 + * 8 bytes = 2 bytes for attr_name_index + + * 4 bytes for attr_length + + * 2 bytes for line_number_table_length + */ + code_attrs++; /* increment code attributes */ + localvar_attr_length = 10 * mb->localvar_table_length + 8; + } + + /* Attribute Length */ + write_u4(12 + mb->code_length + + mb->exception_table_length * 8 + + stack_map_attr_length + + line_no_attr_length + + localvar_attr_length); + write_u2(mb->maxstack); + write_u2(mb->nlocals); + write_u4(mb->code_length); + for (j = 0; j < (int)mb->code_length; j++) { + write_u1(mb->code[j]); + } + write_u2(mb->exception_table_length); + for (j = 0; j < (int)mb->exception_table_length; j++) { + write_u2(mb->exception_table[j].start_pc); + write_u2(mb->exception_table[j].end_pc); + write_u2(mb->exception_table[j].handler_pc); + write_u2(mb->exception_table[j].catchType); + } + + /* Attributes count for Code attribute */ + write_u2(code_attrs); + + /* check if we have a valid line_number_table entries and + * if so, write out the pc and line_number entries. + */ + + if (mb->line_number_table_length > 0) { + /* line_number_table attribute exists */ + /* attribute_name_index for "LineNumberTable" */ + write_u2(lookup_utf8(cb, "LineNumberTable")); + /* Attribute length for line_number_table + * (exclude initial 6 bytes = 2 bytes for attr_name_index + + * 4 bytes for attr_length) + */ + write_u4(line_no_attr_length - 6); + /* Length of line_number_table */ + write_u2(mb->line_number_table_length); + /* write out the line_number_table entries */ + for (j=0; j< (int) mb->line_number_table_length; j++) { + if (mb->line_number_table != NULL) { + write_u2(mb->line_number_table[j].pc); + write_u2(mb->line_number_table[j].line_number); + } + } + } + + /* check if we have a valid localvar_table entries and + * if so, write out its entries + */ + + if (mb->localvar_table_length > 0) { + /* localvar_table attribute exists */ + /* attribute_name_index for "LocalVariableTable" */ + write_u2(lookup_utf8(cb, "LocalVariableTable")); + + /* Attribute length for localvar_table + * (exclude initial 6 bytes = 2 bytes for attr_name_index + + * 4 bytes for attr_length) + */ + write_u4(localvar_attr_length - 6); + + /* Length of localvar_table */ + write_u2(mb->localvar_table_length); + + /* write out the localvar_table entries */ + for (j=0; j< (int) mb->localvar_table_length; j++) { + if (mb->localvar_table != NULL) { + write_u2(mb->localvar_table[j].pc0); + write_u2(mb->localvar_table[j].length); + write_u2(lookup_utf8(cb,mb->localvar_table[j].name)); + write_u2(lookup_utf8(cb,mb->localvar_table[j].signature)); + write_u2(mb->localvar_table[j].slot); + } + } + } + + if (stack_map_on && mb->n_stack_maps > 0) { + write_u2(lookup_utf8(cb, "StackMap")); + write_u4(stack_map_attr_length - 6); + write_u2(mb->n_stack_maps); + for (j = 0; j < mb->n_stack_maps; j++) { + write_u2(mb->stack_maps[j].offset); + write_u2(mb->stack_maps[j].nlocals); + write_stack_map(mb->stack_maps[j].nlocals, + mb->stack_maps[j].locals); + write_u2(mb->stack_maps[j].nstacks); + write_stack_map(mb->stack_maps[j].nstacks, + mb->stack_maps[j].stacks); + } + } + } + if (mb->nexceptions > 0) { + int j; + write_u2(lookup_utf8(cb, "Exceptions")); + write_u4(2 + mb->nexceptions * 2); + write_u2(mb->nexceptions); + for (j = 0; j < mb->nexceptions; j++) { + write_u2(mb->exceptions[j]); + } + } + if (mb->fb.deprecated) { + write_u2(lookup_utf8(cb, "Deprecated")); + write_u4(0); /* Length */ + } + if (mb->fb.synthetic) { + write_u2(lookup_utf8(cb, "Synthetic")); + write_u4(0); /* Length */ + } + } +} + +void ensure_dir_exists(char *dir) +{ + struct stat stat_buf; + char *parent; + char *q; + if (dir[0] == 0) { + return; + } + parent = strdup(dir); + q = strrchr(parent, '/'); + if (q) { + *q = 0; + ensure_dir_exists(parent); + } + if (stat(dir, &stat_buf) < 0) { + if (JAR_DEBUG && verbose) { + // jio_fprintf(stderr, "Creating output directory [%s]\n", dir); + } +#ifdef WIN32 + mkdir(dir); +#endif +#ifdef UNIX + mkdir(dir, 0755); +#endif + } + free(parent); +} + +void ensure_dir_writable(char *dir) +{ + struct stat stat_buf; + + stat(dir, &stat_buf); + if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) { /* is dir ? */ +#ifdef WIN32 + if (access(dir, 06) < 0) { +#endif +#ifdef UNIX + if (access(dir, R_OK | W_OK) < 0) { +#endif + // panic("%s is write protected\n", dir); + } + } else { + // panic("%s is not a directory\n", dir); + } +} + +extern char *output_path; + +void +WriteClass(ClassClass *cb) +{ + int fd; + char fname[1024]; + char buff[BUFSIZ]; + char *nativeName = &buff[0]; + + class_buf = (unsigned char*)malloc(INIT_CLASS_BUF_SIZE); + if (class_buf == NULL) { + // panic("out of memory"); + } + class_buf_size = INIT_CLASS_BUF_SIZE; + + class_index = 0; + + write_u4(0xcafebabe); + + write_u2(cbMinorVersion(cb)); + write_u2(cbMajorVersion(cb)); + + write_constant_pool_preverifier(cb); + + write_u2(cbAccess(cb) & ACC_WRITTEN_FLAGS); + + write_u2(lookup_class(cb, cbName(cb))); + write_u2(unhand(cb)->superclass_idx); + write_interfaces(cb); + write_fields(cb); + write_methods(cb); + + + /* Output number of attributes + * Each item in the following sum is a boolean that returns 1 or 0. + */ + write_u2( (cbSourceName(cb) != NULL) + + (cbAbsoluteSourceName(cb) != NULL) + + (unhand(cb)->hasTimeStamp) + + (unhand(cb)->deprecated) + + (unhand(cb)->synthetic) + + (cbInnerClasses(cb) != NULL) + ); + if (cbSourceName(cb) != NULL) { + /* write the source file attribute used for debugging purposes */ + write_u2(lookup_utf8(cb, "SourceFile")); /* SourceFile attribute */ + write_u4(2); /* Length */ + /* CP entry containing the source name */ + write_u2(lookup_utf8(cb, cbSourceName(cb))); + } + if (cbAbsoluteSourceName(cb) != NULL) { + /* write the source file attribute used for debugging purposes */ + write_u2(lookup_utf8(cb, "AbsoluteSourcePath")); + write_u4(2); + write_u2(lookup_utf8(cb, cbAbsoluteSourceName(cb))); + } + if (unhand(cb)->hasTimeStamp) { + write_u2(lookup_utf8(cb, "TimeStamp")); + write_u4(8); + write_u4(cbTimestamp(cb).high); + write_u4(cbTimestamp(cb).low); + } + if (unhand(cb)->deprecated) { + write_u2(lookup_utf8(cb, "Deprecated")); /* attribute name */ + write_u4(0); /* Length */ + } + if (unhand(cb)->synthetic) { + write_u2(lookup_utf8(cb, "Synthetic")); /* attribute name */ + write_u4(0); /* Length */ + } + + if (cbInnerClasses(cb) != NULL) { + int count = cbInnerClassesCount(cb); + struct innerClasses *thisInnerClass= cbInnerClasses(cb); + struct innerClasses *lastInnerClass = thisInnerClass + count; + write_u2(lookup_utf8(cb, "InnerClasses")); /* Attribute name */ + write_u4(8 * count + 2); /* Length */ + write_u2(count); + for ( ; thisInnerClass < lastInnerClass; thisInnerClass++) { + char *innerName = thisInnerClass->inner_name; + write_u2(thisInnerClass->inner_class); + write_u2(thisInnerClass->outer_class); + write_u2( (innerName != 0) ? lookup_utf8(cb, innerName) : 0); + write_u2(thisInnerClass->access); + } + } + + /* Conversion for Japanese filenames */ + utf2native(cbName(cb), nativeName, BUFSIZ); + + // if (JARfile) { + /* classes need to be put in a JAR file */ + // sprintf(fname, "%s/%s.class", tmp_dir, nativeName); + // } else { + sprintf(fname, "%s/%s.class", output_path, nativeName); +// } + + { + char *dir = strdup(fname); + char *q; + + q = strrchr(dir, '/'); + if (q) { + *q = 0; + ensure_dir_exists(dir); + ensure_dir_writable(dir); + } + free(dir); + } + +#ifdef UNIX + fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC , 0644); +#endif +#ifdef WIN32 + fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); +#endif + + if (fd < 0) { + // panic("failed to open %s", fname); + } + + tmpDirExists = TRUE; /* tmpDir exists with verified classes */ + write(fd, class_buf, class_index); + close(fd); + free(class_buf); + class_buf_size = 0; +} + +void +VerifyFile(char *fn) +{ + /* If this is the first class, we'll run into problems if loading the + * class forces Object to be loaded, when then forces this class to + * be loaded. To prohibit such problems, we force Object to be loaded + */ + FindClass(0, "java/lang/Object", TRUE); + + { + ClassClass *cb = FindClass(0, fn, TRUE); + char *class_name = PrintableClassname(fn); + + if (cb == NULL) { + errorCode = 1; /* set error status to indicate error */ + // jio_fprintf(stderr, "Error loading class %s\n", class_name); + } else { + if (no_native_methods) { + /* Check for native methods in classes */ + struct methodblock *mb; + int size; + mb = cbMethods(cb); + for (size=0; size < (int) cbMethodsCount(cb); size++, mb++) { + if (mb->fb.access & ACC_NATIVE) { + current_class_name = fn; + // panic("native methods should not appear"); + } + } + } + + VerifyClass(cb); + + WriteClass(cb); + } + } +} + +char *PrintableClassname(char *class_name) +{ + char *p; + static char class_copy[257]; + strncpy(class_copy, class_name, 256); + + /* Convert all slashes in the classname to periods */ + for (p = class_copy; ((p = strchr(p, '/')) != 0); *p++ = '.'); + return class_copy; +} + +void printCurrentClassName(void) +{ + if (current_class_name) { + // fprintf(stderr, "Error preverifying class %s\n ", + // PrintableClassname(current_class_name)); + } +} diff --git a/MPC.3.5.LINUX/preverifier/inlinejsr.c b/MPC.3.5.LINUX/preverifier/inlinejsr.c new file mode 100644 index 0000000..32f996d --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/inlinejsr.c @@ -0,0 +1,681 @@ +/* + * @(#)inlinejsr.c 1.22 02/09/27 + * + * Copyright 1995-2001 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +/*========================================================================= + * SYSTEM: Verifier + * SUBSYSTEM: JSR inlining + * FILE: inlinejsr.c + * OVERVIEW: Routines for inlining of JSR and RET bytecodes. + * + * AUTHOR: Frank Yellin, Sun Microsystems, Inc. + * Edited by Tasneem Sayeed, Sun Microsystems + *=======================================================================*/ + +/*========================================================================= + * Include files + *=======================================================================*/ + +#include "check_code.h" + +/*========================================================================= + * Globals and extern declarations + *=======================================================================*/ + +/* Maximum byte code size is 64K. */ +#define MAX_CODE_SIZE 65535 + +typedef struct SubrContext { + int id; /* id, for debugging */ + int depth; /* depth of subroutine */ + struct SubrContext *parent; /* subroutine of caller */ + struct CodeRef *caller; /* jsr that got us there */ + struct CodeRef *nextInstruction; /* first instruction following inlining */ + int target; + + struct SubrContext *next; /* linked list of all subr contexts */ +} SubrContext; + + +/* global context, keep track of info when a method is rewritten */ +typedef struct JsrContext { + context_type *vcontext; /* The verifier's context */ + struct CodeRef *codeRef; /* big array of codeRef's */ + struct CodeRef *codeRefEnd; /* pointer to next codeRef to fill in */ + int scontext_id; /* ID assigned to last SubrContext */ + struct SubrContext *allSubrContexts; /* pointer to linked list */ + struct CodeRef **mapping; /* maps inumbers CodeRef's */ +} JsrContext; + +/* A single instruction in the resulting stream */ +typedef struct CodeRef { + long inumber; /* instruction number in original code */ + SubrContext *subroutine; /* subroutine call that this is part of */ + enum { CRF_NORMAL, /* normal instruction */ + CRF_SKIP, /* skip this instruction */ + CRF_JSR_SIMPLE_GOTO, /* jsr to subroutine that doesn't return */ + CRF_JSR_TARGETED_GOTO, /* jsr to subroutine that does return */ + CRF_RET_SIMPLE_GOTO /* ret that's not at the end of subroutine */ + } flags; + /* My offset in the new code */ + int offset; + struct CodeRef *next; /* next codeRef with same "inumber" */ +} CodeRef; + + +static bool_t matchSubroutine(JsrContext *, instruction_data_type*, + SubrContext *); +static bool_t subroutineGoto(JsrContext *, SubrContext *, SubrContext *); + + +static void +rewriteOneSubroutine(JsrContext *context, SubrContext *subroutine); + +static void fixupCode(JsrContext*); +static void fixupExceptionHandlers(JsrContext*); +static void fixupLineNumberTable(JsrContext*); +static void fixupVariableTable(JsrContext*); + + +static void +updateTarget(JsrContext *, + int inumber, + SubrContext* subroutine, + void* target, int offset, int size); + + +void +rewriteCode(context_type *vcontext, struct methodblock *mb) +{ + JsrContext context_buf; + JsrContext *context = &context_buf; + +#if MYDEBUG + printf("Starting %s.%s%s\n", cbName(mb->fb.clazz), mb->fb.name, mb->fb.signature); +#endif + /* Initialize the context */ + memset(context, 0, sizeof(context)); + context->vcontext = vcontext; /* The verifier context */ + /* Allow up to MAX_CODE_SIZE instructions. */ + context->codeRef = (CodeRef *)malloc(MAX_CODE_SIZE * sizeof(CodeRef)); + context->codeRefEnd = context->codeRef; + /* Id (for debugging) of last subroutine structure created */ + context->scontext_id = 0; + /* Keep a list of all subroutines, so that we can easily free() them */ + context->allSubrContexts = NULL; + /* Make it easy to go from inumber to all CodeRef's that have that inumber*/ + context->mapping = (CodeRef **)calloc(vcontext->instruction_count, + sizeof(CodeRef **)); + + /* Fill in context->codeRef with this routine. In line all subroutine + * calls, and delete all unreachable code */ + rewriteOneSubroutine(context, NULL); + + /* Modify mb->code and mb->code_length for the new code */ + fixupCode(context); + + /* Update the exception table */ + if (mb->exception_table_length != 0) { + fixupExceptionHandlers(context); + } + + /* Update the line number table */ + if (mb->line_number_table_length != 0) { + fixupLineNumberTable(context); + } + + /* Update the local variable table */ + if (mb->localvar_table_length != 0) { + fixupVariableTable(context); + } + + /* Clean up */ + free(context->codeRef); + free(context->mapping); + + /* Free all the subroutine contexts that we created */ + while (context->allSubrContexts != NULL) { + SubrContext *this = context->allSubrContexts; + SubrContext *next = this->next; + free(this); + context->allSubrContexts = next; + } +} + +static void +rewriteOneSubroutine(JsrContext *context, SubrContext *subroutine) +{ + context_type *vcontext = context->vcontext; + int depth = subroutine ? subroutine->depth : 0; + instruction_data_type *idata = vcontext->instruction_data; + int instruction_count = vcontext->instruction_count; + CodeRef **mapping = context->mapping; + + instruction_data_type *this_idata; + int inumber; + int count = 0; + CodeRef *retOpcode = NULL; + + + for ( inumber = 0, this_idata = idata; + inumber < instruction_count; + inumber++, this_idata++) { + if ( (this_idata->or_flags & FLAG_REACHED) + && (this_idata->register_info.mask_count == depth) + && ((depth == 0) + || matchSubroutine(context, this_idata, subroutine))) { + + /* We have an instruction that is part of this subroutine */ + + CodeRef *codeRef = context->codeRefEnd++; +#if MYDEBUG + printf("\t%d:\t%d (%d)\t%s (%d)\n", + (codeRef - context->codeRef), /* new instruction index */ + inumber, (subroutine ? subroutine->id : 0), + (this_idata->opcode == 256 + ? "invokeinit" : opnames[this_idata->opcode]), + this_idata->offset); +#endif + codeRef->inumber = inumber; + codeRef->subroutine = subroutine; + codeRef->flags = CRF_NORMAL; + codeRef->next = mapping[inumber]; /* Add to inumber mapping */ + mapping[inumber] = codeRef; + + count++; + + if (count == 1 && depth > 0) { + /* This is the first instruction included as part of the + * subroutine call. If it's the target of the jsr that got + * us here, then we can just "ignore" the jsr. + * Otherwise, we have to convert the 'jsr' into a 'goto' + */ + CodeRef *caller = subroutine->caller; + if (inumber != idata[caller->inumber].operand.i) { + caller->flags = CRF_JSR_TARGETED_GOTO; + } + } + + switch(this_idata->opcode) { + case opc_jsr: case opc_jsr_w: + if (this_idata->operand2.i == UNKNOWN_RET_INSTRUCTION) { + /* We're calling a subroutine that doesn't return. + * The verifier has already made sure that the + * subroutine doesn't have a deeper depth. + * We turn the JSR into a goto */ + codeRef->flags = CRF_JSR_SIMPLE_GOTO; + } else { + SubrContext *newSubr = malloc(sizeof(SubrContext)); + + /* In rare cases, we'll have to change this in the + * subroutine code */ + codeRef->flags = CRF_SKIP; + + /* Create a new subroutine, and inline it */ + newSubr->id = ++context->scontext_id; + newSubr->caller = codeRef; + newSubr->target = this_idata->operand.i; + newSubr->depth = depth + 1; + newSubr->nextInstruction = NULL; /* unknown for now */ + newSubr->parent = subroutine; + /* Add this to the list of all subroutine contexts */ + newSubr->next = context->allSubrContexts; + context->allSubrContexts = newSubr; + /* Generate the code for this subroutine */ + rewriteOneSubroutine(context, newSubr); + } + break; + + case opc_ret: + if (retOpcode != NULL) { + /* There should only be one per subroutine */ + panic("Multiple return opcodes??"); + } else if (depth == 0) { + /* We're not in a subroutine */ + panic("Ret at depth = 0"); + } + retOpcode = codeRef; + /* Flags are set at the end of the loop, below */ + break; + + case opc_astore: + /* We discard any astore's that move a return address + * from the stack to a register. + */ + if (GET_ITEM_TYPE(this_idata->stack_info.stack->item) + == ITEM_ReturnAddress) { + codeRef->flags = CRF_SKIP; + } + break; + + default: + /* Nothing to do */ + break; + } + } + } + if (depth > 0) { + subroutine->nextInstruction = context->codeRefEnd; + if (retOpcode != NULL) { + /* If the last instruction wasn't a 'ret', then we need to + * convert the 'ret' into a 'goto'. + */ + if (context->codeRefEnd == retOpcode + 1) { + retOpcode->flags = CRF_SKIP; + } else { + retOpcode->flags = CRF_RET_SIMPLE_GOTO; + } + } + } +} + + +static void +fixupCode(JsrContext *context) +{ + context_type *vcontext = context->vcontext; + instruction_data_type *idata = vcontext->instruction_data; + struct methodblock *mb = vcontext->mb; + unsigned char *oldCode = mb->code; + CodeRef *codeRefEnd = context->codeRefEnd; + + unsigned char *newCode; + CodeRef *codeRef; + int pc; + long newCodeLength; + + /* Assign offsets to each instruction. */ +#if MYDEBUG + printf("Assigning offsets\n"); +#endif + for (pc = 0, codeRef = context->codeRef; codeRef < codeRefEnd; codeRef++) { + instruction_data_type *this_idata = &idata[codeRef->inumber]; + opcode_type opcode = this_idata->opcode; + + codeRef->offset = pc; + +#if MYDEBUG + printf("\t%d:\t%d\tpc=%d\t%s (%d) %s\n", + (codeRef - context->codeRef), + (this_idata - vcontext->instruction_data), + pc, + (this_idata->opcode == 256 + ? "invokeinit" : opnames[this_idata->opcode]), + this_idata->offset, + ((codeRef->flags == CRF_SKIP) ? " XX" : "") + ); +#endif + + /* Now increment the pc, depending on the instruction */ + if (codeRef->flags == CRF_SKIP) { + /* do nothing */ + } else if (opcode == opc_tableswitch || opcode == opc_lookupswitch) { + /* This mysterious calculation works. + * The first term increments pc and then rounds it up to a + * multiple of 4. The second term is the size of the word-aligned + * values. + */ + pc = ((pc + 1 + 3) & ~3) + ((this_idata->length - 1) & ~3); + } else if (opcode == opc_ret) { + /* We must be turning it into an opc_goto */ + pc += 3; + } else { + pc += this_idata->length; + } + } + + /* Create a new code object */ + newCode = (unsigned char *)malloc(pc); + newCodeLength = pc; + +#if MYDEBUG + printf("Creating code of length %d\n", pc); +#endif + + for (codeRef = context->codeRef; codeRef < codeRefEnd; codeRef++) { + if (codeRef->flags != CRF_SKIP) { + instruction_data_type *this_idata = &idata[codeRef->inumber]; + opcode_type opcode = this_idata->opcode; + int pc = codeRef->offset; + unsigned char *source = &oldCode[this_idata->offset]; + unsigned char *target = &newCode[pc]; + +#if MYDEBUG + printf("\t%d:\t%d\tpc=%d\t%s (%d) \n", + (codeRef - context->codeRef), + (this_idata - vcontext->instruction_data), + pc, + (this_idata->opcode == 256 + ? "invokeinit" : opnames[this_idata->opcode]), + this_idata->offset + ); +#endif + + switch(opcode) { + case opc_ifeq: case opc_ifne: case opc_iflt: + case opc_ifge: case opc_ifgt: case opc_ifle: + case opc_ifnull: case opc_ifnonnull: + case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmplt: + case opc_if_icmpge: case opc_if_icmpgt: case opc_if_icmple: + case opc_if_acmpeq: case opc_if_acmpne: + case opc_goto: case opc_goto_w: + target[0] = source[0]; + updateTarget(context, this_idata->operand.i, + codeRef->subroutine, + target + 1, pc, this_idata->length - 1); + break; + + case opc_jsr: case opc_jsr_w: + target[0] = opc_goto; + if (codeRef->flags == CRF_JSR_SIMPLE_GOTO) { + updateTarget(context, this_idata->operand.i, + codeRef->subroutine, + target + 1, pc, this_idata->length - 1); + } else if (codeRef->flags == CRF_JSR_TARGETED_GOTO) { + updateTarget(context, this_idata->operand.i, + codeRef[1].subroutine, + target + 1, pc, this_idata->length - 1); + } else { + panic("Shouldn't have anything referring to jsr"); + } + break; + + case opc_ret: + if (codeRef->flags & CRF_RET_SIMPLE_GOTO) { + int gotoTarget = + codeRef->subroutine->nextInstruction->offset; + target[0] = opc_goto; + target[1] = (gotoTarget - pc) >> 8; + target[2] = (gotoTarget - pc); + } else { + panic("Shouldn't have anything referring to ret"); + } + break; + + default: + memcpy(target, source, this_idata->length); + break; + + + case opc_tableswitch: + case opc_lookupswitch: { + int *successors = this_idata->operand.ip; + int keys = successors[0] - 1; /* don't include default */ + SubrContext *subroutine = codeRef->subroutine; + int i; + + long *targetPtr, *sourcePtr; + target[0] = source[0]; + target[1] = target[2] = target[3] = 0; /* clear alignment */ + + targetPtr = (long *)UCALIGN(target + 1); + sourcePtr = (long *)UCALIGN(source + 1); + + /* Update the default target */ + updateTarget(context, successors[1], subroutine, + targetPtr, pc, 4); + if (opcode == opc_tableswitch) { + targetPtr[1] = sourcePtr[1]; /* low */ + targetPtr[2] = sourcePtr[2]; /* high */ + for (i = 0; i < keys; i++) { + updateTarget(context, successors[2 + i], subroutine, + &targetPtr[3 + i], pc, 4); + } + } else { + targetPtr[1] = sourcePtr[1]; /* pairs */ + for (i = 0; i < keys; i++) { + targetPtr[2 + (i << 1)] = sourcePtr[2 + (i << 1)]; + updateTarget(context, successors[2 + i], subroutine, + &targetPtr[3 + (i << 1)], pc, 4); + } + } + break; + + } + } + } + } + mb->code = newCode; + mb->code_length = newCodeLength; +} + +static void fixupExceptionHandlers(JsrContext *context) { + const int catchFrameSize = sizeof(struct CatchFrame); + context_type *vcontext = context->vcontext; + struct methodblock *mb = vcontext->mb; + + short *code_data = vcontext->code_data; /* maps offset to inumber */ + + CodeRef *codeRefEnd = context->codeRefEnd; + + /* Structure to hold new catch frames */ + struct CatchFrame *catchFrames = malloc(catchFrameSize * MAX_CODE_SIZE); + struct CatchFrame *currentCatchFrame = catchFrames; + + CodeRef *hRef, *instRef; + unsigned long i; + + /* Look at each exception handler */ + for (i = 0; i < mb->exception_table_length; i++) { + struct CatchFrame *this_handler = &mb->exception_table[i]; + int start_inumber = code_data[this_handler->start_pc]; + int end_inumber = code_data[this_handler->end_pc]; + int handler_inumber = code_data[this_handler->handler_pc]; + + /* First instruction that maps to the specified handler */ + for (hRef = context->mapping[handler_inumber] + ; hRef != NULL; hRef = hRef->next) { + /* Find all instructions that go to this handler. */ + bool_t wasMatch = FALSE; + for (instRef = context->codeRef; instRef < codeRefEnd; instRef++) { + if (instRef->flags != CRF_SKIP) { + bool_t thisMatch = instRef->inumber >= start_inumber + && instRef->inumber < end_inumber + && subroutineGoto(context, + instRef->subroutine, + hRef->subroutine); + if (thisMatch && !wasMatch) { + /* Start a new catch frame */ + memcpy(currentCatchFrame, this_handler, catchFrameSize); + currentCatchFrame->handler_pc = hRef->offset; + currentCatchFrame->start_pc = instRef->offset; + wasMatch = TRUE; + } else if (wasMatch && !thisMatch) { + currentCatchFrame->end_pc = instRef->offset; + currentCatchFrame++; + wasMatch = FALSE; + } + } + } + if (wasMatch) { + /* We end the code still in the catch frame */ + currentCatchFrame->end_pc = mb->code_length; + currentCatchFrame++; + } + } + } + /* free(mb->exception_table); */ + mb->exception_table_length = currentCatchFrame - catchFrames; + mb->exception_table = realloc(catchFrames, + (char *)currentCatchFrame - (char *)catchFrames); + +} + +static void fixupLineNumberTable(JsrContext *context) { + context_type *vcontext = context->vcontext; + struct methodblock *mb = vcontext->mb; + int tableLength = mb->line_number_table_length; + + instruction_data_type *idata = vcontext->instruction_data; + instruction_data_type *last_idata = &idata[vcontext->instruction_count - 1]; + int oldCodeLength = last_idata->offset + last_idata->length; + struct lineno *lineTable = malloc(sizeof(struct lineno) * MAX_CODE_SIZE); + struct lineno *currentLineTableEntry = lineTable; + unsigned long *mapTable = calloc(sizeof(short *), oldCodeLength); + CodeRef *codeRefEnd = context->codeRefEnd; + CodeRef *codeRef; + int i, currentLineNumber; + + { + unsigned long startPC, endPC, line, pc; + + for (i = 0; i < tableLength - 1; i++) { + startPC = mb->line_number_table[i].pc; + endPC = mb->line_number_table[i + 1].pc; + line = mb->line_number_table[i].line_number; + for (pc = startPC; pc < endPC; pc++) { + mapTable[pc] = line; + } + } + startPC = mb->line_number_table[tableLength - 1].pc; + endPC = oldCodeLength; + line = mb->line_number_table[tableLength - 1].line_number; + for (pc = startPC; pc < endPC; pc++) { + mapTable[pc] = line; + } + } + + currentLineNumber = -1; + for (codeRef = context->codeRef; codeRef < codeRefEnd; codeRef++) { + if (codeRef->flags != CRF_SKIP) { + instruction_data_type *this_idata = &idata[codeRef->inumber]; + int thisLineNumber = mapTable[this_idata->offset]; + if (thisLineNumber != currentLineNumber) { + currentLineTableEntry->line_number = thisLineNumber; + currentLineTableEntry->pc = codeRef->offset; + currentLineTableEntry++; + currentLineNumber = thisLineNumber; + } + } + } + + free(mapTable); + mb->line_number_table = realloc(lineTable, + (char *)currentLineTableEntry - + (char *)lineTable); + mb->line_number_table_length = currentLineTableEntry - lineTable; +} + + +static void fixupVariableTable(JsrContext *context) { + context_type *vcontext = context->vcontext; + struct methodblock *mb = context->vcontext->mb; + instruction_data_type *idata = vcontext->instruction_data; + CodeRef *codeRefEnd = context->codeRefEnd; + CodeRef *codeRef; + unsigned long i; + + struct localvar *localVars = + malloc(sizeof(struct localvar) * MAX_CODE_SIZE); + struct localvar *currentLocalVar = localVars; + + for (i = 0; i < mb->localvar_table_length; i++) { + struct localvar *oldEntry = &mb->localvar_table[i]; + int startPC = oldEntry->pc0; + int endPC = startPC + oldEntry->length; /* inclusive! */ + + bool_t was_matching = FALSE; + + for (codeRef = context->codeRef; codeRef < codeRefEnd; codeRef++) { + if (codeRef->flags != CRF_SKIP) { + instruction_data_type *this_idata = &idata[codeRef->inumber]; + bool_t is_matching = this_idata->offset >= startPC + && this_idata->offset <= endPC; + if (!was_matching && is_matching) { + memcpy(currentLocalVar, oldEntry, sizeof(struct localvar)); + currentLocalVar->pc0 = codeRef->offset; + was_matching = TRUE; + } else if (was_matching && !is_matching) { + currentLocalVar->length = + codeRef[-1].offset - currentLocalVar->pc0; + currentLocalVar++; + was_matching = FALSE; + } + } + } + if (was_matching) { + currentLocalVar->length = + codeRefEnd[-1].offset - currentLocalVar->pc0; + currentLocalVar++; + } + } + + /* free(mb->localvar_table); */ + mb->localvar_table_length = currentLocalVar - localVars; + mb->localvar_table = realloc(localVars, + (char *)currentLocalVar - (char *)localVars); +} + + +static void +updateTarget(JsrContext *context, int inumber, + SubrContext* subroutine, void* target, int offset, int size) +{ + CodeRef *codeRef; + for (codeRef = context->mapping[inumber]; + codeRef != NULL; + codeRef = codeRef->next) { + if (subroutineGoto(context, subroutine, codeRef->subroutine)) { + int value = codeRef->offset - offset; + unsigned char *t = target; + if (size == 2) { + t[0] = value >> 8; + t[1] = value; + } else if (size == 4) { + t[0] = value >> 24; + t[1] = value >> 16; + t[2] = value >> 8; + t[3] = value; + } else { + panic("Bad value passed for size"); + } + return; + } + } + panic("Cannot find value for updateTarget"); +} + + + +static bool_t +subroutineGoto(JsrContext *context, SubrContext *from, SubrContext *to) +{ + if (to == NULL || to == from) { + return TRUE; + } else if (from == NULL || to->depth >= from->depth) { + return FALSE; + } else { + do { from = from->parent; } while (from->depth > to->depth); + return from == to; + } +} + + +static bool_t +matchSubroutine(JsrContext *context, + instruction_data_type *this_idata, + SubrContext *subroutine) +{ + int depth = subroutine->depth; + int i; + + for (i = depth - 1; i >= 0; --i) { + if (this_idata->register_info.masks[i].entry != subroutine->target) { + return FALSE; + } + subroutine = subroutine->parent; + } + return TRUE; +} + diff --git a/MPC.3.5.LINUX/preverifier/jar.c b/MPC.3.5.LINUX/preverifier/jar.c new file mode 100644 index 0000000..216c49f --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/jar.c @@ -0,0 +1,727 @@ +/* + * Copyright (c) 1999 Sun Microsystems, Inc. All Rights Reserved. + * + * This software is the confidential and proprietary information of Sun + * Microsystems, Inc. ("Confidential Information"). You shall not + * disclose such Confidential Information and shall use it only in + * accordance with the terms of the license agreement you entered into + * with Sun. + * + * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE + * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES + * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + * Use is subject to license terms. + */ + +/*========================================================================= + * SYSTEM: Verifier + * SUBSYSTEM: JAR class loader. + * FILE: jar.c + * OVERVIEW: Routines for reading contents of a JAR file. The routines + * are optimized to reduce code size and run-time memory + * requirement so that they can run happily on small devices. + * AUTHOR: Frank Yellin, Sun Microsystems, Inc. + * Modifications for JAR support and comments, + * Tasneem Sayeed, Sun Microsystems + *=======================================================================*/ + +/*========================================================================= + * Include files + *=======================================================================*/ + + +#include +#include +#include +#include + +#include "oobj.h" +#include "typedefs.h" +#include "jar.h" +#include "jarint.h" +#include "jartables.h" + +/*========================================================================= + * Globals and extern declarations + *=======================================================================*/ + +static bool_t decodeDynamicHuffmanTables(inflaterState *state, + HuffmanCodeTable **lcodesPtr, + HuffmanCodeTable **dcodesPtr); + +static HuffmanCodeTable *makeCodeTable(inflaterState *state, + unsigned char *codelen, + unsigned numElems, + unsigned maxQuickBits); + + +static bool_t inflateHuffman(inflaterState *state, bool_t fixedHuffman); +static bool_t inflateStored(inflaterState *state); + + +/*=========================================================================== + * FUNCTION: inflate + * TYPE: jar file decoding + * OVERVIEW Used for decoding JAR files given the compressed data source, + * compressed data length, buffer to store decompressed data and + * length of decompression buffer. + * + * INTERFACE: + * parameters: compressed data source, compressed data length, + * buffer to store decompressed data, decompression buffer size + * returns: TRUE if the data was encoded in a supported and the + * size of the decoded data is exactly the same as + * FALSE if an error occurs + * NOTE: + * The caller of this method must insure that this function can safely get + * up to INFLATER_EXTRA_BYTES beyond compData + compLen without causing + * any problems. + * The inflater algorithm occasionally reads one more byte than it needs + * to. But it double checks that it doesn't actually care what's in that + * extra byte. + *===========================================================================*/ + + +/* Change some definitions so that this compiles nicely, even if it is + * compiled as part of something that requires real malloc() and free() + */ +#if !JAR_INFLATER_INSIDE_KVM +# undef START_TEMPORARY_ROOTS +# undef END_TEMPORARY_ROOTS +# undef MAKE_TEMPORARY_ROOT +# define START_TEMPORARY_ROOTS +# define END_TEMPORARY_ROOTS +# define MAKE_TEMPORARY_ROOT(x) +# define mallocBytes(x) malloc(x) +# define freeBytes(x) if (x == NULL) {} else free(x) +#else +# define freeBytes(x) +#endif + +bool_t +inflate(JarCompressedType compData, /* compressed data source */ + int compLen, /* length of compressed data */ + unsigned char *decompData, /* buffer to store decompressed data */ + int decompLen) /* length of decompression buffer */ +{ + inflaterState stateStruct; + bool_t result; +/* Temporarily define state, so that LOAD_IN, LOAD_OUT, etc. macros work */ +#define state (&stateStruct) + stateStruct.out = decompData; + stateStruct.outStart = decompData; + stateStruct.outEnd = decompData + decompLen; + + stateStruct.inFile = compData; + stateStruct.inData = 0; + stateStruct.inDataSize = 0; + stateStruct.inRemaining = compLen + INFLATER_EXTRA_BYTES; + +#ifdef JAR_DEBUG_FILE + { + static int length = 0; + if (length == 0) { + struct stat stat_buffer; + stat(JAR_DEBUG_FILE, &stat_buffer); + length = stat_buffer.st_size;; + } + if (length == decompLen) { + FILE *f = fopen(JAR_DEBUG_FILE, "rb"); + state->jarDebugBytes = malloc(length); + fseek(f, 0, SEEK_SET); + fread(state->jarDebugBytes, sizeof(char), length, f); + fclose(f); + } else { + state->jarDebugBytes = NULL; + } + } +#endif + + for(;;) { + int type; + DECLARE_IN_VARIABLES + + LOAD_IN; + NEEDBITS(3); + type = NEXTBITS(3); + DUMPBITS(3); + STORE_IN; + + switch (type >> 1) { + default: + case BTYPE_INVALID: + ziperr("Invalid BTYPE"); + result = FALSE; + break; + + case BTYPE_NO_COMPRESSION: + result = inflateStored(state); + break; + + case BTYPE_FIXED_HUFFMAN: + result = inflateHuffman(state, TRUE); + break; + + case BTYPE_DYNA_HUFFMAN: + START_TEMPORARY_ROOTS + result = inflateHuffman(state, FALSE); + END_TEMPORARY_ROOTS + break; + } + + if (!result || (type & 1)) { + break; + } + } + + if (state->inRemaining + (state->inDataSize >> 3) != INFLATER_EXTRA_BYTES) { + ziperr("Error on the input bits"); + result = FALSE; + } else if (state->out != state->outEnd) { + ziperr("Error on the output bits"); + result = FALSE; + } + +#ifdef JAR_DEBUG_FILE + if (state->jarDebugBytes != NULL) { + free(state->jarDebugBytes); + } +#endif + + /* Remove temporary definition of state defined above */ +#undef state + + return result; +} + + +/*========================================================================= + * FUNCTION: inflateStored + * TYPE: Huffman code Decoding helper function + * OVERVIEW: Used by inflate() for BTYPE_NO_COMPRESSION. + * INTERFACE: + * parameters: inflaterState: *state + * + * returns: boolean type + *=======================================================================*/ +static bool_t +inflateStored(inflaterState *state) +{ + DECLARE_IN_VARIABLES + DECLARE_OUT_VARIABLES + unsigned len, nlen; + + LOAD_IN; LOAD_OUT; + + DUMPBITS(inDataSize & 7); /* move to byte boundary */ + NEEDBITS(32) + len = NEXTBITS(16); + DUMPBITS(16); + nlen = NEXTBITS(16); + DUMPBITS(16); + + ASSERT(inDataSize == 0); + + if (len + nlen != 0xFFFF) { + ziperr("Bad length field"); + return FALSE; + } else if ((unsigned) inRemaining < len) { + ziperr("Input overflow"); + return FALSE; + } else if (out + len > state->outEnd) { + ziperr("Output overflow"); + return FALSE; + } else { + if (!COPY_N_BYTES(out, len)) { + ziperr("Bad Read"); + return FALSE; + } + inRemaining -= len; + out += len; + } + STORE_IN; + STORE_OUT; + return TRUE; +} + + +/*========================================================================= + * FUNCTION: inflateHuffman + * TYPE: Huffman code Decoding helper function + * OVERVIEW: Used by inflate() for BTYPE_FIXED_HUFFMAN and BTYPE_DYNA_HUFFMAN. + * INTERFACE: + * parameters: inflaterState: *state + * bool_t: fixedHuffman + * + * returns: boolean type + *=======================================================================*/ +static bool_t +inflateHuffman(inflaterState *state, bool_t fixedHuffman) +{ + DECLARE_IN_VARIABLES + DECLARE_OUT_VARIABLES + unsigned char *outStart = state->outStart; + unsigned char *outEnd = state->outEnd; + + bool_t noerror = FALSE; + unsigned int quickDataSize = 0, quickDistanceSize = 0; + unsigned int code, litxlen; + HuffmanCodeTable *lcodes, *dcodes; + + if (!fixedHuffman) { + if (!decodeDynamicHuffmanTables(state, &lcodes, &dcodes)) { + return FALSE; + } + quickDataSize = lcodes->h.quickBits; + quickDistanceSize = dcodes->h.quickBits; + } + + LOAD_IN; + LOAD_OUT; + + for (;;) { + if (inRemaining < 0) { + goto done_loop; + } + NEEDBITS(MAX_BITS + MAX_ZIP_EXTRA_LENGTH_BITS); + + if (fixedHuffman) { + /* literal (hex) + * 0x100 - 0x117 7 0.0000.00 - 0.0101.11 + * 0 - 8f 8 0.0110.000 - 1.0111.111 + * 118 - 11f 8 1.1000.000 - 1.1000.111 + * 90 - ff 9 1.1001.0000 - 1.1111.1111 + */ + + /* Get 9 bits, and reverse them. */ + code = NEXTBITS(9); + code = REVERSE_9BITS(code); + if (code < 0x060) { + /* A 7-bit code */ + DUMPBITS(7); + litxlen = 0x100 + (code >> 2); + } else if (code < 0x190) { + DUMPBITS(8); + litxlen = (code >> 1) + ((code < 0x180) ? (0x000 - 0x030) + : (0x118 - 0x0c0)); + } else { + DUMPBITS(9); + litxlen = 0x90 + code - 0x190; + } + } else { + GET_HUFFMAN_ENTRY(lcodes, quickDataSize, litxlen, done_loop); + } + + if (litxlen <= 255) { + if (out < outEnd) { +#ifdef JAR_DEBUG_FILE + if (state->jarDebugBytes && state->jarDebugBytes[out - outStart] != litxlen) { + ziperr("Dragon single byte"); + } +#endif + *out++ = litxlen; + } else { + goto done_loop; + } + } else if (litxlen == 256) { /* end of block */ + noerror = TRUE; + goto done_loop; + } else if (litxlen > 285) { + ziperr("Invalid literal/length"); + goto done_loop; + } else { + unsigned int n = litxlen - LITXLEN_BASE; + unsigned int length = ll_length_base[n]; + unsigned int moreBits = ll_extra_bits[n]; + unsigned int d0, distance; + + /* The NEEDBITS(..) above took care of this */ + length += NEXTBITS(moreBits); + DUMPBITS(moreBits); + + NEEDBITS(MAX_BITS); + if (fixedHuffman) { + d0 = REVERSE_5BITS(NEXTBITS(5)); + DUMPBITS(5); + } else { + GET_HUFFMAN_ENTRY(dcodes, quickDistanceSize, d0, done_loop); + } + + if (d0 > MAX_ZIP_DISTANCE_CODE) { + ziperr("Bad distance code"); + goto done_loop; + } + + NEEDBITS(MAX_ZIP_EXTRA_DISTANCE_BITS) + distance = dist_base[d0]; + moreBits = dist_extra_bits[d0]; + distance += NEXTBITS(moreBits); + DUMPBITS(moreBits); + + if (out - distance < outStart) { + ziperr("copy underflow"); + goto done_loop; + } else if (out + length > outEnd) { + ziperr("Output overflow"); + goto done_loop; + } else { + unsigned char *prev = out - distance; + unsigned char *end = out + length; + while (out != end) { +#ifdef JAR_DEBUG_FILE + if (state->jarDebugBytes + && state->jarDebugBytes[out - outStart] != *prev) { + ziperr("Dragon copy error"); + } +#endif + *out++ = *prev++; + } + } + } + } + + done_loop: + STORE_IN; + STORE_OUT; + + if (!JAR_INFLATER_INSIDE_KVM && !fixedHuffman) { + freeBytes(lcodes); + freeBytes(dcodes); + } + return noerror; +} + + +/*========================================================================= + * FUNCTION: decodeDynamicHuffmanTables + * TYPE: Huffman code Decoding + * OVERVIEW: Used by inflateHuffman() for decoding dynamic Huffman tables. + * INTERFACE: + * parameters: inflaterState: *state + * HuffmanCodeTable: **lcodesPtr + * HuffmanCodeTable: **dcodesPtr + * + * returns: TRUE if successful in decoding or + * FALSE if an error occurs + *=======================================================================*/ + +static bool_t +decodeDynamicHuffmanTables(inflaterState *state, + HuffmanCodeTable **lcodesPtr, + HuffmanCodeTable **dcodesPtr) { + DECLARE_IN_VARIABLES + + HuffmanCodeTable *ccodes = NULL; + HuffmanCodeTable *lcodes = NULL; + HuffmanCodeTable *dcodes = NULL; + + int hlit, hdist, hclen; + int i; + unsigned int quickBits; + unsigned char codelen[286 + 32]; + unsigned char *codePtr, *endCodePtr; + + LOAD_IN; + + /* 5 Bits: HLIT, # of Literal/Length codes - 257 (257 - 286) */ + /* 5 Bits: HDIST, # of Distance codes - 1 (1 - 32) */ + /* 4 Bits: HCLEN, # of Code Length codes - 4 (4 - 19) */ + NEEDBITS(14); + hlit = 257 + NEXTBITS(5); + DUMPBITS(5); + hdist = 1 + NEXTBITS(5); + DUMPBITS(5); + hclen = 4 + NEXTBITS(4); + DUMPBITS(4); + + /* + * (HCLEN + 4) x 3 bits: code lengths for the code length + * alphabet given just above, in the order: 16, 17, 18, + * 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + * + * These code lengths are interpreted as 3-bit integers + * (0-7); as above, a code length of 0 means the + * corresponding symbol (literal/length or distance code + * length) is not used. + */ + memset(codelen, 0x0, 19); + for (i=0; ih.quickBits; + + /* + * HLIT + 257 code lengths for the literal/length alphabet, + * encoded using the code length Huffman code. + * + * HDIST + 1 code lengths for the distance alphabet, + * encoded using the code length Huffman code. + * + * The code length repeat codes can cross from HLIT + 257 to the + * HDIST + 1 code lengths. In other words, all code lengths form + * a single sequence of HLIT + HDIST + 258 values. + */ + + memset(codelen, 0x0, sizeof(codelen)); + for ( codePtr = codelen, endCodePtr = codePtr + hlit + hdist; + codePtr < endCodePtr; ) { + int val; + + if (inRemaining < 0) { + goto error; + } + + NEEDBITS(MAX_BITS + 7); /* 7 is max repeat bits below */ + GET_HUFFMAN_ENTRY(ccodes, quickBits, val, error); + + /* + * 0 - 15: Represent code lengths of 0 - 15 + * 16: Copy the previous code length 3 - 6 times. + * 3 + (2 bits of length) + * 17: Repeat a code length of 0 for 3 - 10 times. + * 3 + (3 bits of length) + * 18: Repeat a code length of 0 for 11 - 138 times + * 11 + (7 bits of length) + */ + if (val <= 15) { + *codePtr++ = val; + } else if (val <= 18) { + unsigned repeat = (val == 18) ? 11 : 3; + unsigned bits = (val == 18) ? 7 : (val - 14); + + repeat += NEXTBITS(bits); /* The NEEDBITS is above */ + DUMPBITS(bits); + + if (codePtr + repeat > endCodePtr) { + ziperr("Bad repeat code"); + } + + if (val == 16) { + if (codePtr == codelen) { + ziperr("Bad repeat code"); + goto error; + } + memset(codePtr, codePtr[-1], repeat); + } else { + /* The values have already been set to zero, above, so + * we don't have to do anything */ + } + codePtr += repeat; + } else { + ziperr("Bad code-length code"); + goto error; + } + } + + + lcodes = makeCodeTable(state, codelen, hlit, MAX_QUICK_LXL); + if (lcodes == NULL) { + goto error; + } + + dcodes = makeCodeTable(state, codelen + hlit, hdist, MAX_QUICK_CXD); + if (dcodes == NULL) { + goto error; + } + + *lcodesPtr = lcodes; + *dcodesPtr = dcodes; + STORE_IN; + if (!JAR_INFLATER_INSIDE_KVM) { + freeBytes(ccodes); + } + return TRUE; + +error: + if (!JAR_INFLATER_INSIDE_KVM) { + freeBytes(ccodes); + freeBytes(dcodes); + freeBytes(lcodes); + } + return FALSE; +} + + +/*========================================================================= + * FUNCTION: makeCodeTable + * TYPE: Huffman code table creation + * INTERFACE: + * parameters: inflaterState + * code length + * number of elements of the alphabet + * maxQuickBits + * returns: Huffman code table created if successful or + * NULL if an error occurs + *=======================================================================*/ + +HuffmanCodeTable * makeCodeTable( + inflaterState *state, + unsigned char *codelen, /* Code lengths */ + unsigned numElems, /* Number of elements of the alphabet */ + unsigned maxQuickBits) /* If the length of a code is longer than + * number of bits, the code is + * stored in the sequential lookup table + * instead of the quick lookup array. */ +{ + unsigned int bitLengthCount[MAX_BITS + 1]; + unsigned int codes[MAX_BITS + 1]; + unsigned bits, minCodeLen = 0, maxCodeLen = 0; + const unsigned char *endCodeLen = codelen + numElems; + unsigned int code, quickMask; + unsigned char *p; + + HuffmanCodeTable * table; + int mainTableLength, longTableLength, numLongTables; + int tableSize; + int j; + + unsigned short *nextLongTable; + + /* Count the number of codes for each code length */ + memset(bitLengthCount, 0, sizeof(bitLengthCount)); + for (p = codelen; p < endCodeLen; p++) { + bitLengthCount[*p]++; + } + + if (bitLengthCount[0] == numElems) { + ziperr("Bad code table -- empty"); + return NULL; + } + + /* Find the minimum and maximum. It's faster to do it in a separate + * loop that goes 1..MAX_BITS, than in the above loop that looks at + * every code element */ + code = minCodeLen = maxCodeLen = 0; + for (bits = 1; bits <= MAX_BITS; bits++) { + codes[bits] = code; + if (bitLengthCount[bits] != 0) { + if (minCodeLen == 0) minCodeLen = bits; + maxCodeLen = bits; + code += bitLengthCount[bits] << (MAX_BITS - bits); + } + } + + if (INCLUDEDEBUGCODE) { + if (code != (1 << MAX_BITS)) { + code += (1 << (MAX_BITS - maxCodeLen)); + if (code != (1 << MAX_BITS)) { + ziperr("Unexpected bit codes"); + } + } + } + + /* Calculate the size of the code table and allocate it. */ + if (maxCodeLen <= maxQuickBits) { + /* We don't need any subtables. We may even be able to get + * away with a table smaller than maxCodeLen + */ + maxQuickBits = maxCodeLen; + mainTableLength = (1 << maxCodeLen); + numLongTables = longTableLength = 0; + } else { + mainTableLength = (1 << maxQuickBits); + numLongTables = (1 << MAX_BITS) - codes[maxQuickBits + 1]; + numLongTables = numLongTables >> (MAX_BITS - maxQuickBits); + longTableLength = 1 << (maxCodeLen - maxQuickBits); + } + ASSERT(mainTableLength == 1 << maxQuickBits); + tableSize = sizeof(HuffmanCodeTableHeader) + + (mainTableLength + numLongTables * longTableLength) * + sizeof(table->entries[0]); + table = (HuffmanCodeTable*)mallocBytes(tableSize); + nextLongTable = &table->entries[mainTableLength]; + MAKE_TEMPORARY_ROOT(table); + + memset(table, 0, tableSize); + + table->h.maxCodeLen = maxCodeLen; + table->h.quickBits = maxQuickBits; + + quickMask = (1 << maxQuickBits) - 1; + + for (p = codelen; p < endCodeLen; p++) { + unsigned short huff; + bits = *p; + if (bits == 0) { + continue; + } + /* Get the next code of the current length */ + code = codes[bits]; + codes[bits] += 1 << (MAX_BITS - bits); + code = REVERSE_15BITS(code); + huff = ((p - codelen) << 4) + bits; + if (bits <= maxQuickBits) { + unsigned stride = 1 << bits; + for (j = code; j < mainTableLength; j += stride) { + table->entries[j] = huff; + } + } else { + unsigned short *thisLongTable; + unsigned stride = 1 << (bits - maxQuickBits); + unsigned int prefixCode = code & quickMask; + unsigned int suffixCode = code >> maxQuickBits; + if (table->entries[prefixCode] == 0) { + /* This in the first long code with the indicated prefix. + * Create a pointer to the subtable */ + long delta = (char *)nextLongTable - (char *)table; + table->entries[prefixCode] = (unsigned short)(HUFFINFO_LONG_MASK | delta); + thisLongTable = nextLongTable; + nextLongTable += longTableLength; + } else { + long delta = table->entries[prefixCode] & ~HUFFINFO_LONG_MASK; + thisLongTable = (unsigned short *)((char *)table + delta); + } + for (j = suffixCode; j < longTableLength; j += stride) { + thisLongTable[j] = huff; + } + } + if (INCLUDEDEBUGCODE && inflateVerbose > 0) { + putchar(' '); + + for (j = 15; j >= 0; j--) { + char c = (j >= (signed)bits) ? ' ' + : (code & (1 << j)) ? '1' : '0'; + putchar(c); + } + fprintf(stdout, + " Char = %02x, Code = %4x\n", (p - codelen), code); + } + + } + ASSERT(nextLongTable == &table->entries[mainTableLength + numLongTables * longTableLength]); + + return table; +} + + +#if INCLUDEDEBUGCODE + +/*========================================================================= + * FUNCTION: ziperr + * TYPE: zip error processing function + * OVERVIEW: Used by inflate() and other functions for zip error processing. + * INTERFACE: + * parameters: const char *message + * + * returns: nothing + *=======================================================================*/ +static void +ziperr(const char *message) { + fprintf(stderr, "Zip Error: %s\n", message); +} + +#endif diff --git a/MPC.3.5.LINUX/preverifier/jar.h b/MPC.3.5.LINUX/preverifier/jar.h new file mode 100644 index 0000000..ce1ad40 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/jar.h @@ -0,0 +1,206 @@ +/* + * Copyright (c) 1999 Sun Microsystems, Inc. All Rights Reserved. + * + * This software is the confidential and proprietary information of Sun + * Microsystems, Inc. ("Confidential Information"). You shall not + * disclose such Confidential Information and shall use it only in + * accordance with the terms of the license agreement you entered into + * with Sun. + * + * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE + * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES + * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + * Use is subject to license terms. + */ + +/*========================================================================= + * SYSTEM: KVM + * SUBSYSTEM: JAR file reader. + * FILE: jar.h + * OVERVIEW: Public header file for the JAR file reader module. + * The JAR DataStream API is used by the Pre-verifier for loading + * JAR files. + * AUTHOR: Tasneem Sayeed + *=======================================================================*/ + +#ifndef _JAR_H_ +#define _JAR_H_ + +#include "typedefs.h" +#include "stdio.h" +#include "sys/types.h" +#include "stddef.h" + + +/* + * Debug flag for JAR support + */ +#define JAR_DEBUG 0 + +/*========================================================================= + * JAR file reader defines and macros + *=======================================================================*/ + +/* + * Supported compression types + */ +#define STORED 0 +#define DEFLATED 8 + +#define MAX_BITS 15 /* Maximum number of codes in Huffman Code Table */ + +/* + * Header sizes including signatures + */ +#define LOCHDRSIZ 30 +#define CENHDRSIZ 46 +#define ENDHDRSIZ 22 + +/* + * Header field access macros + */ +#define CH(b, n) ((long)(((unsigned char *)(b))[n])) +#define SH(b, n) ((long)(CH(b, n) | (CH(b, n+1) << 8))) +#define LG(b, n) ((long)(SH(b, n) | (SH(b, n+2) << 16))) + +#define GETSIG(b) LG(b, 0) /* signature */ + +#define LOCSIG (('P' << 0) + ('K' << 8) + (3 << 16) + (4 << 24)) +#define CENSIG (('P' << 0) + ('K' << 8) + (1 << 16) + (2 << 24)) +#define ENDSIG (('P' << 0) + ('K' << 8) + (5 << 16) + (6 << 24)) + +#define freeBytes(x) if (x == NULL) {} else free(x) + + +/* + * Macros for getting local file header (LOC) fields + */ +#define LOCVER(b) SH(b, 4) /* version needed to extract */ +#define LOCFLG(b) SH(b, 6) /* encrypt flags */ +#define LOCHOW(b) SH(b, 8) /* compression method */ +#define LOCTIM(b) LG(b, 10) /* modification time */ +#define LOCCRC(b) LG(b, 14) /* uncompressed file crc-32 value */ +#define LOCSIZ(b) LG(b, 18) /* compressed size */ +#define LOCLEN(b) LG(b, 22) /* uncompressed size */ +#define LOCNAM(b) SH(b, 26) /* filename size */ +#define LOCEXT(b) SH(b, 28) /* extra field size */ + +/* + * Macros for getting central directory header (CEN) fields + */ +#define CENVEM(b) SH(b, 4) /* version made by */ +#define CENVER(b) SH(b, 6) /* version needed to extract */ +#define CENFLG(b) SH(b, 8) /* general purpose bit flags */ +#define CENHOW(b) SH(b, 10) /* compression method */ +#define CENTIM(b) LG(b, 12) /* file modification time (DOS format) */ +#define CENCRC(b) LG(b, 16) /* crc of uncompressed data */ +#define CENSIZ(b) LG(b, 20) /* compressed size */ +#define CENLEN(b) LG(b, 24) /* uncompressed size */ +#define CENNAM(b) SH(b, 28) /* length of filename */ +#define CENEXT(b) SH(b, 30) /* length of extra field */ +#define CENCOM(b) SH(b, 32) /* file comment length */ +#define CENDSK(b) SH(b, 34) /* disk number start */ +#define CENATT(b) SH(b, 36) /* internal file attributes */ +#define CENATX(b) LG(b, 38) /* external file attributes */ +#define CENOFF(b) LG(b, 42) /* offset of local header */ + +/* + * Macros for getting end of central directory header (END) fields + */ +#define ENDSUB(b) SH(b, 8) /* number of entries on this disk */ +#define ENDTOT(b) SH(b, 10) /* total number of entries */ +#define ENDSIZ(b) LG(b, 12) /* central directory size */ +#define ENDOFF(b) LG(b, 16) /* central directory offset */ +#define ENDCOM(b) SH(b, 20) /* size of zip file comment */ + +/*========================================================================= + * Macros for Huffman Codes used by the JAR file reader + *=======================================================================*/ + +/* + * This is the algorithm for decoding Huffman-encoded + * data. + * + * loop (until end of block code recognized) + * decode literal/length value from input stream + * if value < 256 + * copy value (literal byte) to output stream + * otherwise + * if value = end of block (256) + * break from loop + * otherwise (value = 257..285) + * decode distance from input stream + * + * move backwards distance bytes in the output + * stream, and copy length bytes from this + * position to the output stream. + * end loop + */ +#define BTYPE_NO_COMPRESSION 0x00 +#define BTYPE_FIXED_HUFFMAN 0x01 /* Fixed Huffman Code */ +#define BTYPE_DYNA_HUFFMAN 0x02 /* Dynamic Huffman code */ +#define BTYPE_INVALID 0x03 /* Invalid code */ + +#define LITXLEN_BASE 257 + + +/*========================================================================= + * JAR DataStream API for reading and writing to/from JAR files + *=======================================================================*/ + +#define JAR_READ 1 /* Mode for reading from a JAR data stream */ +#define JAR_WRITE 2 /* Mode for writing from a JAR data stream */ +#define JAR_RESOURCE 1 /* type of resource (see JAR_DataStream) */ + +/*========================================================================= + * JAR Data Stream structure + *=======================================================================*/ +typedef struct JAR_DataStream { + unsigned char *data; /* data stream for reading/writing */ + int type; /* indicates type of resource */ + int dataLen; /* length of data stream */ + int dataIndex; /* current position for reading */ + int mode; /* mode for reading or writing */ + /* mode must be either JAR_READ or JAR_WRITE */ +} JAR_DataStream; + +typedef struct JAR_DataStream* JAR_DataStreamPtr; + +/*========================================================================= + * Forward declarations for JAR DataStream API + *=======================================================================*/ +int JAR_ReadBytes(JAR_DataStream *ds, char *buf, int len); +int JAR_WriteBytes(JAR_DataStream *ds, char *buf, int len); +int JAR_SkipBytes(JAR_DataStream *ds, int len); + +/*========================================================================= + * Forward declarations for JAR file reader + *=======================================================================*/ + + + +typedef FILE *JarCompressedType; +/* +typedef const unsigned char *JarCompressedType; +*/ + +bool_t inflate(JarCompressedType data, int compLen, + unsigned char *decompData, int decompLen); + +/* Any caller to inflate must ensure that it is safe to read at least + * this many bytes beyond compData + compLen + */ +#define INFLATER_EXTRA_BYTES 4 + + +/* + * Indicates whether JAR inflater is executed from KVM or a stand-alone + * program. + */ +#define JAR_INFLATER_INSIDE_KVM 0 + +#endif /* _JAR_H_ */ diff --git a/MPC.3.5.LINUX/preverifier/jar_support.c b/MPC.3.5.LINUX/preverifier/jar_support.c new file mode 100644 index 0000000..7748dde --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/jar_support.c @@ -0,0 +1,1347 @@ +/* * @(#)jar_support.c 1.24 01/07/19 + * + * Copyright 1997, 1998 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +/*========================================================================= + * SYSTEM: Verifier + * SUBSYSTEM: JAR support routines for the verifier. + * FILE: jar_support.c + * OVERVIEW: JAR support routines for verifying class files from a ZIP or + * JAR file. + * Note that the JAR file reader used is based on the KVM + * implementation with some modifications. + * AUTHOR: Tasneem Sayeed, Java Consumer Technologies, Sun Microsystems + *=======================================================================*/ + +/*========================================================================= + * Include files + *=======================================================================*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "sys_api.h" +#include "path_md.h" +#include "path.h" +#include "oobj.h" +#include "jar.h" +#include "convert_md.h" + +#include + +#ifdef WIN32 +#include +#endif +/*========================================================================= + * Globals and extern declarations + *=======================================================================*/ + +//extern int errno; +char str_buffer[STRINGBUFFERSIZE]; /* shared string buffer */ +bool_t JARfile = FALSE; /* if true, indicates that output is in a + JAR file */ +extern bool_t tmpDirExists; + /* if true, indicates that a temp dir exists + with classes to be verified */ +char *zipFileName = NULL; /* stores name of the zip file */ +extern char tmp_dir[32]; /* temporary directory for storing + verified classes */ +extern char *output_dir; /* output directory */ + +char manifestfile[1024]; /* used for saving the JAR manifest file name */ + +extern void VerifyFile(register char *fn); + + +/*========================================================================= + * FUNCTION: isJARfile + * OVERVIEW: Determines if the given file is a JAR or ZIP file. + * Returns true if the suffix ends with ".jar" or ".zip". + * INTERFACE: + * parameters: fn: name of the JAR file + * length: length of data, in bytes + * returns: boolean type + *=======================================================================*/ +bool_t +isJARfile (char *fn, int length) +{ + char *suffix; + + + if (length >= 4 && + (( suffix = fn + length - 4)[0] == '.') && + ((( _toupper(suffix[1]) == 'Z') && + ( _toupper(suffix[2]) == 'I') && + ( _toupper(suffix[3]) == 'P')) || + (( _toupper(suffix[1]) == 'J') && + ( _toupper(suffix[2]) == 'A') && + ( _toupper(suffix[3]) == 'R')))) { + return TRUE; + } else { + return FALSE; + } +} + + +/*========================================================================= + * FUNCTION: isManifestfile + * OVERVIEW: Determines if the given file is a JAR Manifest file. + * Returns true if the file ends with "MANIFEST.MF". + * INTERFACE: + * parameters: fn: name of the JAR manifest file + * length: length of data, in bytes + * returns: boolean type + *=======================================================================*/ +bool_t +isManifestfile (char *fn, int length) +{ + if ((length >= 11) && + (strcmp(fn + length - 11, "MANIFEST.MF") == 0)) { + return TRUE; + } else { + return FALSE; + } +} + + +/*========================================================================= + * FUNCTION: ensure_tmpdir_exists + * OVERVIEW: Validates to ensure that the tmpdir exists using the + * system-specific directory delimiters. + * + * INTERFACE: + * parameters: char* dir name + * returns: nothing + *=======================================================================*/ +void ensure_tmpdir_exists(char *dir) +{ + struct stat stat_buf; + char *parent; + char *q; + if (dir[0] == 0) { + return; + } + parent = strdup(dir); + q = strrchr(parent, (char)LOCAL_DIR_SEPARATOR); + if (q) { + *q = 0; + ensure_tmpdir_exists(parent); + } + if (stat(dir, &stat_buf) < 0) { + if (JAR_DEBUG && verbose) { + jio_fprintf(stderr, "Creating output directory [%s]\n", dir); + } +#ifdef WIN32 + mkdir(dir); +#endif +#ifdef UNIX + mkdir(dir, 0755); +#endif + } + free(parent); +} + + +/*========================================================================= + * FUNCTION: JARname2fname + * OVERVIEW: Converts JAR name to the system-specific file name with + * the correct directory delimiters. + * + * INTERFACE: + * parameters: char* source JAR name + * char* dest file name + * int size + * returns: char* + *=======================================================================*/ +char* +JARname2fname(char *src, char *dst, int size) { + char *buf = dst; + for (; (--size > 0) && (*src != '\0') ; src++, dst++) { + if (*src == '/') { + *dst = (char)LOCAL_DIR_SEPARATOR; + } else { + *dst = *src; + } + } + dst++; + *dst = '\0'; + return buf; +} + + +/*========================================================================= + * FUNCTION: getZipEntry + * OVERVIEW: Converts a zip file to a Zip entry type. + * INTERFACE: + * parameters: zipFile: name of the JAR file + * len: length of data, in bytes + * returns: zip entry type + *=======================================================================*/ +zip_t * +getZipEntry (char *zipFile, int len) { + zip_t * zipEntry = NULL; /* for processing errors */ + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "getZipEntry: JAR file [%s] Size [%d]\n", zipFile, len); + + /* create the zip entry for loading the ZIP file */ + zipEntry = (zip_t *) sysMalloc(sizeof(zip_t) + len); + if (zipEntry == NULL) { + fprintf(stderr, "getZipEntry: Out of memory\n"); + exit(1); + } + + memcpy(zipEntry->name, zipFile, len); + + zipEntry->name[len] = '\0'; + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, "getZipEntry: Zip Entry Name [%s]\n", zipEntry->name); + + + zipEntry->type = '\0'; + return zipEntry; +} + + +/*========================================================================= + * FUNCTION: findJARDirectories + * OVERVIEW: Helper function used for JAR loading for locating JAR + * directories. + * It returns TRUE if it is successful in locating the + * JAR directory headers, false otherwise. + * If successful, + * entry->jar.locpos is set to the position of the first + * local header. + * entry->jar.cenpos is set to the position of the first + * central header. + * + * Note that *locpos pointer is the logical "0" of the file. + * All offsets extracted need to have this value added to them. + * + * INTERFACE: + * parameters: entry: zipFileEntry + * statbuf: pointer to the stat buffer + * returns: boolean type + *=======================================================================*/ + +bool_t +findJARDirectories(zip_t *entry, struct stat *statbuf) +{ + bool_t result = FALSE; + long length = statbuf->st_size; + long position, minPosition; + char *bp; + FILE *file; + + char *buffer = str_buffer; + unsigned const int bufferSize = STRINGBUFFERSIZE; + + /* Calculate the smallest possible position for the end header. It + * can be at most 0xFFFF + ENDHDRSIZ bytes from the end of the file, but + * the file must also have a local header and a central header + */ + minPosition = length - (0xFFFF + ENDHDRSIZ); + if (minPosition < LOCHDRSIZ + CENHDRSIZ) { + minPosition = LOCHDRSIZ + CENHDRSIZ; + } + + file = fopen(entry->name, "rb"); + if (file == NULL) { + goto done; + } + + /* Read in the last ENDHDRSIZ bytes into the buffer. 99% of the time, + * the file won't have a comment, and this is the only read we'll need */ + if ( (fseek(file, -ENDHDRSIZ, SEEK_END) < 0) + || (fread(buffer, sizeof(char), ENDHDRSIZ, file) != ENDHDRSIZ)) { + goto done; + } + /* Get the position in the file stored into buffer[0] */ + position = length - ENDHDRSIZ; /* Position in file of buffer[0] */ + bp = buffer; /* Where to start looking */ + for (;;) { + /* "buffer" contains a block of data from the file, starting at + * position "position" in the file. + * We investigate whether position + (bp - buffer) is the start + * of the end header in the zip file. This file position is at + * position bp in the buffer. + */ + /* Use simplified version of Knuth Morris Pratt search algorithm. */ + switch(bp[0]) { + case '\006': /* The header must start at least 3 bytes back */ + bp -= 3; break; + case '\005': /* The header must start at least 2 bytes back */ + bp -= 2; break; + case 'K': /* The header must start at least 1 byte back */ + bp -= 1; break; + case 'P': /* Either this is the header, or the header must + * start at least 4 back + */ + if (bp[1] == 'K' && bp[2] == 5 && bp[3] == 6) { + int endpos = position + (bp - buffer); + if (endpos + ENDHDRSIZ + ENDCOM(bp) == length) { + unsigned long cenpos = endpos - ENDSIZ(bp); + unsigned long locpos = cenpos - ENDOFF(bp); + entry->jar.cenpos = cenpos; + entry->jar.locpos = locpos; + result = TRUE; + goto done; + } + } + /* FALL THROUGH */ + default: /* This char isn't in the header signature, so + * the header must start at least four chars back */ + bp -= 4; + } + + if (bp < buffer) { + /* We've moved outside our window into the file. We must + * move the window backwards */ + int count = position - minPosition; /* Bytes left in file */ + if (count == 0) { + /* Nothing left to read. Time to give up */ + goto done; + } else { + /* up to ((bp - buffer) + ENDHDRSIZ) bytes in the buffer might + * still be part of the end header, so the most bytes we can + * actually read are + * bufferSize - ((bp - buffer) + ENDHDRSIZE). + */ + int available = (bufferSize - ENDHDRSIZ) + (buffer - bp); + if (count > available) { + count = available; + } + } + /* Back up, while keeping our virtual position the same */ + position -= count; + bp += count; + memmove(buffer + count, buffer, bufferSize - count); + if ( (fseek(file, position, SEEK_SET) < 0) + || (fread(buffer, sizeof(char), count, file) != (unsigned)count)) { + goto done; + } + } + } /* end of for loop */ + + done: + if (file != NULL) { + fclose(file); + } + return result; +} + + +/*========================================================================= + * FUNCTION: jarCRC32 + * OVERVIEW: Returns the CRC of an array of bytes, using the same + * algorithm as used by the JAR reader. + * INTERFACE: + * parameters: data: pointer to the array of bytes + * length: length of data, in bytes + * returns: CRC + *=======================================================================*/ + +static unsigned long +jarCRC32(unsigned char *data, unsigned long length) { + unsigned long crc = 0xFFFFFFFF; + unsigned int j; + for ( ; length > 0; length--, data++) { + crc ^= *data; + for (j = 8; j > 0; --j) { + crc = (crc & 1) ? ((crc >> 1) ^ 0xedb88320) : (crc >> 1); + } + } + return ~crc; +} + + +/*========================================================================= + * FUNCTION: loadJARfile() + * TYPE: load JAR file + * OVERVIEW: Internal function used by openClassfileInternal(). + * + * This function reads the specified class file from the JAR file. The + * result is returned as a JAR_DataStream*. NULL is returned if it + * cannot find the file, or there is some error. + * + * INTERFACE: + * parameters: entry: zip file entry for the JAR file + * filename: class file name to search for + * returns: JAR_DataStream* for saving the JAR file info, or NULL. + *=======================================================================*/ + +JAR_DataStreamPtr +loadJARfile(zip_t *entry, const char* filename) +{ + JAR_DataStreamPtr jdstream = NULL; /* result on error */ + unsigned int filenameLength; + unsigned int nameLength; + char buff[BUFSIZ]; + char *UTFfilename = &buff[0]; + char *p = str_buffer; /* temporary storage */ + int offset; + char *fname = NULL; + FILE *file = fopen(entry->name, "rb"); + if (file == NULL) { + goto done; + } + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "loadJARfile: Opening zip file %s to search for [%s]\n", + entry->name, filename); + + /* add the .class to the filename */ + + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "loadJARfile: Adding '.class' to %s size [%d]\n", filename, strlen(filename)); + + /* Conversion for Japanese filenames */ + native2utf8(filename, UTFfilename, BUFSIZ); + + /* allocate fname large enough to hold .class + '\0' terminator */ + fname = (char *)malloc(strlen(UTFfilename) + 6 + 1); + sprintf(fname, "%s.class", UTFfilename); + filenameLength=strlen(fname); + fname[filenameLength]='\0'; + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "loadJARfile: Searching for filename [%s]\n", fname); + + /* Go to the start of the central headers */ + offset = entry->jar.cenpos; + for (;;) { + + if (/* Go to the next central header */ + (fseek(file, offset, SEEK_SET) < 0) + /* Read the bytes */ + || (fread(p, sizeof(char), CENHDRSIZ, file) != CENHDRSIZ) + /* Make sure it is a header */ + || (GETSIG(p) != CENSIG)) { + goto done; + } + + /* Get the nameLength */ + nameLength = CENNAM(p); + + + if (nameLength == filenameLength) { + if (fread(p + CENHDRSIZ, sizeof(char), nameLength, file) + != nameLength) { + goto done; + } + if (memcmp(p + CENHDRSIZ, fname, nameLength) == 0) { + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, "loadJARfile: Class name found [%s]...\n", fname); + break; + } + } + + /* Set offset to the next central header */ + offset += CENHDRSIZ + nameLength + CENEXT(p) + CENCOM(p); + + } /* end loop */ + + /* p points at the central header for the file */ + { + unsigned long decompLen = CENLEN(p); /* the decompressed length */ + unsigned long compLen = CENSIZ(p); /* the compressed length */ + unsigned long method = CENHOW(p); /* how it is stored */ + unsigned long expectedCRC = CENCRC(p); /* expected CRC */ + unsigned long actualCRC; + + unsigned char *decompData; + + /* Make sure file is not encrypted */ + if ((CENFLG(p) & 1) == 1) { + fprintf(stderr, "Entry is encrypted"); + goto done; + } + + + jdstream = + (JAR_DataStreamPtr)sysMalloc(sizeof(JAR_DataStream) + decompLen); + decompData = (unsigned char *)(jdstream + 1); + + if (/* Go to the beginning of the LOC header */ + (fseek(file, entry->jar.locpos + CENOFF(p), SEEK_SET) < 0) + /* Read it */ + || (fread(p, sizeof(char), LOCHDRSIZ, file) != LOCHDRSIZ) + /* Skip over name and extension, if any */ + || (fseek(file, LOCNAM(p) + LOCEXT(p), SEEK_CUR) < 0)) { + goto done; + } + + switch (method) { + case STORED: + if (compLen != decompLen) { + return NULL; + } + fread(decompData, sizeof(char), decompLen, file); + break; + + case DEFLATED: { + bool_t inflateOK; + inflateOK = inflate(file, compLen, decompData, decompLen); + + if (!inflateOK) { + sysFree(jdstream); + jdstream = NULL; + } + break; + } + + default: + sysFree(jdstream); + jdstream = NULL; + break; + } + + actualCRC = jarCRC32(decompData, decompLen); + if (actualCRC != expectedCRC) { + printf("Unexpected CRC value"); + } + + done: + if (file != NULL) { + fclose(file); + } + + if (fname != NULL) { + sysFree(fname); + } + + if (jdstream != NULL) { + + jdstream->type = JAR_RESOURCE; + jdstream->data = decompData; + jdstream->dataLen = decompLen; + jdstream->dataIndex = 0; + jdstream->mode = JAR_READ; + } + return jdstream; + + } +} + + +/*========================================================================= + * FUNCTION: ReadFromZip() + * TYPE: Reads and verifies ZIP file entries + * OVERVIEW: Internal function used by ProcessInputs() and recurse_dir. + * + * This function reads all the Zip entries, and stores them temporarily in + * tmpdir. If the ZIP entry read is a class file, then VerifyFile is invoked + * to verify the class file. Otherwise, the file read is simply copied over + * temporarily to the tmpdir. These are later used for generating a new JAR + * file. + * + * INTERFACE: + * parameters: ZipEntry: name of the zip file entry. + * returns: nothing + *=======================================================================*/ + +void +ReadFromZip(zip_t *entry) +{ + unsigned int nameLength; + char *filename = NULL; + char *p = str_buffer; /* temporary storage */ + int offset, nextOffset; + int fd; + int status; + JAR_DataStreamPtr jdstream = NULL; + struct stat stat_buf; + unsigned char *decompData; + unsigned long decompLen; /* the decompressed length */ + + FILE *file = fopen(entry->name, "rb"); + if (file == NULL) { + goto done; + } + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "ReadFromZip: Opened zip file to read classes \n"); + + /* initialize */ + memset(manifestfile, 0, 1024); + + /* Go to the start of the central headers */ + offset = entry->jar.cenpos; + for (;;) { + + if (/* Go to the next central header */ + (fseek(file, offset, SEEK_SET) < 0) + /* Read the bytes */ + || (fread(p, sizeof(char), CENHDRSIZ, file) != CENHDRSIZ) + /* Make sure it is a header */ + || (GETSIG(p) != CENSIG)) { + goto done; + } + /* Get the nameLength */ + nameLength = CENNAM(p); + + if (fread(p + CENHDRSIZ, sizeof(char), nameLength, file) + != nameLength) { + goto done; + } + + + /* initialize the filename with nulls every time */ + + filename = (char *) sysCalloc(STRINGBUFFERSIZE, nameLength); + + if (filename == NULL) { + fprintf(stderr, "ReadFromZip: Out of memory \n"); + exit(1); + } + + memcpy(filename, p + CENHDRSIZ, nameLength); + + + /* We have to calculate nextOffset now, because VerifyFile bashes + * str_buffer + */ + nextOffset = offset + CENHDRSIZ + nameLength + CENEXT(p) + CENCOM(p); + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "ReadFromZip: filename read %s\n", filename); + + /* extract the .class from the filename */ + if (nameLength > 6 && + strcmp(filename + nameLength - 6, ".class") == 0) { + /* Verify the class file */ + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "ReadFromZip: Extracted '.class' from %s\n", filename); + + filename[nameLength-6] = 0; + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "ReadFromZip: Verifying classfile %s\n", filename); + + /* call VerifyFile to verify the class */ + VerifyFile(filename); + } else { + /* Read and copy over the file to tmpdir */ + /* p points at the central header for the file */ + unsigned long compLen = CENSIZ(p); /* the compressed length */ + unsigned long method = CENHOW(p); /* how it is stored */ + unsigned long expectedCRC = CENCRC(p); /* expected CRC */ + unsigned long actualCRC; + + decompLen = CENLEN(p); + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "READFROMZIP: Reading file [%s]...\n", filename); + + /* Make sure file is not encrypted */ + if ((CENFLG(p) & 1) == 1) { + jio_fprintf(stderr, "Entry is encrypted\n"); + goto done; + } + + jdstream = + (JAR_DataStreamPtr)sysMalloc(sizeof(JAR_DataStream) + decompLen); + decompData = (unsigned char *)(jdstream + 1); + + if (/* Go to the beginning of the LOC header */ + (fseek(file, entry->jar.locpos + CENOFF(p), SEEK_SET) < 0) + /* Read it */ + || (fread(p, sizeof(char), LOCHDRSIZ, file) != LOCHDRSIZ) + /* Skip over name and extension, if any */ + || (fseek(file, LOCNAM(p) + LOCEXT(p), SEEK_CUR) < 0)) { + goto done; + } + + switch (method) { + case STORED: + if (compLen != decompLen) { + sysFree(jdstream); + jdstream = NULL; + goto done; + } + fread(decompData, sizeof(char), decompLen, file); + break; + + case DEFLATED: { + bool_t inflateOK; + inflateOK = inflate(file, compLen, decompData, decompLen); + + if (!inflateOK) { + sysFree(jdstream); + jdstream = NULL; + } + break; + } + + default: + sysFree(jdstream); + jdstream = NULL; + break; + } + + actualCRC = jarCRC32(decompData, decompLen); + if (actualCRC != expectedCRC) { + jio_fprintf(stderr, "Unexpected CRC value\n"); + } + + /* create the tempdir if it doesn't already exist */ + { + char fname[1024]; /* file name restored from JAR */ + char *dir; + char *q; + char *sfname = fname; /* system-specific file name */ + char *dname = fname; /* destination file name */ + + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "Reading filename [%s] from JAR \n", filename); + + sprintf(fname, "%s%c%s", tmp_dir, + (char) LOCAL_DIR_SEPARATOR, + filename); + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "Before conversion: fname [%s] sfname [%s]\n", + fname, sfname); + + /* + * convert JAR name to the system-specific file name + */ + + sfname = JARname2fname(fname, dname, strlen(fname)+1); + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "After conversion: Converted [%s] to [%s]\n", + fname, sfname); + + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "Preparing to write file [%s]\n", sfname); + + dir = strdup(sfname); + q = strrchr(dir, (char)LOCAL_DIR_SEPARATOR); + if (q) { + *q = 0; + ensure_tmpdir_exists(dir); + } + free(dir); + + + /* Attempt to stat or open only if this is NOT a directory */ + + if (!(sfname[strlen(sfname)-1] == (char)LOCAL_DIR_SEPARATOR)) { + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "Attempting stat on dir [%s]\n", sfname); + + status = stat(sfname, &stat_buf); + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "Status from stat of [%s] is %d\n", sfname, status); + + /* Attempt to open only if the file does not already exist. + * This is indicated by the stat command returning -1. + * And this is not a directory. + */ + + if ((status < 0) || !(stat_buf.st_mode & S_IFDIR)) { + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "Opening file [%s]\n", sfname); +#ifdef UNIX + fd = open(sfname, O_WRONLY | O_CREAT | O_TRUNC , 0644); +#endif + +#ifdef WIN32 + fd = open(sfname, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); +#endif + + if (fd < 0) { + panic("failed to open %s", sfname); + } + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "Writing file [%s]...\n", sfname); + + /* write the file to the tmpdir just created */ + write(fd, decompData, decompLen); + + /* check for the JAR Manifest.mf file */ + + if (isManifestfile(sfname, strlen(sfname))) { + /* save it for using it later to create + * the JAR file + */ + memcpy(manifestfile, sfname + strlen(tmp_dir), strlen(sfname)); + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "Saving JAR manifest file [%s]\n", + manifestfile); + } + + close(fd); + } + } + } + if (jdstream != NULL) { + sysFree(jdstream); + jdstream = NULL; + } + } + + /* Set offset to the next central header */ + offset = nextOffset; + sysFree(filename); + filename = NULL; + } +done: + if (file != NULL) { + fclose(file); + } + + if (jdstream != NULL) { + jdstream->type = JAR_RESOURCE; + jdstream->data = decompData; + jdstream->dataLen = decompLen; + jdstream->dataIndex = 0; + jdstream->mode = JAR_READ; + } + + if (filename != NULL) + sysFree(filename); +} + + +/*========================================================================= + * FUNCTION: remove_dir() + * TYPE: Handles removing files from recursive directories + * OVERVIEW: Internal function called by ProcessJARfile(). + * + * This function reads a directory, searching for either another directory, + * or an individual class name that is to be removed using the remove() + * API call. + * + * INTERFACE: + * parameters: dirname name of the directory entry. + * pkgname name of the package + * returns: nothing + *=======================================================================*/ +static void remove_dir(char *dirname, char *pkgname) +{ + struct dirent *ent; + char buf[MAXPACKAGENAME]; + char pkgbuf[MAXPACKAGENAME]; + char tmpbuf[MAXPACKAGENAME]; + char tmppkg[MAXPACKAGENAME]; + char tmppkgbuf[MAXPACKAGENAME]; + char *name = NULL; + DIR *dir = opendir(dirname); + int err = 0; + int status; + + /* Initialize the buffers to 0 */ + memset(buf, 0, sizeof(buf)); + memset(pkgbuf, 0, sizeof(pkgbuf)); + memset(tmpbuf, 0, sizeof(tmpbuf)); + memset(tmppkg, 0, sizeof(tmppkg)); + memset(tmppkgbuf, 0, sizeof(tmppkgbuf)); + + if (dir == NULL) { + fprintf(stderr, "Can't open dir %s\n", dirname); + exit(1); + } + for (ent = readdir(dir); ent; ent = readdir(dir)) { + struct stat stat_buf; + int len; + name = ent->d_name; + + if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { + continue; + } + + strcpy(pkgbuf, pkgname); + if (pkgname[0] != 0) { + /* concatenate '/' to the package name */ + sprintf(tmppkgbuf, "%s%c", pkgbuf, (char)LOCAL_DIR_SEPARATOR); + } + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "remove_dir: Reading filename [%s] from directory [%s]\n", + name, dirname); + + /* we just have a class file that needs to be removed */ + + len = strlen(name); + + /* append the dirname and name */ + strcpy(buf, dirname); + strcat(buf, name); + + + status = stat(buf, &stat_buf); + + if ((status == 0) && !(stat_buf.st_mode & S_IFDIR)) { + /* remove if this is a file and not a directory */ + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "remove_dir: Removing file [%s] \n", buf); + + err = remove(buf); + + if (JAR_DEBUG && verbose) { + jio_fprintf(stderr, + "remove_dir: remove() returned error %d\n", err); + } + + } else { + strcat(tmppkgbuf, name); + stat(buf, &stat_buf); + len = strlen(buf); + + if (stat_buf.st_mode & S_IFDIR) { + /* handle the recursive directory found */ + + sprintf(tmpbuf, "%s%c", buf, (char)LOCAL_DIR_SEPARATOR); + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "remove_dir: Recursive dir, calling remove_dir [%s,%s]\n", + tmpbuf, tmppkgbuf); + remove_dir(tmpbuf, tmppkgbuf); + continue; + } + } + + } + + /* close the directory to free the dirp first */ + closedir(dir); + + +#ifdef WIN32 + /* remove the trailing '\' from the directory */ + { + int tmppkglen = strlen(dirname); + dirname[tmppkglen-1] = '\0'; + } +#endif + + /* Remove the directory by calling rmdir() or remove() API as appropriate */ + + sprintf(tmppkg,"%s", dirname); + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "remove_dir: Removing [%s]\n", tmppkg); + +#ifdef WIN32 + err = rmdir(tmppkg); + + if (JAR_DEBUG && verbose) { + if (err != 0) { + jio_fprintf(stderr, + "remove_dir: rmdir(%s) failed with error %d\n", + tmppkg, err); + } + } +#endif + +#ifdef UNIX + err = remove (tmppkg); + + if (JAR_DEBUG && verbose) { + if (err != 0) { + jio_fprintf(stderr, + "remove_dir: remove(%s) failed with error %d\n", + tmppkg, err); + } + } +#endif + +} +/*========================================================================= + * FUNCTION: ProcessJARfile() + * TYPE: Processes ZIP file entries + * OVERVIEW: Internal function called by ProcessInputs(). + * + * This function processes a JAR file by first creating a zip entry for + * reading JAR directories, then calls ReadFromZip() to read the Zip + * class names and verifies them. It finally creates a new JAR file and + * places all the verified classes into it. + * It returns a boolean type to indicate if a valid JAR file was found + * and the contents of the JAR file were processed without errors. + * + * INTERFACE: + * parameters: buf: JAR file name. + * len: size of the file + * returns: boolean type + *=======================================================================*/ +bool_t ProcessJARfile(char *buf, int len) { + + zip_t *zipEntry; + struct stat stat_buf; + char *fname = NULL; + char *buffer = NULL; + char *jarName = NULL; + char dirdelim = '\0'; /* directory delimiter */ + int err = 0; + int tmpdir_len = 0; + int statcode; + char tmpdir_buf[MAXPACKAGENAME]; + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "ProcessJARfile: JAR file [%s] Size [%d]\n", buf, len); + + statcode = stat(buf, &stat_buf); + + /* Create the zip entry for searching the JAR directories. + * If the zip entry is NULL, it would indicate that we ran + * out of memory and would have exited already. + */ + + zipEntry = getZipEntry (buf, len); + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, "Searching for JAR directories...\n"); + + + /* search for the JAR directories */ + if (findJARDirectories(zipEntry, &stat_buf)) { + /* the JAR directories were found */ + + JARfile = TRUE; + zipFileName = buf; + if (JAR_DEBUG && verbose) { + jio_fprintf(stderr, + "ProcessJARfile: JAR directory [%s] found \n", + zipEntry->name); + } + + zipEntry->type = 'j'; + + /* Read and Verify the classes from the ZIP file */ + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, "ProcessJARfile: Verifying Zip class names...\n"); + + pushJarFileOntoClassPath(zipEntry); + + ReadFromZip(zipEntry); + + popClassPath(); + + /* Ensure that the output_dir also exists or create it if it + * does not already exist + */ + + if (output_dir != NULL) { + char *dir = strdup(output_dir); + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, "ProcessJARfile: Checking if output [%s] exists\n", + output_dir); + ensure_dir_exists(dir); + ensure_dir_writable(dir); + free(dir); + } + + /* Create a JAR file only if the input parameter was a JAR file, + * the tmp_dir was created with classes verified and an output + * dir also exists. + */ + + if (JARfile && tmpDirExists && tmp_dir && output_dir) { + const char *p; + + /* Allocate enough space to hold the JAR name */ + jarName = (char *)sysCalloc(len+32, len); + + if (jarName == NULL) { + fprintf(stderr, "ProcessJARfile: Out of memory"); + exit(1); + } + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, "ProcessJARfile: Creating JAR file of verified classes...\n"); + /* search for the last '/' to get the actual JAR file name */ + for (p = buf+len; ;) { + --p; + + if (*p == '/' || *p == '\\') { + dirdelim = *p; + memcpy(jarName, p+1, (len-1)-(p-buf)); + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, "ProcessJARfile: JAR file [%s]\n", jarName); + break; + } + if (p == buf) { + /* no directories in path, get the individual JAR name */ + strncpy(jarName, buf, len); + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, "ProcessJARfile: JAR filename [%s]\n", jarName); + break; + } + } + + /* move the verified classes into a JAR file */ + + /* Be sure to allocate enough space to hold the sprintfs below */ + fname = (char *)malloc(strlen(output_dir)+ len+32); + + if (fname == NULL) { + fprintf(stderr, "ProcessJARfile: Out of memory"); + exit(1); + } + + if (dirdelim != '\0') { + sprintf(fname, "%s%c%s", output_dir, + dirdelim, jarName); + } else { + sprintf(fname, "%s%c%s", output_dir, + (char)LOCAL_DIR_SEPARATOR, jarName); + } + + /* Be sure to allocate enough space to hold the sprintfs below */ + /* The size here must be adjusted anytime the buffer used in the + * sprintfs is extended. + */ + + buffer = (char *)malloc(strlen(output_dir)+strlen(fname) + + strlen(tmp_dir) + strlen(manifestfile) + + strlen(tmp_dir) + 51); + if (buffer == NULL) { + fprintf(stderr, "ProcessJARfile: Out of memory"); + exit(1); + } + + if (verbose) { + if (isManifestfile(manifestfile, strlen(manifestfile))) { + /* use existing manifest if one exists */ + sprintf(buffer, "jar -cvfm \"%s\" %s%c%s -C %s .", + fname, tmp_dir, + (char)LOCAL_DIR_SEPARATOR, + manifestfile, tmp_dir); + + } else { + + sprintf(buffer, "jar -cvfM \"%s\" -C %s .", + fname, tmp_dir); + + } + } else { + /* Run jar in non-verbose mode, and log errors in a file */ + + if (isManifestfile(manifestfile, strlen(manifestfile))) { + /* use existing manifest if one exists */ + +#ifdef UNIX + /* create JAR with existing manifest file */ + /* Redirect errors and stdout to jarlog.txt */ + sprintf(buffer, + "sh -c \"jar -cfm \\\"%s\\\" %s%c%s -C %s .\" > \"%s%c\"%s", + fname, tmp_dir, (char)LOCAL_DIR_SEPARATOR, + manifestfile, tmp_dir, output_dir, + (char)LOCAL_DIR_SEPARATOR,"jarlog.txt 2>&1"); + +#else + sprintf(buffer, + "jar -cfm \"%s\" %s%c%s -C %s . ", + fname, tmp_dir, (char)LOCAL_DIR_SEPARATOR, + manifestfile, tmp_dir); +#endif + } else { +#ifdef UNIX + /* create JAR with no manifest since none exists */ + /* Redirect errors and stdout to jarlog.txt */ + sprintf(buffer, + "sh -c \"jar -cfM \\\"%s\\\" -C %s .\" > \"%s%c\"%s", + fname, tmp_dir, output_dir, + (char)LOCAL_DIR_SEPARATOR,"jarlog.txt 2>&1"); +#else + sprintf(buffer, + "jar -cfM \"%s\" -C %s . ", + fname, tmp_dir); +#endif + + } + } + if (verbose) { + jio_fprintf(stderr, "Executing command [%s]\n", buffer); + } + +#ifdef WIN32 + /* system() function does not return the exit code of the child + * process under Windows98. + * The documentation states: + * "If command is not NULL, system returns the value that is + * returned by the command interpreter.". + * Thus it is probably a bug within 'command.com'. + * Note that _spawnlp correctly returns the exit status of the + * new process. + */ + if (verbose) { + err = _spawnlp(_P_WAIT, "jar", "jar", buffer+4, NULL); + if (err != 0) { + fprintf(stderr, "%s\n", buffer); + perror("Error"); + } + } else { + int cstderr; + int cstdout; + FILE *logfile; + + /* Save stderr and stdout*/ + if ((cstderr = dup(_fileno(stderr))) == -1) { + fprintf(stderr, "Cannot copy dup stderr\n"); + } + if ((cstdout = dup(_fileno(stdout))) == -1) { + fprintf(stderr, "Cannot copy dup stdout\n"); + } + + sprintf(tmpdir_buf, "%s\\%s", output_dir, "jarlog.txt"); + if ((logfile = fopen(tmpdir_buf, "w")) == NULL) { + fprintf(stderr, "Cannot create output file\n"); + exit(1); + } + + if (_dup2(_fileno(logfile), _fileno(stderr)) == -1) { + fprintf(stderr, "dup2 failed for stderr\n"); + exit(1); + } + + if (_dup2(_fileno(logfile), _fileno(stdout)) == -1) { + fprintf(stderr, "dup2 failed for stdout\n"); + exit(1); + } + + err = _spawnlp(_P_WAIT, "jar", "jar", buffer+4, NULL); + if (err != 0) { + fprintf(stderr, "%s\n", buffer); + perror("Error"); + } + + fflush(stderr); + fflush(stdout); + fclose(logfile); + + /* Restore stderr and stdout */ + _dup2(cstderr, _fileno(stderr)); + _dup2(cstdout, _fileno(stdout)); + + memset(tmpdir_buf,0,sizeof(tmpdir_buf)); + } +#else + err = system(buffer); +#endif + + if (err != 0) { + /* jar file creation failed - return back the error */ + fprintf(stderr, "JAR file creation failed with error %d\n", err); + if (!verbose) + fprintf(stderr, +"The preverified classes if any are in %s. See jar log of errors in %s%c%s \n", + tmp_dir, output_dir, (char)LOCAL_DIR_SEPARATOR, "jarlog.txt"); + } else { + if (!verbose) { + /* remove the jar log file if no error occurred */ + char *jarfn = NULL; + int error; + + jarfn = (char *)malloc(strlen(output_dir)+10+1+1); + + if (jarfn == NULL) { + fprintf(stderr, "ProcessJARfile: Out of memory"); + exit(1); + } + + sprintf(jarfn, "%s%c%s", output_dir, + (char)LOCAL_DIR_SEPARATOR, "jarlog.txt"); + error = remove(jarfn); /* remove the file */ + + if (jarfn != NULL) + sysFree(jarfn); + } + + /* prepare to remove the tmp directory */ + /* copy the tmp directory name to a buffer */ + strcpy(tmpdir_buf, tmp_dir); + tmpdir_len = strlen(tmp_dir); + + /* Append dir separator if it does not yet exist */ + if (tmpdir_buf[tmpdir_len - 1] != LOCAL_DIR_SEPARATOR && + tmpdir_buf[tmpdir_len - 1] != DIR_SEPARATOR) { + tmpdir_buf[tmpdir_len] = LOCAL_DIR_SEPARATOR; + tmpdir_buf[tmpdir_len + 1] = 0; + } + + /* remove the tmp_dir and all its contents recursively */ + remove_dir(tmpdir_buf, ""); + } /* jar creation returned no error */ + } + } else { + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, "JAR directories not found for JAR file [%s]\n", buf); + if (fname != NULL) + sysFree(fname); + if (zipEntry != NULL) + sysFree(zipEntry); + + return FALSE; /* could not locate JAR directories - invalid JAR file */ + } + + if (fname != NULL) + sysFree(fname); + + if (zipEntry != NULL) + sysFree(zipEntry); + + if (buffer != NULL) + sysFree(buffer); + + if (jarName != NULL) + sysFree(jarName); + + if ( err!=0 ) { + exit(errorCode = 1); + } + + return JARfile; +} diff --git a/MPC.3.5.LINUX/preverifier/jarint.h b/MPC.3.5.LINUX/preverifier/jarint.h new file mode 100644 index 0000000..18ec849 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/jarint.h @@ -0,0 +1,224 @@ +/* + * Copyright (c) 1999 Sun Microsystems, Inc. All Rights Reserved. + * + * This software is the confidential and proprietary information of Sun + * Microsystems, Inc. ("Confidential Information"). You shall not + * disclose such Confidential Information and shall use it only in + * accordance with the terms of the license agreement you entered into + * with Sun. + * + * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE + * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES + * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + * Use is subject to license terms. + */ + +/*========================================================================= + * SYSTEM: KVM + * SUBSYSTEM: JAR file reader. + * FILE: jarint.h + * OVERVIEW: Internal declarations for JAR file reader. This file should + * be included only by files in the core KVM. + * AUTHOR: Ioi Lam. + *=======================================================================*/ + +#ifndef _JAR_INT_H_ +#define _JAR_INT_H_ + +/* + * indicates whether JAR inflater uses standard i/o during decompression + */ +#define JAR_INFLATER_USES_STDIO 1 + +/* + * The HuffmanCodeTable structure contains the dynamic huffman codes for + * the Code Length Codes or the Distance Codes. The structure is + * dynamically allocated. We just allocate enough space to contain all + * possible codes. + */ + +typedef struct HuffmanCodeTableHeader { + unsigned short quickBits; /* quick bit size */ + unsigned short maxCodeLen; /* Max number of bits in any code */ +} HuffmanCodeTableHeader; + + +/* If this bit is set in a huffman entry, it means that this is not + * really an entry, but a pointer into the long codes table. + * The remaining 15 bits is the offset (in bytes) from the table header + * to first "long" entry representing this item. + */ + +#define HUFFINFO_LONG_MASK 0x8000 /* high bit set */ + +#define MAX_QUICK_CXD 6 +#define MAX_QUICK_LXL 9 + +/* For debugging, the following can be set to the name of a file (in quotes). + * If we are decompressing something that is the exact same length as that + * file, this will check to make sure that the decompressed bytes look + * exactly the same as the bytes in the specified file. + * java/lang/String.class is a particularly useful file to try. + * + */ + +#ifndef inflateVerbose +#define inflateVerbose 0 +#endif + +#if INCLUDEDEBUGCODE + static void ziperr(const char * msg); +# define ASSERT(x) assert((x)) +#else +# define ziperr(msg) +# define ASSERT(x) (void)0 +#endif + + +/* A normal sized huffman code table with a 9-bit quick bit */ +typedef struct HuffmanCodeTable { + struct HuffmanCodeTableHeader h; + /* There are 1 << quickBit entries. 512 is just an example. + * For each entry: + * If the high bit is 0: + * Next 11 bits give the character + * Low 4 bits give the actual number of bits used + * If the high bit is 1: + * Next 15 bits give the offset (in bytes) from the header to + * the first long entry dealing with this long code. + */ + unsigned short entries[512]; +} HuffmanCodeTable; + + +/* A small sized huffman code table with a 9-bit quick bit. We have + * this so that we can initialize fixedHuffmanDistanceTable in jartables.h + */ +typedef struct shortHuffmanCodeTable { + struct HuffmanCodeTableHeader h; + unsigned short entries[32]; +} shortHuffmanCodeTable; + + +typedef struct inflaterState { + /* The input stream */ + JarCompressedType inFile; + + int inRemaining; /* Number of bytes left that we can read */ + unsigned int inDataSize; /* Number of good bits in inData */ + unsigned long inData; /* Low inDataSize bits are from stream. + * High unused bits must be zero + */ + /* The output stream */ + unsigned char *out; /* Current output position */ + unsigned char *outStart; /* Start and end of output buffer */ + unsigned char *outEnd; +#ifdef JAR_DEBUG_FILE + unsigned char *jarDebugBytes; +#endif +} inflaterState; + + +/*========================================================================= + * Macros used internally + *=======================================================================*/ + +/* Call this macro to make sure that we have at least "j" bits of + * input available + */ + +#define NEEDBITS(j) { \ + while (inDataSize < (j)) { \ + inData |= ((unsigned long)NEXTBYTE) << inDataSize; \ + inRemaining--; inDataSize += 8; \ + } \ + ASSERT(inDataSize <= 32); \ +} + + +/* Return (without consuming) the next "j" bits of the input */ +#define NEXTBITS(j) \ + (ASSERT((j) <= inDataSize), inData & ((1 << (j)) - 1)) + +/* Consume (quietly) "j" bits of input, and make them no longer available + * to the user + */ +#define DUMPBITS(j) { \ + ASSERT((j) <= inDataSize); \ + inData >>= (j); \ + inDataSize -= (j); \ + } + +/* Read bits from the input stream and decode it using the specified + * table. The resulting decoded character is placed into "result". + * If there is a problem, we goto "errorLabel" + * + * For speed, we assume that quickBits = table->h.quickBits and that + * it has been cached into a variable. + */ + + +#define GET_HUFFMAN_ENTRY(table, quickBits, result, errorLabel) { \ + unsigned int huff = table->entries[NEXTBITS(quickBits)]; \ + if (huff & HUFFINFO_LONG_MASK) { \ + long delta = (huff & ~HUFFINFO_LONG_MASK); \ + unsigned short *table2 = (unsigned short *)((char *)table + delta); \ + huff = table2[NEXTBITS(table->h.maxCodeLen) >> quickBits]; \ + } \ + if (huff == 0) { goto errorLabel; } \ + DUMPBITS(huff & 0xF); \ + result = huff >> 4; \ + } + + +#if JAR_INFLATER_USES_STDIO +# define LOAD_INFILE_IF_NECESSARY +# define STORE_INFILE_IF_NECESSARY +# define INITIALIZE_INFILE_IF_NECESSARY = state->inFile +# define NEXTBYTE fgetc(inFile) +# define COPY_N_BYTES(buffer, n) (fread(buffer, 1, n, inFile) == n) + +#else +# define LOAD_INFILE_IF_NECESSARY inFile = state->inFile; +# define STORE_INFILE_IF_NECESSARY state->inFile = inFile; +# define INITIALIZE_INFILE_IF_NECESSARY +# define NEXTBYTE (*inFile++) +# define COPY_N_BYTES(buffer, n) \ + (memcpy(buffer, inFile, n), inFile += n, TRUE) +#endif + + +/* Copy values from the inflaterState structure to local variables */ +#define LOAD_IN \ + LOAD_INFILE_IF_NECESSARY \ + inData = state->inData; \ + inDataSize = state->inDataSize; \ + inRemaining = state->inRemaining; + + +/* Copy values from local variables back to the inflaterState structure */ +#define STORE_IN \ + STORE_INFILE_IF_NECESSARY \ + state->inData = inData; \ + state->inDataSize = inDataSize; \ + state->inRemaining = inRemaining; + + +#define DECLARE_IN_VARIABLES \ + register JarCompressedType inFile INITIALIZE_INFILE_IF_NECESSARY; \ + register unsigned long inData; \ + register unsigned int inDataSize; \ + register long inRemaining; \ + +#define LOAD_OUT out = state->out; + +#define STORE_OUT state->out = out; + +#define DECLARE_OUT_VARIABLES \ + register unsigned char *out; + +#endif /* JAR_INT_H_ */ diff --git a/MPC.3.5.LINUX/preverifier/jartables.h b/MPC.3.5.LINUX/preverifier/jartables.h new file mode 100644 index 0000000..b6c2e8f --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/jartables.h @@ -0,0 +1,779 @@ +/* + * Copyright (c) 1999 Sun Microsystems, Inc. All Rights Reserved. + * + * This software is the confidential and proprietary information of Sun + * Microsystems, Inc. ("Confidential Information"). You shall not + * disclose such Confidential Information and shall use it only in + * accordance with the terms of the license agreement you entered into + * with Sun. + * + * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE + * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES + * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + * Use is subject to license terms. + */ + +/*========================================================================= + * SYSTEM: KVM + * SUBSYSTEM: JAR file reader. + * FILE: jartables.h + * OVERVIEW: Public header file for the JAR file reader tables. + * AUTHOR: Ioi Lam + * Tasneem Sayeed + *=========================================================================*/ + +#ifndef _KJARTABLES_H_ +#define _KJARTABLES_H_ + +static const unsigned char ll_extra_bits[] = { + /* 257 */ 0, /* 3 */ + /* 258 */ 0, /* 4 */ + /* 259 */ 0, /* 5 */ + /* 260 */ 0, /* 6 */ + /* 261 */ 0, /* 7 */ + /* 262 */ 0, /* 8 */ + /* 263 */ 0, /* 9 */ + /* 264 */ 0, /* 10 */ + /* 265 */ 1, /* 11,12 */ + /* 266 */ 1, /* 13,14 */ + + /* 267 */ 1, /* 15,16 */ + /* 268 */ 1, /* 17,18 */ + /* 269 */ 2, /* 19-22 */ + /* 270 */ 2, /* 23-26 */ + /* 271 */ 2, /* 27-30 */ + /* 272 */ 2, /* 31-34 */ + /* 273 */ 3, /* 35-42 */ + /* 274 */ 3, /* 43-50 */ + /* 275 */ 3, /* 51-58 */ + /* 276 */ 3, /* 59-66 */ + + /* 277 */ 4, /* 67-82 */ + /* 278 */ 4, /* 83-98 */ + /* 279 */ 4, /* 99-114 */ + /* 280 */ 4, /* 115-130 */ + /* 281 */ 5, /* 131-162 */ + /* 282 */ 5, /* 163-194 */ + /* 283 */ 5, /* 195-226 */ + /* 284 */ 5, /* 227-257 */ + /* 285 */ 0, /* 258 */ +}; + +#define MAX_ZIP_EXTRA_LENGTH_BITS 5 + +static const unsigned short ll_length_base[] = { + /* 257 0 */ 3, + /* 258 0 */ 4, + /* 259 0 */ 5, + /* 260 0 */ 6, + /* 261 0 */ 7, + /* 262 0 */ 8, + /* 263 0 */ 9, + /* 264 0 */ 10, + /* 265 1 */ 11, /* - 12 */ + /* 266 1 */ 13, /* - 14 */ + + /* 267 1 */ 15, /* - 16 */ + /* 268 1 */ 17, /* - 18 */ + /* 269 2 */ 19, /* - 22 */ + /* 270 2 */ 23, /* - 26 */ + /* 271 2 */ 27, /* - 30 */ + /* 272 2 */ 31, /* - 34 */ + /* 273 3 */ 35, /* - 42 */ + /* 274 3 */ 43, /* - 50 */ + /* 275 3 */ 51, /* - 58 */ + /* 276 3 */ 59, /* - 66 */ + + /* 277 4 */ 67, /* - 82 */ + /* 278 4 */ 83, /* - 98 */ + /* 279 4 */ 99, /* - 114 */ + /* 280 4 */ 115, /* - 130 */ + /* 281 5 */ 131, /* - 162 */ + /* 282 5 */ 163, /* - 194 */ + /* 283 5 */ 195, /* - 226 */ + /* 284 5 */ 227, /* - 257 */ + /* 285 0 */ 258 +}; + + +static const unsigned char dist_extra_bits[] = { + /* 0 */ 0, /* 1 */ + /* 1 */ 0, /* 2 */ + /* 2 */ 0, /* 3 */ + /* 3 */ 0, /* 4 */ + /* 4 */ 1, /* 5,6 */ + /* 5 */ 1, /* 7,8 */ + /* 6 */ 2, /* 9-12 */ + /* 7 */ 2, /* 13-16 */ + /* 8 */ 3, /* 17-24 */ + /* 9 */ 3, /* 25-32 */ + + /* 10 */ 4, /* 33-48 */ + /* 11 */ 4, /* 49-64 */ + /* 12 */ 5, /* 65-96 */ + /* 13 */ 5, /* 97-128 */ + /* 14 */ 6, /* 129-192 */ + /* 15 */ 6, /* 193-256 */ + /* 16 */ 7, /* 257-384 */ + /* 17 */ 7, /* 385-512 */ + /* 18 */ 8, /* 513-768 */ + /* 19 */ 8, /* 769-1024 */ + + /* 20 */ 9, /* 1025-1536 */ + /* 21 */ 9, /* 1537-2048 */ + /* 22 */ 10, /* 2049-3072 */ + /* 23 */ 10, /* 3073-4096 */ + /* 24 */ 11, /* 4097-6144 */ + /* 25 */ 11, /* 6145-8192 */ + /* 26 */ 12, /* 8193-12288 */ + /* 27 */ 12, /* 12289-16384 */ + /* 28 */ 13, /* 16385-24576 */ + /* 29 */ 13, /* 24577-32768 */ +}; + +#define MAX_ZIP_EXTRA_DISTANCE_BITS 13 +#define MAX_ZIP_DISTANCE_CODE 29 + +static const unsigned int dist_base[] = { + /* 0 0 */ 1, + /* 1 0 */ 2, + /* 2 0 */ 3, + /* 3 0 */ 4, + /* 4 1 */ 5, /* -6 */ + /* 5 1 */ 7, /* -8 */ + /* 6 2 */ 9, /* -12 */ + /* 7 2 */ 13, /* -16 */ + /* 8 3 */ 17, /* -24 */ + /* 9 3 */ 25, /* -32 */ + + /* 10 4 */ 33, /* -48 */ + /* 11 4 */ 49, /* -64 */ + /* 12 5 */ 65, /* -96 */ + /* 13 5 */ 97, /* -128 */ + /* 14 6 */ 129, /* -192 */ + /* 15 6 */ 193, /* -256 */ + /* 16 7 */ 257, /* -384 */ + /* 17 7 */ 385, /* -512 */ + /* 18 8 */ 513, /* -768 */ + /* 19 8 */ 769, /* -1024 */ + /* 20 9 */ 1025, /* -1536 */ + /* 21 9 */ 1537, /* -2048 */ + /* 22 10 */ 2049, /* -3072 */ + /* 23 10 */ 3073, /* -4096 */ + /* 24 11 */ 4097, /* -6144 */ + /* 25 11 */ 6145, /* -8192 */ + /* 26 12 */ 8193, /* -12288 */ + /* 27 12 */ 12289, /* -16384 */ + /* 28 13 */ 16385, /* -24576 */ + /* 29 13 */ 24577, /* -32768 */ +}; + + +/* + * The order in which the code lengths of the Code Length Alphabet is + * given. See section 3.2.7 of RFC 1951. + */ + +static const char ccode_idx[] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15, +}; + +/* A table for reversing 5 bits in a binary number */ + +static const unsigned char reverse5[] = { + 0x0, 0x10, 0x8, 0x18, 0x4, 0x14, 0xc, 0x1c, + 0x2, 0x12, 0xa, 0x1a, 0x6, 0x16, 0xe, 0x1e, + 0x1, 0x11, 0x9, 0x19, 0x5, 0x15, 0xd, 0x1d, + 0x3, 0x13, 0xb, 0x1b, 0x7, 0x17, 0xf, 0x1f +}; + +#define REVERSE_5BITS(code) reverse5[code] +#define REVERSE_9BITS(code) \ + ((reverse5[((code) & 0x1F)] << 4) | reverse5[(code) >> 4]) +#define REVERSE_15BITS(code) \ + ( (reverse5[code & 0x1F] << 10) | (reverse5[((code) >> 5) & 0x1F] << 5) \ + | (reverse5[code >> 10]) ) + + +#define HUFFMAN_ENTRY(char, bits) ((char << 4) + bits) + + +#ifdef USE_FIXED_HUFFMAN_CODE_TABLES + +/* The following tables are currently used, but they can be in + * releases that care for speed rather that size. + * + * "Fixed Huffman" can use the following tables, rather than doing the + * complicated calculations that it does. + */ + + +static const struct HuffmanCodeTable fixedHuffmanCodeTable = { + { + 7, /* min code length */ + 9, /* max code length */ + }, + { + HUFFMAN_ENTRY(0x100, 7), + HUFFMAN_ENTRY('P', 8), + HUFFMAN_ENTRY(0x010, 8), + HUFFMAN_ENTRY(0x118, 8), + HUFFMAN_ENTRY(0x110, 7), + HUFFMAN_ENTRY('p', 8), + HUFFMAN_ENTRY('0', 8), + HUFFMAN_ENTRY(0x0c0, 9), + HUFFMAN_ENTRY(0x108, 7), + HUFFMAN_ENTRY('`', 8), + HUFFMAN_ENTRY(' ', 8), + HUFFMAN_ENTRY(0x0a0, 9), + HUFFMAN_ENTRY(0x000, 8), + HUFFMAN_ENTRY(0x080, 8), + HUFFMAN_ENTRY('@', 8), + HUFFMAN_ENTRY(0x0e0, 9), + HUFFMAN_ENTRY(0x104, 7), + HUFFMAN_ENTRY('X', 8), + HUFFMAN_ENTRY(0x018, 8), + HUFFMAN_ENTRY(0x090, 9), + HUFFMAN_ENTRY(0x114, 7), + HUFFMAN_ENTRY('x', 8), + HUFFMAN_ENTRY('8', 8), + HUFFMAN_ENTRY(0x0d0, 9), + HUFFMAN_ENTRY(0x10c, 7), + HUFFMAN_ENTRY('h', 8), + HUFFMAN_ENTRY('(', 8), + HUFFMAN_ENTRY(0x0b0, 9), + HUFFMAN_ENTRY(0x008, 8), + HUFFMAN_ENTRY(0x088, 8), + HUFFMAN_ENTRY('H', 8), + HUFFMAN_ENTRY(0x0f0, 9), + HUFFMAN_ENTRY(0x102, 7), + HUFFMAN_ENTRY('T', 8), + HUFFMAN_ENTRY(0x014, 8), + HUFFMAN_ENTRY(0x11c, 8), + HUFFMAN_ENTRY(0x112, 7), + HUFFMAN_ENTRY('t', 8), + HUFFMAN_ENTRY('4', 8), + HUFFMAN_ENTRY(0x0c8, 9), + HUFFMAN_ENTRY(0x10a, 7), + HUFFMAN_ENTRY('d', 8), + HUFFMAN_ENTRY('$', 8), + HUFFMAN_ENTRY(0x0a8, 9), + HUFFMAN_ENTRY(0x004, 8), + HUFFMAN_ENTRY(0x084, 8), + HUFFMAN_ENTRY('D', 8), + HUFFMAN_ENTRY(0x0e8, 9), + HUFFMAN_ENTRY(0x106, 7), + HUFFMAN_ENTRY('\\', 8), + HUFFMAN_ENTRY(0x01c, 8), + HUFFMAN_ENTRY(0x098, 9), + HUFFMAN_ENTRY(0x116, 7), + HUFFMAN_ENTRY('|', 8), + HUFFMAN_ENTRY('<', 8), + HUFFMAN_ENTRY(0x0d8, 9), + HUFFMAN_ENTRY(0x10e, 7), + HUFFMAN_ENTRY('l', 8), + HUFFMAN_ENTRY(',', 8), + HUFFMAN_ENTRY(0x0b8, 9), + HUFFMAN_ENTRY(0x00c, 8), + HUFFMAN_ENTRY(0x08c, 8), + HUFFMAN_ENTRY('L', 8), + HUFFMAN_ENTRY(0x0f8, 9), + HUFFMAN_ENTRY(0x101, 7), + HUFFMAN_ENTRY('R', 8), + HUFFMAN_ENTRY(0x012, 8), + HUFFMAN_ENTRY(0x11a, 8), + HUFFMAN_ENTRY(0x111, 7), + HUFFMAN_ENTRY('r', 8), + HUFFMAN_ENTRY('2', 8), + HUFFMAN_ENTRY(0x0c4, 9), + HUFFMAN_ENTRY(0x109, 7), + HUFFMAN_ENTRY('b', 8), + HUFFMAN_ENTRY('"', 8), + HUFFMAN_ENTRY(0x0a4, 9), + HUFFMAN_ENTRY(0x002, 8), + HUFFMAN_ENTRY(0x082, 8), + HUFFMAN_ENTRY('B', 8), + HUFFMAN_ENTRY(0x0e4, 9), + HUFFMAN_ENTRY(0x105, 7), + HUFFMAN_ENTRY('Z', 8), + HUFFMAN_ENTRY(0x01a, 8), + HUFFMAN_ENTRY(0x094, 9), + HUFFMAN_ENTRY(0x115, 7), + HUFFMAN_ENTRY('z', 8), + HUFFMAN_ENTRY(':', 8), + HUFFMAN_ENTRY(0x0d4, 9), + HUFFMAN_ENTRY(0x10d, 7), + HUFFMAN_ENTRY('j', 8), + HUFFMAN_ENTRY('*', 8), + HUFFMAN_ENTRY(0x0b4, 9), + HUFFMAN_ENTRY(0x00a, 8), + HUFFMAN_ENTRY(0x08a, 8), + HUFFMAN_ENTRY('J', 8), + HUFFMAN_ENTRY(0x0f4, 9), + HUFFMAN_ENTRY(0x103, 7), + HUFFMAN_ENTRY('V', 8), + HUFFMAN_ENTRY(0x016, 8), + HUFFMAN_ENTRY(0x11e, 8), + HUFFMAN_ENTRY(0x113, 7), + HUFFMAN_ENTRY('v', 8), + HUFFMAN_ENTRY('6', 8), + HUFFMAN_ENTRY(0x0cc, 9), + HUFFMAN_ENTRY(0x10b, 7), + HUFFMAN_ENTRY('f', 8), + HUFFMAN_ENTRY('&', 8), + HUFFMAN_ENTRY(0x0ac, 9), + HUFFMAN_ENTRY(0x006, 8), + HUFFMAN_ENTRY(0x086, 8), + HUFFMAN_ENTRY('F', 8), + HUFFMAN_ENTRY(0x0ec, 9), + HUFFMAN_ENTRY(0x107, 7), + HUFFMAN_ENTRY('^', 8), + HUFFMAN_ENTRY(0x01e, 8), + HUFFMAN_ENTRY(0x09c, 9), + HUFFMAN_ENTRY(0x117, 7), + HUFFMAN_ENTRY('~', 8), + HUFFMAN_ENTRY('>', 8), + HUFFMAN_ENTRY(0x0dc, 9), + HUFFMAN_ENTRY(0x10f, 7), + HUFFMAN_ENTRY('n', 8), + HUFFMAN_ENTRY('.', 8), + HUFFMAN_ENTRY(0x0bc, 9), + HUFFMAN_ENTRY(0x00e, 8), + HUFFMAN_ENTRY(0x08e, 8), + HUFFMAN_ENTRY('N', 8), + HUFFMAN_ENTRY(0x0fc, 9), + HUFFMAN_ENTRY(0x100, 7), + HUFFMAN_ENTRY('Q', 8), + HUFFMAN_ENTRY(0x011, 8), + HUFFMAN_ENTRY(0x119, 8), + HUFFMAN_ENTRY(0x110, 7), + HUFFMAN_ENTRY('q', 8), + HUFFMAN_ENTRY('1', 8), + HUFFMAN_ENTRY(0x0c2, 9), + HUFFMAN_ENTRY(0x108, 7), + HUFFMAN_ENTRY('a', 8), + HUFFMAN_ENTRY('!', 8), + HUFFMAN_ENTRY(0x0a2, 9), + HUFFMAN_ENTRY(0x001, 8), + HUFFMAN_ENTRY(0x081, 8), + HUFFMAN_ENTRY('A', 8), + HUFFMAN_ENTRY(0x0e2, 9), + HUFFMAN_ENTRY(0x104, 7), + HUFFMAN_ENTRY('Y', 8), + HUFFMAN_ENTRY(0x019, 8), + HUFFMAN_ENTRY(0x092, 9), + HUFFMAN_ENTRY(0x114, 7), + HUFFMAN_ENTRY('y', 8), + HUFFMAN_ENTRY('9', 8), + HUFFMAN_ENTRY(0x0d2, 9), + HUFFMAN_ENTRY(0x10c, 7), + HUFFMAN_ENTRY('i', 8), + HUFFMAN_ENTRY(')', 8), + HUFFMAN_ENTRY(0x0b2, 9), + HUFFMAN_ENTRY(0x009, 8), + HUFFMAN_ENTRY(0x089, 8), + HUFFMAN_ENTRY('I', 8), + HUFFMAN_ENTRY(0x0f2, 9), + HUFFMAN_ENTRY(0x102, 7), + HUFFMAN_ENTRY('U', 8), + HUFFMAN_ENTRY(0x015, 8), + HUFFMAN_ENTRY(0x11d, 8), + HUFFMAN_ENTRY(0x112, 7), + HUFFMAN_ENTRY('u', 8), + HUFFMAN_ENTRY('5', 8), + HUFFMAN_ENTRY(0x0ca, 9), + HUFFMAN_ENTRY(0x10a, 7), + HUFFMAN_ENTRY('e', 8), + HUFFMAN_ENTRY('%', 8), + HUFFMAN_ENTRY(0x0aa, 9), + HUFFMAN_ENTRY(0x005, 8), + HUFFMAN_ENTRY(0x085, 8), + HUFFMAN_ENTRY('E', 8), + HUFFMAN_ENTRY(0x0ea, 9), + HUFFMAN_ENTRY(0x106, 7), + HUFFMAN_ENTRY(']', 8), + HUFFMAN_ENTRY(0x01d, 8), + HUFFMAN_ENTRY(0x09a, 9), + HUFFMAN_ENTRY(0x116, 7), + HUFFMAN_ENTRY('}', 8), + HUFFMAN_ENTRY('=', 8), + HUFFMAN_ENTRY(0x0da, 9), + HUFFMAN_ENTRY(0x10e, 7), + HUFFMAN_ENTRY('m', 8), + HUFFMAN_ENTRY('-', 8), + HUFFMAN_ENTRY(0x0ba, 9), + HUFFMAN_ENTRY(0x00d, 8), + HUFFMAN_ENTRY(0x08d, 8), + HUFFMAN_ENTRY('M', 8), + HUFFMAN_ENTRY(0x0fa, 9), + HUFFMAN_ENTRY(0x101, 7), + HUFFMAN_ENTRY('S', 8), + HUFFMAN_ENTRY(0x013, 8), + HUFFMAN_ENTRY(0x11b, 8), + HUFFMAN_ENTRY(0x111, 7), + HUFFMAN_ENTRY('s', 8), + HUFFMAN_ENTRY('3', 8), + HUFFMAN_ENTRY(0x0c6, 9), + HUFFMAN_ENTRY(0x109, 7), + HUFFMAN_ENTRY('c', 8), + HUFFMAN_ENTRY('#', 8), + HUFFMAN_ENTRY(0x0a6, 9), + HUFFMAN_ENTRY(0x003, 8), + HUFFMAN_ENTRY(0x083, 8), + HUFFMAN_ENTRY('C', 8), + HUFFMAN_ENTRY(0x0e6, 9), + HUFFMAN_ENTRY(0x105, 7), + HUFFMAN_ENTRY('[', 8), + HUFFMAN_ENTRY(0x01b, 8), + HUFFMAN_ENTRY(0x096, 9), + HUFFMAN_ENTRY(0x115, 7), + HUFFMAN_ENTRY('{', 8), + HUFFMAN_ENTRY(';', 8), + HUFFMAN_ENTRY(0x0d6, 9), + HUFFMAN_ENTRY(0x10d, 7), + HUFFMAN_ENTRY('k', 8), + HUFFMAN_ENTRY('+', 8), + HUFFMAN_ENTRY(0x0b6, 9), + HUFFMAN_ENTRY(0x00b, 8), + HUFFMAN_ENTRY(0x08b, 8), + HUFFMAN_ENTRY('K', 8), + HUFFMAN_ENTRY(0x0f6, 9), + HUFFMAN_ENTRY(0x103, 7), + HUFFMAN_ENTRY('W', 8), + HUFFMAN_ENTRY(0x017, 8), + HUFFMAN_ENTRY(0x11f, 8), + HUFFMAN_ENTRY(0x113, 7), + HUFFMAN_ENTRY('w', 8), + HUFFMAN_ENTRY('7', 8), + HUFFMAN_ENTRY(0x0ce, 9), + HUFFMAN_ENTRY(0x10b, 7), + HUFFMAN_ENTRY('g', 8), + HUFFMAN_ENTRY('\'', 8), + HUFFMAN_ENTRY(0x0ae, 9), + HUFFMAN_ENTRY(0x007, 8), + HUFFMAN_ENTRY(0x087, 8), + HUFFMAN_ENTRY('G', 8), + HUFFMAN_ENTRY(0x0ee, 9), + HUFFMAN_ENTRY(0x107, 7), + HUFFMAN_ENTRY('_', 8), + HUFFMAN_ENTRY(0x01f, 8), + HUFFMAN_ENTRY(0x09e, 9), + HUFFMAN_ENTRY(0x117, 7), + HUFFMAN_ENTRY(0x07f, 8), + HUFFMAN_ENTRY('?', 8), + HUFFMAN_ENTRY(0x0de, 9), + HUFFMAN_ENTRY(0x10f, 7), + HUFFMAN_ENTRY('o', 8), + HUFFMAN_ENTRY('/', 8), + HUFFMAN_ENTRY(0x0be, 9), + HUFFMAN_ENTRY(0x00f, 8), + HUFFMAN_ENTRY(0x08f, 8), + HUFFMAN_ENTRY('O', 8), + HUFFMAN_ENTRY(0x0fe, 9), + HUFFMAN_ENTRY(0x100, 7), + HUFFMAN_ENTRY('P', 8), + HUFFMAN_ENTRY(0x010, 8), + HUFFMAN_ENTRY(0x118, 8), + HUFFMAN_ENTRY(0x110, 7), + HUFFMAN_ENTRY('p', 8), + HUFFMAN_ENTRY('0', 8), + HUFFMAN_ENTRY(0x0c1, 9), + HUFFMAN_ENTRY(0x108, 7), + HUFFMAN_ENTRY('`', 8), + HUFFMAN_ENTRY(' ', 8), + HUFFMAN_ENTRY(0x0a1, 9), + HUFFMAN_ENTRY(0x000, 8), + HUFFMAN_ENTRY(0x080, 8), + HUFFMAN_ENTRY('@', 8), + HUFFMAN_ENTRY(0x0e1, 9), + HUFFMAN_ENTRY(0x104, 7), + HUFFMAN_ENTRY('X', 8), + HUFFMAN_ENTRY(0x018, 8), + HUFFMAN_ENTRY(0x091, 9), + HUFFMAN_ENTRY(0x114, 7), + HUFFMAN_ENTRY('x', 8), + HUFFMAN_ENTRY('8', 8), + HUFFMAN_ENTRY(0x0d1, 9), + HUFFMAN_ENTRY(0x10c, 7), + HUFFMAN_ENTRY('h', 8), + HUFFMAN_ENTRY('(', 8), + HUFFMAN_ENTRY(0x0b1, 9), + HUFFMAN_ENTRY(0x008, 8), + HUFFMAN_ENTRY(0x088, 8), + HUFFMAN_ENTRY('H', 8), + HUFFMAN_ENTRY(0x0f1, 9), + HUFFMAN_ENTRY(0x102, 7), + HUFFMAN_ENTRY('T', 8), + HUFFMAN_ENTRY(0x014, 8), + HUFFMAN_ENTRY(0x11c, 8), + HUFFMAN_ENTRY(0x112, 7), + HUFFMAN_ENTRY('t', 8), + HUFFMAN_ENTRY('4', 8), + HUFFMAN_ENTRY(0x0c9, 9), + HUFFMAN_ENTRY(0x10a, 7), + HUFFMAN_ENTRY('d', 8), + HUFFMAN_ENTRY('$', 8), + HUFFMAN_ENTRY(0x0a9, 9), + HUFFMAN_ENTRY(0x004, 8), + HUFFMAN_ENTRY(0x084, 8), + HUFFMAN_ENTRY('D', 8), + HUFFMAN_ENTRY(0x0e9, 9), + HUFFMAN_ENTRY(0x106, 7), + HUFFMAN_ENTRY('\\', 8), + HUFFMAN_ENTRY(0x01c, 8), + HUFFMAN_ENTRY(0x099, 9), + HUFFMAN_ENTRY(0x116, 7), + HUFFMAN_ENTRY('|', 8), + HUFFMAN_ENTRY('<', 8), + HUFFMAN_ENTRY(0x0d9, 9), + HUFFMAN_ENTRY(0x10e, 7), + HUFFMAN_ENTRY('l', 8), + HUFFMAN_ENTRY(',', 8), + HUFFMAN_ENTRY(0x0b9, 9), + HUFFMAN_ENTRY(0x00c, 8), + HUFFMAN_ENTRY(0x08c, 8), + HUFFMAN_ENTRY('L', 8), + HUFFMAN_ENTRY(0x0f9, 9), + HUFFMAN_ENTRY(0x101, 7), + HUFFMAN_ENTRY('R', 8), + HUFFMAN_ENTRY(0x012, 8), + HUFFMAN_ENTRY(0x11a, 8), + HUFFMAN_ENTRY(0x111, 7), + HUFFMAN_ENTRY('r', 8), + HUFFMAN_ENTRY('2', 8), + HUFFMAN_ENTRY(0x0c5, 9), + HUFFMAN_ENTRY(0x109, 7), + HUFFMAN_ENTRY('b', 8), + HUFFMAN_ENTRY('"', 8), + HUFFMAN_ENTRY(0x0a5, 9), + HUFFMAN_ENTRY(0x002, 8), + HUFFMAN_ENTRY(0x082, 8), + HUFFMAN_ENTRY('B', 8), + HUFFMAN_ENTRY(0x0e5, 9), + HUFFMAN_ENTRY(0x105, 7), + HUFFMAN_ENTRY('Z', 8), + HUFFMAN_ENTRY(0x01a, 8), + HUFFMAN_ENTRY(0x095, 9), + HUFFMAN_ENTRY(0x115, 7), + HUFFMAN_ENTRY('z', 8), + HUFFMAN_ENTRY(':', 8), + HUFFMAN_ENTRY(0x0d5, 9), + HUFFMAN_ENTRY(0x10d, 7), + HUFFMAN_ENTRY('j', 8), + HUFFMAN_ENTRY('*', 8), + HUFFMAN_ENTRY(0x0b5, 9), + HUFFMAN_ENTRY(0x00a, 8), + HUFFMAN_ENTRY(0x08a, 8), + HUFFMAN_ENTRY('J', 8), + HUFFMAN_ENTRY(0x0f5, 9), + HUFFMAN_ENTRY(0x103, 7), + HUFFMAN_ENTRY('V', 8), + HUFFMAN_ENTRY(0x016, 8), + HUFFMAN_ENTRY(0x11e, 8), + HUFFMAN_ENTRY(0x113, 7), + HUFFMAN_ENTRY('v', 8), + HUFFMAN_ENTRY('6', 8), + HUFFMAN_ENTRY(0x0cd, 9), + HUFFMAN_ENTRY(0x10b, 7), + HUFFMAN_ENTRY('f', 8), + HUFFMAN_ENTRY('&', 8), + HUFFMAN_ENTRY(0x0ad, 9), + HUFFMAN_ENTRY(0x006, 8), + HUFFMAN_ENTRY(0x086, 8), + HUFFMAN_ENTRY('F', 8), + HUFFMAN_ENTRY(0x0ed, 9), + HUFFMAN_ENTRY(0x107, 7), + HUFFMAN_ENTRY('^', 8), + HUFFMAN_ENTRY(0x01e, 8), + HUFFMAN_ENTRY(0x09d, 9), + HUFFMAN_ENTRY(0x117, 7), + HUFFMAN_ENTRY('~', 8), + HUFFMAN_ENTRY('>', 8), + HUFFMAN_ENTRY(0x0dd, 9), + HUFFMAN_ENTRY(0x10f, 7), + HUFFMAN_ENTRY('n', 8), + HUFFMAN_ENTRY('.', 8), + HUFFMAN_ENTRY(0x0bd, 9), + HUFFMAN_ENTRY(0x00e, 8), + HUFFMAN_ENTRY(0x08e, 8), + HUFFMAN_ENTRY('N', 8), + HUFFMAN_ENTRY(0x0fd, 9), + HUFFMAN_ENTRY(0x100, 7), + HUFFMAN_ENTRY('Q', 8), + HUFFMAN_ENTRY(0x011, 8), + HUFFMAN_ENTRY(0x119, 8), + HUFFMAN_ENTRY(0x110, 7), + HUFFMAN_ENTRY('q', 8), + HUFFMAN_ENTRY('1', 8), + HUFFMAN_ENTRY(0x0c3, 9), + HUFFMAN_ENTRY(0x108, 7), + HUFFMAN_ENTRY('a', 8), + HUFFMAN_ENTRY('!', 8), + HUFFMAN_ENTRY(0x0a3, 9), + HUFFMAN_ENTRY(0x001, 8), + HUFFMAN_ENTRY(0x081, 8), + HUFFMAN_ENTRY('A', 8), + HUFFMAN_ENTRY(0x0e3, 9), + HUFFMAN_ENTRY(0x104, 7), + HUFFMAN_ENTRY('Y', 8), + HUFFMAN_ENTRY(0x019, 8), + HUFFMAN_ENTRY(0x093, 9), + HUFFMAN_ENTRY(0x114, 7), + HUFFMAN_ENTRY('y', 8), + HUFFMAN_ENTRY('9', 8), + HUFFMAN_ENTRY(0x0d3, 9), + HUFFMAN_ENTRY(0x10c, 7), + HUFFMAN_ENTRY('i', 8), + HUFFMAN_ENTRY(')', 8), + HUFFMAN_ENTRY(0x0b3, 9), + HUFFMAN_ENTRY(0x009, 8), + HUFFMAN_ENTRY(0x089, 8), + HUFFMAN_ENTRY('I', 8), + HUFFMAN_ENTRY(0x0f3, 9), + HUFFMAN_ENTRY(0x102, 7), + HUFFMAN_ENTRY('U', 8), + HUFFMAN_ENTRY(0x015, 8), + HUFFMAN_ENTRY(0x11d, 8), + HUFFMAN_ENTRY(0x112, 7), + HUFFMAN_ENTRY('u', 8), + HUFFMAN_ENTRY('5', 8), + HUFFMAN_ENTRY(0x0cb, 9), + HUFFMAN_ENTRY(0x10a, 7), + HUFFMAN_ENTRY('e', 8), + HUFFMAN_ENTRY('%', 8), + HUFFMAN_ENTRY(0x0ab, 9), + HUFFMAN_ENTRY(0x005, 8), + HUFFMAN_ENTRY(0x085, 8), + HUFFMAN_ENTRY('E', 8), + HUFFMAN_ENTRY(0x0eb, 9), + HUFFMAN_ENTRY(0x106, 7), + HUFFMAN_ENTRY(']', 8), + HUFFMAN_ENTRY(0x01d, 8), + HUFFMAN_ENTRY(0x09b, 9), + HUFFMAN_ENTRY(0x116, 7), + HUFFMAN_ENTRY('}', 8), + HUFFMAN_ENTRY('=', 8), + HUFFMAN_ENTRY(0x0db, 9), + HUFFMAN_ENTRY(0x10e, 7), + HUFFMAN_ENTRY('m', 8), + HUFFMAN_ENTRY('-', 8), + HUFFMAN_ENTRY(0x0bb, 9), + HUFFMAN_ENTRY(0x00d, 8), + HUFFMAN_ENTRY(0x08d, 8), + HUFFMAN_ENTRY('M', 8), + HUFFMAN_ENTRY(0x0fb, 9), + HUFFMAN_ENTRY(0x101, 7), + HUFFMAN_ENTRY('S', 8), + HUFFMAN_ENTRY(0x013, 8), + HUFFMAN_ENTRY(0x11b, 8), + HUFFMAN_ENTRY(0x111, 7), + HUFFMAN_ENTRY('s', 8), + HUFFMAN_ENTRY('3', 8), + HUFFMAN_ENTRY(0x0c7, 9), + HUFFMAN_ENTRY(0x109, 7), + HUFFMAN_ENTRY('c', 8), + HUFFMAN_ENTRY('#', 8), + HUFFMAN_ENTRY(0x0a7, 9), + HUFFMAN_ENTRY(0x003, 8), + HUFFMAN_ENTRY(0x083, 8), + HUFFMAN_ENTRY('C', 8), + HUFFMAN_ENTRY(0x0e7, 9), + HUFFMAN_ENTRY(0x105, 7), + HUFFMAN_ENTRY('[', 8), + HUFFMAN_ENTRY(0x01b, 8), + HUFFMAN_ENTRY(0x097, 9), + HUFFMAN_ENTRY(0x115, 7), + HUFFMAN_ENTRY('{', 8), + HUFFMAN_ENTRY(';', 8), + HUFFMAN_ENTRY(0x0d7, 9), + HUFFMAN_ENTRY(0x10d, 7), + HUFFMAN_ENTRY('k', 8), + HUFFMAN_ENTRY('+', 8), + HUFFMAN_ENTRY(0x0b7, 9), + HUFFMAN_ENTRY(0x00b, 8), + HUFFMAN_ENTRY(0x08b, 8), + HUFFMAN_ENTRY('K', 8), + HUFFMAN_ENTRY(0x0f7, 9), + HUFFMAN_ENTRY(0x103, 7), + HUFFMAN_ENTRY('W', 8), + HUFFMAN_ENTRY(0x017, 8), + HUFFMAN_ENTRY(0x11f, 8), + HUFFMAN_ENTRY(0x113, 7), + HUFFMAN_ENTRY('w', 8), + HUFFMAN_ENTRY('7', 8), + HUFFMAN_ENTRY(0x0cf, 9), + HUFFMAN_ENTRY(0x10b, 7), + HUFFMAN_ENTRY('g', 8), + HUFFMAN_ENTRY('\'', 8), + HUFFMAN_ENTRY(0x0af, 9), + HUFFMAN_ENTRY(0x007, 8), + HUFFMAN_ENTRY(0x087, 8), + HUFFMAN_ENTRY('G', 8), + HUFFMAN_ENTRY(0x0ef, 9), + HUFFMAN_ENTRY(0x107, 7), + HUFFMAN_ENTRY('_', 8), + HUFFMAN_ENTRY(0x01f, 8), + HUFFMAN_ENTRY(0x09f, 9), + HUFFMAN_ENTRY(0x117, 7), + HUFFMAN_ENTRY(0x07f, 8), + HUFFMAN_ENTRY('?', 8), + HUFFMAN_ENTRY(0x0df, 9), + HUFFMAN_ENTRY(0x10f, 7), + HUFFMAN_ENTRY('o', 8), + HUFFMAN_ENTRY('/', 8), + HUFFMAN_ENTRY(0x0bf, 9), + HUFFMAN_ENTRY(0x00f, 8), + HUFFMAN_ENTRY(0x08f, 8), + HUFFMAN_ENTRY('O', 8), + HUFFMAN_ENTRY(0x0ff, 9), + } +}; + +static const struct shortHuffmanCodeTable fixedHuffmanDistanceTable = { + { + 5, /* quick bits */ + 5, /* max code length */ + }, + { + HUFFMAN_ENTRY(0x00, 5), + HUFFMAN_ENTRY(0x10, 5), + HUFFMAN_ENTRY(0x08, 5), + HUFFMAN_ENTRY(0x18, 5), + HUFFMAN_ENTRY(0x04, 5), + HUFFMAN_ENTRY(0x14, 5), + HUFFMAN_ENTRY(0x0c, 5), + HUFFMAN_ENTRY(0x1c, 5), + HUFFMAN_ENTRY(0x02, 5), + HUFFMAN_ENTRY(0x12, 5), + HUFFMAN_ENTRY(0x0a, 5), + HUFFMAN_ENTRY(0x1a, 5), + HUFFMAN_ENTRY(0x06, 5), + HUFFMAN_ENTRY(0x16, 5), + HUFFMAN_ENTRY(0x0e, 5), + HUFFMAN_ENTRY(0x1e, 5), + HUFFMAN_ENTRY(0x01, 5), + HUFFMAN_ENTRY(0x11, 5), + HUFFMAN_ENTRY(0x09, 5), + HUFFMAN_ENTRY(0x19, 5), + HUFFMAN_ENTRY(0x05, 5), + HUFFMAN_ENTRY(0x15, 5), + HUFFMAN_ENTRY(0x0d, 5), + HUFFMAN_ENTRY(0x1d, 5), + HUFFMAN_ENTRY(0x03, 5), + HUFFMAN_ENTRY(0x13, 5), + HUFFMAN_ENTRY(0x0b, 5), + HUFFMAN_ENTRY(0x1b, 5), + HUFFMAN_ENTRY(0x07, 5), + HUFFMAN_ENTRY(0x17, 5), + HUFFMAN_ENTRY(0x0f, 5), + HUFFMAN_ENTRY(0x1f, 5), + } +}; + +#endif + +#endif diff --git a/MPC.3.5.LINUX/preverifier/locale_md.h b/MPC.3.5.LINUX/preverifier/locale_md.h new file mode 100644 index 0000000..b4e198b --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/locale_md.h @@ -0,0 +1,22 @@ +/* + * @(#)locale_md.h 1.0 00/11/22 + * + * Copyright 1995-1998 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +#ifndef _LOCALE_MD_ +#define _LOCALE_MD_ + +#include +#define SET_DEFAULT_LOCALE setlocale(LC_ALL,"") + +#endif diff --git a/MPC.3.5.LINUX/preverifier/main.c b/MPC.3.5.LINUX/preverifier/main.c new file mode 100644 index 0000000..1212e30 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/main.c @@ -0,0 +1,479 @@ +/* * @(#)main.c 1.6 00/08/26 + * + * Copyright 1997, 1998 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +/*========================================================================= + * SYSTEM: Verifier + * SUBSYSTEM: main program + * FILE: main.c + * OVERVIEW: Runs the Java class verifier. + * AUTHOR: Sheng Liang, Sun Microsystems, Inc. + * Modifications for JAR support, CLDC compliance, and comments, + * Tasneem Sayeed, Sun Microsystems + *=======================================================================*/ + + +/*========================================================================= + * Include files + *=======================================================================*/ + +#include +#include +#include +#include +#include +#include + +#include "sys_api.h" +#include "path_md.h" +#include "path.h" +#include "oobj.h" +//#include "jar.h" +#include "locale_md.h" + +/* +#include "../util/strings.h" +#include "../util/error.h" +#include "../util/message.h" +#include "../structures/type_list.h" +#include "../structures/string_list.h" +#include "../structures/type.h" +#include "../structures/identifier.h" +#include "../structures/name_table.h" +#include "../classgen/bytecode.h" +#include "../structures/block.h" + +#include "../parser/parser.h" + +#include "../util/memory.h" + +#include "../main/static_entry.h" + +#include +#include +#include +*/ +/*========================================================================= + * Globals and extern declarations + *=======================================================================*/ + +char str_buffer[STRINGBUFFERSIZE]; /* shared string buffer */ + +int processedfile = 0; +int errorCode = 0; /* Error code returned by program */ + +bool_t no_native_methods = FALSE; +bool_t no_floating_point = FALSE; +bool_t no_finalizers = FALSE; +char tmp_dir[32]; /* temporary directory for storing + verified classes */ +extern char *output_dir; /* output directory */ +bool_t tmpDirExists = FALSE; + +extern void VerifyFile(register char *fn); +//extern bool_t ProcessJARfile(char *buf, int len); +//extern bool_t isJARfile(char *fn, int length); + +//static void usage(char *progname); + + +/*========================================================================= + * FUNCTION: recurse_dir() + * TYPE: Handles recursive directories + * OVERVIEW: Internal function called by ProcessInputs(). + * + * This function reads a directory, searching for either another directory, + * JAR file or an individual class name that is to be verified. + * + * INTERFACE: + * parameters: dirname name of the directory entry. + * pkgname name of the package + * returns: nothing + *=======================================================================*/ +/* +static void recurse_dir(char *dirname, char *pkgname) +{ + struct dirent *ent; + char buf[MAXPACKAGENAME]; + char pkgbuf[MAXPACKAGENAME]; + DIR *dir = opendir(dirname); + + if (dir == NULL) { + fprintf(stderr, "Can't open dir %s\n", dirname); + exit(1); + } + for (ent = readdir(dir); ent; ent = readdir(dir)) { + struct stat stat_buf; + char *name = ent->d_name; + int len; + + if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { + continue; + } + + strcpy(pkgbuf, pkgname); + if (pkgname[0] != 0) { + strcat(pkgbuf, "/"); + } + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "recurse_dir: Reading filename [%s] from directory [%s]\n", + name, dirname); + + strcat(pkgbuf, name); + + strcpy(buf, dirname); + strcat(buf, name); + + stat(buf, &stat_buf); + len = strlen(buf); + + if (stat_buf.st_mode & S_IFDIR) { + // handle the recursive directory found + strcat(buf, "/"); + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "recurse_dir: Recursive directory found, calling recurse_dir ([%s] [%s])\n", + buf, pkgbuf); + recurse_dir(buf, pkgbuf); + continue; + } else if (isJARfile (buf, len)) { + + // + // this directory contains a JAR file which contains + // the classes to be verified + // + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "recurse_dir: Found JAR file [%s] in dir!\n", buf); + + if (!ProcessJARfile(buf, len)) { + + fprintf(stderr, "Not a valid JAR file [%s]\n", buf); + exit(1); + } + } + + // we just have a class file that needs verification + + len = strlen(pkgbuf); + if (len > 6 && strcmp(pkgbuf + len - 6, ".class") == 0) { + + pkgbuf[len - 6] = 0; + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "recurse_dir: Verifying Class [%s] \n", pkgbuf); + VerifyFile(pkgbuf); + } + } + + closedir(dir); +} +*/ + +/*========================================================================= + * FUNCTION: ProcessInputs() + * TYPE: Processes inputs + * OVERVIEW: Internal function called by main(). + * + * This function processes input entries for specifying classes that are to + * be verified. The inputs may be in 3 forms: a directory, or nested + * directories, one or more JAR files, or one or more individual class files. + * If a directory entry is specified, it may also contain one or more JAR + * files, or one or more individual class files. + * + * INTERFACE: + * parameters: argname: directory, JAR file or an individual class file. + * returns: nothing + *=======================================================================*/ +/* +static void ProcessInputs(char *argname) +{ + char buf[MAXPACKAGENAME]; + struct stat stat_buf; + int res = stat(argname, &stat_buf); + int len; + + + strcpy(buf, argname); + len = strlen(argname); + + + if ((res == 0) && (stat_buf.st_mode & S_IFDIR)) { + /* Append dir separator if it does not yet exist. + if (buf[len - 1] != LOCAL_DIR_SEPARATOR && + buf[len - 1] != DIR_SEPARATOR) { + buf[len] = DIR_SEPARATOR; + buf[len + 1] = 0; + } + pushDirectoryOntoClassPath(buf); + recurse_dir(buf, ""); + popClassPath(); + } else if ((res == 0) && (isJARfile (buf, len))) { + /* the classes to be verified are in a JAR file + if (!ProcessJARfile(buf, len)) { + fprintf(stderr, "Not a valid JAR file [%s]\n", buf); + exit(1); + } + } else { + char *p; + /* Convert all periods in the argname to slashes + for (p = buf; ((p = strchr(p, '.')) != 0); *p++ = '/'); + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, + "ProcessInputs: Verifying file [%s]\n", buf ); + VerifyFile(buf); + } +}*/ + + +/*========================================================================= + * FUNCTION: main() + * TYPE: Runs the verifier. + * OVERVIEW: Main function. + * + * This is the main function that invokes the Java class verifier. + * + * INTERFACE: + * parameters: argc: arg count. + * argv: arg value(s) + * returns: nothing + *=======================================================================*/ +/* +int main(argc, argv) + register char **argv; +{ + char *progname; + char *argv0 = argv[0]; + + SET_DEFAULT_LOCALE; + + if ((progname = strrchr(argv[0], LOCAL_DIR_SEPARATOR)) != 0) { + progname++; + } else { + progname = argv[0]; + } + + // initialize tmp_dir + memset(tmp_dir, 0, 32); + + // initialize the seed for the random number + srand(time(NULL)); + + // generate a random temp directory name + sprintf(tmp_dir, "%s%d%c", "tmp", rand(), '\0'); + + while (--argc > 0) + if ((++argv)[0][0] == '-') { + if (strcmp(argv[0], "-verbose") == 0) { + extern bool_t verbose; + verbose = TRUE; +#ifdef DEBUG_VERIFIER + } else if (strcmp(argv[0], "-verify-verbose") == 0) { + extern int verify_verbose; + verify_verbose++; +#endif + } else if (strcmp(argv[0], "-cldc") == 0) { + no_native_methods = TRUE; + no_floating_point = TRUE; + no_finalizers = TRUE; + } else if (strcmp(argv[0], "-nofinalize") == 0) { + no_finalizers = TRUE; + } else if (strcmp(argv[0], "-nonative") == 0) { + no_native_methods = TRUE; + } else if (strcmp(argv[0], "-nofp") == 0) { + no_floating_point = TRUE; + } else if (strcmp(argv[0], "-Xns") == 0) { + extern bool_t stack_map_on; + stack_map_on = FALSE; + } else if (strcmp(argv[0], "-Xni") == 0) { + extern bool_t inline_jsr_on; + inline_jsr_on = FALSE; + } else if (strcmp(argv[0], "-d") == 0) { + output_dir = strdup(argv[1]); + argc--; argv++; + } else if (strcmp(argv[0], "-classpath") == 0) { + if (argc > 1) { + char *buf = (char *)malloc(strlen(argv[1]) + 32); + sprintf(buf, "CLASSPATH=%s", argv[1]); + putenv(buf); + argc--; argv++; + } else { + //fprintf(stderr, + // "-classpath requires class path specification\n"); +// usage(progname); + exit(1); + } + } else { + //fprintf(stderr, "%s: Illegal option %s\n\n", progname, argv[0]); +// usage(progname); + exit(1); + } + } else if (argv[0][0] == '@') { + char *new_argv[MAXOPTIONS]; + char *buffer; + int new_argc = 1; + char *token; + bool_t done = FALSE; + struct stat sbuf; + FILE *fp; + int buflen; + int filelength; + int i; + + new_argv[0] = argv0; + + fp = fopen(&argv[0][1], "rt"); + if (fp == NULL) { + fprintf(stderr, "Can't open %s\n", &argv[0][1]); + exit(1); + } + + // get the size of the file + stat(&argv[0][1], &sbuf); + filelength = sbuf.st_size; + + // allocate the buffer + if ((buffer = (char *) malloc(filelength+1)) == NULL) { + fprintf(stderr, "Out of memory\n"); + exit(1); + } + + if (fgets(buffer, filelength+1, fp) != NULL) { + buflen = strlen(buffer); + + if (DEBUG_READFROMFILE) { + fprintf(stderr, "Buffer = [%s]\n", buffer); + } + // get the first parameter + token = strtok(buffer, " \0\n\r\t\""); + + // Search for parameters until none can be found + while (token != NULL && !done) { + + if ((strcmp(token, "\n") == 0) || + (strcmp(token, "\r") == 0) || + (strcmp(token, "\t") == 0)) { + // , or + done = TRUE; + } else { + // On Win32, it's possible to have a + // appended at the end of the token, which needs + // to be extracted before restoring the arg + // + char *p; + // Convert all to NULL + for (p = token; *p != '\0'; p++) { + if (*p == '\n' || *p == '\r') + *p = '\0'; + } + + // save the parameter + new_argv[new_argc++] = token; + + if ((strcmp(token, "-classpath") == 0) || + (strcmp(token, "-d") == 0)) { + // search for the beginning of a string literal + token = strtok(NULL, "\""); + + } else { // get the next token + token = strtok(NULL," \0\n\r\t\""); + } + } + } + + if (DEBUG_READFROMFILE) { + // print the arguments after restoring all of them + for (i=0; i < new_argc; i++) + fprintf(stderr, "new_argv[%d] = [%s]\n", i, new_argv[i]); + } + } + + fclose(fp); + main(new_argc, new_argv); + + if (buffer != NULL) { + free(buffer); + } + argc--; argv++; + } else { + processedfile++; + if (strlen(argv[0]) > MAXPACKAGENAME) { + // fprintf(stderr, + // "Package name for class exceeds max allowed size [1024]\n"); +// usage(progname); + exit(1); + } + + + + ProcessInputs(argv[0]); + } + if (processedfile == 0) { + usage(progname); + exit(1); + } + return errorCode; // normal errorCode=0 indicates successful completion +}*/ +/* +static void usage(char *progname) { + fprintf(stderr, "Usage: %s [options] classnames|dirnames ...\n", progname); + fprintf(stderr, "\n"); + fprintf(stderr, "where options include:\n"); + fprintf(stderr, " -classpath \n", (char)PATH_SEPARATOR); + fprintf(stderr, " Directories in which to look for classes\n"); + fprintf(stderr, " -d Directory in which output is written (default is ./output/)\n"); + + fprintf(stderr, " -cldc Checks for existence of language features prohibited\n"); + fprintf(stderr, " by CLDC (native methods, floating point and finalizers)\n"); + + fprintf(stderr, " -nofinalize No finalizers allowed\n"); + fprintf(stderr, " -nonative No native methods allowed\n"); + fprintf(stderr, " -nofp No floating point operations allowed\n"); + fprintf(stderr, " @ Read command line arguments from a text file\n"); + fprintf(stderr, " Command line arguments must all be on a single line\n"); + fprintf(stderr, " Directory names must be enclosed in double quotes (\")\n"); + + fprintf(stderr, "\n"); +} + */ + + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +//static +int +OpenCode(char *fn, char *sfn, char *dir, struct stat * st) +{ + long codefd; + char *fullname = (char*) malloc(strlen(fn) + strlen(dir) + 10); + #ifdef WIN32 + sprintf(fullname, "%s\\%s", dir, fn); + #endif + #ifdef UNIX + sprintf(fullname, "%s/%s", dir, fn); + #endif + if (fn == 0 || (codefd = open(fullname, O_BINARY, 0644)) < 0 + || fstat(codefd, st) < 0) + { + free(fullname); + return -2; + } + free(fullname); + return codefd; +} diff --git a/MPC.3.5.LINUX/preverifier/oobj.h b/MPC.3.5.LINUX/preverifier/oobj.h new file mode 100644 index 0000000..8ef2c96 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/oobj.h @@ -0,0 +1,682 @@ +/* + * @(#)oobj.h 1.5 00/04/12 + * + * Copyright 1995-1998 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ +/* + * Java object header format + */ + +#ifndef _OOBJ_H_ +#define _OOBJ_H_ + +#include +#include +#include +#include +#include +#include + +#include "typedefs.h" +#include "signature.h" + +#define JAVA_CLASSFILE_MAGIC 0xCafeBabe + +#define JAVASRCEXT "java" +#define JAVASRCEXTLEN 4 +#define JAVAOBJEXT "class" +#define JAVAOBJEXTLEN 5 + +#define JAVA_VERSION 45 +#define JAVA_MINOR_VERSION 3 +#define ARRAYHEADER long alloclen + +/* The size (in bytes) of a statically allocated area that the + * verifier uses internally in various string operations. + */ +#ifndef STRINGBUFFERSIZE +#define STRINGBUFFERSIZE 512 +#endif + +#define MAXOPTIONS 2048 /* maximum # of parameters */ + +/* maximum size allowed for package name of a class file */ +#define MAXPACKAGENAME 1024 + +#define MAXPATHLEN 255 + +#define HandleTo(T) typedef struct H##T { Class##T *obj; struct methodtable *methods;} H##T + + +typedef long OBJECT; +typedef OBJECT Classjava_lang_Object; +typedef OBJECT ClassObject; +HandleTo(java_lang_Object); +typedef Hjava_lang_Object JHandle; +typedef Hjava_lang_Object HObject; + +typedef unsigned short unicode; + +extern unicode *str2unicode(char *, unicode *, long); +extern char *int642CString(int64_t number, char *buf, int buflen); + +#define ALIGN(n) (((n)+3)&~3) +#define UCALIGN(n) ((unsigned char *)ALIGN((int)(n))) + +struct Hjava_lang_Class; /* forward reference for some compilers */ +struct Classjava_lang_Class; /* forward reference for some compilers */ + +typedef struct Classjava_lang_Class Classjava_lang_Class; + +HandleTo(java_lang_Class); +typedef struct Hjava_lang_Class ClassClass; + + +struct fieldblock { + ClassClass *clazz; + char *signature; + char *name; + unsigned long ID; + unsigned short access; + union { + unsigned long offset; /* info of data */ + OBJECT static_value; + void *static_address; + } u; + unsigned deprecated:1; + unsigned synthetic:1; +}; + +#define fieldname(fb) ((fb)->name) +#define fieldsig(fb) ((fb)->signature) +#define fieldIsArray(fb) (fieldsig(fb)[0] == SIGNATURE_ARRAY) +#define fieldIsClass(fb) (fieldsig(fb)[0] == SIGNATURE_CLASS) +#define fieldclass(fb) ((fb)->clazz) + +struct execenv; + +#define VERIFIER_TOOL + +/* Includes/eliminates a large amount of optional debugging code + * (such as class and stack frame printing operations) in/from + * the system. By eliminating debug code, the system will be smaller. + * Inclusion of debugging code increases the size of the system but + * does not introduce any performance overhead unless calls to the + * debugging routines are added to the source code or various tracing + * options are turned on. + */ + +#ifndef INCLUDEDEBUGCODE +#define INCLUDEDEBUGCODE 0 +#endif + +#define DEBUG_VERIFIER 1 +#define DEBUG_READFROMFILE 0 + +enum { + ITEM_Bogus, + ITEM_Void, /* only as a function return value */ + ITEM_Integer, + ITEM_Float, + ITEM_Double, + ITEM_Double_2, /* 2nd word of double in register */ + ITEM_Long, + ITEM_Long_2, /* 2nd word of long in register */ + ITEM_InitObject, /* "this" is init method, before call + to super() */ + ITEM_Object, /* Extra info field gives name. */ + ITEM_NewObject, /* Like object, but uninitialized. */ + ITEM_ReturnAddress, /* Extra info gives instr # of start pc */ + /* The following three are only used within array types. + * Normally, we use ITEM_Integer, instead. */ + ITEM_Boolean, + ITEM_Byte, + ITEM_Short, + ITEM_Char +}; + +/* These are the constants that appear in class files. */ +enum { + CF_ITEM_Bogus, + CF_ITEM_Integer, + CF_ITEM_Float, + CF_ITEM_Double, + CF_ITEM_Long, + CF_ITEM_Null, + CF_ITEM_InitObject, + + CF_ITEM_Object, + CF_ITEM_NewObject, +}; + +struct map_entry { + unsigned char type; + long info; +}; + +struct stack_map { + int offset; + int nlocals; + struct map_entry *locals; + int nstacks; + struct map_entry *stacks; +}; + +struct methodblock { + struct fieldblock fb; + unsigned char *code; /* the code */ + struct CatchFrame *exception_table; + struct lineno *line_number_table; + struct localvar *localvar_table; + + unsigned long code_length; + unsigned long exception_table_length; + unsigned long line_number_table_length; + unsigned long localvar_table_length; + + bool_t (*invoker) + (JHandle *o, struct methodblock *mb, int args_size, struct execenv *ee); + unsigned short args_size; /* total size of all arguments */ + unsigned short maxstack; /* maximum stack usage */ + unsigned short nlocals; /* maximum number of locals */ + /* 2 spare bytes here */ + void *CompiledCode; /* it's type is machine dependent */ + void *CompiledCodeInfo; /* it's type is machine dependent */ + long CompiledCodeFlags; /* machine dependent bits */ + unsigned long inlining; /* possible inlining of code */ + unsigned short nexceptions; /* number of checked exceptions */ + unsigned short *exceptions; /* constant pool indices */ + char *mp_marks; + int n_stack_maps; + struct stack_map *stack_maps; +}; + +struct HIOstream; + +struct methodtable { + ClassClass *classdescriptor; + struct methodblock *methods[1]; +}; + +struct imethodtable { + int icount; /* number of interfaces to follow */ + struct { + ClassClass *classdescriptor; + unsigned long *offsets; /* info of data */ + } itable[1]; +}; + +typedef struct { + char body[1]; +} ArrayOfByte; +typedef ArrayOfByte ClassArrayOfByte; +HandleTo(ArrayOfByte); + +typedef struct { + unicode body[1]; +} ArrayOfChar; +typedef ArrayOfChar ClassArrayOfChar; +HandleTo(ArrayOfChar); + +typedef struct { + signed short body[1]; +} ArrayOfShort; +typedef ArrayOfShort ClassArrayOfShort; +HandleTo(ArrayOfShort); + +typedef struct { + long body[1]; +} ArrayOfInt; +typedef ArrayOfInt ClassArrayOfInt; +HandleTo(ArrayOfInt); + +typedef struct { + int64_t body[1]; +} ArrayOfLong; +typedef ArrayOfLong ClassArrayOfLong; +HandleTo(ArrayOfLong); + +typedef struct { + float body[1]; +} ArrayOfFloat; +typedef ArrayOfFloat ClassArrayOfFloat; +HandleTo(ArrayOfFloat); + +typedef struct { + double body[1]; +} ArrayOfDouble; +typedef ArrayOfDouble ClassArrayOfDouble; +HandleTo(ArrayOfDouble); + +typedef struct { + JHandle *(body[1]); +} ArrayOfArray; +typedef ArrayOfArray ClassArrayOfArray; +HandleTo(ArrayOfArray); + +typedef struct { + HObject *(body[1]); +} ArrayOfObject; +typedef ArrayOfObject ClassArrayOfObject; +HandleTo(ArrayOfObject); + +typedef struct Hjava_lang_String HString; + +typedef struct { + HString *(body[1]); +} ArrayOfString; +typedef ArrayOfString ClassArrayOfString; +HandleTo(ArrayOfString); + + +/* Note: any handles in this structure must also have explicit + code in the ScanClasses() routine of the garbage collector + to mark the handle. */ +struct Classjava_lang_Class { + /* Things following here are saved in the .class file */ + unsigned short major_version; + unsigned short minor_version; + char *name; + char *super_name; + char *source_name; + ClassClass *superclass; + ClassClass *HandleToSelf; + struct Hjava_lang_ClassLoader *loader; + struct methodblock *finalizer; + + union cp_item_type *constantpool; + struct methodblock *methods; + struct fieldblock *fields; + short *implements; + + struct methodtable *methodtable; + struct methodtable *methodtable_mem; + struct fieldblock **slottable; + + int superclass_idx; + + HString *classname; + + union { + struct { + unsigned long thishash; /* unused */ + unsigned long totalhash; /* unused */ + } cbhash; + struct { + unsigned char typecode; /* VM typecode */ + char typesig; /* signature constant */ + unsigned char slotsize; /* (bytes) in slot */ + unsigned char elementsize; /* (bytes) in array */ + unsigned long xxspare; + } cbtypeinfo; + } hashinfo; + + unsigned short constantpool_count; /* number of items in pool */ + unsigned short methods_count; /* number of methods */ + unsigned short fields_count; /* number of fields */ + unsigned short implements_count; /* number of protocols */ + + unsigned short methodtable_size; /* the size of method table */ + unsigned short slottbl_size; /* size of slottable */ + unsigned short instance_size; /* (bytes) of an instance */ + + unsigned short access; /* how this class can be accesses */ + unsigned short flags; /* see the CCF_* macros */ + struct HArrayOfObject *signers; + struct imethodtable *imethodtable; + + void *init_thread; /* EE of initializing thread */ + + ClassClass *last_subclass_of; + void *reserved_for_jit; + char *absolute_source_name; + struct { int high, low; } timestamp; + int n_new_class_entries; + char **new_class_entries; + int n_new_utf8_entries; + char **new_utf8_entries; + int has_stack_maps; + + int inner_classes_count; + struct innerClasses *inner_classes; + + unsigned deprecated:1; + unsigned synthetic:1; + unsigned hasTimeStamp:1; +}; + +struct innerClasses { + int inner_class; + int outer_class; + char *inner_name; + int access; +}; + +extern void FreeClass(ClassClass *cb); +extern void MakeClassSticky(ClassClass *cb); + +#define cbAccess(cb) ((unhand(cb))->access) +#define cbClassname(cb) ((unhand(cb))->classname) +#define cbConstantPool(cb) ((unhand(cb))->constantpool) +#define cbConstantPoolCount(cb) ((unhand(cb))->constantpool_count) +#define cbFields(cb) ((unhand(cb))->fields) +#define cbFieldsCount(cb) ((unhand(cb))->fields_count) +#define cbFinalizer(cb) ((unhand(cb))->finalizer) +#define cbFlags(cb) ((unhand(cb))->flags) +#define cbHandle(cb) (cb) +#define cbImplements(cb) ((unhand(cb))->implements) +#define cbImplementsCount(cb) ((unhand(cb))->implements_count) +#define cbInstanceSize(cb) ((unhand(cb))->instance_size) +#define cbIntfMethodTable(cb) ((unhand(cb))->imethodtable) +#define cbLastSubclassOf(cb) ((unhand(cb))->last_subclass_of) +#define cbLoader(cb) ((unhand(cb))->loader) +#define cbMajorVersion(cb) ((unhand(cb))->major_version) +#define cbMethods(cb) ((unhand(cb))->methods) +#define cbMethodsCount(cb) ((unhand(cb))->methods_count) +#define cbMethodTable(cb) ((unhand(cb))->methodtable) +#define cbMethodTableMem(cb) ((unhand(cb))->methodtable_mem) +#define cbMethodTableSize(cb) ((unhand(cb))->methodtable_size) +#define cbMinorVersion(cb) ((unhand(cb))->minor_version) +#define cbName(cb) ((unhand(cb))->name) +#define cbSigners(cb) ((unhand(cb))->signers) +#define cbSlotTable(cb) ((unhand(cb))->slottable) +#define cbSlotTableSize(cb) ((unhand(cb))->slottbl_size) +#define cbSourceName(cb) ((unhand(cb))->source_name) +#define cbSuperclass(cb) ((unhand(cb))->superclass) +#define cbSuperName(cb) ((unhand(cb))->super_name) +#define cbThisHash(cb) ((unhand(cb))->hashinfo.cbhash.thishash) +#define cbTotalHash(cb) ((unhand(cb))->hashinfo.cbhash.totalhash) +#define cbInitThread(cb) ((unhand(cb))->init_thread) +#define cbInnerClasses(cb) ((unhand(cb))->inner_classes) +#define cbInnerClassesCount(cb)((unhand(cb))->inner_classes_count) + + + +#define cbAbsoluteSourceName(cb) ((unhand(cb))->absolute_source_name) +#define cbTimestamp(cb) ((unhand(cb))->timestamp) + +#define cbIsInterface(cb) ((cbAccess(cb) & ACC_INTERFACE) != 0) +#define cbIsAbstract(cb) ((cbAccess(cb) & ACC_ABSTRACT) != 0) +#define cbAccessNotAbstract(cb) ((unhand(cb))->access & ~ACC_ABSTRACT) + +/* These are currently only valid for primitive types */ +#define cbIsPrimitive(cb) (CCIs(cb, Primitive)) +#define cbTypeCode(cb) ((unhand(cb))->hashinfo.cbtypeinfo.typecode) +#define cbTypeSig(cb) ((unhand(cb))->hashinfo.cbtypeinfo.typesig) +#define cbSlotSize(cb) ((unhand(cb))->hashinfo.cbtypeinfo.slotsize) +#define cbElementSize(cb) ((unhand(cb))->hashinfo.cbtypeinfo.elementsize) + +extern char *classname2string(char *str, char *dst, int size); + +#define twoword_static_address(fb) ((fb)->u.static_address) +#define normal_static_address(fb) (&(fb)->u.static_value) + +/* ClassClass flags */ +#define CCF_IsSysLock 0x01 /* any instance treated as a "system" lock */ +#define CCF_IsResolved 0x02 /* has been run? */ +#define CCF_IsError 0x04 /* Resolution caused an error */ +#define CCF_IsSoftRef 0x08 /* whether this is class Ref or subclass */ +#define CCF_IsInitialized 0x10 /* whether this is class has been inited */ +#define CCF_IsLinked 0x20 /* Has symbolic entries been linked */ +#define CCF_IsVerified 0x40 /* has the verifier been run */ + +#define CCF_IsPrimitive 0x100 /* if pseudo-class for a primitive type */ +#define CCF_IsReferenced 0x200 /* Class is in use */ +#define CCF_IsSticky 0x400 /* Don't unload this class */ + +#define CCIs(cb,flag) (((unhand(cb))->flags & CCF_Is##flag) != 0) +#define CCSet(cb,flag) ((unhand(cb))->flags |= CCF_Is##flag) +#define CCClear(cb,flag) ((unhand(cb))->flags &= ~CCF_Is##flag) + +/* map from pc to line number */ +struct lineno { + unsigned long pc, + line_number; +}; + +extern struct lineno *lntbl; +extern long lntsize, lntused; + +/* Symbol table entry for local variables and parameters. + pc0/length defines the range that the variable is valid, slot + is the position in the local variable array in ExecEnv. + nameoff and sigoff are offsets into the string table for the + variable name and type signature. A variable is defined with + DefineVariable, and at that time, the node for that name is + stored in the localvar entry. When code generate is completed + for a particular scope, a second pass it made to replace the + src node entry with the correct length. */ + +struct localvar { + long pc0; /* starting pc for this variable */ + long length; /* -1 initially, end pc - pc when we're done */ + char *name; /* */ + char *signature; + long slot; /* local variable slot */ +}; + +/* Try/catch is implemented as follows. On a per class basis, + there is a catch frame handler (below) for each catch frame + that appears in the source. It contains the pc range of the + corresponding try body, a pc to jump to in the event that that + handler is chosen, and a catchType which must match the object + being thrown if that catch handler is to be taken. + + The list of catch frames are sorted by pc. If one range is + inside another, then outer most range (the one that encompasses + the other) appears last in the list. Therefore, it is possible + to search forward, and the first one that matches is the + innermost one. + + Methods with catch handlers will layout the code without the + catch frames. After all the code is generated, the catch + clauses are generated and table entries are created. + + When the class is complete, the table entries are dumped along + with the rest of the class. */ + +struct CatchFrame { + long start_pc, end_pc; /* pc range of corresponding try block */ + long handler_pc; /* pc of catch handler */ + void* compiled_CatchFrame; /* space to be used by machine code */ + short catchType; /* type of catch parameter */ +}; + +#define MC_SUPER (1<<5) +#define MC_NARGSMASK (MC_SUPER-1) +#define MC_INT (0<<6) +#define MC_FLOAT (1<<6) +#define MC_VOID (2<<6) +#define MC_OTHER (3<<6) +#define MC_TYPEMASK (3<<6) + +enum { + CONSTANT_Utf8 = 1, + CONSTANT_Unicode, /* unused */ + CONSTANT_Integer, + CONSTANT_Float, + CONSTANT_Long, + CONSTANT_Double, + CONSTANT_Class, + CONSTANT_String, + CONSTANT_Fieldref, + CONSTANT_Methodref, + CONSTANT_InterfaceMethodref, + CONSTANT_NameAndType +}; + +union cp_item_type { + int i; + float f; + char *cp; + unsigned char *type; /* for type table */ + ClassClass *clazz; + struct methodblock *mb; + struct fieldblock *fb; + struct Hjava_lang_String *str; + void *p; /* for very rare occasions */ +}; + +typedef union cp_item_type cp_item_type; + +#define CONSTANT_POOL_ENTRY_RESOLVED 0x80 +#define CONSTANT_POOL_ENTRY_TYPEMASK 0x7F +#define CONSTANT_POOL_TYPE_TABLE_GET(cp,i) (((unsigned char *)(cp))[i]) +#define CONSTANT_POOL_TYPE_TABLE_PUT(cp,i,v) (CONSTANT_POOL_TYPE_TABLE_GET(cp,i) = (v)) +#define CONSTANT_POOL_TYPE_TABLE_SET_RESOLVED(cp,i) \ + (CONSTANT_POOL_TYPE_TABLE_GET(cp,i) |= CONSTANT_POOL_ENTRY_RESOLVED) +#define CONSTANT_POOL_TYPE_TABLE_IS_RESOLVED(cp,i) \ + ((CONSTANT_POOL_TYPE_TABLE_GET(cp,i) & CONSTANT_POOL_ENTRY_RESOLVED) != 0) +#define CONSTANT_POOL_TYPE_TABLE_GET_TYPE(cp,i) \ + (CONSTANT_POOL_TYPE_TABLE_GET(cp,i) & CONSTANT_POOL_ENTRY_TYPEMASK) + +#define CONSTANT_POOL_TYPE_TABLE_INDEX 0 +#define CONSTANT_POOL_UNUSED_INDEX 1 + +/* The following are used by the constant pool of "array" classes. */ + +#define CONSTANT_POOL_ARRAY_DEPTH_INDEX 1 +#define CONSTANT_POOL_ARRAY_TYPE_INDEX 2 +#define CONSTANT_POOL_ARRAY_CLASS_INDEX 3 +#define CONSTANT_POOL_ARRAY_LENGTH 4 + +/* + * Package shorthand: this isn't obviously the correct place. + */ +#define JAVAPKG "java/lang/" +#define JAVAIOPKG "java/io/" +#define JAVANETPKG "java/net/" + +#define unhand(o) ((o)->obj) + + +extern ClassClass *classJavaLangClass; /* class java/lang/Class */ +extern ClassClass *classJavaLangObject; /* class java/lang/Object */ +extern ClassClass *classJavaLangString; /* class java/lang/String */ + +extern ClassClass *classJavaLangThrowable; +extern ClassClass *classJavaLangException; +extern ClassClass *classJavaLangError; +extern ClassClass *classJavaLangRuntimeException; +extern ClassClass *classJavaLangThreadDeath; + +extern ClassClass *interfaceJavaLangCloneable; /* class java/lang/Cloneable */ +extern ClassClass *interfaceJavaIoSerializable; /* class java/io/Serializable */ + +enum { VERIFY_NONE, VERIFY_REMOTE, VERIFY_ALL }; + +extern int verifyclasses; +extern bool_t verbose; +extern char * const opnames[]; + +int jio_snprintf(char *str, size_t count, const char *fmt, ...); +int jio_vsnprintf(char *str, size_t count, const char *fmt, va_list args); + +int jio_printf(const char *fmt, ...); +int jio_fprintf(FILE *, const char *fmt, ...); +int jio_vfprintf(FILE *, const char *fmt, va_list args); + +struct StrIDhash; +unsigned short Str2ID(struct StrIDhash **, char *, void ***, int); +char *ID2Str(struct StrIDhash *, unsigned short, void ***); +void Str2IDFree(struct StrIDhash **); + +unsigned NameAndTypeToHash(char *name, char *type); +bool_t IsSameClassPackage(ClassClass *class1, ClassClass *class2); +unsigned Signature2ArgsSize(char *method_signature); +char *GetClassConstantClassName(cp_item_type *constant_pool, int index); +ClassClass *FindClass(struct execenv *ee, char *name, bool_t resolve); +ClassClass *FindClassFromClass(struct execenv *ee, char *name, + bool_t resolve, ClassClass *from); + +bool_t createInternalClass(unsigned char *bytes, unsigned char *limit, + ClassClass *cb, struct Hjava_lang_ClassLoader *, + char *utfname, char **detail); + +bool_t VerifyClass(ClassClass *cb); +//bool_t IsLegalClassname(char *name, bool_t allowArrayClass); +bool_t verify_class_codes(ClassClass *cb); + +struct execenv { + /* Detecting class circularities */ + struct seenclass { + ClassClass *cb; + struct seenclass *next; + } seenclasses; + + /* error message occurred during class loading */ + char *class_loading_msg; +}; + +typedef struct execenv ExecEnv; + +extern ExecEnv * EE(); + +ClassClass *FindStickySystemClass(struct execenv *, char *, bool_t resolve); +bool_t VerifyClassAccess(ClassClass *, ClassClass *, bool_t); +void InitializeInvoker(ClassClass *cb); +bool_t RunStaticInitializers(ClassClass *cb); +ClassClass *ClassLoaderFindClass(ExecEnv *ee, + struct Hjava_lang_ClassLoader *loader, + char *name, bool_t resolve); +ClassClass *LoadClassLocally(char *name); +ClassClass *createFakeArrayClass(char *name, int base_type, int depth, + ClassClass *inner_cb, + struct Hjava_lang_ClassLoader *); +ClassClass *createPrimitiveClass(char *name, char sig, unsigned char typecode, + unsigned char slotsize, unsigned char elementsize); + +bool_t isJARfile(char *fn, int length); + +#define BINCLASS_LOCK() +#define BINCLASS_UNLOCK() +#define LOADCLASS_LOCK() +#define LOADCLASS_UNLOCK() +#define NAMETYPEHASH_LOCK() +#define NAMETYPEHASH_UNLOCK() + +#define FINALIZER_METHOD_NAME "finalize" +#define FINALIZER_METHOD_SIGNATURE "()V" + +#define CLS_RESLV_INIT_CLASS "java/lang/Class" +#define CLS_RESLV_INIT_OBJECT "java/lang/Object" +#define CLS_RESLV_INIT_REF "sun/misc/Ref" + +#define METHOD_FLAG_BITS 5 +#define FLAG_MASK ((1<methods[slot] + +#define monitorEnter(m) +#define monitorExit(m) + +#define exceptionOccurred(ee) 0 +void SignalError(struct execenv *, char *, char *); + +void panic(const char *format, ...); + +void printCurrentClassName(void); + +void ensure_dir_exists(char *dir); +void ensure_dir_writable(char *dir); + +extern bool_t no_native_methods; +extern bool_t no_floating_point; +extern bool_t no_finalizers; + +extern int errorCode; /* status error returned by program*/ + /* Set to 1 if any errors encountered + * during class verification in VerifyFile() + */ +#endif /* !_OOBJ_H_ */ diff --git a/MPC.3.5.LINUX/preverifier/opcodes.h b/MPC.3.5.LINUX/preverifier/opcodes.h new file mode 100644 index 0000000..a797db4 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/opcodes.h @@ -0,0 +1,248 @@ +/* + * Copyright 1995-2002 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +typedef enum { + opc_nop = 0, + opc_aconst_null = 1, + opc_iconst_m1 = 2, + opc_iconst_0 = 3, + opc_iconst_1 = 4, + opc_iconst_2 = 5, + opc_iconst_3 = 6, + opc_iconst_4 = 7, + opc_iconst_5 = 8, + opc_lconst_0 = 9, + opc_lconst_1 = 10, + opc_fconst_0 = 11, + opc_fconst_1 = 12, + opc_fconst_2 = 13, + opc_dconst_0 = 14, + opc_dconst_1 = 15, + opc_bipush = 16, + opc_sipush = 17, + opc_ldc = 18, + opc_ldc_w = 19, + opc_ldc2_w = 20, + opc_iload = 21, + opc_lload = 22, + opc_fload = 23, + opc_dload = 24, + opc_aload = 25, + opc_iload_0 = 26, + opc_iload_1 = 27, + opc_iload_2 = 28, + opc_iload_3 = 29, + opc_lload_0 = 30, + opc_lload_1 = 31, + opc_lload_2 = 32, + opc_lload_3 = 33, + opc_fload_0 = 34, + opc_fload_1 = 35, + opc_fload_2 = 36, + opc_fload_3 = 37, + opc_dload_0 = 38, + opc_dload_1 = 39, + opc_dload_2 = 40, + opc_dload_3 = 41, + opc_aload_0 = 42, + opc_aload_1 = 43, + opc_aload_2 = 44, + opc_aload_3 = 45, + opc_iaload = 46, + opc_laload = 47, + opc_faload = 48, + opc_daload = 49, + opc_aaload = 50, + opc_baload = 51, + opc_caload = 52, + opc_saload = 53, + opc_istore = 54, + opc_lstore = 55, + opc_fstore = 56, + opc_dstore = 57, + opc_astore = 58, + opc_istore_0 = 59, + opc_istore_1 = 60, + opc_istore_2 = 61, + opc_istore_3 = 62, + opc_lstore_0 = 63, + opc_lstore_1 = 64, + opc_lstore_2 = 65, + opc_lstore_3 = 66, + opc_fstore_0 = 67, + opc_fstore_1 = 68, + opc_fstore_2 = 69, + opc_fstore_3 = 70, + opc_dstore_0 = 71, + opc_dstore_1 = 72, + opc_dstore_2 = 73, + opc_dstore_3 = 74, + opc_astore_0 = 75, + opc_astore_1 = 76, + opc_astore_2 = 77, + opc_astore_3 = 78, + opc_iastore = 79, + opc_lastore = 80, + opc_fastore = 81, + opc_dastore = 82, + opc_aastore = 83, + opc_bastore = 84, + opc_castore = 85, + opc_sastore = 86, + opc_pop = 87, + opc_pop2 = 88, + opc_dup = 89, + opc_dup_x1 = 90, + opc_dup_x2 = 91, + opc_dup2 = 92, + opc_dup2_x1 = 93, + opc_dup2_x2 = 94, + opc_swap = 95, + opc_iadd = 96, + opc_ladd = 97, + opc_fadd = 98, + opc_dadd = 99, + opc_isub = 100, + opc_lsub = 101, + opc_fsub = 102, + opc_dsub = 103, + opc_imul = 104, + opc_lmul = 105, + opc_fmul = 106, + opc_dmul = 107, + opc_idiv = 108, + opc_ldiv = 109, + opc_fdiv = 110, + opc_ddiv = 111, + opc_irem = 112, + opc_lrem = 113, + opc_frem = 114, + opc_drem = 115, + opc_ineg = 116, + opc_lneg = 117, + opc_fneg = 118, + opc_dneg = 119, + opc_ishl = 120, + opc_lshl = 121, + opc_ishr = 122, + opc_lshr = 123, + opc_iushr = 124, + opc_lushr = 125, + opc_iand = 126, + opc_land = 127, + opc_ior = 128, + opc_lor = 129, + opc_ixor = 130, + opc_lxor = 131, + opc_iinc = 132, + opc_i2l = 133, + opc_i2f = 134, + opc_i2d = 135, + opc_l2i = 136, + opc_l2f = 137, + opc_l2d = 138, + opc_f2i = 139, + opc_f2l = 140, + opc_f2d = 141, + opc_d2i = 142, + opc_d2l = 143, + opc_d2f = 144, + opc_i2b = 145, + opc_i2c = 146, + opc_i2s = 147, + opc_lcmp = 148, + opc_fcmpl = 149, + opc_fcmpg = 150, + opc_dcmpl = 151, + opc_dcmpg = 152, + opc_ifeq = 153, + opc_ifne = 154, + opc_iflt = 155, + opc_ifge = 156, + opc_ifgt = 157, + opc_ifle = 158, + opc_if_icmpeq = 159, + opc_if_icmpne = 160, + opc_if_icmplt = 161, + opc_if_icmpge = 162, + opc_if_icmpgt = 163, + opc_if_icmple = 164, + opc_if_acmpeq = 165, + opc_if_acmpne = 166, + opc_goto = 167, + opc_jsr = 168, + opc_ret = 169, + opc_tableswitch = 170, + opc_lookupswitch = 171, + opc_ireturn = 172, + opc_lreturn = 173, + opc_freturn = 174, + opc_dreturn = 175, + opc_areturn = 176, + opc_return = 177, + opc_getstatic = 178, + opc_putstatic = 179, + opc_getfield = 180, + opc_putfield = 181, + opc_invokevirtual = 182, + opc_invokespecial = 183, + opc_invokestatic = 184, + opc_invokeinterface = 185, + opc_xxxunusedxxx = 186, + opc_new = 187, + opc_newarray = 188, + opc_anewarray = 189, + opc_arraylength = 190, + opc_athrow = 191, + opc_checkcast = 192, + opc_instanceof = 193, + opc_monitorenter = 194, + opc_monitorexit = 195, + opc_wide = 196, + opc_multianewarray = 197, + opc_ifnull = 198, + opc_ifnonnull = 199, + opc_goto_w = 200, + opc_jsr_w = 201, + opc_breakpoint = 202, + opc_ldc_quick = 203, + opc_ldc_w_quick = 204, + opc_ldc2_w_quick = 205, + opc_getfield_quick = 206, + opc_putfield_quick = 207, + opc_getfield2_quick = 208, + opc_putfield2_quick = 209, + opc_getstatic_quick = 210, + opc_putstatic_quick = 211, + opc_getstatic2_quick = 212, + opc_putstatic2_quick = 213, + opc_invokevirtual_quick = 214, + opc_invokenonvirtual_quick = 215, + opc_invokesuper_quick = 216, + opc_invokestatic_quick = 217, + opc_invokeinterface_quick = 218, + opc_invokevirtualobject_quick = 219, + opc_invokeignored_quick = 220, + opc_new_quick = 221, + opc_anewarray_quick = 222, + opc_multianewarray_quick = 223, + opc_checkcast_quick = 224, + opc_instanceof_quick = 225, + opc_invokevirtual_quick_w = 226, + opc_getfield_quick_w = 227, + opc_putfield_quick_w = 228, + opc_nonnull_quick = 229, + opc_first_unused_index = 230, + opc_software = 254, + opc_hardware = 255 +} opcode_type; diff --git a/MPC.3.5.LINUX/preverifier/opcodes.in_out b/MPC.3.5.LINUX/preverifier/opcodes.in_out new file mode 100644 index 0000000..d898616 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/opcodes.in_out @@ -0,0 +1,245 @@ +/* + * Copyright 1995-2002 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +char * const opcode_in_out[][2] = { + {"", ""}, /* nop */ + {"", "A"}, /* aconst_null */ + {"", "I"}, /* iconst_m1 */ + {"", "I"}, /* iconst_0 */ + {"", "I"}, /* iconst_1 */ + {"", "I"}, /* iconst_2 */ + {"", "I"}, /* iconst_3 */ + {"", "I"}, /* iconst_4 */ + {"", "I"}, /* iconst_5 */ + {"", "L"}, /* lconst_0 */ + {"", "L"}, /* lconst_1 */ + {"", "F"}, /* fconst_0 */ + {"", "F"}, /* fconst_1 */ + {"", "F"}, /* fconst_2 */ + {"", "D"}, /* dconst_0 */ + {"", "D"}, /* dconst_1 */ + {"", "I"}, /* bipush */ + {"", "I"}, /* sipush */ + {"", "?"}, /* ldc */ + {"", "?"}, /* ldc_w */ + {"", "?"}, /* ldc2_w */ + {"", "I"}, /* iload */ + {"", "L"}, /* lload */ + {"", "F"}, /* fload */ + {"", "D"}, /* dload */ + {"", "A"}, /* aload */ + {"", "I"}, /* iload_0 */ + {"", "I"}, /* iload_1 */ + {"", "I"}, /* iload_2 */ + {"", "I"}, /* iload_3 */ + {"", "L"}, /* lload_0 */ + {"", "L"}, /* lload_1 */ + {"", "L"}, /* lload_2 */ + {"", "L"}, /* lload_3 */ + {"", "F"}, /* fload_0 */ + {"", "F"}, /* fload_1 */ + {"", "F"}, /* fload_2 */ + {"", "F"}, /* fload_3 */ + {"", "D"}, /* dload_0 */ + {"", "D"}, /* dload_1 */ + {"", "D"}, /* dload_2 */ + {"", "D"}, /* dload_3 */ + {"", "A"}, /* aload_0 */ + {"", "A"}, /* aload_1 */ + {"", "A"}, /* aload_2 */ + {"", "A"}, /* aload_3 */ + {"[I]I", "I"}, /* iaload */ + {"[L]I", "L"}, /* laload */ + {"[F]I", "F"}, /* faload */ + {"[D]I", "D"}, /* daload */ + {"[A]I", "A"}, /* aaload */ + {"[b]I", "I"}, /* baload */ + {"[C]I", "I"}, /* caload */ + {"[S]I", "I"}, /* saload */ + {"I", ""}, /* istore */ + {"L", ""}, /* lstore */ + {"F", ""}, /* fstore */ + {"D", ""}, /* dstore */ + {"A", ""}, /* astore */ + {"I", ""}, /* istore_0 */ + {"I", ""}, /* istore_1 */ + {"I", ""}, /* istore_2 */ + {"I", ""}, /* istore_3 */ + {"L", ""}, /* lstore_0 */ + {"L", ""}, /* lstore_1 */ + {"L", ""}, /* lstore_2 */ + {"L", ""}, /* lstore_3 */ + {"F", ""}, /* fstore_0 */ + {"F", ""}, /* fstore_1 */ + {"F", ""}, /* fstore_2 */ + {"F", ""}, /* fstore_3 */ + {"D", ""}, /* dstore_0 */ + {"D", ""}, /* dstore_1 */ + {"D", ""}, /* dstore_2 */ + {"D", ""}, /* dstore_3 */ + {"A", ""}, /* astore_0 */ + {"A", ""}, /* astore_1 */ + {"A", ""}, /* astore_2 */ + {"A", ""}, /* astore_3 */ + {"[I]II", ""}, /* iastore */ + {"[L]IL", ""}, /* lastore */ + {"[F]IF", ""}, /* fastore */ + {"[D]ID", ""}, /* dastore */ + {"[A]IA", ""}, /* aastore */ + {"[b]II", ""}, /* bastore */ + {"[C]II", ""}, /* castore */ + {"[S]II", ""}, /* sastore */ + {"1", ""}, /* pop */ + {"2+1", ""}, /* pop2 */ + {"1", "11"}, /* dup */ + {"21", "121"}, /* dup_x1 */ + {"3+21", "1321"}, /* dup_x2 */ + {"2+1", "2121"}, /* dup2 */ + {"32+1", "21321"}, /* dup2_x1 */ + {"4+32+1", "214321"}, /* dup2_x2 */ + {"21", "12"}, /* swap */ + {"II", "I"}, /* iadd */ + {"LL", "L"}, /* ladd */ + {"FF", "F"}, /* fadd */ + {"DD", "D"}, /* dadd */ + {"II", "I"}, /* isub */ + {"LL", "L"}, /* lsub */ + {"FF", "F"}, /* fsub */ + {"DD", "D"}, /* dsub */ + {"II", "I"}, /* imul */ + {"LL", "L"}, /* lmul */ + {"FF", "F"}, /* fmul */ + {"DD", "D"}, /* dmul */ + {"II", "I"}, /* idiv */ + {"LL", "L"}, /* ldiv */ + {"FF", "F"}, /* fdiv */ + {"DD", "D"}, /* ddiv */ + {"II", "I"}, /* irem */ + {"LL", "L"}, /* lrem */ + {"FF", "F"}, /* frem */ + {"DD", "D"}, /* drem */ + {"I", "I"}, /* ineg */ + {"L", "L"}, /* lneg */ + {"F", "F"}, /* fneg */ + {"D", "D"}, /* dneg */ + {"II", "I"}, /* ishl */ + {"LI", "L"}, /* lshl */ + {"II", "I"}, /* ishr */ + {"LI", "L"}, /* lshr */ + {"II", "I"}, /* iushr */ + {"LI", "L"}, /* lushr */ + {"II", "I"}, /* iand */ + {"LL", "L"}, /* land */ + {"II", "I"}, /* ior */ + {"LL", "L"}, /* lor */ + {"II", "I"}, /* ixor */ + {"LL", "L"}, /* lxor */ + {"", ""}, /* iinc */ + {"I", "L"}, /* i2l */ + {"I", "F"}, /* i2f */ + {"I", "D"}, /* i2d */ + {"L", "I"}, /* l2i */ + {"L", "F"}, /* l2f */ + {"L", "D"}, /* l2d */ + {"F", "I"}, /* f2i */ + {"F", "L"}, /* f2l */ + {"F", "D"}, /* f2d */ + {"D", "I"}, /* d2i */ + {"D", "L"}, /* d2l */ + {"D", "F"}, /* d2f */ + {"I", "I"}, /* i2b */ + {"I", "I"}, /* i2c */ + {"I", "I"}, /* i2s */ + {"LL", "I"}, /* lcmp */ + {"FF", "I"}, /* fcmpl */ + {"FF", "I"}, /* fcmpg */ + {"DD", "I"}, /* dcmpl */ + {"DD", "I"}, /* dcmpg */ + {"I", ""}, /* ifeq */ + {"I", ""}, /* ifne */ + {"I", ""}, /* iflt */ + {"I", ""}, /* ifge */ + {"I", ""}, /* ifgt */ + {"I", ""}, /* ifle */ + {"II", ""}, /* if_icmpeq */ + {"II", ""}, /* if_icmpne */ + {"II", ""}, /* if_icmplt */ + {"II", ""}, /* if_icmpge */ + {"II", ""}, /* if_icmpgt */ + {"II", ""}, /* if_icmple */ + {"AA", ""}, /* if_acmpeq */ + {"AA", ""}, /* if_acmpne */ + {"", ""}, /* goto */ + {"", "R"}, /* jsr */ + {"", ""}, /* ret */ + {"I", ""}, /* tableswitch */ + {"I", ""}, /* lookupswitch */ + {"I", ""}, /* ireturn */ + {"L", ""}, /* lreturn */ + {"F", ""}, /* freturn */ + {"D", ""}, /* dreturn */ + {"A", ""}, /* areturn */ + {"", ""}, /* return */ + {"", "?"}, /* getstatic */ + {"?", ""}, /* putstatic */ + {"A", "?"}, /* getfield */ + {"?", ""}, /* putfield */ + {"?", "?"}, /* invokevirtual */ + {"?", "?"}, /* invokespecial */ + {"?", "?"}, /* invokestatic */ + {"?", "?"}, /* invokeinterface */ + {"?", "?"}, /* xxxunusedxxx */ + {"", "A"}, /* new */ + {"I", "A"}, /* newarray */ + {"I", "A"}, /* anewarray */ + {"[?]", "I"}, /* arraylength */ + {"O", ""}, /* athrow */ + {"A", "A"}, /* checkcast */ + {"A", "I"}, /* instanceof */ + {"A", ""}, /* monitorenter */ + {"A", ""}, /* monitorexit */ + {"", ""}, /* wide */ + {"?", "A"}, /* multianewarray */ + {"A", ""}, /* ifnull */ + {"A", ""}, /* ifnonnull */ + {"", ""}, /* goto_w */ + {"", "R"}, /* jsr_w */ + {"", ""}, /* breakpoint */ + {"", "?"}, /* ldc_quick */ + {"", "?"}, /* ldc_w_quick */ + {"", "?"}, /* ldc2_w_quick */ + {"A", "?"}, /* getfield_quick */ + {"?", ""}, /* putfield_quick */ + {"A", "?"}, /* getfield2_quick */ + {"?", ""}, /* putfield2_quick */ + {"", "?"}, /* getstatic_quick */ + {"?", ""}, /* putstatic_quick */ + {"", "?"}, /* getstatic2_quick */ + {"?", "_"}, /* putstatic2_quick */ + {"?", "?"}, /* invokevirtual_quick */ + {"?", "?"}, /* invokenonvirtual_quick */ + {"?", "?"}, /* invokesuper_quick */ + {"?", "?"}, /* invokestatic_quick */ + {"?", "?"}, /* invokeinterface_quick */ + {"?", "?"}, /* invokevirtualobject_quick */ + {"?", "?"}, /* invokeignored_quick */ + {"", "A"}, /* new_quick */ + {"I", "A"}, /* anewarray_quick */ + {"?", "A"}, /* multianewarray_quick */ + {"A", "A"}, /* checkcast_quick */ + {"A", "I"}, /* instanceof_quick */ + {"?", "?"}, /* invokevirtual_quick_w */ + {"A", "?"}, /* getfield_quick_w */ + {"?", ""}, /* putfield_quick_w */ + {"A", ""}, /* nonnull_quick */ +}; diff --git a/MPC.3.5.LINUX/preverifier/opcodes.init b/MPC.3.5.LINUX/preverifier/opcodes.init new file mode 100644 index 0000000..2e58ccf --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/opcodes.init @@ -0,0 +1,271 @@ +/* + * Copyright 1995-2002 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +char * const opnames[256] = { + "nop", + "aconst_null", + "iconst_m1", + "iconst_0", + "iconst_1", + "iconst_2", + "iconst_3", + "iconst_4", + "iconst_5", + "lconst_0", + "lconst_1", + "fconst_0", + "fconst_1", + "fconst_2", + "dconst_0", + "dconst_1", + "bipush", + "sipush", + "ldc", + "ldc_w", + "ldc2_w", + "iload", + "lload", + "fload", + "dload", + "aload", + "iload_0", + "iload_1", + "iload_2", + "iload_3", + "lload_0", + "lload_1", + "lload_2", + "lload_3", + "fload_0", + "fload_1", + "fload_2", + "fload_3", + "dload_0", + "dload_1", + "dload_2", + "dload_3", + "aload_0", + "aload_1", + "aload_2", + "aload_3", + "iaload", + "laload", + "faload", + "daload", + "aaload", + "baload", + "caload", + "saload", + "istore", + "lstore", + "fstore", + "dstore", + "astore", + "istore_0", + "istore_1", + "istore_2", + "istore_3", + "lstore_0", + "lstore_1", + "lstore_2", + "lstore_3", + "fstore_0", + "fstore_1", + "fstore_2", + "fstore_3", + "dstore_0", + "dstore_1", + "dstore_2", + "dstore_3", + "astore_0", + "astore_1", + "astore_2", + "astore_3", + "iastore", + "lastore", + "fastore", + "dastore", + "aastore", + "bastore", + "castore", + "sastore", + "pop", + "pop2", + "dup", + "dup_x1", + "dup_x2", + "dup2", + "dup2_x1", + "dup2_x2", + "swap", + "iadd", + "ladd", + "fadd", + "dadd", + "isub", + "lsub", + "fsub", + "dsub", + "imul", + "lmul", + "fmul", + "dmul", + "idiv", + "ldiv", + "fdiv", + "ddiv", + "irem", + "lrem", + "frem", + "drem", + "ineg", + "lneg", + "fneg", + "dneg", + "ishl", + "lshl", + "ishr", + "lshr", + "iushr", + "lushr", + "iand", + "land", + "ior", + "lor", + "ixor", + "lxor", + "iinc", + "i2l", + "i2f", + "i2d", + "l2i", + "l2f", + "l2d", + "f2i", + "f2l", + "f2d", + "d2i", + "d2l", + "d2f", + "i2b", + "i2c", + "i2s", + "lcmp", + "fcmpl", + "fcmpg", + "dcmpl", + "dcmpg", + "ifeq", + "ifne", + "iflt", + "ifge", + "ifgt", + "ifle", + "if_icmpeq", + "if_icmpne", + "if_icmplt", + "if_icmpge", + "if_icmpgt", + "if_icmple", + "if_acmpeq", + "if_acmpne", + "goto", + "jsr", + "ret", + "tableswitch", + "lookupswitch", + "ireturn", + "lreturn", + "freturn", + "dreturn", + "areturn", + "return", + "getstatic", + "putstatic", + "getfield", + "putfield", + "invokevirtual", + "invokespecial", + "invokestatic", + "invokeinterface", + "xxxunusedxxx", + "new", + "newarray", + "anewarray", + "arraylength", + "athrow", + "checkcast", + "instanceof", + "monitorenter", + "monitorexit", + "wide", + "multianewarray", + "ifnull", + "ifnonnull", + "goto_w", + "jsr_w", + "breakpoint", + "ldc_quick", + "ldc_w_quick", + "ldc2_w_quick", + "getfield_quick", + "putfield_quick", + "getfield2_quick", + "putfield2_quick", + "getstatic_quick", + "putstatic_quick", + "getstatic2_quick", + "putstatic2_quick", + "invokevirtual_quick", + "invokenonvirtual_quick", + "invokesuper_quick", + "invokestatic_quick", + "invokeinterface_quick", + "invokevirtualobject_quick", + "invokeignored_quick", + "new_quick", + "anewarray_quick", + "multianewarray_quick", + "checkcast_quick", + "instanceof_quick", + "invokevirtual_quick_w", + "getfield_quick_w", + "putfield_quick_w", + "nonnull_quick", + "??", + "??", + "??", + "??", + "??", + "??", + "??", + "??", + "??", + "??", + "??", + "??", + "??", + "??", + "??", + "??", + "??", + "??", + "??", + "??", + "??", + "??", + "??", + "??", + "software", + "hardware", +}; diff --git a/MPC.3.5.LINUX/preverifier/opcodes.length b/MPC.3.5.LINUX/preverifier/opcodes.length new file mode 100644 index 0000000..1d741e6 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/opcodes.length @@ -0,0 +1,271 @@ +/* + * Copyright 1995-2002 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +const short opcode_length[256] = { + 1, /* nop */ + 1, /* aconst_null */ + 1, /* iconst_m1 */ + 1, /* iconst_0 */ + 1, /* iconst_1 */ + 1, /* iconst_2 */ + 1, /* iconst_3 */ + 1, /* iconst_4 */ + 1, /* iconst_5 */ + 1, /* lconst_0 */ + 1, /* lconst_1 */ + 1, /* fconst_0 */ + 1, /* fconst_1 */ + 1, /* fconst_2 */ + 1, /* dconst_0 */ + 1, /* dconst_1 */ + 2, /* bipush */ + 3, /* sipush */ + 2, /* ldc */ + 3, /* ldc_w */ + 3, /* ldc2_w */ + 2, /* iload */ + 2, /* lload */ + 2, /* fload */ + 2, /* dload */ + 2, /* aload */ + 1, /* iload_0 */ + 1, /* iload_1 */ + 1, /* iload_2 */ + 1, /* iload_3 */ + 1, /* lload_0 */ + 1, /* lload_1 */ + 1, /* lload_2 */ + 1, /* lload_3 */ + 1, /* fload_0 */ + 1, /* fload_1 */ + 1, /* fload_2 */ + 1, /* fload_3 */ + 1, /* dload_0 */ + 1, /* dload_1 */ + 1, /* dload_2 */ + 1, /* dload_3 */ + 1, /* aload_0 */ + 1, /* aload_1 */ + 1, /* aload_2 */ + 1, /* aload_3 */ + 1, /* iaload */ + 1, /* laload */ + 1, /* faload */ + 1, /* daload */ + 1, /* aaload */ + 1, /* baload */ + 1, /* caload */ + 1, /* saload */ + 2, /* istore */ + 2, /* lstore */ + 2, /* fstore */ + 2, /* dstore */ + 2, /* astore */ + 1, /* istore_0 */ + 1, /* istore_1 */ + 1, /* istore_2 */ + 1, /* istore_3 */ + 1, /* lstore_0 */ + 1, /* lstore_1 */ + 1, /* lstore_2 */ + 1, /* lstore_3 */ + 1, /* fstore_0 */ + 1, /* fstore_1 */ + 1, /* fstore_2 */ + 1, /* fstore_3 */ + 1, /* dstore_0 */ + 1, /* dstore_1 */ + 1, /* dstore_2 */ + 1, /* dstore_3 */ + 1, /* astore_0 */ + 1, /* astore_1 */ + 1, /* astore_2 */ + 1, /* astore_3 */ + 1, /* iastore */ + 1, /* lastore */ + 1, /* fastore */ + 1, /* dastore */ + 1, /* aastore */ + 1, /* bastore */ + 1, /* castore */ + 1, /* sastore */ + 1, /* pop */ + 1, /* pop2 */ + 1, /* dup */ + 1, /* dup_x1 */ + 1, /* dup_x2 */ + 1, /* dup2 */ + 1, /* dup2_x1 */ + 1, /* dup2_x2 */ + 1, /* swap */ + 1, /* iadd */ + 1, /* ladd */ + 1, /* fadd */ + 1, /* dadd */ + 1, /* isub */ + 1, /* lsub */ + 1, /* fsub */ + 1, /* dsub */ + 1, /* imul */ + 1, /* lmul */ + 1, /* fmul */ + 1, /* dmul */ + 1, /* idiv */ + 1, /* ldiv */ + 1, /* fdiv */ + 1, /* ddiv */ + 1, /* irem */ + 1, /* lrem */ + 1, /* frem */ + 1, /* drem */ + 1, /* ineg */ + 1, /* lneg */ + 1, /* fneg */ + 1, /* dneg */ + 1, /* ishl */ + 1, /* lshl */ + 1, /* ishr */ + 1, /* lshr */ + 1, /* iushr */ + 1, /* lushr */ + 1, /* iand */ + 1, /* land */ + 1, /* ior */ + 1, /* lor */ + 1, /* ixor */ + 1, /* lxor */ + 3, /* iinc */ + 1, /* i2l */ + 1, /* i2f */ + 1, /* i2d */ + 1, /* l2i */ + 1, /* l2f */ + 1, /* l2d */ + 1, /* f2i */ + 1, /* f2l */ + 1, /* f2d */ + 1, /* d2i */ + 1, /* d2l */ + 1, /* d2f */ + 1, /* i2b */ + 1, /* i2c */ + 1, /* i2s */ + 1, /* lcmp */ + 1, /* fcmpl */ + 1, /* fcmpg */ + 1, /* dcmpl */ + 1, /* dcmpg */ + 3, /* ifeq */ + 3, /* ifne */ + 3, /* iflt */ + 3, /* ifge */ + 3, /* ifgt */ + 3, /* ifle */ + 3, /* if_icmpeq */ + 3, /* if_icmpne */ + 3, /* if_icmplt */ + 3, /* if_icmpge */ + 3, /* if_icmpgt */ + 3, /* if_icmple */ + 3, /* if_acmpeq */ + 3, /* if_acmpne */ + 3, /* goto */ + 3, /* jsr */ + 2, /* ret */ + 99, /* tableswitch */ + 99, /* lookupswitch */ + 1, /* ireturn */ + 1, /* lreturn */ + 1, /* freturn */ + 1, /* dreturn */ + 1, /* areturn */ + 1, /* return */ + 3, /* getstatic */ + 3, /* putstatic */ + 3, /* getfield */ + 3, /* putfield */ + 3, /* invokevirtual */ + 3, /* invokespecial */ + 3, /* invokestatic */ + 5, /* invokeinterface */ + 0, /* xxxunusedxxx */ + 3, /* new */ + 2, /* newarray */ + 3, /* anewarray */ + 1, /* arraylength */ + 1, /* athrow */ + 3, /* checkcast */ + 3, /* instanceof */ + 1, /* monitorenter */ + 1, /* monitorexit */ + 0, /* wide */ + 4, /* multianewarray */ + 3, /* ifnull */ + 3, /* ifnonnull */ + 5, /* goto_w */ + 5, /* jsr_w */ + 1, /* breakpoint */ + 2, /* ldc_quick */ + 3, /* ldc_w_quick */ + 3, /* ldc2_w_quick */ + 3, /* getfield_quick */ + 3, /* putfield_quick */ + 3, /* getfield2_quick */ + 3, /* putfield2_quick */ + 3, /* getstatic_quick */ + 3, /* putstatic_quick */ + 3, /* getstatic2_quick */ + 3, /* putstatic2_quick */ + 3, /* invokevirtual_quick */ + 3, /* invokenonvirtual_quick */ + 3, /* invokesuper_quick */ + 3, /* invokestatic_quick */ + 5, /* invokeinterface_quick */ + 3, /* invokevirtualobject_quick */ + 3, /* invokeignored_quick */ + 3, /* new_quick */ + 3, /* anewarray_quick */ + 4, /* multianewarray_quick */ + 3, /* checkcast_quick */ + 3, /* instanceof_quick */ + 3, /* invokevirtual_quick_w */ + 3, /* getfield_quick_w */ + 3, /* putfield_quick_w */ + 1, /* nonnull_quick */ + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, +}; diff --git a/MPC.3.5.LINUX/preverifier/path.h b/MPC.3.5.LINUX/preverifier/path.h new file mode 100644 index 0000000..d4624ad --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/path.h @@ -0,0 +1,50 @@ +/* + * @(#)path.h 1.6 02/09/27 + * + * Copyright 1995-1998 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +#ifndef _PATH_H_ +#define _PATH_H_ + +#include +#include "path_md.h" + +typedef struct { + struct { + unsigned long locpos; + unsigned long cenpos; + } jar; + char type; + char name[1]; +} zip_t; + +/* + * Class path element, which is either a directory or zip file. + */ +typedef struct { + enum { CPE_DIR, CPE_ZIP } type; + union { + zip_t *zip; + char *dir; + } u; +} cpe_t; + +cpe_t **sysGetClassPath(void); +void pushDirectoryOntoClassPath(char* directory); +void pushJarFileOntoClassPath(zip_t *zip); +void popClassPath(void); + +bool_t +findJARDirectories(zip_t *entry, struct stat *statbuf); + +#endif /* !_PATH_H_ */ diff --git a/MPC.3.5.LINUX/preverifier/path_md.h b/MPC.3.5.LINUX/preverifier/path_md.h new file mode 100644 index 0000000..f7553d6 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/path_md.h @@ -0,0 +1,50 @@ +/* + * @(#)path_md.h 1.4 02/09/27 + * + * Copyright 1995-1998 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +#ifndef _PATH_MD_H_ +#define _PATH_MD_H_ + +#define DIR_SEPARATOR '/' + +#ifdef UNIX +#define LOCAL_DIR_SEPARATOR '/' +#define PATH_SEPARATOR ':' + +#include +#endif +#ifdef WIN32 + +#define LOCAL_DIR_SEPARATOR '\\' +#define PATH_SEPARATOR ';' + +#include +struct dirent { + char d_name[1024]; +}; + +typedef struct { + struct dirent dirent; + char *path; + HANDLE handle; + WIN32_FIND_DATA find_data; +} DIR; + +DIR *opendir(const char *dirname); +struct dirent *readdir(DIR *dirp); +int closedir(DIR *dirp); + +#endif + +#endif /* !_PATH_MD_H_ */ diff --git a/MPC.3.5.LINUX/preverifier/signature.h b/MPC.3.5.LINUX/preverifier/signature.h new file mode 100644 index 0000000..94afc71 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/signature.h @@ -0,0 +1,59 @@ +/* + * @(#)signature.h 1.2 02/09/27 + * + * Copyright 1995-1998 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +/* + * The keyletters used in type signatures + */ + +#ifndef _SIGNATURE_H_ +#define _SIGNATURE_H_ + +#define SIGNATURE_ANY 'A' +#define SIGNATURE_ARRAY '[' +#define SIGNATURE_BYTE 'B' +#define SIGNATURE_CHAR 'C' +#define SIGNATURE_CLASS 'L' +#define SIGNATURE_ENDCLASS ';' +#define SIGNATURE_ENUM 'E' +#define SIGNATURE_FLOAT 'F' +#define SIGNATURE_DOUBLE 'D' +#define SIGNATURE_FUNC '(' +#define SIGNATURE_ENDFUNC ')' +#define SIGNATURE_INT 'I' +#define SIGNATURE_LONG 'J' +#define SIGNATURE_SHORT 'S' +#define SIGNATURE_VOID 'V' +#define SIGNATURE_BOOLEAN 'Z' + +#define SIGNATURE_ANY_STRING "A" +#define SIGNATURE_ARRAY_STRING "[" +#define SIGNATURE_BYTE_STRING "B" +#define SIGNATURE_CHAR_STRING "C" +#define SIGNATURE_CLASS_STRING "L" +#define SIGNATURE_ENDCLASS_STRING ";" +#define SIGNATURE_ENUM_STRING "E" +#define SIGNATURE_FLOAT_STRING "F" +#define SIGNATURE_DOUBLE_STRING "D" +#define SIGNATURE_FUNC_STRING "(" +#define SIGNATURE_ENDFUNC_STRING ")" +#define SIGNATURE_INT_STRING "I" +#define SIGNATURE_LONG_STRING "J" +#define SIGNATURE_SHORT_STRING "S" +#define SIGNATURE_VOID_STRING "V" +#define SIGNATURE_BOOLEAN_STRING "Z" + + + +#endif /* !_SIGNATURE_H_ */ diff --git a/MPC.3.5.LINUX/preverifier/stubs.c b/MPC.3.5.LINUX/preverifier/stubs.c new file mode 100644 index 0000000..09c15fb --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/stubs.c @@ -0,0 +1,100 @@ +/* + * @(#)stubs.c 1.6 02/09/27 + * + * Copyright 1995-1998 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +/*========================================================================= + * SYSTEM: Verifier + * SUBSYSTEM: Stubs. + * FILE: stubs.c + * OVERVIEW: Miscellaneous functions used during class loading, etc. + * + * AUTHOR: Sheng Liang, Sun Microsystems, Inc. + * Edited by Tasneem Sayeed, Sun Microsystems + *=======================================================================*/ + +/*========================================================================= + * Include files + *=======================================================================*/ + +#include "oobj.h" +#include "sys_api.h" + +void +SignalError(struct execenv * ee, char *ename, char *DetailMessage) +{ + printCurrentClassName(); + jio_fprintf(stderr, "%s", ename); + if (DetailMessage) { + jio_fprintf(stderr, ": %s\n", DetailMessage); + } else { + jio_fprintf(stderr, "\n"); + } + exit(1); +} + +bool_t +VerifyClassAccess(ClassClass *current_class, ClassClass *new_class, + bool_t classloader_only) +{ + return TRUE; +} + +/* This is called by FindClassFromClass when a class name is being requested + * by another class that was loaded via a classloader. For javah, we don't + * really care. + */ + +ClassClass * +ClassLoaderFindClass(struct execenv *ee, + struct Hjava_lang_ClassLoader *loader, + char *name, bool_t resolve) +{ + return NULL; +} + +/* Get the execution environment + */ +ExecEnv * +EE() { + static struct execenv lee; + return &lee; +} + +bool_t RunStaticInitializers(ClassClass *cb) +{ + return TRUE; +} + +void InitializeInvoker(ClassClass *cb) +{ +} + +int verifyclasses = VERIFY_ALL; +long nbinclasses, sizebinclasses; +ClassClass **binclasses; +bool_t verbose; +struct StrIDhash *nameTypeHash; +struct StrIDhash *stringHash; + +void *allocClassClass() +{ + ClassClass *cb = sysCalloc(1, sizeof(ClassClass)); + Classjava_lang_Class *ucb = sysCalloc(1, sizeof(Classjava_lang_Class)); + + cb->obj = ucb; + ucb->HandleToSelf = cb; + return cb; +} + +void DumpThreads() {} diff --git a/MPC.3.5.LINUX/preverifier/sys_api.h b/MPC.3.5.LINUX/preverifier/sys_api.h new file mode 100644 index 0000000..539f197 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/sys_api.h @@ -0,0 +1,207 @@ +/* + * @(#)sys_api.h 1.6 02/09/27 + * + * Copyright 1995-1999 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +/* + * System or Host dependent API. This defines the "porting layer" for + * POSIX.1 compliant operating systems. + */ + +#ifndef _SYS_API_H_ +#define _SYS_API_H_ + +/* + * typedefs_md.h includes basic types for this platform; + * any macros for HPI functions have been moved to "sysmacros_md.h" + */ +#include "typedefs.h" + +/* + * Miscellaneous system utility APIs that fall outside the POSIX.1 + * spec. + * + * Until POSIX (P1003.1a) formerly P.4 is standard, we'll use our + * time struct definitions found in timeval.h. + */ +long sysGetMilliTicks(void); +long sysTime(long *); +int64_t sysTimeMillis(void); + +#include +struct tm * sysLocaltime(time_t *, struct tm*); +struct tm * sysGmtime(time_t *, struct tm*); +void sysStrftime(char *, int, char *, struct tm *); +time_t sysMktime(struct tm*); + +/* + * System API for general allocations + */ +void * sysMalloc(size_t); +void * sysRealloc(void*, size_t); +void sysFree(void*); +void * sysCalloc(size_t, size_t); +#ifdef PAGED_HEAPS +void * sysAllocBlock(size_t, void**); +void sysFreeBlock(void *); +#endif /* PAGED_HEAPS */ + +/* + * System API for dynamic linking libraries into the interpreter + */ +char * sysInitializeLinker(void); +int sysAddDLSegment(char *); +void sysSaveLDPath(char *); +long sysDynamicLink(char *); +void sysBuildLibName(char *, int, char *, char *); +int sysBuildFunName(char *, int, void *, int); +long * sysInvokeNative(void *, void *, long *, char *, int, void *); + +/* + * System API for invoking the interpreter from native applications + */ +void sysGetDefaultJavaVMInitArgs(void *); +int sysInitializeJavaVM(void *, void *); +int sysFinalizeJavaVM(void *); +void sysAttachThreadLock(); +void sysAttachThreadUnlock(); + +/* + * System API for threads + */ +typedef struct sys_thread sys_thread_t; +typedef struct sys_mon sys_mon_t; +typedef void * stackp_t; + +int sysThreadBootstrap(sys_thread_t **, void *); +void sysThreadInitializeSystemThreads(void); + +#ifdef UNIX +int sysThreadCreate(long, uint flags, void *(*)(void *), + sys_thread_t **, void *); +#else +int sysThreadCreate(long, uint_t flags, void *(*)(void *), + sys_thread_t **, void *); +#endif + +void sysThreadExit(void); +sys_thread_t * sysThreadSelf(void); +void sysThreadYield(void); +int sysThreadVMSuspend(sys_thread_t *, sys_thread_t *); +void sysThreadVMSuspendMe(void); +int sysThreadVMUnsuspend(sys_thread_t *); +int sysThreadSuspend(sys_thread_t *); +int sysThreadResume(sys_thread_t *); +int sysThreadSetPriority(sys_thread_t *, int); +int sysThreadGetPriority(sys_thread_t *, int *); +void * sysThreadStackPointer(sys_thread_t *); +stackp_t sysThreadStackBase(sys_thread_t *); +void sysThreadSetStackBase(sys_thread_t *, stackp_t); +int sysThreadSingle(void); +void sysThreadMulti(void); +int sysThreadEnumerateOver(int (*)(sys_thread_t *, void *), void *); +void sysThreadInit(sys_thread_t *, stackp_t); +void * sysThreadGetBackPtr(sys_thread_t *); +int sysThreadCheckStack(void); +int sysInterruptsPending(void); +void sysThreadPostException(sys_thread_t *, void *); +void sysThreadDumpInfo(sys_thread_t *); +void sysThreadInterrupt(sys_thread_t *); +int sysThreadIsInterrupted(sys_thread_t *, long); +int sysThreadAlloc(sys_thread_t **, stackp_t, void *); +int sysThreadFree(sys_thread_t *); + +/* + * System API for monitors + */ +int sysMonitorSizeof(void); +int sysMonitorInit(sys_mon_t *); +int sysMonitorDestroy(sys_mon_t *); +int sysMonitorEnter(sys_mon_t *); +bool_t sysMonitorEntered(sys_mon_t *); +int sysMonitorExit(sys_mon_t *); +int sysMonitorNotify(sys_mon_t *); +int sysMonitorNotifyAll(sys_mon_t *); +int sysMonitorWait(sys_mon_t *, int, bool_t); +void sysMonitorDumpInfo(sys_mon_t *); +bool_t sysMonitorInUse(sys_mon_t *); + +#define SYS_OK 0 +#define SYS_ERR -1 +#define SYS_INTRPT -2 /* Operation was interrupted */ +#define SYS_TIMEOUT -3 /* A timer ran out */ +#define SYS_NOMEM -5 /* Ran out of memory */ +#define SYS_NORESOURCE -6 /* Ran out of some system resource */ + +/* + * Symbolic constant to be used when waiting indefinitely on a condition + * variable + */ +#define SYS_TIMEOUT_INFINITY -1 + +/* + * System API for raw memory allocation + */ +void * sysMapMem(long, long *); +void * sysUnmapMem(void *, long, long *); +void * sysCommitMem(void *, long, long *); +void * sysDecommitMem(void *, long, long *); +void * sysUncommitMem(void *, long, long *); + +/* + * System API for termination + */ +void sysExit(int); +int sysAtexit(void (*func)(void)); +void sysAbort(void); + +/* + * System API for files + */ +extern int sysIsAbsolute(const char* path); +extern int sysAccess(const char* pFile, int perm); + +extern int sysStat(const char *path, struct stat *sbuf); +extern int sysFStat(int fd, struct stat * sbuf); + +extern int sysOpen(const char *name, int openMode, int filePerm); +extern int sysClose(int fd); + +extern long sysSeek(int fd, long offset, int whence); +extern int sysAvailable(int fd, long* bytes); +extern size_t sysRead(int fd, void *buf, unsigned int nBytes); +extern size_t sysWrite(int fd, const void *buf, unsigned int nBytes); + +extern int sysRename(const char* srcName, const char* dstName); +extern int sysUnlink(const char* file); + +extern int sysMkdir(const char* path, int mode); +extern int sysRmdir(const char* path); +extern int sysCanonicalPath(char *path, char *result, int result_len); + +/* + * API support needed for various multiprocessor related synchronization + * primitives. Systems that don't use real threads can just define + * these to be 0 in their sysmacros_md.h. + */ + +int sysIsMP(); +void sysMemoryFlush(); +void sysStoreBarrier(); + +/* + * Include platform specific macros to override these + */ +#include "sysmacros_md.h" + +#endif /* !_SYS_API_H_ */ diff --git a/MPC.3.5.LINUX/preverifier/sys_support.c b/MPC.3.5.LINUX/preverifier/sys_support.c new file mode 100644 index 0000000..f8a3ab7 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/sys_support.c @@ -0,0 +1,475 @@ +/* + * @(#)sys_support.c 1.7 01/01/18 + * + * Copyright 1995-1999 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +/*========================================================================= + * SYSTEM: Verifier + * SUBSYSTEM: System support functions + * FILE: sys_support.c + * OVERVIEW: Routines for system support functions. The routines + * are for retrieving system class path and for certain + * Windows specific file parsing functions. + * + * AUTHOR: Sheng Liang, Sun Microsystems, Inc. + * Modifications for JAR support and comments, + * Tasneem Sayeed, Sun Microsystems, Inc. + *=======================================================================*/ + +/*========================================================================= + * Include files + *=======================================================================*/ + +#include +#include +#include +//#include + +#include "oobj.h" +#include "jar.h" +#include "typedefs.h" +#include "sys_api.h" +#include "path.h" + +/*========================================================================= + * Globals and extern declarations + *=======================================================================*/ + +static cpe_t **saved_classpath; +static cpe_t **saved_classpath_end; + +extern zip_t * getZipEntry(char *zipFile, int len); + +/*========================================================================= + * FUNCTION: sysGetClassPath + * OVERVIEW: Returns the system class path using the getenv() system + * call for retrieving the CLASSPATH environment. + * INTERFACE: + * parameters: none + * + * returns: Pointer to cpe_t struct ptr (see path.h) + *=======================================================================*/ +cpe_t ** +sysGetClassPath(void) +{ + struct stat sbuf; + int length; + zip_t *zipEntry; + bool_t includedDot = FALSE; + + if (saved_classpath == 0) { + char *cps, *s; + int ncpe = 1; + cpe_t **cpp; + if ((cps = getenv("CLASSPATH")) == 0) { + cps = "."; + } + if ((cps = strdup(cps)) == 0) { + return 0; + } + for (s = cps; *s != '\0'; s++) { + if (*s == PATH_SEPARATOR) { + ncpe++; + } + } + /* We add 2 since we automatically append "." to the list, and we + * need a NULL element at the end. + * We add an extra 10 to allow pushing and popping of the classpath. + * Generally, we'll need two, at most, but we can afford to be + * a little extravagant. + */ + cpp = saved_classpath = sysMalloc((ncpe + 2 + 10) * sizeof(cpe_t *)); + if (cpp == 0) { + return 0; + } + while (cps && *cps) { + char *path = cps; + cpe_t *cpe; + if ((cps = strchr(cps, PATH_SEPARATOR)) != 0) { + *cps++ = '\0'; + } + if (*path == '\0') { + path = "."; + } + cpe = sysMalloc(sizeof(cpe_t)); + if (cpe == 0) { + return 0; + } + length = strlen(path); + if (JAR_DEBUG && verbose) { + jio_fprintf(stderr, "SysGetClassPath: Length : %d\n", length); + jio_fprintf(stderr, "SysGetClasspath: Path : %s\n", path); + } + if (stat(path, &sbuf) < 0) { + /* we don't have to do anything */ + } else if (sbuf.st_mode & S_IFDIR) { + /* this is a directory */ + cpe->type = CPE_DIR; + cpe->u.dir = path; + if (strcmp(path, ".") == 0) { + includedDot = TRUE; + } + + /* restore only for a valid directory */ + *cpp++ = cpe; + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, "SysGetClassPath: Found directory [%s]\n", path); + + } else if (isJARfile (path, length)) { + /* this looks like a JAR file */ + /* initialize the zip structure */ + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, "SysGetClassPath: Found .JAR file [%s]\n", path); + + /* Create the zip entry for searching the JAR + * directories. If the zip entry is NULL, it + * would indicate that we ran out of memory + * and would have exited already. + */ + zipEntry = getZipEntry(path, length); + + /* search for the JAR directories */ + if (findJARDirectories(zipEntry, &sbuf)) { + /* this is a JAR file - initialize the cpe */ + + if (JAR_DEBUG && verbose) + jio_fprintf(stderr, "SysGetClassPath: JAR directories OK in [%s]\n", zipEntry->name); + + zipEntry->type = 'j'; + cpe->type = CPE_ZIP; + cpe->u.zip = zipEntry; + /* restore entry only for a valid JAR */ + *cpp++ = cpe; + } + } + } + if (!includedDot) { + cpe_t *cpe = sysMalloc(sizeof(cpe_t)); + cpe->type = CPE_DIR; + cpe->u.dir = "."; + *cpp++ = cpe; + } + *cpp = 0; + saved_classpath_end = cpp; + } + + return saved_classpath; +} + + +/* Puts this directory at the beginning of the class path */ + +void +pushDirectoryOntoClassPath(char* directory) +{ + cpe_t **ptr; + + cpe_t *cpe = sysMalloc(sizeof(cpe_t)); + cpe->type = CPE_DIR; + cpe->u.dir = directory; + + sysGetClassPath(); /* just in case not done yet */ + + /* Note that saved_classpath_end points to the NULL at the end. */ + saved_classpath_end++; + for (ptr = saved_classpath_end; ptr > saved_classpath; ptr--) { + ptr[0] = ptr[-1]; + } + ptr[0] = cpe; +} + + +/* Puts this jar file at the beginning of the class path */ + +void +pushJarFileOntoClassPath(zip_t *zipEntry) +{ + cpe_t **ptr; + + cpe_t *cpe = sysMalloc(sizeof(cpe_t)); + cpe->type = CPE_ZIP; + cpe->u.zip = zipEntry; + + sysGetClassPath(); /* just in case not done yet */ + + /* Note that saved_classpath_end points to the NULL at the end. */ + saved_classpath_end++; + for (ptr = saved_classpath_end; ptr > saved_classpath; ptr--) { + ptr[0] = ptr[-1]; + } + ptr[0] = cpe; +} + + +/* Pop the first element off the class path */ +void +popClassPath() +{ + cpe_t **ptr; + + sysFree(*saved_classpath); + + --saved_classpath_end; + for (ptr = saved_classpath; ptr <= saved_classpath_end; ptr++) { + /* This copies all of the elements, including the NULL at the end */ + ptr[0] = ptr[1]; + } +} + + +/*========================================================================= + * Win32 file parsing functions + *=======================================================================*/ + +#ifdef WIN32 + +#undef DEBUG_PATH /* Define this to debug path code */ + +#define isfilesep(c) ((c) == '/' || (c) == '\\') +#define islb(c) (IsDBCSLeadByte((BYTE)(c))) + + +/*========================================================================= + * FUNCTION: sysNativePath + * OVERVIEW: Converts a path name to native format. On win32, this + * involves forcing all separators to be '\\' rather than '/' + * (both are legal inputs, but Win95 sometimes rejects '/') + * and removing redundant separators. The input path is assumed + * to have been converted into the character encoding used by + * the local system. Because this might be a double-byte + * encoding, care is taken to treat double-byte lead characters + * correctly. + * + * INTERFACE: + * parameters: char *path + * + * returns: char * + *=======================================================================*/ +char * +sysNativePath(char *path) +{ + char *src = path, *dst = path; + char *colon = NULL; /* If a drive specifier is found, this will + point to the colon following the drive + letter */ + + /* Assumption: '/', '\\', ':', and drive letters are never lead bytes */ + sysAssert(!islb('/') && !islb('\\') && !islb(':')); + + /* Check for leading separators */ + while (isfilesep(*src)) src++; + if (!islb(*src) && src[1] == ':') { + /* Remove leading separators if followed by drive specifier. This + hack is necessary to support file URLs containing drive + specifiers (e.g., "file://c:/path"). As a side effect, + "/c:/path" can be used as an alternative to "c:/path". */ + *dst++ = *src++; + colon = dst; + *dst++ = ':'; src++; + } else { + src = path; + if (isfilesep(src[0]) && isfilesep(src[1])) { + /* UNC pathname: Retain first separator; leave src pointed at + second separator so that further separators will be collapsed + into the second separator. The result will be a pathname + beginning with "\\\\" followed (most likely) by a host name. */ + src = dst = path + 1; + path[0] = '\\'; /* Force first separator to '\\' */ + } + } + + /* Remove redundant separators from remainder of path, forcing all + separators to be '\\' rather than '/' */ + while (*src != '\0') { + if (isfilesep(*src)) { + *dst++ = '\\'; src++; + while (isfilesep(*src)) src++; + if (*src == '\0') { /* Check for trailing separator */ + if (colon == dst - 2) break; /* "z:\\" */ + if (dst == path + 1) break; /* "\\" */ + if (dst == path + 2 && isfilesep(path[0])) { + /* "\\\\" is not collapsed to "\\" because "\\\\" marks the + beginning of a UNC pathname. Even though it is not, by + itself, a valid UNC pathname, we leave it as is in order + to be consistent with sysCanonicalPath() (below) as well + as the win32 APIs, which treat this case as an invalid + UNC pathname rather than as an alias for the root + directory of the current drive. */ + break; + } + dst--; /* Path does not denote a root directory, so + remove trailing separator */ + break; + } + } else { + if (islb(*src)) { /* Copy a double-byte character */ + *dst++ = *src++; + if (*src) { + *dst++ = *src++; + } + } else { /* Copy a single-byte character */ + *dst++ = *src++; + } + } + } + + *dst = '\0'; +#ifdef DEBUG_PATH + jio_fprintf(stderr, "sysNativePath: %s\n", path); +#endif /* DEBUG_PATH */ + return path; +} + + +/*========================================================================= + * FUNCTION: opendir + * OVERVIEW: open directory given dir pointer. + * + * INTERFACE: + * parameters: const char *dirarg + * + * returns: Pointer to DIR structure + *=======================================================================*/ +DIR * +opendir(const char *dirarg) +{ + DIR *dirp = (DIR *)sysMalloc(sizeof(DIR)); + unsigned long fattr; + char alt_dirname[4] = { 0, 0, 0, 0 }; + char dirname_buf[1024]; + char *dirname = dirname_buf; + + if (dirp == 0) { +// errno = ENOMEM; + return 0; + } + + strcpy(dirname, dirarg); + sysNativePath(dirname); + + /* + * Win32 accepts "\" in its POSIX stat(), but refuses to treat it + * as a directory in FindFirstFile(). We detect this case here and + * prepend the current drive name. + */ + if (dirname[1] == '\0' && dirname[0] == '\\') { + alt_dirname[0] = _getdrive() + 'A' - 1; + alt_dirname[1] = ':'; + alt_dirname[2] = '\\'; + alt_dirname[3] = '\0'; + dirname = alt_dirname; + } + + dirp->path = (char *)sysMalloc(strlen(dirname) + 5); + if (dirp->path == 0) { + sysFree(dirp); +// errno = ENOMEM; + return 0; + } + strcpy(dirp->path, dirname); + + fattr = GetFileAttributes(dirp->path); + if (fattr == 0xffffffff) { + sysFree(dirp->path); + sysFree(dirp); +// errno = ENOENT; + return 0; + } else if ((fattr & FILE_ATTRIBUTE_DIRECTORY) == 0) { + sysFree(dirp->path); + sysFree(dirp); +// errno = ENOTDIR; + return 0; + } + + /* Append "*.*", or possibly "\\*.*", to path */ + if (dirp->path[1] == ':' + && (dirp->path[2] == '\0' + || (dirp->path[2] == '\\' && dirp->path[3] == '\0'))) { + /* No '\\' needed for cases like "Z:" or "Z:\" */ + strcat(dirp->path, "*.*"); + } else { + strcat(dirp->path, "\\*.*"); + } + + dirp->handle = FindFirstFile(dirp->path, &dirp->find_data); + if (dirp->handle == INVALID_HANDLE_VALUE) { + if (GetLastError() != ERROR_FILE_NOT_FOUND) { + sysFree(dirp->path); + sysFree(dirp); +// errno = EACCES; + return 0; + } + } + return dirp; +} + + +/*========================================================================= + * FUNCTION: readdir + * OVERVIEW: read directory given pointer to DIR structure. + * + * INTERFACE: + * parameters: DIR *dirp + * + * returns: Pointer to dirent structure. + *=======================================================================*/ +struct dirent * +readdir(DIR *dirp) +{ + if (dirp->handle == INVALID_HANDLE_VALUE) { + return 0; + } + + strcpy(dirp->dirent.d_name, dirp->find_data.cFileName); + + if (!FindNextFile(dirp->handle, &dirp->find_data)) { + if (GetLastError() == ERROR_INVALID_HANDLE) { +// errno = EBADF; + return 0; + } + FindClose(dirp->handle); + dirp->handle = INVALID_HANDLE_VALUE; + } + + return &dirp->dirent; +} + + +/*========================================================================= + * FUNCTION: closedir + * OVERVIEW: close directory given pointer to DIR structure. + * Returns non-zero status if the close fails. + * + * INTERFACE: + * parameters: DIR: *dirp + * + * returns: int: status + *=======================================================================*/ +int +closedir(DIR *dirp) +{ + if (dirp->handle != INVALID_HANDLE_VALUE) { + if (!FindClose(dirp->handle)) { +// errno = EBADF; + return -1; + } + dirp->handle = INVALID_HANDLE_VALUE; + } + sysFree(dirp->path); + sysFree(dirp); + return 0; +} + +#endif diff --git a/MPC.3.5.LINUX/preverifier/sysmacros_md.h b/MPC.3.5.LINUX/preverifier/sysmacros_md.h new file mode 100644 index 0000000..0f02961 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/sysmacros_md.h @@ -0,0 +1,74 @@ +/* + * @(#)sysmacros_md.h 1.5 02/09/27 + * + * Copyright 1995-1998 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +#ifndef _SYSMACROS_MD_H_ +#define _SYSMACROS_MD_H_ + +/* + * Because these are used directly as function ptrs, just redefine the name + */ +#define sysMalloc malloc +#define sysFree free +#define sysCalloc calloc +#define sysRealloc realloc + +/* A macro for sneaking into a sys_mon_t to get the owner sys_thread_t */ +#define sysMonitorOwner(mid) ((mid)->monitor_owner) + +#ifdef DEBUG +extern void DumpThreads(void); +void panic (const char *, ...); +#define sysAssert(expression) { \ + if (!(expression)) { \ + DumpThreads(); \ + panic("\"%s\", line %d: assertion failure\n", __FILE__, __LINE__); \ + } \ +} +#else +#define sysAssert(expression) +#endif + +/* + * Case insensitive compare of ASCII strings + */ +#define sysStricmp(a, b) strcasecmp(a, b) + +/* + * File system macros + */ +#ifdef UNIX +#define sysOpen(_path, _oflag, _mode) open(_path, _oflag, _mode) +#define sysNativePath(path) (path) +#endif +#ifdef WIN32 +#include +#define sysOpen(_path, _oflag, _mode) open(_path, _oflag | O_BINARY, _mode) +char *sysNativePath(char *); +#endif +#define sysRead(_fd, _buf, _n) read(_fd, _buf, _n) +#define sysWrite(_fd, _buf, _n) write(_fd, _buf, _n) +#define sysClose(_fd) close(_fd) +#define sysAccess(_path, _mode) access(_path, _mode) +#define sysStat(_path, _buf) stat(_path, _buf) +#define sysMkdir(_path, _mode) mkdir(_path, _mode) +#define sysUnlink(_path) unlink(_path) +#define sysIsAbsolute(_path) (*(_path) == '/') +#define sysCloseDir(_dir) closedir(_dir) +#define sysOpenDir(_path) opendir(_path) +#define sysRmdir(_dir) remove(_dir) +#define sysSeek(fd, offset, whence) lseek(fd, offset, whence) +#define sysRename(s, d) rename(s, d) + +#endif /*_SYSMACROS_MD_H_*/ diff --git a/MPC.3.5.LINUX/preverifier/tree.h b/MPC.3.5.LINUX/preverifier/tree.h new file mode 100644 index 0000000..dca770f --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/tree.h @@ -0,0 +1,69 @@ +/* + * @(#)tree.h 1.3 02/09/27 + * + * Copyright 1995-1998 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +/* + * Definitions having to do with the program tree + */ + +#ifndef _TREE_H_ +#define _TREE_H_ + +#include "oobj.h" /* for the definition of unicode */ +#include "typecodes.h" + +extern int SkipSourceChecks; +extern char *progname; +extern ClassClass **binclasses; +extern long nbinclasses, sizebinclasses; + +/* User specifiable attributes */ +#define ACC_PUBLIC 0x0001 /* visible to everyone */ +#define ACC_PRIVATE 0x0002 /* visible only to the defining class */ +#define ACC_PROTECTED 0x0004 /* visible to subclasses */ +#define ACC_STATIC 0x0008 /* instance variable is static */ +#define ACC_FINAL 0x0010 /* no further subclassing, overriding */ +#define ACC_SYNCHRONIZED 0x0020 /* wrap method call in monitor lock */ +#define ACC_SUPER 0x0020 /* funky handling of invokespecial */ +#define ACC_THREADSAFE 0x0040 /* can cache in registers */ +#define ACC_TRANSIENT 0x0080 /* not persistant */ +#define ACC_NATIVE 0x0100 /* implemented in C */ +#define ACC_INTERFACE 0x0200 /* class is an interface */ +#define ACC_ABSTRACT 0x0400 /* no definition provided */ +#define ACC_XXUNUSED1 0x0800 /* */ + +#define ACC_WRITTEN_FLAGS 0x0FFF /* flags actually put in .class file */ + +/* Other attributes */ +#define ACC_VALKNOWN 0x1000 /* constant with known value */ +#define ACC_DOCED 0x2000 /* documentation generated */ +#define ACC_MACHINE_COMPILED 0x4000 /* compiled to machine code */ +#define ACC_XXUNUSED3 0x8000 /* */ + +#define IsPrivate(access) (((access) & ACC_PRIVATE) != 0) +#define IsPublic(access) (((access) & ACC_PUBLIC) != 0) +#define IsProtected(access) (((access) & ACC_PROTECTED) != 0) + +char *addstr(char *s, char *buf, char *limit, char term); +char *addhex(long n, char *buf, char *limit); +char *adddec(long n, char *buf, char *limit); + +#ifdef TRIMMED +# undef DEBUG +# undef STATS +# define NOLOG +#endif + + +#endif /* !_TREE_H_ */ diff --git a/MPC.3.5.LINUX/preverifier/typecodes.h b/MPC.3.5.LINUX/preverifier/typecodes.h new file mode 100644 index 0000000..8e4b4e3 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/typecodes.h @@ -0,0 +1,145 @@ +/* + * @(#)typecodes.h 1.2 02/09/27 + * + * Copyright 1995-1998 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +/* + * Type codes 6/12/91 + + This typecode system allows us to represent the type + of scalars in a uniform way. For instance, all integer types + have some bits in common, and are distinguished by a built-in + size field. Types without multiple sizes don't have a size field. + + Scalars may only have sizes which are powers of 2. The size + field holds the log-based-2 of the object's size. + + All run-time types can be encoded in 4 bits. There are more + compile- time types. These fit in 5 bits. + Schematically, we have: + +----+----+----+----+----+ + | c | t | s | + +----+----+----+----+----+ + + Encoding is: + c t s type + ------------------------- + 0 00 00 unassigned + 0 00 01 array + 0 00 10 class + 0 00 11 proxy (OBSOLETE) + 0 01 00 boolean (1 byte) + 0 01 01 char (2 bytes) + 0 01 1s float (single=1; double=2) + 0 1u xx integer (byte=0; short=1; int=2; long=3; + u=1 => unsigned) + + For runtime types, the size of an object + is 1<<(t&3) + + 1 00 00 typedef (compiler only) + 1 00 01 void (compiler only) + 1 00 10 func (compiler only) + 1 00 11 unknown (compiler only) + 1 01 00 error (compiler only) + + Char and Boolean are not int's because they need a different signature, + so have to be distinguishable, even at runtime. We allow arrays + of objects, arrays(?), booleans, char, integers, and floats. + Note that the low-order two bits of all these gives the log of + the size, except for arrays, of course. + + I would prefer not to have unsigned int in the language, but + don't want to make that decision at this level. We could come up + with a better encoding of boolean and char if there were no + unsigned. + + The compile-only type values that could be confused with the + integer and float scalar types must not ever be used. Value 0 must + not be assigned a runtime type, as this is used for some sleazy + trickery in punning types and pointer. In fact, we even have a name + for it. +*/ + +/* If you change these typecodes, you'll have to fix the arrayinfo table + in gc.c and the {in,}direct_{load,store}_ops tables in + compiler/tree2code.c */ + +#ifndef _TYPECODES_H_ +#define _TYPECODES_H_ + +#define T_NORMAL_OBJECT 0 +#define T_XXUNUSEDXX1 1 /* Used to be T_ARRAY */ +#define T_CLASS 2 +#define T_BOOLEAN 4 +#define T_CHAR 5 + +#define T_FLOATING 4 /* add log2 size to get correct code: + float has code 6, + double has code 7 */ +#define T_INTEGER 010 +#define T_UINTEGER 014 + +#define T_MAXNUMERIC 020 + +#define T_XXUNUSEDXX2 020 +#define T_VOID 021 +#define T_FUNC 022 +#define T_UNKNOWN 023 +#define T_ERROR 024 + +/* for type construction */ +#define T_TMASK 034 +#define T_LMASK 003 +#define T_LSIZE 2 +#define T_MKTYPE( t, l ) ( ( (t)&T_TMASK ) | ( (l)&T_LMASK) ) + +/* for type deconstruction */ + /* + * Because we promise always to let ints and compile-only types be + * distinguished by the "t" and "s" bits above, we can simplify + * some of our predicates by masking out the "c" bit when testing + * for integers. Thus the T_TS_MASK... + */ +#define T_TS_MASK 034 +#define T_ISINTEGER(t) ( ((t)&030) == T_INTEGER ) +#define T_ISFLOATING(t) ( ((t)&036) == T_FLOAT ) +#define T_ISNUMERIC(t) ( (t) >= T_CHAR && (t) < T_MAXNUMERIC ) +#define T_SIZEFIELD(t) ((t)&T_LMASK) +#define T_ELEMENT_SIZE(t) (1< +#include + +#ifdef SOLARIS2 +/* don't redefine typedef's on Solaris 2.6 or Later */ + +#if !defined(_ILP32) && !defined(_LP64) + +#ifndef _UINT64_T +#define _UINT64_T +typedef unsigned long long uint64_t; +#define _UINT32_T +typedef unsigned long uint32_t; +#endif + +#ifndef _INT64_T +#define _INT64_T +typedef long long int64_t; +#define _INT32_T +typedef long int32_t; +#endif + +#endif /* !defined(_ILP32) && !defined(_LP64) */ +#endif /* SOLARIS2 */ + +#ifdef LINUX +#ifndef _UINT64_T +#define _UINT64_T +typedef unsigned long long uint64_t; +#define _UINT32_T +typedef unsigned long uint32_t; +#endif +#endif /* LINUX */ + +#ifdef WIN32 +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +typedef long int32_t; +typedef unsigned long uint32_t; +typedef unsigned int uint_t; +#endif + +/* use these macros when the compiler supports the long long type */ + +#define ll_high(a) ((long)((a)>>32)) +#define ll_low(a) ((long)(a)) +#define int2ll(a) ((int64_t)(a)) +#define ll2int(a) ((int)(a)) +#define ll_add(a, b) ((a) + (b)) +#define ll_and(a, b) ((a) & (b)) +#define ll_div(a, b) ((a) / (b)) +#define ll_mul(a, b) ((a) * (b)) +#define ll_neg(a) (-(a)) +#define ll_not(a) (~(a)) +#define ll_or(a, b) ((a) | (b)) +#define ll_shl(a, n) ((a) << (n)) +#define ll_shr(a, n) ((a) >> (n)) +#define ll_sub(a, b) ((a) - (b)) +#define ll_ushr(a, n) ((unsigned long long)(a) >> (n)) +#define ll_xor(a, b) ((a) ^ (b)) +#define uint2ll(a) ((uint64_t)(unsigned long)(a)) +#define ll_rem(a,b) ((a) % (b)) + +#define INT_OP(x,op,y) ((x) op (y)) +#define NAN_CHECK(l,r,x) x +#define IS_NAN(x) isnand(x) + + +/* On Intel these conversions have to be method calls and not typecasts. + See the win32 typedefs_md.h file */ +#if defined(i386) || defined (__i386) + +extern int32_t float2l(float f); +extern int32_t double2l(double d); +extern int64_t float2ll(float f); +extern int64_t double2ll(double d); + +#else /* not i386 */ + +#define float2l(f) (f) +#define double2l(f) (f) +#define float2ll(f) ((int64_t) (f)) +#define double2ll(f) ((int64_t) (f)) + +#endif /* i386 */ + + +#define ll2float(a) ((float) (a)) +#define ll2double(a) ((double) (a)) + +/* comparison operators */ +#define ll_ltz(ll) ((ll)<0) +#define ll_gez(ll) ((ll)>=0) +#define ll_eqz(a) ((a) == 0) +#define ll_eq(a, b) ((a) == (b)) +#define ll_ne(a,b) ((a) != (b)) +#define ll_ge(a,b) ((a) >= (b)) +#define ll_le(a,b) ((a) <= (b)) +#define ll_lt(a,b) ((a) < (b)) +#define ll_gt(a,b) ((a) > (b)) + +#define ll_zero_const ((int64_t) 0) +#define ll_one_const ((int64_t) 1) + +extern void ll2str(int64_t a, char *s, char *limit); + +#ifdef ppc +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#endif + +#ifdef SOLARIS2 +#include +#endif + +#ifdef LINUX +#include +#endif + +#ifdef WIN32 +#include +#endif + +#endif /* !_TYPES_MD_H_ */ diff --git a/MPC.3.5.LINUX/preverifier/utf.c b/MPC.3.5.LINUX/preverifier/utf.c new file mode 100644 index 0000000..3f1eb20 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/utf.c @@ -0,0 +1,216 @@ +/* + * @(#)utf.c 1.5 02/09/27 + * + * Copyright 1995-1998 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +/*========================================================================= + * SYSTEM: Verifier + * SUBSYSTEM: Unicode translators. + * FILE: utf.c + * OVERVIEW: Routines for Unicode -> UTF and UTF -> unicode translators. + * + * This file implements the unicode -> UTF and UTF -> unicode translators + * needed by the various parts of the compiler and interpreter. + * + * UTF strings are streams of bytes, in which unicode characters are encoded + * as follows: + * Unicode UTF + * 00000000 0jklmnop 0jklmnop + * 00000fgh ijklmnop 110fghij 10klmnop + * abcdefgh ijklmnop 1110abcd 10efghij 10klmnop + * + * unicode bytes with 7 or fewer significant bits MUST be converted using the + * first format. bytes with 11 or fewer bits MUST be converted using the + * second format. + * + * In JAVA/JAVAC, we deviate slightly from the above. + * 1) The null unicode character is represented using the 2-byte format + * 2) All UTF strings are null-terminated. + * In this way, we do not need to separately maintain a length field for the + * UTF string. + * + * Given a unicode string and its length, convert it to a utf string. But + * the result into the given buffer, whose length is buflength. The utf + * string should include a null terminator. + * + * If both buffer and buflength are 0, then malloc an appropriately sized + * buffer for the result. + * + * AUTHOR: Sheng Liang, Sun Microsystems, Inc. + * Edited by Tasneem Sayeed, Sun Microsystems + *=======================================================================*/ + +/*========================================================================= + * Include files + *=======================================================================*/ + +#include +#include +#include + +#include "oobj.h" +#include "utf.h" +#include "sys_api.h" + +char *unicode2utf(unicode *unistring, int length, char *buffer, int buflength) +{ + int i; + unicode *uniptr; + char *bufptr; + unsigned bufleft; + + if ((buffer == 0) && (buflength == 0)) { + buflength = unicode2utfstrlen(unistring, length); + if ((buffer = (char *) sysMalloc(buflength)) == 0) + return 0; + } + + bufleft = buflength - 1; /* take note of null now! */ + + for(i = length, uniptr = unistring, bufptr = buffer; --i >= 0; uniptr++) { + unicode ch = *uniptr; + if ((ch != 0) && (ch <=0x7f)) { + if ((int)(--bufleft) < 0) /* no space for character */ + break; + *bufptr++ = (char)ch; + } else if (ch <= 0x7FF) { + /* 11 bits or less. */ + unsigned char high_five = ch >> 6; + unsigned char low_six = ch & 0x3F; + if ((int)(bufleft -= 2) < 0) /* no space for character */ + break; + *bufptr++ = high_five | 0xC0; /* 110xxxxx */ + *bufptr++ = low_six | 0x80; /* 10xxxxxx */ + } else { + /* possibly full 16 bits. */ + char high_four = ch >> 12; + char mid_six = (ch >> 6) & 0x3F; + char low_six = ch & 0x3f; + if ((int)(bufleft -= 3) < 0) /* no space for character */ + break; + *bufptr++ = high_four | 0xE0; /* 1110xxxx */ + *bufptr++ = mid_six | 0x80; /* 10xxxxxx */ + *bufptr++ = low_six | 0x80; /* 10xxxxxx*/ + } + } + *bufptr = 0; + return buffer; +} + +/* Return the number of characters that would be needed to hold the unicode + * string in utf. This INCLUDES the NULL! + */ +int unicode2utfstrlen(unicode *unistring, int unilength) +{ + int result_length = 1; + + for (; unilength > 0; unistring++, unilength--) { + unicode ch = *unistring; + if ((ch != 0) && (ch <= 0x7f)) /* 1 byte */ + result_length++; + else if (ch <= 0x7FF) + result_length += 2; /* 2 byte character */ + else + result_length += 3; /* 3 byte character */ + } + return result_length; +} + +/* Give the number of unicode characters in a utf string */ +int utfstrlen(char *utfstring) +{ + int length; + for (length = 0; *utfstring != 0; length++) + next_utf2unicode(&utfstring); + return length; +} + +/* Convert a utfstring to unicode in the buffer provided. Put at most + * max_length characters into the buffer. Whether or not we actually overflow + * the space, indicate the actual unicode length. + * + * Whether or not we overflow the space, return the actual number of + * characters that we used. + */ + +void +utf2unicode(char *utfstring, unicode *unistring, + int max_length, int *lengthp) +{ + int length_remaining = max_length; + + while (length_remaining > 0 && *utfstring != 0) { + *unistring++ = next_utf2unicode(&utfstring); + length_remaining--; + } + + if (length_remaining == 0) { + *lengthp = max_length + utfstrlen(utfstring); + } else { + *lengthp = max_length - length_remaining; + } +} + +bool_t is_simple_utf(char *utfstring) +{ + unsigned char *ptr; + for (ptr = (unsigned char *)utfstring; *ptr != 0; ptr++) { + if (*ptr > 0x80) return FALSE; + } + return TRUE; +} + + +unicode next_utf2unicode(char **utfstring_ptr) { + unsigned char *ptr = (unsigned char *)(*utfstring_ptr); + unsigned char ch, ch2, ch3; + int length = 1; /* default length */ + unicode result = 0x80; /* default bad result; */ + switch ((ch = ptr[0]) >> 4) { + default: + result = ch; + break; + + case 0x8: case 0x9: case 0xA: case 0xB: case 0xF: + /* Shouldn't happen. */ + break; + + case 0xC: case 0xD: + /* 110xxxxx 10xxxxxx */ + if (((ch2 = ptr[1]) & 0xC0) == 0x80) { + unsigned char high_five = ch & 0x1F; + unsigned char low_six = ch2 & 0x3F; + result = (high_five << 6) + low_six; + length = 2; + } + break; + + case 0xE: + /* 1110xxxx 10xxxxxx 10xxxxxx */ + if (((ch2 = ptr[1]) & 0xC0) == 0x80) { + if (((ch3 = ptr[2]) & 0xC0) == 0x80) { + unsigned char high_four = ch & 0x0f; + unsigned char mid_six = ch2 & 0x3f; + unsigned char low_six = ch3 & 0x3f; + result = (((high_four << 6) + mid_six) << 6) + low_six; + length = 3; + } else { + length = 2; + } + } + break; + } /* end of switch */ + + *utfstring_ptr = (char *)(ptr + length); + return result; +} diff --git a/MPC.3.5.LINUX/preverifier/utf.h b/MPC.3.5.LINUX/preverifier/utf.h new file mode 100644 index 0000000..b5a3cd2 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/utf.h @@ -0,0 +1,32 @@ +/* + * @(#)utf.h 1.2 02/09/27 + * + * Copyright 1995-1998 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +/* + * Prototypes for the various UTF support functions. + */ + +#ifndef _UTF_H_ +#define _UTF_H_ + +char *unicode2utf(unicode *unistring, int length, char *buffer, int buflength); +int unicode2utfstrlen(unicode *unistring, int unilength); +int utfstrlen(char *utfstring); +void utf2unicode(char *utfstring, unicode *unistring, + int max_length, int *lengthp); +bool_t is_simple_utf(char *utfstring); + +unicode next_utf2unicode(char **utfstring); + +#endif /* !_UTF_H_ */ diff --git a/MPC.3.5.LINUX/preverifier/util.c b/MPC.3.5.LINUX/preverifier/util.c new file mode 100644 index 0000000..07b1db0 --- /dev/null +++ b/MPC.3.5.LINUX/preverifier/util.c @@ -0,0 +1,745 @@ +/* + * @(#)util.c 1.7 02/09/27 + * + * Copyright 1995-1999 by Sun Microsystems, Inc., + * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. + * All rights reserved. + * + * This software is the confidential and proprietary information + * of Sun Microsystems, Inc. ("Confidential Information"). You + * shall not disclose such Confidential Information and shall use + * it only in accordance with the terms of the license agreement + * you entered into with Sun. + * Use is subject to license terms. + */ + +/*========================================================================= + * SYSTEM: Verifier + * SUBSYSTEM: Utility functions. + * FILE: util.c + * OVERVIEW: Utility routines needed by both the compiler and the interpreter. + * + * AUTHOR: Sheng Liang, Sun Microsystems, Inc. + * Edited by Tasneem Sayeed, Sun Microsystems + *=======================================================================*/ + +/*========================================================================= + * Include files + *=======================================================================*/ + +#include +#include +#include +#include + +#include "oobj.h" +#include "utf.h" +#include "sys_api.h" +#include "path.h" /* DIR_SEPARATOR */ + +/*========================================================================= + * Globals and extern declarations + *=======================================================================*/ + +extern struct StrIDhash *nameTypeHash; +extern struct StrIDhash *stringHash; + +unicode * +str2unicode(char *str, unicode *ustr, long len) +{ + unicode *dst = ustr; + + memset((char *) dst, 0, len * sizeof(*dst)); + while (*str && --len >= 0) + *ustr++ = 0xff & *str++; + return dst; +} + +void +unicode2str(unicode *src, char *dst, long len) +{ + while (--len >= 0) + *dst++ = (char)(*src++); + *dst = '\0'; +} + + +int +jio_printf (const char *format, ...) +{ + int len; + + va_list args; + va_start(args, format); + len = jio_vfprintf(stdout, format, args); + va_end(args); + + return len; +} + +int +jio_fprintf (FILE *handle, const char *format, ...) +{ + int len; + + va_list args; + va_start(args, format); + len = jio_vfprintf(handle, format, args); + va_end(args); + + return len; +} + +int +jio_vfprintf (FILE *handle, const char *format, va_list args) +{ + return vfprintf(handle, format, args); +} + + +/* + * Print s null terminated C-style character string. + */ +void +prints(char *s) +{ + jio_fprintf(stdout, "%s", s); +} + +#undef HTSIZE /* Avoid conflict on PC */ +#define HTSIZE 2003 /* Default size -- must be prime */ +#define HTOVERFLOWPOINT(h) (h->size * 4 / 5) + +/* + * We store most of the result of the hash in hash_bits to quickly + * reject impossible matches because strcmp() is fairly expensive, + * especially when many strings will have common prefixes. + */ +typedef struct { + char *hash; /* the string for this entry */ + unsigned is_malloced : 1; /* 1 if hash was malloced */ + unsigned hash_bits : 31; /* low 31 bits of the hash */ +} StrIDhashSlot; + +typedef void (*hash_fn)(const char *s, unsigned *h1, unsigned *h2); + +typedef struct StrIDhash { + int size; /* number of entries */ + hash_fn hash; /* hash function for this table */ + struct StrIDhash *next; /* next bucket */ + short used; /* number of full entries */ + short baseid; /* ID for item in slot[0] */ + void **params; /* param table, if needed */ + StrIDhashSlot slot[1]; /* expanded to be number of slots */ +} StrIDhash; + +/* Hash a string into a primary and secondary hash value */ +static void +default_hash(const char *s, unsigned *h1, unsigned *h2) +{ + int i; + unsigned raw_hash; + for (raw_hash = 0; (i = *s) != '\0'; ++s) + + raw_hash = raw_hash * 37 + i; + *h1 = raw_hash; + *h2 = (raw_hash & 7) + 1; /* between 1 and 8 */ +} + +/* Create a hash table of the specified size */ +static StrIDhash * +createHash(int entries) +{ + StrIDhash *h; + int size = offsetof(struct StrIDhash, slot) + (entries * sizeof(h->slot)); + h = (StrIDhash *)sysCalloc(1, size); + if (h != NULL) { + h->size = entries; + h->hash = default_hash; /* only custom tables get something else */ + h->next = NULL; + } + return h; +} + +/* + * Given a string, return a unique 16 bit id number. + * If param isn't null, we also set up an array of void * for holding info + * about each object. The address of this void * is stored into param + * If CopyNeeded is true, then the name argument "s" must be dup'ed, since + * the current item is allocated on the stack. + * + * Note about returning 0 in the case of out of memory errors: 0 is *not* + * a valid ID! The out of memory error should be thrown by the calling code. + */ +unsigned short +Str2ID(StrIDhash **hash_ptr, register char *s, void ***param, + int CopyNeeded) +{ + /* + * The database is a hash table. When the hash table overflows, a new + * hashtable is created chained onto the previous one. This is done so + * that we can use the hashtable slot index as the ID, without worrying + * about having the IDs change when the hashtable grows. + */ + StrIDhash *h = *hash_ptr; + long i; + unsigned primary_hash; + unsigned secondary_hash; + unsigned hash_bits; + hash_fn current_hash_func = NULL; + + if (h == NULL) + goto not_found; + + /* Create the hash values */ + current_hash_func = h->hash; + current_hash_func(s, &primary_hash, &secondary_hash); + hash_bits = primary_hash & ((1u << 31) - 1); + + for (;;) { + char *s2; + int bucketSize = h->size; + + /* See if the new hash table has a different hash function */ + if (h->hash != current_hash_func) { + current_hash_func = h->hash; + current_hash_func(s, &primary_hash, &secondary_hash); + hash_bits = primary_hash & ((1u << 31) - 1); + } + i = primary_hash % bucketSize; + + while ((s2 = h->slot[i].hash) != NULL) { + if (h->slot[i].hash_bits == hash_bits && strcmp(s2, s) == 0) + goto found_it; + if ((i -= secondary_hash) < 0) + i += bucketSize; + } + /* Not found in this table. Try the next table. */ + if (h->next == NULL) + break; + h = h->next; + } + +not_found: + /* Either the hash table is empty, or the item isn't yet found. */ + if (h == NULL || (h->used >= HTOVERFLOWPOINT(h))) { + /* Need to create a new bucket */ + StrIDhash *next; + if (h && h->baseid > 30000 && *hash_ptr != stringHash) { + panic("16-bit string hash table overflow"); + } + next = createHash(HTSIZE); + if (next == NULL) { + /* Calling code should signal OutOfMemoryError */ + return 0; + } + if (h == NULL) { + /* Create a new table */ + *hash_ptr = h = next; + h->baseid = 1; /* guarantee that no ID is 0 */ + } else { + next->baseid = h->baseid + h->size; + h->next = next; + h = next; + } + if (h->hash != current_hash_func) { + current_hash_func = h->hash; + current_hash_func(s, &primary_hash, &secondary_hash); + hash_bits = primary_hash & ((1u << 31) - 1); + } + i = primary_hash % h->size; + } + if (CopyNeeded) { + char *d = strdup(s); + if (d == NULL) { + /* Calling code should signal OutOfMemoryError */ + return 0; + } + s = d; + h->slot[i].is_malloced = 1; + } + h->slot[i].hash = s; + h->slot[i].hash_bits = hash_bits; + h->used++; + +found_it: + /* We have found or created slot "i" in hash bucket "h" */ + if (param != NULL) { + if (h->params == NULL) { + h->params = sysCalloc(h->size, sizeof(void *)); + if (h->params == NULL) { + /* Calling code should signal OutOfMemoryError */ + return 0; + } + } + *param = &(h->params[i]); + } + return (unsigned short)(h->baseid + i); +} + +/* Free an StrIDhash table and all the entries in it */ +void Str2IDFree(StrIDhash **hash_ptr) +{ + StrIDhash *hash = *hash_ptr; + + while (hash != NULL) { + StrIDhash *next = hash->next; + StrIDhashSlot *ptr, *endPtr; + for (ptr = &hash->slot[0], endPtr = ptr + hash->size; + ptr < endPtr; ptr++) { + if (ptr->is_malloced) + sysFree(ptr->hash); + } + if (hash->params != NULL) + sysFree(hash->params); + sysFree(hash); + hash = next; + } + *hash_ptr = 0; +} + +/* + * Call the callback function on every entry in the table. This + * should only be invoked holding the string hash table lock. + */ +void Str2IDCallback(StrIDhash **hash_ptr, void (*callback)(char *, void *)) +{ + StrIDhash *hash, *next; + int i; + + hash = *hash_ptr; + while (hash) { + void **params = hash->params; + next = hash->next; + for (i = 0; i < hash->size; i++) { + if (hash->slot[i].hash != 0) { + callback(hash->slot[i].hash, params ? params[i] : NULL); + } + } + hash = next; + } +} + +/* + * Returns NULL in the case of an error. + */ +char * +ID2Str(StrIDhash *h, unsigned short ID, void ***param) +{ + int entry; + + while ((long)(ID - h->baseid) >= h->size) { + h = h->next; + } + entry = ID - h->baseid; + if (param != NULL) { + if (h->params == NULL) { + h->params = (void **)sysCalloc(h->size, sizeof(*param)); + if (h->params == NULL) { + /* Calling code should signal OutOfMemoryError */ + return NULL; + } + } + *param = &h->params[entry]; + } + return h->slot[entry].hash; +} + +char * +addstr(char *s, char *buf, char *limit, char term) +{ + char c; + while ((c = *s) && c != term && buf < limit) { + *buf++ = c; + s++; + } + return buf; +} + +char * +unicode2rd(unicode *s, long len) +{ /* unicode string to readable C string */ +#define CSTRLEN 40 + static char buf[CSTRLEN+1]; + char *dp = buf; + int c; + if (s == 0) + return "NULL"; + *dp++ = '"'; + while (--len>=0 && (c = *s++) != 0 && dp < buf + sizeof buf - 10) + if (040 <= c && c < 0177) + *dp++ = c; + else + switch (c) { + case '\n': + *dp++ = '\\'; + *dp++ = 'n'; + break; + case '\t': + *dp++ = '\\'; + *dp++ = 't'; + break; + case '\r': + *dp++ = '\\'; + *dp++ = 'r'; + break; + case '\b': + *dp++ = '\\'; + *dp++ = 'b'; + break; + case '\f': + *dp++ = '\\'; + *dp++ = 'f'; + break; + default: + /* Should not be possible to overflow, truncate if so */ + (void) jio_snprintf(dp, CSTRLEN+1 - (dp - buf), "\\%X", c); + dp += strlen(dp); + break; + } + *dp++ = '"'; + if (len >= 0 && c != 0) + *dp++ = '.', *dp++ = '.', *dp++ = '.'; + *dp++ = 0; + return buf; +} + +/* + * WARNING: out_of_memory() aborts the runtime! It should not be used + * except in the case of out of memory situations that are clearly not + * survivable, like running out of memory before the runtime is initialized. + * If the runtime has finished initializing and you run out of memory, you + * should throw an OutOfMemoryError instead. + */ +void +out_of_memory() +{ + jio_fprintf(stderr, "**Out of memory, exiting**\n"); + exit(1); +} + +void +panic(const char *format, ...) +{ + va_list ap; + char buf[256]; + + printCurrentClassName(); + va_start(ap, format); + + /* If buffer overflow, quietly truncate */ + (void) jio_vsnprintf(buf, sizeof(buf), format, ap); + + jio_fprintf(stdout, "\nERROR: %s\n", buf); + + exit(1); +} + +char * +classname2string(char *src, char *dst, int size) { + char *buf = dst; + for (; (--size > 0) && (*src != '\0') ; src++, dst++) { + if (*src == '/') { + *dst = '.'; + } else { + *dst = *src; + } + } + *dst = '\0'; + return buf; +} + +typedef struct InstanceData { + char *buffer; + char *end; +} InstanceData; + +#define ERROR_RETVAL -1 +#undef SUCCESS +#define SUCCESS 0 +#undef CheckRet +#define CheckRet(x) { if ((x) == ERROR_RETVAL) return ERROR_RETVAL; } + +static int +put_char(InstanceData *this, int c) +{ + if (iscntrl(0xff & c) && c != '\n' && c != '\t') { + c = '@' + (c & 0x1F); + if (this->buffer >= this->end) { + return ERROR_RETVAL; + } + *this->buffer++ = '^'; + } + if (this->buffer >= this->end) { + return ERROR_RETVAL; + } + *this->buffer++ = c; + return SUCCESS; +} + +static int +format_string(InstanceData *this, char *str, int left_justify, int min_width, + int precision) +{ + int pad_length; + char *p; + + if (str == 0) { + return ERROR_RETVAL; + } + + if ((int)strlen(str) < precision) { + pad_length = min_width - strlen(str); + } else { + pad_length = min_width - precision; + } + if (pad_length < 0) + pad_length = 0; + if (left_justify) { + while (pad_length > 0) { + CheckRet(put_char(this, ' ')); + --pad_length; + } + } + + for (p = str; *p != '\0' && --precision >= 0; p++) { + CheckRet(put_char(this, *p)); + } + + if (!left_justify) { + while (pad_length > 0) { + CheckRet(put_char(this, ' ')); + --pad_length; + } + } + return SUCCESS; +} + +#define MAX_DIGITS 32 + +static int +format_number(InstanceData *this, long value, int format_type, int left_justify, + int min_width, int precision, bool_t zero_pad) +{ + int sign_value = 0; + unsigned long uvalue; + char convert[MAX_DIGITS+1]; + int place = 0; + int pad_length = 0; + static char digits[] = "0123456789abcdef"; + int base = 0; + bool_t caps = FALSE; + bool_t add_sign = FALSE; + + switch (format_type) { + case 'o': case 'O': + base = 8; + break; + case 'd': case 'D': + add_sign = TRUE; /* fall through */ + case 'u': case 'U': + base = 10; + break; + case 'X': + caps = TRUE; /* fall through */ + case 'x': + base = 16; + break; + } + sysAssert(base > 0 && base <= 16); + + uvalue = value; + if (add_sign) { + if (value < 0) { + sign_value = '-'; + uvalue = -value; + } + } + + do { + convert[place] = digits[uvalue % (unsigned)base]; + if (caps) { + convert[place] = toupper(convert[place]); + } + place++; + uvalue = (uvalue / (unsigned)base); + if (place > MAX_DIGITS) { + return ERROR_RETVAL; + } + } while(uvalue); + convert[place] = 0; + + pad_length = min_width - place; + if (pad_length < 0) { + pad_length = 0; + } + if (left_justify) { + if (zero_pad && pad_length > 0) { + if (sign_value) { + CheckRet(put_char(this, sign_value)); + --pad_length; + sign_value = 0; + } + while (pad_length > 0) { + CheckRet(put_char(this, '0')); + --pad_length; + } + } else { + while (pad_length > 0) { + CheckRet(put_char(this, ' ')); + --pad_length; + } + } + } + if (sign_value) { + CheckRet(put_char(this, sign_value)); + } + + while (place > 0 && --precision >= 0) { + CheckRet(put_char(this, convert[--place])); + } + + if (!left_justify) { + while (pad_length > 0) { + CheckRet(put_char(this, ' ')); + --pad_length; + } + } + return SUCCESS; +} + +int +jio_vsnprintf(char *str, size_t count, const char *fmt, va_list args) +{ + char *strvalue; + long value; + InstanceData this; + bool_t left_justify, zero_pad, long_flag, add_sign, fPrecision; + int min_width, precision, ch; + + if (str == NULL) { + return ERROR_RETVAL; + } + str[0] = '\0'; + + this.buffer = str; + this.end = str + count - 1; + *this.end = '\0'; /* ensure null-termination in case of failure */ + + while ((ch = *fmt++) != 0) { + if (ch == '%') { + zero_pad = long_flag = add_sign = fPrecision = FALSE; + left_justify = TRUE; + min_width = 0; + precision = this.end - this.buffer; + next_char: + ch = *fmt++; + switch (ch) { + case 0: + return ERROR_RETVAL; + case '-': + left_justify = FALSE; + goto next_char; + case '0': /* set zero padding if min_width not set */ + if (min_width == 0) + zero_pad = TRUE; + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + if (fPrecision == TRUE) { + precision = precision * 10 + (ch - '0'); + } else { + min_width = min_width * 10 + (ch - '0'); + } + goto next_char; + case '.': + fPrecision = TRUE; + precision = 0; + goto next_char; + case 'l': + long_flag = TRUE; + goto next_char; + case 's': + strvalue = va_arg(args, char *); + CheckRet(format_string(&this, strvalue, left_justify, + min_width, precision)); + break; + case 'c': + ch = va_arg(args, int); + CheckRet(put_char(&this, ch)); + break; + case '%': + CheckRet(put_char(&this, '%')); + break; + case 'd': case 'D': + case 'u': case 'U': + case 'o': case 'O': + case 'x': case 'X': + value = long_flag ? va_arg(args, long) : va_arg(args, int); + CheckRet(format_number(&this, value, ch, left_justify, + min_width, precision, zero_pad)); + break; + default: + return ERROR_RETVAL; + } + } else { + CheckRet(put_char(&this, ch)); + } + } + *this.buffer = '\0'; + return strlen(str); +} + +int +jio_snprintf(char *str, size_t count, const char *fmt, ...) +{ + va_list args; + int len; + + va_start(args, fmt); + len = jio_vsnprintf(str, count, fmt, args); + va_end(args); + return len; +} + +/* Return true if the two classes are in the same class package */ + +bool_t +IsSameClassPackage(ClassClass *class1, ClassClass *class2) +{ + if (cbLoader(class1) != cbLoader(class2)) + return FALSE; + else { + char *name1 = cbName(class1); + char *name2 = cbName(class2); + char *last_slash1 = strrchr(name1, DIR_SEPARATOR); + char *last_slash2 = strrchr(name2, DIR_SEPARATOR); + if ((last_slash1 == NULL) || (last_slash2 == NULL)) { + /* One of the two doesn't have a package. Only return true + * if the other one also doesn't have a package. */ + return (last_slash1 == last_slash2); + } else { + int length1, length2; + if (*name1 == SIGNATURE_ARRAY) { + do name1++; while (*name1 == SIGNATURE_ARRAY); + if (*name1 != SIGNATURE_CLASS) { + /* Something is terribly wrong. Shouldn't be here */ + return FALSE; + } + name1++; + } + if (*name2 == SIGNATURE_ARRAY) { + do name2++; while (*name2 == SIGNATURE_ARRAY); + if (*name2 != SIGNATURE_CLASS) { + /* Something is terribly wrong. Shouldn't be here */ + return FALSE; + } + name2++; + } + length1 = last_slash1 - name1; + length2 = last_slash2 - name2; + return ((length1 == length2) + && (strncmp(name1, name2, length1) == 0)); + } + } +} diff --git a/MPC.3.5.LINUX/readme.txt b/MPC.3.5.LINUX/readme.txt new file mode 100644 index 0000000..7d88d1a --- /dev/null +++ b/MPC.3.5.LINUX/readme.txt @@ -0,0 +1,10 @@ +This is the official MIDletPascal 3.5 compiler source code. + +To read the enhancements, adjustments, modifications and bugfixes that I made check the header comments of the main/main.c file. + +To get it working use Code::Blocks 8.02 (http://www.codeblocks.org/) and GCC. + +Enjoy, + +Javier Santo Domingo +02.february.2013 diff --git a/MPC.3.5.LINUX/structures/block.c b/MPC.3.5.LINUX/structures/block.c new file mode 100644 index 0000000..cb7b9d4 --- /dev/null +++ b/MPC.3.5.LINUX/structures/block.c @@ -0,0 +1,3040 @@ +/******************************************************************** + + block.h - structures and functions used to hold program + block descriptions + + Niksa Orlic, 2004-04-29 + +********************************************************************/ + + +#include "../util/strings.h" +#include "../util/error.h" +//#include "../util/message.h" +#include "../classgen/bytecode.h" +#include "type_list.h" +#include "string_list.h" +#include "type.h" +#include "identifier.h" +#include "name_table.h" +#include "unit.h" +#include "block.h" +#include "../classgen/preverify.h" + +#include "../util/memory.h" + +#include +#include +#include + +#include "../classgen/constant_pool.h" +#include "../classgen/classgen.h" + +extern int linenum; +extern int new_linenum; +extern block* root_block; +extern char *global_library_directory; +extern char *project_library_directory; + +extern char *user_libraries; +extern char **units; + +extern int detect_units_only; + +extern constant_pool *constants; +extern int constant_pool_size; + +extern int usesFloat; +extern int usesRecordStore; +extern int usesHttp; + +extern int canvasType; + +extern int mathType; + +extern int compiling_unit; +extern string* str_program_name; + +extern char* output_path; + +#pragma warning (disable:4305) +#pragma warning (disable:4761) + +/* + Create an empty block +*/ +block* block_create(block *parent_block, string *block_name) +{ + block *new_block; + new_block = (block*) mem_alloc(sizeof(block)); + + new_block->names = name_table_create(); + new_block->parent_block = parent_block; + new_block->block_name = block_name; /* do not copy the name, just point to it */ + + new_block->next_variable_index = 0; + new_block->next_parameter_index = 0; + + new_block->code = bytecode_create(); + + new_block->children_count = 0; + + return new_block; +} + + +/* + Delete a block +*/ +void block_destroy(block *item) +{ + int i; + name_table_destroy(item->names); + bytecode_destroy(item->code); + + /* delete all of its children */ + for(i=0; ichildren_count; i++) + { + block_destroy(item->children[i]); + } + + if (item->children_count > 0) + { + mem_free(item->children); + } + + /* do not delete the item->block_name */ + mem_free(item); +} + + +/* + Check if a given name is legal name for a + new identifier in a block. +*/ +int block_check_name(block *item, char *cstr) +{ + int return_value = 1; + + string *name; + identifier *descriptor; + name = string_from_cstr(cstr); + + descriptor = name_table_find(item->names, name); + + if (descriptor != NULL) + { + if (((descriptor->identifier_class == procedure_name) + || (descriptor->identifier_class == function_name)) + && (descriptor->forward_declaration == 1)) + return_value = 1; + else + return_value = 0; + } + + /* check the root block's types - those types are protected */ + if (return_value == 1) + { + while (item->parent_block != NULL) + item = item->parent_block; + + descriptor = name_table_find(item->names, name); + + if ((descriptor != NULL) && (descriptor->identifier_class == type_name)) + return_value = 0; + } + + string_destroy(name); + + return return_value; +} + +/* + Adds a single real constant into the block +*/ +void add_real_constant(block *item, float value, char *cstr_name) +{ + string *name; + identifier *descriptor; + + name = string_from_cstr(cstr_name); + descriptor = identifier_create(); + descriptor->identifier_class = constant_name; + descriptor->constant_type = type_create(); + descriptor->constant_type->type_class = real_type; + descriptor->constant_real_value = value; + name_table_insert(item->names, name, descriptor); +} + + +/* + Adds a single integer constant into the block +*/ +void add_integer_constant(block *item, long int value, char *cstr_name) +{ + string *name; + identifier *descriptor; + + name = string_from_cstr(cstr_name); + descriptor = identifier_create(); + descriptor->identifier_class = constant_name; + descriptor->constant_type = type_create(); + descriptor->constant_type->type_class = integer_type; + descriptor->constant_int_value = value; + name_table_insert(item->names, name, descriptor); +} + + +/* + Adds a single character constant into the block +*/ +void add_char_constant(block *item, char value, char *cstr_name) +{ + string *name; + identifier *descriptor; + + name = string_from_cstr(cstr_name); + descriptor = identifier_create(); + descriptor->identifier_class = constant_name; + descriptor->constant_type = type_create(); + descriptor->constant_type->type_class = char_type; + descriptor->constant_int_value = value; + name_table_insert(item->names, name, descriptor); +} + + +/* + Adds a single boolean constant into the block +*/ +void add_boolean_constant(block *item, char value, char *cstr_name) +{ + string *name; + identifier *descriptor; + + name = string_from_cstr(cstr_name); + descriptor = identifier_create(); + descriptor->identifier_class = constant_name; + descriptor->constant_type = type_create(); + descriptor->constant_type->type_class = boolean_type; + descriptor->constant_int_value = value; + name_table_insert(item->names, name, descriptor); +} + + +/* + Adds a single string constant into the block +*/ +void add_string_constant(block *item, string *value, char *cstr_name) +{ + string *name; + identifier *descriptor; + + name = string_from_cstr(cstr_name); + descriptor = identifier_create(); + descriptor->identifier_class = constant_name; + descriptor->constant_type = type_create(); + descriptor->constant_type->type_class = string_type; + descriptor->constant_string_value = string_duplicate(value); + name_table_insert(item->names, name, descriptor); +} + + +/* + Adds variables into a block. The variable names are + located inside a string list, and a type for all + the variables is described in var_type parameter. +*/ +void add_variables(block *item, string_list *identifier_list, type *var_type) +{ + string_list *it; + identifier *descriptor; + identifier *block_identifier; + + it = identifier_list; + + if (it->data == NULL) + { + type_destroy(var_type); + return; + } + + if(item->parent_block != root_block) + { + block_identifier = name_table_find(item->parent_block->names, item->block_name); + if (block_identifier->variables == NULL) + block_identifier->variables = type_list_create(); + } + else + block_identifier = NULL; + + while (it != NULL) + { + // j-a-s-d: consecutive variable name collision fix + if (!block_check_name(item, it->data->cstr)) + { + add_error_message(400, it->data->cstr, ""); + } + descriptor = identifier_create(); + descriptor->identifier_class = variable_name; + descriptor->variable_type = type_duplicate(var_type); + descriptor->variable_index = item->next_variable_index; + descriptor->belongs_to_program_block = (item->parent_block == root_block); + name_table_insert(item->names, string_duplicate(it->data), descriptor); + + if (compiling_unit == 0) + initialize_variable(item, descriptor, it->data->cstr, 1, "M"); + else + initialize_variable(item, descriptor, it->data->cstr, 1, string_get_cstr(str_program_name)); + + if (block_identifier != NULL) + type_list_append(block_identifier->variables, descriptor->variable_type); + + item->next_variable_index ++; + + it = it->next; + } + +} + +/* + Add a type into block. The name and type_type + are NOT copied. +*/ +void add_type(block *item, string *name, type *type_type) +{ + identifier *descriptor; + + descriptor = identifier_create(); + descriptor->identifier_class = type_name; + descriptor->defined_type = type_type; + name_table_insert(item->names, name, descriptor); +} + + +/* + Adds a procedure declaration into the block +*/ +void add_procedure(block *item, string *name, type_list *parameters, + int forward_declaration, int linenum) +{ + identifier *descriptor; + + descriptor = name_table_find(item->names, name); + + if (descriptor != NULL) + { + if ((forward_declaration != -1) + && (descriptor->forward_declaration != -1)) + check_forward_declaration(descriptor, parameters, + forward_declaration, NULL); + + if ((descriptor->forward_declaration == -1) + || (forward_declaration != -1)) + descriptor->forward_declaration = forward_declaration; + } + else + { + descriptor = identifier_create(); + descriptor->identifier_class = procedure_name; + descriptor->parameters = parameters; + descriptor->forward_declaration = forward_declaration; + descriptor->subprogram_linenum = linenum; + name_table_insert(item->names, name, descriptor); + } +} + + +/* + Adds a function declaration into the block +*/ +void add_function(block *item, string *name, type_list *parameters, + type *return_type, int forward_declaration, int linenum) +{ + identifier *descriptor; + + descriptor = name_table_find(item->names, name); + + if (descriptor != NULL) + { + if ((forward_declaration != -1) + && (descriptor->forward_declaration != -1)) + check_forward_declaration(descriptor, parameters, + forward_declaration, return_type); + + if ((descriptor->forward_declaration == -1) + || (forward_declaration != -1)) + descriptor->forward_declaration = forward_declaration; + } + else + { + descriptor = identifier_create(); + descriptor->identifier_class = function_name; + descriptor->parameters = parameters; + descriptor->return_type = return_type; + descriptor->forward_declaration = forward_declaration; + descriptor->subprogram_linenum = linenum; + name_table_insert(item->names, name, descriptor); + } +} + + +/* + Loads (inserts) an external library into the project - load the class file and + enumerate all static functions. +*/ +void load_extern_library(string* library_name) +{ + FILE *library_file = NULL; + FILE *symbol_file = NULL; + string *global_library_path; + string *project_library_path; + unit *library_unit; + identifier *unit_identifier; + + lowercase(library_name->cstr); + + /* create the full path to the library file */ + /* global library directory */ + global_library_path = string_from_cstr(global_library_directory); + #ifdef WIN32 + string_append(global_library_path, string_from_cstr("\\Lib_")); + #endif + #ifdef UNIX + string_append(global_library_path, string_from_cstr("/Lib_")); + #endif + string_append(global_library_path, library_name); + string_append(global_library_path, string_from_cstr(".class")); + /* project library directory */ + project_library_path = string_from_cstr(project_library_directory); + #ifdef WIN32 + string_append(project_library_path, string_from_cstr("\\Lib_")); + #endif + #ifdef UNIX + string_append(project_library_path, string_from_cstr("/Lib_")); + #endif + string_append(project_library_path, library_name); + string_append(project_library_path, string_from_cstr(".class")); + + if (name_table_find(root_block->names, library_name) != NULL) + { + add_error_message(450, string_get_cstr(library_name), ""); + fclose(library_file); + goto lel_finally; + } + + /* create a new unit object */ + library_unit = unit_create(string_duplicate(library_name)); + unit_identifier = identifier_create(); + unit_identifier->identifier_class = unit_name; + unit_identifier->unit_block = library_unit; + name_table_insert(root_block->names, string_duplicate(library_name), unit_identifier); + + /* try open the library file from the libraries directories */ + library_file = fopen(project_library_path->cstr, "rb"); + if (library_file == NULL) + { + library_file = fopen(global_library_path->cstr, "rb"); + } + if (library_file == NULL) + { + /* if this fails, try to open an unit file */ + char *filename = (char*)malloc(strlen(output_path) + string_length(library_name) + 10); + + #ifdef WIN32 + sprintf(filename, "%s\\%s.bsf", output_path, string_get_cstr(library_name)); + #endif + #ifdef UNIX + sprintf(filename, "%s/%s.bsf", output_path, string_get_cstr(library_name)); + #endif + + symbol_file = fopen(filename, "rb"); + + free(filename); + + if (symbol_file == NULL) + { + // j-a-s-d: if unit is not found it must stop only if compiling + if (!detect_units_only) + { + add_error_message(448, library_name->cstr, ""); + goto lel_finally; + } + + } + + if (detect_units_only) + requires(0, library_name->cstr); + } else { + if (!detect_units_only) + requires(1, library_name->cstr); + } + + /* read the library file */ + if (library_file) + { + library_unit->is_library = 1; + if (detect_units_only == 0) + read_library_file(library_file, library_unit); + fclose(library_file); + } + + if (symbol_file) + { + library_unit->is_library = 0; + if (detect_units_only == 0) + read_symbol_file(symbol_file, library_unit); + fclose(symbol_file); + } + + unit_identifier->identifier_class = unit_name; + unit_identifier->unit_block = library_unit; + + name_table_insert(root_block->names, library_name , unit_identifier); + + if (library_file) + { + if (user_libraries == NULL) + { + user_libraries = malloc(library_name->length+1); + strcpy(user_libraries, library_name->cstr); + } + else + { + int len = strlen(user_libraries); + user_libraries = realloc(user_libraries, len + 3 + library_name->length); + user_libraries[strlen(user_libraries)] = ' '; + strcpy(user_libraries + len + 1, library_name->cstr); + } + } + + if (symbol_file) + { +save_unit_name: + if (*units == NULL) + { + *units = malloc(library_name->length+1); + strcpy(*units, library_name->cstr); + } + else + { + int len = strlen(*units); + *units = realloc(*units, len + 3 + library_name->length); + (*units)[len] = ' '; + strcpy(*units + len + 1, library_name->cstr); + } + } + + +lel_finally: + string_destroy(library_name); + string_destroy(project_library_path); + string_destroy(global_library_path); +} + + +/* + Reads the library file. +*/ +void read_library_file(FILE* library_file, unit* library_unit) +{ + int constant_pool_count; + struct constant_pool_struct *constant_pool; + int access_flags, this_class, super_class; + int interface_count, field_count, methods_count; + int i, j; + + /* read and check magic number */ + if ((fgetc(library_file) != 0xca) + || (fgetc(library_file) != 0xfe) + || (fgetc(library_file) != 0xba) + || (fgetc(library_file) != 0xbe) + ) + { + add_error_message(449, "", ""); + fclose(library_file); + die(6); + return; + } + + /* skip major and minor count */ + read_long_int(library_file); + + /* read the number of constant pool entries */ + constant_pool_count = read_short_int(library_file); + + /* allocate and read the constant pool */ + constant_pool = mem_alloc(sizeof(struct constant_pool_struct) * constant_pool_count); + + for (i = 1; iforward_declaration = 0; + method->standard_function = 0; + method->parameters = type_list_create(); + + /* check that method parameters and return value are OK */ + descriptor = constant_pool[method_descriptor_index].data; + + for(j = 1; jtype_class = string_type; + + if (!parsing_return_type) + type_list_append(method->parameters, new_type); + else + { + method->return_type = new_type; + method->identifier_class = function_name; + } + j += 17; + } + else + if ((descriptor[j] == 'L') && (strncmp(descriptor+j, "Ljavax/microedition/lcdui/Image;", 32) == 0)) + { + type* new_type = type_create(); + new_type->type_class = image_type; + + if (!parsing_return_type) + type_list_append(method->parameters, new_type); + else + { + method->return_type = new_type; + method->identifier_class = function_name; + } + j += 31; + } + else + if ((descriptor[j] == 'L') && (strncmp(descriptor+j, "Ljavax/microedition/lcdui/Command;", 34) == 0)) + { + type* new_type = type_create(); + new_type->type_class = command_type; + + if (!parsing_return_type) + type_list_append(method->parameters, new_type); + else + { + method->return_type = new_type; + method->identifier_class = function_name; + } + j += 33; + } + else + if ((descriptor[j] == 'L') && (strncmp(descriptor+j, "Ljava/io/InputStream;", 21) == 0)) + { + type* new_type = type_create(); + new_type->type_class = stream_type; + + if (!parsing_return_type) + type_list_append(method->parameters, new_type); + else + { + method->return_type = new_type; + method->identifier_class = function_name; + } + j += 20; + } + else + if ((descriptor[j] == 'L') && (strncmp(descriptor+j, "Ljavax/microedition/rms/RecordStore;", 36) == 0)) + { + type* new_type = type_create(); + new_type->type_class = record_store_type; + + if (!parsing_return_type) + type_list_append(method->parameters, new_type); + else + { + method->return_type = new_type; + method->identifier_class = function_name; + } + j += 35; + } + else + if (descriptor[j] == 'I') + { + type* new_type = type_create(); + new_type->type_class = integer_type; + if (!parsing_return_type) + type_list_append(method->parameters, new_type); + else + { + method->return_type = new_type; + method->identifier_class = function_name; + } + } + else + if ((descriptor[j] == 'V') && (parsing_return_type)) + { + method->identifier_class = procedure_name; + } + else + { + add_error_message(452, "", ""); + break; + } + } + + method->unit_function = 1; + method->container_unit = library_unit; + method_name = string_create(); + method_name->length = constant_pool[method_name_index].data_len; + method_name->cstr = malloc(method_name->length + 1); + strcpy(method_name->cstr, constant_pool[method_name_index].data); + method_name->cstr[method_name->length] = '\0'; + name_table_insert(library_unit->names, method_name, method); + } + + /* skip over all attributes */ + for (j=0; jidentifier_class = constant_name; + constant->unit_function = 1; + constant->container_unit = library_unit; + + name = bsf_read_STRING(symbol_file); + fread(&type, 1, 1, symbol_file); + + constant->constant_type = type_create(); + + switch (type) + { + case 1: + constant->constant_type->type_class = integer_type; + fread(&constant->constant_int_value, sizeof(int), 1, symbol_file); + break; + case 2: + constant->constant_type->type_class = real_type; + fread(&constant->constant_real_value, sizeof(float), 1, symbol_file); + break; + case 3: + constant->constant_type->type_class = boolean_type; + fread(&constant->constant_int_value, sizeof(char), 1, symbol_file); + break; + case 4: + constant->constant_type->type_class = char_type; + fread(&constant->constant_int_value, sizeof(char), 1, symbol_file); + break; + case 5: + constant->constant_type->type_class = string_type; + constant->constant_string_value = bsf_read_STRING(symbol_file); + break; + } + + name_table_insert(library_unit->names, name, constant); + } + break; + + case 2: + { + string *var_name; + type *var_type; + identifier *variable = identifier_create(); + + variable->identifier_class = variable_name; + + var_name = bsf_read_STRING(symbol_file); + var_type = bsf_read_TYPE(symbol_file); + + variable->variable_type = var_type; + variable->unit_function = 1; + variable->container_unit = library_unit; + + name_table_insert(library_unit->names, var_name, variable); + } + break; + + case 3: + { + string *name; + identifier *type_identifier = identifier_create(); + + type_identifier->identifier_class = type_name; + + name = bsf_read_STRING(symbol_file); + type_identifier->defined_type = bsf_read_TYPE(symbol_file); + type_identifier->unit_function = 1; + type_identifier->container_unit = library_unit; + + name_table_insert(library_unit->names, name, type_identifier); + } + break; + + case 4: + { + string *name; + char params; + identifier* procedure = identifier_create(); + + procedure->forward_declaration = 0; + procedure->standard_function = 0; + procedure->identifier_class = procedure_name; + procedure->unit_function = 1; + procedure->container_unit = library_unit; + procedure->subprogram_linenum = 1; + + procedure->parameters = type_list_create(); + + name = bsf_read_STRING(symbol_file); + fread(¶ms, 1, 1, symbol_file); + + while (params > 0) + { + type_list_append(procedure->parameters, bsf_read_TYPE(symbol_file)); + params --; + } + + name_table_insert(library_unit->names, name, procedure); + } + break; + + case 5: + { + string *name; + char params; + identifier* function = identifier_create(); + + function->forward_declaration = 0; + function->standard_function = 0; + function->identifier_class = function_name; + function->unit_function = 1; + function->container_unit = library_unit; + function->subprogram_linenum = 1; + + function->parameters = type_list_create(); + + name = bsf_read_STRING(symbol_file); + function->return_type = bsf_read_TYPE(symbol_file); + fread(¶ms, 1, 1, symbol_file); + + while (params > 0) + { + type_list_append(function->parameters, bsf_read_TYPE(symbol_file)); + params --; + } + + name_table_insert(library_unit->names, name, function); + } + break; + } + } +} + + +/* + Adds parameters names into block. +*/ +void add_parameters(block *item, string_list *parameters_list, + type *parameters_type, int is_parameter_variable) +{ + string_list *it; + identifier *descriptor; + + it = parameters_list; + + if (it->data == NULL) + { + type_destroy(parameters_type); + return; + } + + while (it != NULL) + { + descriptor = identifier_create(); + descriptor->identifier_class = parameter_name; + descriptor->parameter_index = item->next_parameter_index; + item-> next_parameter_index ++; + descriptor->parameter_type = type_duplicate(parameters_type); + descriptor->is_parameter_variable = is_parameter_variable; + name_table_insert(item->names, string_duplicate(it->data), descriptor); + + it = it->next; + } + + item->next_variable_index = item->next_parameter_index; + + type_destroy(parameters_type); +} + + +/* + Checks if a forward declaration corresponds to a real + function definition. + + The identifier 'declaration' is a function or a + procedure that is forward. +*/ +void check_forward_declaration(identifier *declaration, + type_list *parameters, + int forward_declaration, + type *return_type) +{ + int different_parameter; + + if ((declaration->identifier_class != procedure_name) + && (declaration->identifier_class != function_name)) + { + return; + } + + if (forward_declaration) + { + add_error_message(401, "", ""); + return; + } + + if ((return_type == NULL) /* it is a procedure */ + && (declaration->identifier_class == function_name)) + add_error_message(402, "function", ""); + + if ((return_type != NULL) /* it is a function*/ + && (declaration->identifier_class == procedure_name)) + add_error_message(402, "procedure", ""); + + different_parameter = type_list_different_parameter( + parameters, declaration->parameters); + + if (different_parameter == -1) + add_error_message(403, "", ""); + + if (different_parameter > 0) + { + char number[8]; + + sprintf(number, "%d", different_parameter); + add_error_message(404, number, ""); + } + + if (return_type != NULL) + { + if ((declaration->identifier_class != function_name) || (!type_equal(return_type, declaration->return_type))) + add_error_message(405, "", ""); + } +} + + +/* + Checks if there is any identifier contained in the current block that is + forward function or procedure delcaration. If there is, report an error. +*/ +void check_unmatched_forward_declarations(block *current_block, name_table *node) +{ + int i; + identifier *declaration; + + if ((node == NULL) || (node->descriptor == NULL)) + return; + + declaration = node->descriptor; + + if ( + ((declaration->identifier_class == procedure_name) || + (declaration->identifier_class == function_name)) + && (declaration->forward_declaration == 1) + ) + { + new_linenum=declaration->subprogram_linenum; + add_error_message(441, "", ""); + } + + check_unmatched_forward_declarations(current_block, node->left_child); + check_unmatched_forward_declarations(current_block, node->right_child); + +} + + +/* + Uses a given name to access all the defined types. + Return a found type, or an error type if no type + was found. +*/ +type *type_from_name(block *current_block, char *cstr) +{ + type *found_type; + string *name; + identifier *declaration; + + + found_type = type_create(); + found_type->type_class = error_type; + + name = string_from_cstr(cstr); + + while (current_block != NULL) + { + declaration = name_table_find(current_block->names, name); + + if (declaration != NULL) + { + if (declaration->identifier_class == type_name) + { + type_destroy(found_type); + found_type = type_duplicate(declaration->defined_type); + } + + break; + } + + current_block = current_block->parent_block; + } + + string_destroy(name); + return found_type; +} + + +/* + Retuns the type of the constant given by its name, + or return error_type if cstr is not a constant name. +*/ +type *get_constant_type(block *current_block, char *cstr) +{ + type *found_type; + string *name; + identifier *declaration; + + found_type = type_create(); + found_type->type_class = error_type; + + name = string_from_cstr(cstr); + + while (current_block != NULL) + { + declaration = name_table_find(current_block->names, name); + + if (declaration != NULL) + { + if (declaration->identifier_class == constant_name) + { + type_destroy(found_type); + found_type = type_duplicate(declaration->constant_type); + } + + break; + } + + current_block = current_block->parent_block; + } + + string_destroy(name); + return found_type; +} + + +/* + Return a copy of an identifier associated with a + constant of a given name, or a none identifier + if identifier is not a constant or not found. +*/ +identifier *get_constant_identifier(block *current_block, char *cstr) +{ + string *name; + identifier *found_constant = NULL; + identifier *declaration; + + name = string_from_cstr(cstr); + + while (current_block != NULL) + { + declaration = name_table_find(current_block->names, name); + + if (declaration != NULL) + { + if (declaration->identifier_class == constant_name) + found_constant = identifier_duplicate(declaration); + + break; + } + + current_block = current_block->parent_block; + } + + string_destroy(name); + + if (found_constant == NULL) + found_constant = identifier_create(); + + return found_constant; +} + + +/* + Return an identifier from a given name +*/ +identifier *get_identifier(block *current_block, char *cstr) +{ + string *name; + identifier *found_identifier = NULL; + identifier *declaration; + name_table *name_table_it; + + name = string_from_cstr(cstr); + + while (current_block != NULL) + { + declaration = name_table_find(current_block->names, name); + + if (declaration != NULL) + { + found_identifier = identifier_duplicate(declaration); + + if (current_block->parent_block == root_block) + found_identifier->belongs_to_program_block = 1; + else + found_identifier->belongs_to_program_block = 0; + + break; + } + + current_block = current_block->parent_block; + } + + string_destroy(name); + + if (found_identifier != NULL) + return found_identifier; + + /* + Search all units for a given identifier. If the same identifier is found + in more then one unit, output ambiguity error. + */ + if (root_block->names->name != NULL) + { + name_table_it = root_block->names; + + while (name_table_it != NULL) + { + identifier *descriptor = name_table_it->descriptor; + + if (descriptor->identifier_class == unit_name) + { + /* + Search inside the unit for the given name + */ + name_table *unit_table_it = descriptor->unit_block->names; + + if (unit_table_it->name != NULL) + { + while (unit_table_it != NULL) + { + if(STRING_COMPARE(string_get_cstr(unit_table_it->name), + cstr) == 0) + { + if (found_identifier == NULL) + found_identifier = identifier_duplicate(unit_table_it->descriptor); + else + { + add_error_message(459, cstr, ""); + found_identifier = NULL; + goto unit_search_done; + } + } + + + unit_table_it = unit_table_it->next; + } + } + } + + name_table_it = name_table_it->next; + } + } + +unit_search_done: + + if (found_identifier == NULL) + { + found_identifier = identifier_create(); + found_identifier->belongs_to_program_block = 0; + } + + return found_identifier; +} + + +/* + Returns the type of a variable given by its name. + Return an error type if no variable was found. +*/ +type *get_variable_type(block *current_block, char *cstr) +{ + type *found_type; + string *name; + identifier *declaration; + + found_type = type_create(); + found_type->type_class = error_type; + + name = string_from_cstr(cstr); + + while (current_block != NULL) + { + declaration = name_table_find(current_block->names, name); + + if (declaration != NULL) + { + if (declaration->identifier_class == variable_name) + found_type = type_duplicate(declaration->variable_type); + + break; + } + + current_block = current_block->parent_block; + } + + string_destroy(name); + return found_type; +} + +/* + Create the bytecode to initialize the new variable. +*/ +void initialize_variable(block *item, identifier *variable, char *name, int is_static, char *class_name) +{ + int storeIntoField = 0; + + /* if the variable belongs to the program block */ + if (variable->belongs_to_program_block) + { + storeIntoField = 1; + } + + switch(variable->variable_type->type_class) + { + case integer_type: + case char_type: + case boolean_type: + { + bytecode_append(item->code, iconst_0$); + + if (!storeIntoField) + { + switch(variable->variable_index) + { + case 0: + bytecode_append(item->code, istore_0$); + break; + case 1: + bytecode_append(item->code, istore_1$); + break; + case 2: + bytecode_append(item->code, istore_2$); + break; + case 3: + bytecode_append(item->code, istore_3$); + break; + default: + bytecode_append(item->code, istore$); + bytecode_append(item->code, (char)variable->variable_index); + break; + } + } + } + break; // case integer_type + + case real_type: + { + if (mathType == 1) + { + bytecode_append(item->code, iconst_0$); + + if (!storeIntoField) + { + switch(variable->variable_index) + { + case 0: + bytecode_append(item->code, istore_0$); + break; + case 1: + bytecode_append(item->code, istore_1$); + break; + case 2: + bytecode_append(item->code, istore_2$); + break; + case 3: + bytecode_append(item->code, istore_3$); + break; + default: + bytecode_append(item->code, istore$); + bytecode_append(item->code, (char)variable->variable_index); + break; + } + } + } + else + { + int method_index; + int class_index; + + usesFloat = 1; + + class_index = cp_add_class("Real"); + method_index = cp_add_methodref("Real", "", "()V"); + + bytecode_append(item->code, new$); + bytecode_append_short_int(item->code, (short)class_index); + bytecode_append(item->code, dup$); + bytecode_append(item->code, invokespecial$); + bytecode_append_short_int(item->code, (short)method_index); + + if (!storeIntoField) + { + switch(variable->variable_index) + { + case 0: + bytecode_append(item->code, astore_0$); + break; + case 1: + bytecode_append(item->code, astore_1$); + break; + case 2: + bytecode_append(item->code, astore_2$); + break; + case 3: + bytecode_append(item->code, astore_3$); + break; + default: + bytecode_append(item->code, astore$); + bytecode_append(item->code, variable->variable_index); + break; + } + } + } + } + break; + + + case string_type: + { + int method_index; + int class_index; + + class_index = cp_add_class("java/lang/String"); + method_index = cp_add_methodref("java/lang/String", "", "()V"); + + bytecode_append(item->code, new$); + bytecode_append_short_int(item->code, (short)class_index); + bytecode_append(item->code, dup$); + bytecode_append(item->code, invokespecial$); + bytecode_append_short_int(item->code, (short)method_index); + + if (!storeIntoField) + { + switch(variable->variable_index) + { + case 0: + bytecode_append(item->code, astore_0$); + break; + case 1: + bytecode_append(item->code, astore_1$); + break; + case 2: + bytecode_append(item->code, astore_2$); + break; + case 3: + bytecode_append(item->code, astore_3$); + break; + default: + bytecode_append(item->code, astore$); + bytecode_append(item->code, variable->variable_index); + break; + } + } + } + break; + + case image_type: + { + int method_index = cp_add_methodref("javax/microedition/lcdui/Image", "createImage", "(II)Ljavax/microedition/lcdui/Image;"); + + bytecode_append(item->code, iconst_1$); + bytecode_append(item->code, iconst_1$); + bytecode_append(item->code, invokestatic$); + bytecode_append_short_int(item->code, method_index); + + if (!storeIntoField) + { + switch(variable->variable_index) + { + case 0: + bytecode_append(item->code, astore_0$); + break; + case 1: + bytecode_append(item->code, astore_1$); + break; + case 2: + bytecode_append(item->code, astore_2$); + break; + case 3: + bytecode_append(item->code, astore_3$); + break; + default: + bytecode_append(item->code, astore$); + bytecode_append(item->code, (char)variable->variable_index); + break; + } + } + } + break; // case image_type + + + case stream_type: + { + bytecode_append(item->code, aconst_null$); + + if (!storeIntoField) + { + switch(variable->variable_index) + { + case 0: + bytecode_append(item->code, astore_0$); + break; + case 1: + bytecode_append(item->code, astore_1$); + break; + case 2: + bytecode_append(item->code, astore_2$); + break; + case 3: + bytecode_append(item->code, astore_3$); + break; + default: + bytecode_append(item->code, astore$); + bytecode_append(item->code, (char)variable->variable_index); + break; + } + } + } + break; // case stream_type + + case command_type: + { + int method_index = cp_add_methodref("javax/microedition/lcdui/Command", "", "(Ljava/lang/String;II)V"); + + bytecode_append(item->code, new$); + bytecode_append_short_int(item->code, cp_add_class("javax/microedition/lcdui/Command")); + bytecode_append(item->code, dup$); + + bytecode_append(item->code, new$); + bytecode_append_short_int(item->code, cp_add_class("java/lang/String")); + bytecode_append(item->code, dup$); + bytecode_append(item->code, invokespecial$); + bytecode_append_short_int(item->code, cp_add_methodref("java/lang/String", "", "()V")); + + bytecode_append(item->code, iconst_1$); + bytecode_append(item->code, iconst_1$); + bytecode_append(item->code, invokespecial$); + bytecode_append_short_int(item->code, method_index); + + if (!storeIntoField) + { + switch(variable->variable_index) + { + case 0: + bytecode_append(item->code, astore_0$); + break; + case 1: + bytecode_append(item->code, astore_1$); + break; + case 2: + bytecode_append(item->code, astore_2$); + break; + case 3: + bytecode_append(item->code, astore_3$); + break; + default: + bytecode_append(item->code, astore$); + bytecode_append(item->code, (char)variable->variable_index); + break; + } + } + } + break; // case command_type + + case http_type: + { + int method_index = cp_add_methodref("H", "", "()V"); + usesHttp = 1; + + bytecode_append(item->code, new$); + bytecode_append_short_int(item->code, cp_add_class("H")); + bytecode_append(item->code, dup$); + + bytecode_append(item->code, invokespecial$); + bytecode_append_short_int(item->code, method_index); + + if (!storeIntoField) + { + switch(variable->variable_index) + { + case 0: + bytecode_append(item->code, astore_0$); + break; + case 1: + bytecode_append(item->code, astore_1$); + break; + case 2: + bytecode_append(item->code, astore_2$); + break; + case 3: + bytecode_append(item->code, astore_3$); + break; + default: + bytecode_append(item->code, astore$); + bytecode_append(item->code, (char)variable->variable_index); + break; + } + } + } + break; // case http_type + + case record_store_type: + { + usesRecordStore = 1; + /* no initialization needeed */ + } + break; + + case array_type: + { + int count = 0; + type_list *it = variable->variable_type->dimensions_list; + char *descriptor; + descriptor = (char*) mem_alloc(1024); + if (descriptor == NULL) + die(1); + + get_field_descriptor(variable->variable_type, descriptor); + + /* put dimensions on to the stack */ + while (it != NULL) + { + if (it->data != NULL) + { + int size; + size = it->data->last_element - it->data->first_element + 1; + + if (size <= 0) { + add_error_message(437, "", ""); + } else if (size <= 127) { + bytecode_append(item->code, bipush$); + bytecode_append(item->code, (char)size); + } else if (size <= 32767) { + bytecode_append(item->code, sipush$); + bytecode_append_short_int(item->code, (short)size); + } else { + add_error_message(438, "", ""); + } + } + it = it->next; + + count ++; + } + + bytecode_append(item->code, multianewarray$); + bytecode_append_short_int(item->code, cp_add_class(descriptor)); + bytecode_append(item->code, (char)count); + + // NEW: + create_put_variable_bytecode(variable, item->code, name, storeIntoField); + + if((variable->variable_type->element_type->type_class == record_type) + || (variable->variable_type->element_type->type_class == string_type) + || ((variable->variable_type->element_type->type_class == real_type) && (mathType != 1)) + || (variable->variable_type->element_type->type_class == image_type) + || (variable->variable_type->element_type->type_class == command_type)) + { + /* initialize the fields */ + unsigned short int c = 0; + char descriptor[128]; + unsigned short int num; + int *offsets; + int *dimensions_sizes; // j-a-s-d: OOB in initialization of complex-type multidimensional arrays bug fix + type_list *it = variable->variable_type->dimensions_list; + + while (it != NULL) + { + it = it->next; + c ++; + } + + if (variable->variable_type->element_type->type_class == real_type) + usesFloat = 1; + + offsets = (int*) mem_alloc(c * sizeof(int)); + dimensions_sizes = (int*) mem_alloc(c * sizeof(int)); // j-a-s-d: OOB in initialization of complex-type multidimensional arrays bug fix + num = c; + + /* reset */ + it = variable->variable_type->dimensions_list; + c = 0; + while (it != NULL) + { + if (it->data != NULL) + { + bytecode_append(item->code, getstatic$); + bytecode_append_short_int(item->code, cp_add_fieldref("M", "IC", "[I")); + bytecode_append(item->code, sipush$); + bytecode_append_short_int(item->code, c); + bytecode_append(item->code, iconst_0$); + bytecode_append(item->code, iastore$); + + offsets[c] = item->code->bytecode_pos; + dimensions_sizes[c] = it->data->last_element-it->data->first_element; // j-a-s-d: OOB in initialization of complex-type multidimensional arrays bug fix + } + c++; + it = it->next; + } + + /* load */ + for(c=0; ccode, dup$); + // NEW: + create_variable_bytecode(variable, item->code, name, storeIntoField); + } + bytecode_append(item->code, getstatic$); + bytecode_append_short_int(item->code, cp_add_fieldref("M", "IC", "[I")); + bytecode_append(item->code, sipush$); + bytecode_append_short_int(item->code, c); + bytecode_append(item->code, iaload$); + if (c < (num-1)) + bytecode_append(item->code, aaload$); + } + + /* new */ + get_field_descriptor(variable->variable_type->element_type, descriptor); + descriptor[strlen(descriptor)-1] = '\0'; + + if (variable->variable_type->element_type->type_class == image_type) + { + bytecode_append(item->code, iconst_1$); + bytecode_append(item->code, iconst_1$); + bytecode_append(item->code, invokestatic$); + bytecode_append_short_int(item->code, cp_add_methodref("javax/microedition/lcdui/Image", "createImage", "(II)Ljavax/microedition/lcdui/Image;")); + } + else if (variable->variable_type->element_type->type_class == command_type) + { + int method_index = cp_add_methodref("javax/microedition/lcdui/Command", "", "(Ljava/lang/String;II)V"); + + bytecode_append(item->code, new$); + bytecode_append_short_int(item->code, cp_add_class("javax/microedition/lcdui/Command")); + bytecode_append(item->code, dup$); + + bytecode_append(item->code, new$); + bytecode_append_short_int(item->code, cp_add_class("java/lang/String")); + bytecode_append(item->code, dup$); + bytecode_append(item->code, invokespecial$); + bytecode_append_short_int(item->code, cp_add_methodref("java/lang/String", "", "()V")); + + bytecode_append(item->code, iconst_1$); + bytecode_append(item->code, iconst_1$); + bytecode_append(item->code, invokespecial$); + bytecode_append_short_int(item->code, method_index); + } + else + { + bytecode_append(item->code, new$); + bytecode_append_short_int(item->code, cp_add_class(descriptor+1)); + bytecode_append(item->code, dup$); + bytecode_append(item->code, invokespecial$); + bytecode_append_short_int(item->code, cp_add_methodref(descriptor+1, "", "()V")); + } + + bytecode_append(item->code, aastore$); + + /* jump back */ + it = variable->variable_type->dimensions_list; + c = num-1; + while (it != NULL) + { + if (it->data != NULL) + { + short int offset; + bytecode_append(item->code, getstatic$); + bytecode_append_short_int(item->code, cp_add_fieldref("M", "IC", "[I")); + bytecode_append(item->code, dup$); + bytecode_append(item->code, sipush$); + bytecode_append_short_int(item->code, c); + bytecode_append(item->code, iaload$); + bytecode_append(item->code, iconst_1$); + bytecode_append(item->code, iadd$); + bytecode_append(item->code, sipush$); + bytecode_append_short_int(item->code, c); + bytecode_append(item->code, swap$); + bytecode_append(item->code, iastore$); + /* the value is increased by one */ + + bytecode_append(item->code, getstatic$); + bytecode_append_short_int(item->code, cp_add_fieldref("M", "IC", "[I")); + bytecode_append(item->code, sipush$); + bytecode_append_short_int(item->code, c); + bytecode_append(item->code, iaload$); + bytecode_append(item->code, sipush$); + bytecode_append_short_int(item->code, + //it->data->last_element-it->data->first_element); + dimensions_sizes[c]); // j-a-s-d: OOB in initialization of complex-type multidimensional arrays bug fix + bytecode_append(item->code, if_icmple$); + offset = offsets[c] - item->code->bytecode_pos + 1; + bytecode_append_short_int(item->code, offset); + } + c--; + it = it->next; + } + + mem_free(offsets); + } + + /*OLD: if (!storeIntoField) + { + switch(variable->variable_index) + { + case 0: + bytecode_append(item->code, astore_0$); + break; + case 1: + bytecode_append(item->code, astore_1$); + break; + case 2: + bytecode_append(item->code, astore_2$); + break; + case 3: + bytecode_append(item->code, astore_3$); + break; + default: + bytecode_append(item->code, astore$); + bytecode_append(item->code, (char)variable->variable_index); + break; + } + } */ + + mem_free(descriptor); + + break; + } // case array_type + + case record_type: + { + char *descriptor; + descriptor = (char*) mem_alloc(1024); + + if(descriptor == NULL) + die(1); + + get_field_descriptor(variable->variable_type, descriptor); + + descriptor[strlen(descriptor) - 1] = '\0'; + + bytecode_append(item->code, new$); + bytecode_append_short_int(item->code, cp_add_class(descriptor + 1)); + bytecode_append(item->code, dup$); + bytecode_append(item->code, invokespecial$); + bytecode_append_short_int(item->code, cp_add_methodref(descriptor + 1, "", "()V")); + + mem_free(descriptor); + + if (!storeIntoField) + { + switch(variable->variable_index) + { + case 0: + bytecode_append(item->code, astore_0$); + break; + case 1: + bytecode_append(item->code, astore_1$); + break; + case 2: + bytecode_append(item->code, astore_2$); + break; + case 3: + bytecode_append(item->code, astore_3$); + break; + default: + bytecode_append(item->code, astore$); + bytecode_append(item->code, (char)variable->variable_index); + break; + } + } + } + break; + + case error_type: + break; + + default: + { + die(14); + } + } + + + /* create the bytecode for storing data into the field */ + if ((storeIntoField) + && (variable->variable_type->type_class != record_store_type) + && (variable->variable_type->type_class != array_type)) /* array initialization stores the variable */ + { + int field_index; + char descriptor[512]; + get_field_descriptor(variable->variable_type, descriptor); + + if (name == NULL) + die(23); + + lowercase(name); + field_index = cp_add_fieldref(class_name, name, descriptor); + + if (is_static) + bytecode_append(item->code, putstatic$); + else + bytecode_append(item->code, putfield$); + bytecode_append_short_int(item->code, (short)field_index); + } +} + + +void transform_break_stmts(bytecode *code, int start_offset, int end_offset, int jump_pos) +{ + int jump_offset; + int pos = start_offset; + + while (pos < end_offset) + { + if (((unsigned char)(code->bytecode[pos]) == (unsigned char)break_stmt$) + && ((pos + 2) < end_offset)) + { + if ((code->bytecode[pos+1] == 0) + && (code->bytecode[pos+2] == 0)) + { + jump_offset = jump_pos - pos; + code->bytecode[pos] = goto$; + code->bytecode[pos+1] = (jump_offset) >> 8; + code->bytecode[pos+2] = jump_offset; + } + } + + pos ++; + } +} + + +/* + Writes the class file based on the information provided in the + root block. +*/ +void create_class_file(block *program_block, FILE *fp) +{ + int this_class_index; + int super_class_index; + int i; + + /*** Insert the additional data into the constant pool ***/ + if (compiling_unit == 0) + { + this_class_index = cp_add_class("M"); + switch (canvasType) + { + case NORMAL: + super_class_index = cp_add_class("javax/microedition/lcdui/Canvas"); + break; + case FULL_NOKIA: + super_class_index = cp_add_class("com/nokia/mid/ui/FullCanvas"); + break; + case FULL_MIDP20: + super_class_index = cp_add_class("javax/microedition/lcdui/game/GameCanvas"); + break; + } + } + else + { + this_class_index = cp_add_class(string_get_cstr(str_program_name)); + super_class_index = cp_add_class("java/lang/Object"); + } + + + /* Insert the data needed by the methods into the constant pool */ + write_method(program_block, NULL); + for(i=0; ichildren_count; i++) + { + write_method(program_block->children[i], NULL); + } + write_block_fields(program_block->names, NULL); + + if (compiling_unit == 0) + { + write_constructor(NULL); + write_paint_method(NULL); + write_run_method(NULL); + write_keypressed_method(NULL); + write_keyreleased_method(NULL); + } + + /* add data to constant poll that is later needed */ + cp_add_utf8("I"); + cp_add_utf8("T"); + cp_add_utf8("G"); + cp_add_utf8("KC"); + cp_add_utf8("KP"); + cp_add_utf8("IC"); + cp_add_utf8("[I"); + cp_add_utf8("Ljavax/microedition/lcdui/Image;"); + cp_add_utf8("LM;"); + cp_add_class("M"); + cp_add_utf8("Ljavax/microedition/lcdui/Graphics;"); + cp_add_class("java/lang/Runnable"); + cp_add_utf8("StackMap"); + + /*** Write data to the file ***/ + + /* write the header */ + create_class_file_header(fp); + + /* write constant pool */ + write_constant_pool(fp); + + /* write the access flags, set to ACC_PUBLIC and ACC_SUPER */ + write_short_int(fp, 0x0021); + + /* write the index to constat pool with this class description */ + write_short_int(fp, (short)this_class_index); + + /* write the index to constant pool with the super class description */ + write_short_int(fp, (short)super_class_index); + + if (compiling_unit == 0) + { + /* we have 1 interface */ + write_short_int(fp, 1); + + write_short_int(fp, cp_add_class("java/lang/Runnable")); + } + else + { + /* unit has 0 interfaces */ + write_short_int(fp, 0); + } + + /* write the fields (global variables in pascal) */ + if (compiling_unit == 0) + { + write_short_int(fp, (short)(program_block->next_variable_index + 7)); + + /* write the RNG field */ + { + /* access flags: ACC_PUBLIC and ACC_STATIC */ + write_short_int(fp, 0x0001 | 0x0008); + + /* write the name index */ + write_short_int(fp, cp_add_utf8("RNG")); + + /* write the descriptor index */ + write_short_int(fp, cp_add_utf8("Ljava/util/Random;")); + + /* write 0 attributes */ + write_short_int(fp, 0); + } + + /* write the image (I) field */ + { + /* access flags: ACC_PUBLIC and ACC_STATIC */ + write_short_int(fp, 0x0001 | 0x0008); + + /* write the name index */ + write_short_int(fp, cp_add_utf8("I")); + + /* write the descriptor index */ + write_short_int(fp, cp_add_utf8("Ljavax/microedition/lcdui/Image;")); + + /* write 0 attributes */ + write_short_int(fp, 0); + } + + /* write the this (T) field */ + { + /* access flags: ACC_PUBLIC and ACC_STATIC */ + write_short_int(fp, 0x0001 | 0x0008); + + /* write the name index */ + write_short_int(fp, cp_add_utf8("T")); + + /* write the descriptor index */ + write_short_int(fp, cp_add_utf8("LM;")); + + /* write 0 attributes */ + write_short_int(fp, 0); + } + + + /* write the graphics (G) field */ + { + /* access flags: ACC_PUBLIC and ACC_STATIC */ + write_short_int(fp, 0x0001 | 0x0008); + + /* write the name index */ + write_short_int(fp, cp_add_utf8("G")); + + /* write the descriptor index */ + write_short_int(fp, cp_add_utf8("Ljavax/microedition/lcdui/Graphics;")); + + /* write 0 attributes */ + write_short_int(fp, 0); + } + + /* write the key clicked (KC) field */ + { + /* access flags: ACC_PUBLIC and ACC_STATIC */ + write_short_int(fp, 0x0001 | 0x0008); + + /* write the name index */ + write_short_int(fp, cp_add_utf8("KC")); + + /* write the descriptor index */ + write_short_int(fp, cp_add_utf8("I")); + + /* write 0 attributes */ + write_short_int(fp, 0); + } + + /* write the key pressed (KP) field */ + { + /* access flags: ACC_PUBLIC and ACC_STATIC */ + write_short_int(fp, 0x0001 | 0x0008); + + /* write the name index */ + write_short_int(fp, cp_add_utf8("KP")); + + /* write the descriptor index */ + write_short_int(fp, cp_add_utf8("I")); + + /* write 0 attributes */ + write_short_int(fp, 0); + } + + /* write the INDEX COUNTER (IC) field */ + { + /* access flags: ACC_PUBLIC and ACC_STATIC */ + write_short_int(fp, 0x0001 | 0x0008); + + /* write the name index */ + write_short_int(fp, cp_add_utf8("IC")); + + /* write the descriptor index */ + write_short_int(fp, cp_add_utf8("[I")); + + /* write 0 attributes */ + write_short_int(fp, 0); + } + } + else + { + write_short_int(fp, (short)(program_block->next_variable_index)); + } + + write_block_fields(program_block->names, fp); + + + /* write the methods */ + if (compiling_unit == 0) + { + /* write the methods count */ + write_short_int(fp, (short)(program_block->children_count + 6)); + + /* write the constructor */ + write_constructor(fp); + + /* write the paint method */ + write_paint_method(fp); + + /* write the run method */ + write_run_method(fp); + + /* write the key pressed and key released methods */ + write_keypressed_method(fp); + write_keyreleased_method(fp); + } + else + { + write_short_int(fp, (short)(program_block->children_count + 1)); + } + + /* write all other methods */ + for(i=0; ichildren_count; i++) + { + write_method(program_block->children[i], fp); + } + + /* write the main (R) method - for interfaces */ + write_method(program_block, fp); + + + /* we have no attributes */ + write_short_int(fp, 0); + + + // TODO: deallocate constant pool +} + + +/* + Writes the method to the file, if fp is NULL only add needeed + data to the constant pool +*/ +void write_method(block *current_block, FILE *fp) +{ + identifier *block_identifier = NULL; + stack_map_list *map_list; + int code_attribute_length, code_attribute_length_offset; + int stack_map_attribute_offset; + int stack_map_size; + int stack_map_entries; + int tmp_offset; + + /* write access flags, ACC_PUBLIC and ACC_STATIC */ + write_short_int(fp, 0x0001 | 0x0008); + + if(current_block->parent_block == root_block) + { + /*** it is the main block ***/ + + /* write name index */ + if (compiling_unit == 0) + write_short_int(fp, cp_add_utf8("R")); + else + write_short_int(fp, cp_add_utf8("")); + + /* write the descriptor */ + write_short_int(fp, cp_add_utf8("()V")); + } + else + { + char *descriptor; + int pos = 1; + type_list *it; + + descriptor = (char*) mem_alloc(5*1024); + + if (descriptor == NULL) + die(1); + + descriptor[0] = '('; + + /*** procedure or function ***/ + + /* write name index */ + lowercase(current_block->block_name->cstr); + write_short_int(fp, cp_add_utf8(current_block->block_name->cstr)); + + /* write the descriptor */ + block_identifier = name_table_find(current_block->parent_block->names, current_block->block_name); + + if ((block_identifier == NULL) + || (block_identifier->identifier_class != function_name + && block_identifier->identifier_class != procedure_name)) + { + mem_free(descriptor); + die(17); + } + + it = block_identifier->parameters; + + while(it != NULL) + { + if (it->data == NULL) + break; + + get_field_descriptor(it->data, descriptor + pos); + pos = strlen(descriptor); + it = it->next; + } + + descriptor[pos] = ')'; + pos ++; + descriptor[pos] = '\0'; + + if (block_identifier->identifier_class == procedure_name) + strcat(descriptor, "V"); + else + get_field_descriptor(block_identifier->return_type, descriptor + pos); + + write_short_int(fp, cp_add_utf8(descriptor)); + + mem_free(descriptor); + } + +//PREVERIFY map_list = preverify_bytecode(current_block->code, block_identifier); + map_list = NULL; + + + /* write the code */ + write_short_int(fp, 2); /* attribute count */ + + write_short_int(fp, cp_add_utf8("Code")); + if (fp != NULL) + code_attribute_length_offset = ftell(fp); + write_long_int(fp, current_block->code->bytecode_pos + 12); /* update the size later when we know it */ + code_attribute_length = current_block->code->bytecode_pos + 12; + + write_short_int(fp, 32); /* max stack */ + + if (current_block->parent_block == root_block) + write_short_int(fp, 0); /* max locals for program block */ + else + write_short_int(fp, current_block->next_variable_index + 2); /* max locals */ + + write_long_int(fp, current_block->code->bytecode_pos); /* code length */ + + if(fp != NULL) + fwrite(current_block->code->bytecode, current_block->code->bytecode_pos, 1, fp); + + write_short_int(fp, 0); + if (map_list != NULL) + { + write_short_int(fp, 1); /* The Code has one attribute (The StackMap attribute) */ + + write_short_int(fp, cp_add_utf8("StackMap")); + if (fp != NULL) + stack_map_attribute_offset = ftell(fp); + write_long_int(fp, 0); /* attribute length */ + write_short_int(fp, 0); /* number of entries; these two fields will be filled in later */ + + stack_map_size = 2; + stack_map_entries = 0; + + do + { + int i; + stack_map *map = stack_map_list_get(&map_list); + + if (map != NULL) + write_short_int(fp, (short)(map->bytecode_offset)); + stack_map_size += 2; + + /* write the locals */ + if (current_block->parent_block == root_block) + { + write_short_int(fp, 0); + stack_map_size += 2; + } + else + { + identifier *block_identifier; + + /* write the StackMap for locals */ + block_identifier = name_table_find(current_block->parent_block->names, current_block->block_name); + + write_short_int(fp, (short)current_block->next_variable_index); + stack_map_size += 2; + + write_locals_stackmap(fp, block_identifier, &stack_map_size); + } + + if (map == NULL) + break; + + /* write the stack items */ + write_short_int(fp, (short)map->number_of_items); + stack_map_size += 2; + for(i=0; inumber_of_items; i++) + { + if (fp != NULL) + { + fwrite(&(map->stack[i]->item_type), 1, 1, fp); + } + + if ((map->stack[i]->item_type == ITEM_Object) + || (map->stack[i]->item_type == ITEM_NewObject)) + { + write_short_int(fp, map->stack[i]->additional_data); + stack_map_size += 2; + } + + stack_map_size ++; + } + + stack_map_destroy(map); + + stack_map_entries ++; + + } while (map_list != NULL); + + /* write the stack map size and the number of entries and + the code attribute length */ + if (fp != NULL) + { + tmp_offset = ftell(fp); + fseek(fp, stack_map_attribute_offset, SEEK_SET); + write_long_int(fp, stack_map_size); /* attribute length */ + write_short_int(fp, (short)stack_map_entries); /* number of entries */ + + fseek(fp, code_attribute_length_offset, SEEK_SET); + write_long_int(fp, code_attribute_length + 6 + stack_map_size); + + fseek(fp, tmp_offset, SEEK_SET); + } + } + else + { + write_short_int(fp, 0); + } + + /* write the Exceptions attribute */ + write_short_int(fp, cp_add_utf8("Exceptions")); + + write_long_int(fp, 4); + + write_short_int(fp, 1); + write_short_int(fp, cp_add_class("java/lang/Exception")); + +} + + +/* + Creates the code for the following method: + + public void paint(Graphics g) + { + g.drawImage(IMG, 0, 0, Graphics.TOP|Graphics.LEFT); + } +*/ +void write_paint_method(FILE *fp) +{ + bytecode *code = bytecode_create(); + if (code == NULL) + die(1); + + /* create the code */ + + /* PUSH param_1 */ + bytecode_append(code, aload_1$); + + /* PUSH (I) */ + bytecode_append(code, getstatic$); + bytecode_append_short_int(code, cp_add_fieldref("M", "I", "Ljavax/microedition/lcdui/Image;")); + + /* PUSH 0; PUSH 0*/ + bytecode_append(code, iconst_0$); + bytecode_append(code, iconst_0$); + + /* PUSH Graphics.LEFT|Graphics.TOP */ + bytecode_append(code, bipush$); + bytecode_append(code, 20); + + /* invoke drawImage(Image, int, int, int) */ + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, + cp_add_methodref("javax/microedition/lcdui/Graphics", "drawImage", "(Ljavax/microedition/lcdui/Image;III)V")); + + bytecode_append(code, return$); + + /* write the method headers */ + + /* write access flags, ACC_PUBLIC */ + write_short_int(fp, 0x0001); + + /* write method name */ + write_short_int(fp, cp_add_utf8("paint")); + + /* write method descriptor */ + write_short_int(fp, cp_add_utf8("(Ljavax/microedition/lcdui/Graphics;)V")); + + /* write 1 attribute */ + write_short_int(fp, 1); + + /* write the Code attribute */ + write_short_int(fp, cp_add_utf8("Code")); + write_long_int(fp, code->bytecode_pos + 12); + + /* write the max stack */ + write_short_int(fp, 10); + + /* max locals for program block */ + write_short_int(fp, 2); + + + /* code length */ + write_long_int(fp, code->bytecode_pos); + + /* write the code itself */ + if (fp != NULL) + fwrite(code->bytecode, 1, code->bytecode_pos, fp); + + bytecode_destroy(code); + + write_short_int(fp, 0); + write_short_int(fp, 0); +} + +/* + Creates the code for the following method: + + public void run() + { + R(); + } +*/ +void write_run_method(FILE *fp) +{ + char tag; + + bytecode *code = bytecode_create(); + if (code == NULL) + die(1); + + /* create the code */ + bytecode_append(code, invokestatic$); + bytecode_append_short_int(code, cp_add_methodref("M", "R", "()V")); + + bytecode_append(code, goto$); + bytecode_append_short_int(code, 4); + + bytecode_append(code, pop$); /* the exception handler */ + + bytecode_append(code, return$); + + /* write the method headers */ + + /* write access flags, ACC_PUBLIC */ + write_short_int(fp, 0x0001); + + /* write method name */ + write_short_int(fp, cp_add_utf8("run")); + + /* write method descriptor */ + write_short_int(fp, cp_add_utf8("()V")); + + /* write 1 attribute */ + write_short_int(fp, 1); + + /* write the Code attribute */ + write_short_int(fp, cp_add_utf8("Code")); + write_long_int(fp, code->bytecode_pos + 20 + 38); /* 38 = stackmap size */ + + /* write the max stack */ + write_short_int(fp, 2); + + /* max locals for program block */ + write_short_int(fp, 1); + + /* code length */ + write_long_int(fp, code->bytecode_pos); + + /* write the code itself */ + if (fp != NULL) + fwrite(code->bytecode, 1, code->bytecode_pos, fp); + + bytecode_destroy(code); + + /* write exception table length*/ + write_short_int(fp, 1); + + /* write the exception table */ + write_short_int(fp, 0); + write_short_int(fp, 3); + write_short_int(fp, 6); + write_short_int(fp, cp_add_class("java/lang/Exception")); + + + /* StackMap attribute */ + write_short_int(fp, 1); + + write_short_int(fp, cp_add_utf8("StackMap")); + write_long_int(fp, 32); + + /* 2 frames*/ + write_short_int(fp, 3); + + /* write the frame 0 */ + write_short_int(fp, 0); + + /* write the locals */ + write_short_int(fp, 1); + tag = 7; + if (fp != NULL) + fwrite(&tag, 1, 1, fp); + write_short_int(fp, cp_add_class("M")); + + + /* 0 stack entries */ + write_short_int(fp, 0); + + /* write the frame 1 */ + write_short_int(fp, 6); + + /* write the locals*/ + write_short_int(fp, 1); + tag = 7; + if (fp != NULL) + fwrite(&tag, 1, 1, fp); + write_short_int(fp, cp_add_class("M")); + + /* 1 stack entry */ + write_short_int(fp, 1); + tag = 7; + if (fp != NULL) + fwrite(&tag, 1, 1, fp); + write_short_int(fp, cp_add_class("java/lang/Exception")); + + + /* write the frame 2 */ + write_short_int(fp, 7); + + /* write the locals */ + write_short_int(fp, 1); + tag = 7; + if (fp != NULL) + fwrite(&tag, 1, 1, fp); + write_short_int(fp, cp_add_class("M")); + + /* 0 stack entries */ + write_short_int(fp, 0); + +} + + +/* + Creates the code for the following methods: + + public void keyPressed(int keyCode) + { + KC = keyCode; + KP = keyCode; + } + + public void keyReleased(int keyCode) + { + KP = 0; + } +*/ +void write_keypressed_method(FILE *fp) +{ + bytecode *code = bytecode_create(); + if (code == NULL) + die(1); + + /* create the code */ + bytecode_append(code, iload_1$); + bytecode_append(code, dup$); + bytecode_append(code, putstatic$); + bytecode_append_short_int(code, cp_add_fieldref("M", "KC", "I")); + bytecode_append(code, putstatic$); + bytecode_append_short_int(code, cp_add_fieldref("M", "KP", "I")); + + bytecode_append(code, return$); + + /* write the method headers */ + + /* write access flags, ACC_PUBLIC */ + write_short_int(fp, 0x0001); + + /* write method name */ + write_short_int(fp, cp_add_utf8("keyPressed")); + + /* write method descriptor */ + write_short_int(fp, cp_add_utf8("(I)V")); + + /* write 1 attribute */ + write_short_int(fp, 1); + + /* write the Code attribute */ + write_short_int(fp, cp_add_utf8("Code")); + write_long_int(fp, code->bytecode_pos + 12); + + /* write the max stack */ + write_short_int(fp, 2); + + /* max locals for program block */ + write_short_int(fp, 2); + + + /* code length */ + write_long_int(fp, code->bytecode_pos); + + /* write the code itself */ + if (fp != NULL) + fwrite(code->bytecode, 1, code->bytecode_pos, fp); + + bytecode_destroy(code); + + write_short_int(fp, 0); + write_short_int(fp, 0); +} +void write_keyreleased_method(FILE *fp) +{ + bytecode *code = bytecode_create(); + if (code == NULL) + die(1); + + /* create the code */ + bytecode_append(code, iconst_0$); + bytecode_append(code, putstatic$); + bytecode_append_short_int(code, cp_add_fieldref("M", "KP", "I")); + + bytecode_append(code, return$); + + /* write the method headers */ + + /* write access flags, ACC_PUBLIC */ + write_short_int(fp, 0x0001); + + /* write method name */ + write_short_int(fp, cp_add_utf8("keyReleased")); + + /* write method descriptor */ + write_short_int(fp, cp_add_utf8("(I)V")); + + /* write 1 attribute */ + write_short_int(fp, 1); + + /* write the Code attribute */ + write_short_int(fp, cp_add_utf8("Code")); + write_long_int(fp, code->bytecode_pos + 12); + + /* write the max stack */ + write_short_int(fp, 2); + + /* max locals for program block */ + write_short_int(fp, 2); + + + /* code length */ + write_long_int(fp, code->bytecode_pos); + + /* write the code itself */ + if (fp != NULL) + fwrite(code->bytecode, 1, code->bytecode_pos, fp); + + bytecode_destroy(code); + + write_short_int(fp, 0); + write_short_int(fp, 0); +} + + +/* + Creates the code for the class constructor. +*/ +void write_constructor(FILE *fp) +{ + bytecode *code = bytecode_create(); + if (code == NULL) + die(1); + + /* create the code */ + switch (canvasType) + { + case NORMAL: + bytecode_append(code, aload_0$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Canvas", "", "()V")); + break; + case FULL_NOKIA: + bytecode_append(code, aload_0$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("com/nokia/mid/ui/FullCanvas", "", "()V")); + break; + case FULL_MIDP20: + bytecode_append(code, aload_0$); + bytecode_append(code, iconst_0$); + bytecode_append(code, invokespecial$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/game/GameCanvas", "", "(Z)V")); + + bytecode_append(code, aload_0$); + bytecode_append(code, iconst_1$); + bytecode_append(code, invokevirtual$); + bytecode_append_short_int(code, cp_add_methodref("javax/microedition/lcdui/Canvas", "setFullScreenMode", "(Z)V")); + break; + } + + bytecode_append(code, return$); + + /* write the method headers */ + + /* write access flags, ACC_PUBLIC */ + write_short_int(fp, 0x0001); + + /* write method name */ + write_short_int(fp, cp_add_utf8("")); + + /* write method descriptor */ + write_short_int(fp, cp_add_utf8("()V")); + + /* write 1 attribute */ + write_short_int(fp, 1); + + /* write the Code attribute */ + write_short_int(fp, cp_add_utf8("Code")); + write_long_int(fp, code->bytecode_pos + 12); + + /* write the max stack */ + write_short_int(fp, 10); + + /* max locals for program block */ + write_short_int(fp, 2); + + + /* code length */ + write_long_int(fp, code->bytecode_pos); + + /* write the code itself */ + if (fp != NULL) + fwrite(code->bytecode, 1, code->bytecode_pos, fp); + + bytecode_destroy(code); + + write_short_int(fp, 0); + write_short_int(fp, 0); + +} + + +/* + Write the variables from the block as fields into the + given class file. If fp==NULL only add constants into + the constant pool. +*/ +void write_block_fields(name_table *names, FILE *fp) +{ + char descriptor[128]; + + if ((names->descriptor != NULL) + && (names->descriptor->identifier_class == variable_name)) + { + /* access flags: ACC_PUBLIC and ACC_STATIC */ + write_short_int(fp, 0x0001 | 0x0008); + + /* write the name index */ + lowercase(names->name->cstr); + write_short_int(fp, cp_add_utf8(names->name->cstr)); + + /* write the descriptor index */ + get_field_descriptor(names->descriptor->variable_type, descriptor); + write_short_int(fp, cp_add_utf8(descriptor)); + + /* write 0 attributes */ + write_short_int(fp, 0); + } + + /* write the left child */ + if ((names->descriptor != NULL) + && (names->left_child != NULL)) + { + write_block_fields(names->left_child, fp); + } + + /* write the right child */ + if ((names->descriptor != NULL) + && (names->right_child != NULL)) + { + write_block_fields(names->right_child, fp); + } +} + + +void write_locals_stackmap(FILE *fp, identifier *block_identifier, int *stack_map_size) +{ + type_list *it = block_identifier->parameters; + write_stackmap(fp, it, stack_map_size); + + /* for functions, add the return value */ + if (block_identifier->identifier_class == function_name) + { + it = type_list_create(); + type_list_append(it, block_identifier->return_type); + write_stackmap(fp, it, stack_map_size); + type_list_destroy(it); + } + + it = block_identifier->variables; + write_stackmap(fp, it, stack_map_size); +} + +void write_stackmap(FILE *fp, type_list *it, int *stack_map_size) +{ + + while (it != NULL) + { + char c; + + if (it->data != NULL) + { + switch(it->data->type_class) + { + case integer_type: + case char_type: + case boolean_type: + c = 1; + if (fp != NULL) + fwrite(&c, 1, 1, fp); + (*stack_map_size) ++; + break; + + case real_type: + { + if (mathType == 1) + { + c = 1; + if (fp != NULL) + fwrite(&c, 1, 1, fp); + (*stack_map_size) ++; + } + else + { + c = 7; + if (fp != NULL) + fwrite(&c, 1, 1, fp); + write_short_int(fp, cp_add_class("Real")); + (*stack_map_size) += 3; + } + } + break; + + case string_type: + c = 7; + if (fp != NULL) + fwrite(&c, 1, 1, fp); + write_short_int(fp, cp_add_class("java/lang/String")); + (*stack_map_size) += 3; + break; + + case image_type: + c = 7; + if (fp != NULL) + fwrite(&c, 1, 1, fp); + write_short_int(fp, cp_add_class("javax/microedition/lcdui/Image")); + (*stack_map_size) += 3; + break; + + case command_type: + c = 7; + if (fp != NULL) + fwrite(&c, 1, 1, fp); + write_short_int(fp, cp_add_class("javax/microedition/lcdui/Command")); + (*stack_map_size) += 3; + break; + + + case stream_type: + c = 7; + if (fp != NULL) + fwrite(&c, 1, 1, fp); + write_short_int(fp, cp_add_class("java/io/InputStream")); + (*stack_map_size) += 3; + break; + + case record_store_type: + c = 7; + if (fp != NULL) + fwrite(&c, 1, 1, fp); + write_short_int(fp, cp_add_class("javax/microedition/rms/RecordStore")); + (*stack_map_size) += 3; + break; + + case http_type: + c = 7; + if (fp != NULL) + fwrite(&c, 1, 1, fp); + write_short_int(fp, cp_add_class("H")); + (*stack_map_size) += 3; + break; + + case alert_type: + c = 7; + if (fp != NULL) + fwrite(&c, 1, 1, fp); + write_short_int(fp, cp_add_class("Ljavax/microedition/lcdui/AlertType;")); + (*stack_map_size) += 3; + break; + + case array_type: + { + char descriptor[512]; + char element_type[128]; + int i, len; + + get_field_descriptor(it->data->element_type, element_type); + + len = type_list_length(it->data->dimensions_list); + for(i=0; i < len; i++) + { + descriptor[i] = '['; + } + + descriptor[len] = '\0'; + + sprintf(descriptor + len, "%s", element_type); + + c = 7; + if (fp != NULL) + fwrite(&c, 1, 1, fp); + write_short_int(fp, cp_add_class(descriptor)); + (*stack_map_size) += 3; + } + break; + + case record_type: + { + char descriptor[16]; + c = 7; + if (fp != NULL) + fwrite(&c, 1, 1, fp); + sprintf(descriptor, "R_%d", it->data->unique_record_ID); + write_short_int(fp, cp_add_class(descriptor)); + (*stack_map_size) += 3; + } + break; + } + } + + it = it->next; + } +} diff --git a/MPC.3.5.LINUX/structures/block.h b/MPC.3.5.LINUX/structures/block.h new file mode 100644 index 0000000..0d9acbb --- /dev/null +++ b/MPC.3.5.LINUX/structures/block.h @@ -0,0 +1,90 @@ +/******************************************************************** + + block.h - structures and functions used to hold program + block descriptions + + Niksa Orlic, 2004-04-23 + +********************************************************************/ + +#include + +/* + The structure to hold description for + one block; +*/ +struct block_struct +{ + struct block_struct *parent_block; + + name_table *names; + + string *block_name; + + int next_variable_index; + int next_parameter_index; + + bytecode *code; + + struct block_struct **children; + int children_count; +}; + +typedef struct block_struct block; + +/* canvas types */ +#define NORMAL 0 +#define FULL_MIDP20 1 +#define FULL_NOKIA 2 + + +block* block_create(block*, string*); +void block_destroy(block*); + +int block_check_name(block*, char*); + +void add_real_constant(block*, float, char*); +void add_integer_constant(block*, long int, char*); +void add_char_constant(block*, char, char*); +void add_boolean_constant(block*, char, char*); +void add_string_constant(block*, string*, char*); + +void add_variables(block*, string_list*, type*); + +void add_type(block*, string*, type*); + +void add_procedure(block*, string*, type_list*, int, int); +void add_function(block*, string*, type_list*,type*, int, int); + +void load_extern_library(string*); +void read_library_file(FILE*, struct unit_struct*); +void read_symbol_file(FILE*, struct unit_struct*); + +void add_parameters(block*, string_list*, type*, int); + +void check_forward_declaration(identifier*, type_list*, + int, type*); +void check_unmatched_forward_declarations(block*, name_table*); + +void transform_break_stmts(bytecode*, int, int, int); + +type *type_from_name(block*, char*); +type *get_constant_type(block*, char*); +type *get_variable_type(block*, char*); +identifier *get_constant_identifier(block*, char*); +identifier *get_identifier(block*, char*); + +void initialize_variable(block*, identifier*, char*, int, char*); + +void create_class_file(block *root_block, FILE *fp); +void write_method(block *current_block, FILE *fp); +void write_block_fields(name_table *, FILE*); + +void write_paint_method(FILE *fp); +void write_constructor(FILE *fp); +void write_run_method(FILE *fp); +void write_keypressed_method(FILE *fp); +void write_keyreleased_method(FILE *fp); + +void write_locals_stackmap(FILE *fp, identifier *block_identifier, int* stack_map_size); +void write_stackmap(FILE *fp, type_list *it, int *stack_map_size); diff --git a/MPC.3.5.LINUX/structures/identifier.c b/MPC.3.5.LINUX/structures/identifier.c new file mode 100644 index 0000000..6485b35 --- /dev/null +++ b/MPC.3.5.LINUX/structures/identifier.c @@ -0,0 +1,506 @@ +/******************************************************************** + + identifier.c - handling identifier descriptions + + Niksa Orlic, 2004-04-28 + +********************************************************************/ + +#include "../util/strings.h" +#include "../util/error.h" +//#include "../util/message.h" +#include "type_list.h" +#include "string_list.h" +#include "type.h" +#include "identifier.h" +#include "name_table.h" +#include "../classgen/bytecode.h" +#include "block.h" +#include "unit.h" +#include "../util/memory.h" + +#include +#include + +extern FILE* symbols_file; + +/* + Creates an empty identifier +*/ + +identifier *identifier_create() +{ + identifier *new_identifier; + new_identifier = (identifier*) mem_alloc(sizeof(identifier)); + + if (new_identifier == NULL) + die(1); + + new_identifier->identifier_class = none; + + new_identifier->standard_function = 0; + + new_identifier->variables = NULL; + + new_identifier->forward_declaration = 0; + + new_identifier->unit_block = NULL; + + new_identifier->unit_function = 0; + new_identifier->container_unit = NULL; + + return new_identifier; +} + + +/* + Deletes an identifier +*/ +void identifier_destroy(identifier *item) +{ + switch (item->identifier_class) + { + case constant_name: + { + if (item->constant_type->type_class == string_type) + string_destroy(item->constant_string_value); + type_destroy(item->constant_type); + break; + } + + case variable_name: + { + if (item->variable_type != NULL) + type_destroy(item->variable_type); + break; + } + + case type_name: + { + type_destroy(item->defined_type); + break; + } + + case procedure_name: + { + type_list_destroy(item->parameters); + if (item->variables != NULL) + type_list_destroy(item->variables); + break; + } + + case function_name: + { + type_destroy(item->return_type); + type_list_destroy(item->parameters); + if (item->variables != NULL) + type_list_destroy(item->variables); + break; + } + + case parameter_name: + { + type_destroy(item->parameter_type); + break; + } + + case unit_name: + { + unit_destroy(item->unit_block); + break; + } + } + + mem_free(item); +} + +/* + Create a copy of a given identifier +*/ +identifier *identifier_duplicate(identifier *item) +{ + identifier *new_identifier; + new_identifier = (identifier*) mem_alloc(sizeof(identifier)); + + if (new_identifier == NULL) + die(1); + + new_identifier->identifier_class = item->identifier_class; + new_identifier->unit_function = item->unit_function; + + switch(new_identifier->identifier_class) + { + case constant_name: + { + new_identifier->constant_type = type_duplicate(item->constant_type); + switch(item->constant_type->type_class) + { + case integer_type: + { + new_identifier->constant_int_value = item->constant_int_value; + break; + } + case char_type: + { + new_identifier->constant_int_value = item->constant_int_value; + break; + } + case string_type: + { + new_identifier->constant_string_value = string_duplicate(item->constant_string_value); + break; + } + case boolean_type: + { + new_identifier->constant_int_value = item->constant_int_value; + break; + } + case real_type: + { + new_identifier->constant_real_value = item->constant_real_value; + break; + } + case command_type: + case record_store_type: + case http_type: + case image_type: + case stream_type: + case alert_type: + { + break; + } + default: + { + die(11); + } + } + break; + } + + case variable_name: + { + new_identifier->variable_type = type_duplicate(item->variable_type); + new_identifier->variable_index = item->variable_index; + break; + } + + case type_name: + { + new_identifier->defined_type = type_duplicate(item->defined_type); + break; + } + + case procedure_name: + { + new_identifier->parameters = type_list_duplicate(item->parameters); + new_identifier->forward_declaration = item->forward_declaration; + new_identifier->standard_function = item->standard_function; + new_identifier->variables = type_list_duplicate(item->variables); + if (item->container_unit != NULL) + new_identifier->container_unit = unit_duplicate(item->container_unit); + else + new_identifier->container_unit = NULL; + break; + } + + case function_name: + { + new_identifier->parameters = type_list_duplicate(item->parameters); + new_identifier->return_type = type_duplicate(item->return_type); + new_identifier->forward_declaration = item->forward_declaration; + new_identifier->standard_function = item->standard_function; + new_identifier->variables = type_list_duplicate(item->variables); + break; + } + + case parameter_name: + { + new_identifier->parameter_type = type_duplicate(item->parameter_type); + new_identifier->is_parameter_variable = item->is_parameter_variable; + new_identifier->parameter_index = item->parameter_index; + break; + } + + case unit_name: + { + new_identifier->unit_block = unit_duplicate(item->unit_block); + break; + } + + } + + if (item->container_unit != NULL) + new_identifier->container_unit = unit_duplicate(item->container_unit); + else + new_identifier->container_unit = NULL; + + if (item->unit_block != NULL) + new_identifier->unit_block = unit_duplicate(item->unit_block); + else + new_identifier->unit_block = NULL; + + return new_identifier; +} + +void bsf_write_integer_constant(long int value, char* name) +{ + char tag = 1; + char type = 1; + fwrite(&tag, 1, 1, symbols_file); + bsf_write_STRING(name); + fwrite(&type, 1, 1, symbols_file); + fwrite(&value, sizeof(long int), 1, symbols_file); +} + +void bsf_write_real_constant(float value, char* name) +{ + char tag = 1; + char type = 2; + fwrite(&tag, 1, 1, symbols_file); + bsf_write_STRING(name); + fwrite(&type, 1, 1, symbols_file); + fwrite(&value, sizeof(float), 1, symbols_file); +} + +void bsf_write_boolean_constant(char value, char* name) +{ + char tag = 1; + char type = 3; + fwrite(&tag, 1, 1, symbols_file); + bsf_write_STRING(name); + fwrite(&type, 1, 1, symbols_file); + fwrite(&value, sizeof(char), 1, symbols_file); +} + +void bsf_write_char_constant(char value, char* name) +{ + char tag = 1; + char type = 4; + fwrite(&tag, 1, 1, symbols_file); + bsf_write_STRING(name); + fwrite(&type, 1, 1, symbols_file); + fwrite(&value, sizeof(char), 1, symbols_file); +} + +void bsf_write_string_constant(string* value, char* name) +{ + char tag = 1; + char type = 5; + fwrite(&tag, 1, 1, symbols_file); + bsf_write_STRING(name); + fwrite(&type, 1, 1, symbols_file); + + bsf_write_STRING(string_get_cstr(value)); +} + +void bsf_write_variables(string_list* names, type* var_type) +{ + string_list *it = names; + + while ((it != NULL) && (it->data != NULL)) + { + char tag = 2; + fwrite(&tag, 1, 1, symbols_file); + bsf_write_STRING(string_get_cstr(it->data)); + bsf_write_TYPE(var_type); + it = it->next; + } +} + +void bsf_write_type(string* type_name, type* type_type) +{ + char tag = 3; + fwrite(&tag, 1, 1, symbols_file); + bsf_write_STRING(string_get_cstr(type_name)); + bsf_write_TYPE(type_type); +} + +void bsf_write_procedure(string* name, type_list* parameters) +{ + type_list *it; + char params_count = 0; + + char tag = 4; + fwrite(&tag, 1, 1, symbols_file); + bsf_write_STRING(string_get_cstr(name)); + + params_count = type_list_length(parameters); + fwrite(¶ms_count, 1, 1, symbols_file); + + it = parameters; + + while ((it != NULL) && (it->data != NULL)) + { + bsf_write_TYPE(it->data); + it = it->next; + } +} + +void bsf_write_function(string* name, type_list* parameters, type* return_type) +{ + type_list *it; + char params_count = 0; + + char tag = 5; + fwrite(&tag, 1, 1, symbols_file); + bsf_write_STRING(string_get_cstr(name)); + + bsf_write_TYPE(return_type); + + params_count = type_list_length(parameters); + fwrite(¶ms_count, 1, 1, symbols_file); + + it = parameters; + + while ((it != NULL) && (it->data != NULL)) + { + bsf_write_TYPE(it->data); + it = it->next; + } +} + +void bsf_write_STRING(char* value) +{ + char len = strlen(value); + lowercase(value); + fwrite(&len, 1, 1, symbols_file); + fwrite(value, 1, len, symbols_file); +} + +string* bsf_read_STRING(FILE* file) +{ + char length; + char *buffer; + string* string_value; + + fread(&length, 1, 1, file); + buffer = (char*) malloc(length + 5); + fread(buffer, 1, length, file); + buffer[length] = '\0'; + string_value = string_from_cstr(buffer); + free(buffer); + + return string_value; +} + +void bsf_write_TYPE(type* type_desc) +{ + // j-a-s-d + #ifdef __GNUC__ + fwrite((char *)&type_desc->type_class, 1, 1, symbols_file); + #else + fwrite(&(char)type_desc->type_class, 1, 1, symbols_file); + #endif + + if (type_desc->type_class == array_type) + { + char dimensions; + type_list *it; + + bsf_write_TYPE(type_desc->element_type); + + dimensions = type_list_length(type_desc->dimensions_list); + fwrite(&dimensions, 1, 1, symbols_file); + + it = type_desc->dimensions_list; + + while ((it != NULL) && (it->data != NULL)) + { + bsf_write_TYPE(it->data); + it = it->next; + } + } + + if (type_desc->type_class == record_type) + { + char elements; + string_list *name_it; + type_list *type_it; + + elements = string_list_length(type_desc->elements_name_list); + fwrite(&elements, 1, 1, symbols_file); + + name_it = type_desc->elements_name_list; + type_it = type_desc->elements_type_list; + + while ((name_it != NULL) && (name_it->data != NULL)) + { + bsf_write_STRING(string_get_cstr(name_it->data)); + bsf_write_TYPE(type_it->data); + + name_it = name_it->next; + type_it = type_it->next; + } + + fwrite(&type_desc->unique_record_ID, 4, 1, symbols_file); + } + + if (type_desc->type_class == interval_type) + { + // j-a-s-d + #ifdef __GNUC__ + fwrite((char *)&type_desc->interval_base_type, 1, 1, symbols_file); + #else + fwrite(&(char)type_desc->interval_base_type, 1, 1, symbols_file); + #endif + fwrite(&type_desc->first_element, 4, 1, symbols_file); + fwrite(&type_desc->last_element, 4, 1, symbols_file); + } +} + +type* bsf_read_TYPE(FILE* symbol_file) +{ + char type_class; + + type* result_type = type_create(); + + fread(&type_class, 1, 1, symbol_file); + result_type->type_class = (enum en_type_class)type_class; + + if (result_type->type_class == array_type) + { + char dimensions; + + result_type->element_type = bsf_read_TYPE(symbol_file); + fread(&dimensions, 1, 1, symbol_file); + + result_type->dimensions_list = type_list_create(); + + while (dimensions > 0) + { + type_list_append(result_type->dimensions_list, bsf_read_TYPE(symbol_file)); + dimensions --; + } + } + + if (result_type->type_class == record_type) + { + char elements; + fread(&elements, 1, 1, symbol_file); + + result_type->elements_name_list = string_list_create(); + result_type->elements_type_list = type_list_create(); + + while (elements > 0) + { + string_list_append(result_type->elements_name_list, bsf_read_STRING(symbol_file)); + type_list_append(result_type->elements_type_list, bsf_read_TYPE(symbol_file)); + elements --; + } + + fread(&result_type->unique_record_ID, sizeof(int), 1, symbol_file); + } + + if (result_type->type_class == interval_type) + { + char base_type_class; + fread(&base_type_class, 1, 1, symbol_file); + + result_type->interval_base_type = (enum en_type_class)base_type_class; + + fread(&result_type->first_element, sizeof(long int), 1, symbol_file); + fread(&result_type->last_element, sizeof(long int), 1, symbol_file); + } + + return result_type; +} diff --git a/MPC.3.5.LINUX/structures/identifier.h b/MPC.3.5.LINUX/structures/identifier.h new file mode 100644 index 0000000..ce04ad4 --- /dev/null +++ b/MPC.3.5.LINUX/structures/identifier.h @@ -0,0 +1,169 @@ +/******************************************************************** + + identifier.h - structures used to hold identifier descriptions + + Niksa Orlic, 2004-04-28 + +********************************************************************/ + +/* + When an unit compiles, it exports public symbols into + + unit_name.bsf (binary symbol file) + + The bsf file contains an array of symbol entries. + + Symbols are divided into the following categories: + + Constant + --------- + 1 byte identifier: set to 1 to indicate that it is an constant + STRING - symbol name + 1 byte to indicate the constant type, (1-integer, 2-real, 3-boolean, 4-char, 5-string) + value: if a constant is integer or float, this is 4-byte field + if a constant is string, then a STRING entry follows + if a constant is a boolean or a char, 1 byte follows + + Variable + -------- + 1 byte indentifier: set to 2 for variable + STRING - symbol name + TYPE - variable type + + Type + ---- + 1 byte identifier: set to 3 for type definition + STRING - symbol name + TYPE - the type description + + Procedure + --------- + 1 byte identifier: set to 4 for procedures + STRING - name + 1 byte - the number of parameters (n) + TYPE[n] - parameters type + + Function + -------- + 1 byte identifier: set to 5 for functions + STRING - name + TYPE - return type + 1 byte - number of parameters + TYPE[n] - parameter types + + + Special fields used are: + + STRING + ------ + 1 byte containing the string length (n) + n bytes with the string data (NOT zero terminated) + + TYPE + ---- + 1 byte : type class, a value from en_type_class enumeration + + if a type is an array: TYPE element_type + 1 byte dimensions num + TYPE[n] dimension interval types + + if a type is a record: 1 byte number of elements + {STRING, TYPE} [n] for each element there is a pair name/type describing the member + 4 bytes record ID + + if a type is an interval: 1 byte interval base type (from the en_type_class) + 4 bytes: starting value + 4 bytes: ending value + +*/ + +#include + +/* + The possible identifier classes +*/ +enum en_identifier_class +{ + none, + program_name, + constant_name, + variable_name, + type_name, + procedure_name, + function_name, + parameter_name, + unit_name +}; + + +/* + The structure used to hold the description of + a single identifier +*/ +struct identifier_descriptor_struct +{ + enum en_identifier_class identifier_class; + + /* for constants */ + type *constant_type; + int constant_int_value; + float constant_real_value; + string *constant_string_value; + + /* for variables */ + type *variable_type; + int variable_index; + + /* for types */ + type *defined_type; + + /* for procedures and functions */ + type *return_type; + type_list *parameters; /* the list of formal parameters to the function, each one is identifier_descriptor */ + type_list *variables; /* the list of names of variables */ + int forward_declaration; + int standard_function; + int subprogram_linenum; /* the number of the first line of the subprogram */ + int unit_function; /* used by all items that are defined inside an unit , 1 says that the item is inside a unit */ + struct unit_struct *container_unit; + + /* for parameters */ + type *parameter_type; + short int is_parameter_variable; + int parameter_index; + + /* for units */ + struct unit_struct *unit_block; + + /* this field is set in get_identifier function and is true + if this struct describes identifier directly located inside + the program block*/ + int belongs_to_program_block; +}; + + +typedef struct identifier_descriptor_struct identifier; + +identifier *identifier_create(); +void identifier_destroy(identifier*); +identifier *identifier_duplicate(identifier*); + +struct type_struct; +struct string_list_struct; +struct string_struct; + +void bsf_write_integer_constant(long int value, char* name); +void bsf_write_real_constant(float value, char* name); +void bsf_write_boolean_constant(char value, char* name); +void bsf_write_char_constant(char value, char* name); +void bsf_write_string_constant(string* value, char* name); +void bsf_write_variables(struct string_list_struct* names, struct type_struct* var_type); +void bsf_write_type(string* type_name, struct type_struct* type_type); +void bsf_write_procedure(string* name, type_list* parameters); +void bsf_write_function(string* name, type_list* parameters, type* return_type); +void bsf_write_STRING(char* value); +void bsf_write_TYPE(type* type_desc); + +struct string_struct* bsf_read_STRING(FILE*); +struct type_struct* bsf_read_TYPE(FILE*); + diff --git a/MPC.3.5.LINUX/structures/name_table.c b/MPC.3.5.LINUX/structures/name_table.c new file mode 100644 index 0000000..b7cd2e8 --- /dev/null +++ b/MPC.3.5.LINUX/structures/name_table.c @@ -0,0 +1,213 @@ +/******************************************************************** + + name-table.c - the functions used for name table handling. The + name table is a binary tree. The node's left child has the name + alphabetically before the name in the node, and the right child + has the name which is alphabetically after the name in the node. + + Niksa Orlic, 2004-04-25 + +********************************************************************/ + +#include "../util/strings.h" +#include "../util/error.h" +//#include "../util/message.h" +#include "type_list.h" +#include "string_list.h" +#include "type.h" +#include "identifier.h" +#include "name_table.h" +#include "../classgen/bytecode.h" +#include "block.h" +#include "unit.h" +#include "../util/memory.h" + +#include +#include + + +/* + Create an empty name table. +*/ +name_table *name_table_create() +{ + name_table *new_item; + new_item = (name_table*) mem_alloc(sizeof(name_table)); + + if (new_item == NULL) + die(1); + + new_item->left_child = NULL; + new_item->right_child = NULL; + new_item->name = NULL; + new_item->descriptor = NULL; + + new_item->last = new_item; + new_item->next = NULL; + + return new_item; +} + + +/* + Destroy an allocated name table and free all memory. +*/ +void name_table_destroy(name_table *item) +{ + if (item == NULL) + return; + + if (item->name != NULL) + string_destroy(item->name); + + if (item->descriptor != NULL) + identifier_destroy(item->descriptor); + + if (item->left_child != NULL) + name_table_destroy(item->left_child); + + if (item->right_child != NULL) + name_table_destroy(item->right_child); +} + +/* +name_table *name_table_duplicate(name_table *item) +{ + name_table *new_item = mem_alloc(sizeof(name_table)); + + new_item->descriptor = identifier_duplicate(item->descriptor); + new_item->name = string_duplicate(item->name); + + if (item->left_child != NULL) + new_item->left_child = name_table_duplicate(item->left_child); + else + new_item->left_child = NULL; + + if (item->right_child != NULL) + new_item->right_child = name_table_duplicate(item->right_child); + else + new_item->right_child = NULL; + + return new_item; +}*/ + + +/* + Inserts an entry into the name table. The string and the descriptor are + not copied, only pointers to the string and descriptor are copied. +*/ +void name_table_insert(name_table *root, string *name, + identifier *descriptor) +{ + int string_compare; + name_table *item, *new_item; + + if (root == NULL) + return; + + if (root->name == NULL) + { + /* the root item is empty, insert the value + into the root item */ + + root->name = name; + root->descriptor = descriptor; + return; + } + + + /* go through the tree to the first free element */ + item = root; + + do + { + string_compare = STRING_COMPARE(string_get_cstr(name), string_get_cstr(item->name)); + + if (string_compare == 0) + { + /* an error occured, just return */ + return; + } + + if (string_compare < 0) + { + if (item->left_child == NULL) + break; + + item = item->left_child; + } + + if (string_compare > 0) + { + if (item->right_child == NULL) + break; + + item = item->right_child; + } + } while (1); /* until the break is called */ + + new_item = name_table_create(); + new_item->name = name; + new_item->descriptor = descriptor; + new_item->next = NULL; + + root->last->next = new_item; + root->last = new_item; + + if (string_compare < 0) + item->left_child = new_item; + + if (string_compare > 0) + item->right_child = new_item; + +} + + +/* + Searches name table for an element with a given name. + Return the identifier descriptor if found or NULL if + not found. +*/ +identifier* name_table_find(name_table *item, string *name) +{ + int string_compare; + + while ((item != NULL) && (item->name != NULL)) + { + string_compare = STRING_COMPARE(string_get_cstr(name), string_get_cstr(item->name)); + + if (string_compare == 0) + return item->descriptor; + + if (string_compare < 0) + item = item->left_child; + + if (string_compare > 0) + item = item->right_child; + + } + + return NULL; +} + +identifier *name_table_find_cstr(name_table *item, char *name) +{ + int string_compare; + + while ((item != NULL) && (item->name != NULL)) + { + string_compare = STRING_COMPARE(name, string_get_cstr(item->name)); + + if (string_compare == 0) + return item->descriptor; + + if (string_compare < 0) + item = item->left_child; + + if (string_compare > 0) + item = item->right_child; + + } + + return NULL; +} \ No newline at end of file diff --git a/MPC.3.5.LINUX/structures/name_table.h b/MPC.3.5.LINUX/structures/name_table.h new file mode 100644 index 0000000..fc0216c --- /dev/null +++ b/MPC.3.5.LINUX/structures/name_table.h @@ -0,0 +1,40 @@ +/******************************************************************** + + name_table.h - structures and function prototypes for handling + names + + Niksa Orlic, 2004-04-28 + +********************************************************************/ + +struct name_table_struct +{ + string *name; + struct name_table_struct *left_child; + struct name_table_struct *right_child; + + struct name_table_struct *last; // used only in the first item + struct name_table_struct *next; + + identifier *descriptor; +}; + +typedef struct name_table_struct name_table; + + +name_table *name_table_create(); +//name_table *name_table_duplicate(name_table*); +void name_table_destroy(name_table *item); +void name_table_insert(name_table *root, string *name, + identifier *descriptor); +identifier* name_table_find(name_table *item, string *name); +identifier *name_table_find_cstr(name_table *item, char *name); + +/* + Define the case insensitive string-compare routine. + + _stricmp on MSVC + strcasecmp on gcc (I think) +*/ +//#define STRING_COMPARE _stricmp +#define STRING_COMPARE strcasecmp diff --git a/MPC.3.5.LINUX/structures/string_list.c b/MPC.3.5.LINUX/structures/string_list.c new file mode 100644 index 0000000..a8f1453 --- /dev/null +++ b/MPC.3.5.LINUX/structures/string_list.c @@ -0,0 +1,128 @@ +/******************************************************************** + + string_list.c - function for handling string lists + + Niksa Orlic, 2004-04-28 + +********************************************************************/ + +#include "../util/strings.h" +#include "../util/error.h" +//#include "../util/message.h" +#include "string_list.h" + + +#include +#include + +/* + Create a new empty list +*/ +string_list *string_list_create() +{ + string_list *new_list = (string_list*) mem_alloc(sizeof(string_list)); + + if (new_list == NULL) + die(1); + + new_list->data = NULL; + new_list->next = NULL; + + return new_list; +} + + +/* + Delete the list and the data in the list +*/ +void string_list_destroy(string_list* item) +{ + string_list *it, *next; + + it = item; + while (it != NULL) + { + next = it->next; + + if (it->data != NULL) + string_destroy(it->data); + + mem_free (it); + + it = next; + } +} + +/* + Creates a copy of the list, the data + values are also copied +*/ +string_list *string_list_duplicate(string_list *item) +{ + string_list *new_list; + + new_list = string_list_create(); + + if (item->data == NULL) + return new_list; + + do + { + if(item->data == NULL) + break; + + string_list_append(new_list, string_duplicate(item->data)); + item = item->next; + } while (item != NULL); + + return new_list; +} + + +/* + Add an element into the list, the data is + copied. +*/ +void string_list_append(string_list *item, string *data) +{ + string_list *new_element; + + if (item->data == NULL) + item->data = string_duplicate(data); + else + { + new_element = (string_list*) mem_alloc(sizeof(string_list)); + + if (new_element == NULL) + die(1); + + new_element->data = string_duplicate(data); + new_element->next = NULL; + + /* move to the end of the list */ + while (item->next != NULL) + item = item->next; + + item->next = new_element; + } +} + + +/* + Returns the number of elements in the list +*/ +int string_list_length(string_list *item) +{ + int counter = 0; + + if (item->data == NULL) + return counter; + + do + { + item = item->next; + counter ++; + } while (item != NULL); + + return counter; +} diff --git a/MPC.3.5.LINUX/structures/string_list.h b/MPC.3.5.LINUX/structures/string_list.h new file mode 100644 index 0000000..d735e73 --- /dev/null +++ b/MPC.3.5.LINUX/structures/string_list.h @@ -0,0 +1,22 @@ +/******************************************************************** + + string_list.h - list of strings + + Niksa Orlic, 2004-04-29 + +********************************************************************/ + +struct string_list_struct +{ + struct string_list_struct *next; + string *data; +}; + +typedef struct string_list_struct string_list; + +string_list *string_list_create(); +void string_list_destroy(string_list*); + +string_list *string_list_duplicate(string_list*); +void string_list_append(string_list*, string*); +int string_list_length(string_list*); diff --git a/MPC.3.5.LINUX/structures/type.c b/MPC.3.5.LINUX/structures/type.c new file mode 100644 index 0000000..4974774 --- /dev/null +++ b/MPC.3.5.LINUX/structures/type.c @@ -0,0 +1,329 @@ +/******************************************************************** + + type.c - function for handling types in pascal + + Niksa Orlic, 2004-04-28 + +********************************************************************/ + +#include "../util/strings.h" +#include "../util/error.h" +//#include "../util/message.h" +#include "type_list.h" +#include "string_list.h" +#include "type.h" +#include "identifier.h" +#include "name_table.h" +#include "../classgen/bytecode.h" +#include "block.h" +#include "../util/memory.h" + +#include +#include + +extern int linenum; + +/* + Create an empty type +*/ +type* type_create() +{ + type *new_type; + new_type = (type*) mem_alloc(sizeof(type)); + + if (new_type == NULL) + die(1); + + new_type->type_class = void_type; + + return new_type; +} + + +/* + Deletes a type +*/ +void type_destroy(type *item) +{ + if (item == NULL) + return; + + switch(item->type_class) + { + case array_type: + { + type_list_destroy(item->dimensions_list); + type_destroy(item->element_type); + break; + } + + case record_type: + { + type_list_destroy(item->elements_type_list); + string_list_destroy(item->elements_name_list); + break; + } + } + + mem_free(item); +} + + +/* + Create a copy of a type +*/ +type* type_duplicate(type *item) +{ + type *new_item; + new_item = (type*) mem_alloc(sizeof(type)); + + if (new_item == NULL) + die(1); + + memcpy(new_item, item, sizeof(type)); + + if (new_item->type_class == array_type) + { + new_item->dimensions_list = type_list_duplicate(item->dimensions_list); + new_item->element_type = type_duplicate(item->element_type); + } + + if (new_item->type_class == record_type) + { + new_item->elements_type_list = type_list_duplicate(item->elements_type_list); + new_item->elements_name_list = string_list_duplicate(item->elements_name_list); + new_item->unique_record_ID = item->unique_record_ID; + } + + return new_item; +} + + +/* + Return a nonzero value if both types are equal. +*/ +int type_equal(type *type1, type *type2) +{ + if (type1 == type2) + return 1; + + if ((type1 == NULL) || (type2 == NULL)) + return 0; + + if (type1->type_class != type2->type_class) + return 0; + + switch (type1->type_class) + { + case array_type: + { + if (!type_equal(type1->element_type, type2->element_type)) + return 0; + + if (type_list_different_parameter(type1->dimensions_list, + type2->dimensions_list) != 0) + return 0; + + break; + } + + case record_type: + { + return (type1->unique_record_ID == type2->unique_record_ID); + + break; + } + + case interval_type: + { + if (type1->interval_base_type != type2->interval_base_type) + return 0; + + if (type1->first_element != type2->first_element) + return 0; + + if (type1->last_element != type2->last_element) + return 0; + + break; + } + } + + return 1; +} + +/* + Return 0 if types are not equal; 1 if the types + are exactly the same, 2 if type1 is real and type2 int + or 3 if type2 is real and type1 int + + Also, char can be casted into string +*/ +int type_equal_cast(type *type1, type* type2) +{ + if (type_equal(type1, type2)) + return 1; + + if ((type1->type_class == real_type) + && (type2->type_class == integer_type)) + return 2; + + if ((type1->type_class == integer_type) + && (type2->type_class == real_type)) + return 3; + + if ((type1->type_class == string_type) + && (type2->type_class == char_type)) + return 2; + + if ((type1->type_class == char_type) + && (type2->type_class == string_type)) + return 3; + + return 0; +} + + +/* + Returns a name for any basic type, string 'unknown type' otherwise +*/ +string *type_get_name(type *basic_type) +{ + switch(basic_type->type_class) + { + case integer_type: + return string_from_cstr("integer"); + + case real_type: + return string_from_cstr("real"); + + case boolean_type: + return string_from_cstr("boolean"); + + case char_type: + return string_from_cstr("char"); + + case image_type: + return string_from_cstr("image"); + + case command_type: + return string_from_cstr("command"); + + case stream_type: + return string_from_cstr("stream"); + + case string_type: + return string_from_cstr("string"); + + case array_type: + return string_from_cstr("array"); + + case record_type: + return string_from_cstr("record"); + + case record_store_type: + return string_from_cstr("recordStore"); + + case http_type: + return string_from_cstr("http"); + + case alert_type: + return string_from_cstr("alert type"); + + case interval_type: + return string_from_cstr("interval"); + + default: + return string_from_cstr("unknown type"); + } + + return NULL; +} + + +/* + Check if any name from element_names already exists in + item->elements_name_list +*/ +void type_record_check_duplicate_names(type *item, string_list *element_names) +{ + string_list *item_list; + + while (element_names != NULL) + { + if (element_names->data != NULL) + { + item_list = item->elements_name_list; + + while (item_list != NULL) + { + if (item_list->data != NULL) + { + if (STRING_COMPARE(string_get_cstr(item_list->data), + string_get_cstr(element_names->data)) == 0) + { + add_error_message(418, string_get_cstr(item_list->data), ""); + } + } + + item_list = item_list->next; + } + } + + element_names = element_names->next; + } +} + + +/* + Add elements into a record type +*/ +void type_add_record(type *item, string_list *element_names, type *element_type) +{ + /* check for duplicate names in the names */ + type_record_check_duplicate_names(item, element_names); + + while (element_names != NULL) + { + if (element_names->data != NULL) + { + string_list_append(item->elements_name_list, element_names->data); + type_list_append(item->elements_type_list, element_type); + } + + element_names = element_names->next; + } +} + + +/* + Returns the type of an element of a given record type identified + by a given name. In case of an error, NULL is returned. +*/ +type* type_find_record_element(type *record, char *cstr) +{ + string_list *names; + type_list *types; + + if (record->type_class != record_type) + return NULL; + + names = record->elements_name_list; + types = record->elements_type_list; + + while (names != NULL) + { + if (names->data != NULL) + { + if(STRING_COMPARE(cstr, string_get_cstr(names->data)) == 0) + { + return type_duplicate(types->data); + } + } + + names = names->next; + types = types->next; + } + + return NULL; +} \ No newline at end of file diff --git a/MPC.3.5.LINUX/structures/type.h b/MPC.3.5.LINUX/structures/type.h new file mode 100644 index 0000000..0ec2852 --- /dev/null +++ b/MPC.3.5.LINUX/structures/type.h @@ -0,0 +1,74 @@ +/******************************************************************** + + type.h - structures used to hold descriptions of pascal types + + Niksa Orlic, 2004-04-28 + +********************************************************************/ + + +/* + The possible type classes +*/ +enum en_type_class +{ + error_type, /* used to detect errors */ + void_type, + integer_type, + real_type, + char_type, + boolean_type, + string_type, + array_type, + record_type, + interval_type, + image_type, + command_type, + stream_type, + record_store_type, + http_type, + alert_type /* this is only an internal type, the user cannot declare variables to be alert_type */ + + /* add our own types */ +} en_type_class; + +/* + The structure to hold description for a single + type. +*/ +struct type_struct +{ + enum en_type_class type_class; + + /* for array types */ + struct type_struct* element_type; /* the type of array elements */ + type_list *dimensions_list; /* the type for each dimension */ + + /* for record type */ + string_list *elements_name_list; /* the elements in record, their names */ + type_list *elements_type_list; /* the elements in record, their types */ + int unique_record_ID; /* the name that identifies the record */ + + /* for interval type */ + enum en_type_class interval_base_type; + long int first_element; + long int last_element; +}; + +typedef struct type_struct type; + + +type* type_create(); +void type_destroy(type*); + +type* type_duplicate(type*); + +int type_equal(type*, type*); +int type_equal_cast(type*, type*); + +string *type_get_name(type*); + +void type_record_check_duplicate_names(type*, string_list*); +void type_add_record(type*, string_list*, type*); + +type *type_find_record_element(type*, char*); \ No newline at end of file diff --git a/MPC.3.5.LINUX/structures/type_list.c b/MPC.3.5.LINUX/structures/type_list.c new file mode 100644 index 0000000..4ef2c75 --- /dev/null +++ b/MPC.3.5.LINUX/structures/type_list.c @@ -0,0 +1,236 @@ +/******************************************************************** + + type_list.c - function for handling type lists + + Niksa Orlic, 2004-04-28 + +********************************************************************/ + +#include "../util/strings.h" +#include "../util/error.h" +//#include "../util/message.h" +#include "type_list.h" +#include "string_list.h" +#include "type.h" +#include "identifier.h" +#include "name_table.h" +#include "../classgen/bytecode.h" +#include "block.h" +#include "../util/memory.h" + +#include + +/* + Create a new empty list +*/ +type_list *type_list_create() +{ + type_list *new_list = (type_list*) mem_alloc(sizeof(type_list)); + + if (new_list == NULL) + die(1); + + new_list->data = NULL; + new_list->next = NULL; + + return new_list; +} + + +/* + Delete the list with all associated data +*/ +void type_list_destroy(type_list* item) +{ + type_list *it, *next; + it = item; + + while (it != NULL) + { + next = it->next; + + if (it->data != NULL) + mem_free(it->data); + + mem_free (it); + + it = next; + } + +} + +/* + Creates a copy of the list, the data + values are also copied +*/ +type_list *type_list_duplicate(type_list *item) +{ + type_list *new_list; + + if (item == NULL) + return NULL; + + new_list = type_list_create(); + + if ((item == NULL) ||(item->data == NULL)) + return new_list; + + do + { + type_list_append(new_list, item->data); + item = item->next; + } while (item != NULL); + + return new_list; +} + + +/* + Add an element into the list, the data is + copied. +*/ +void type_list_append(type_list *item, struct type_struct *data) +{ + type_list *new_element; + + if (item->data == NULL) + item->data = type_duplicate(data); + else + { + new_element = (type_list*) mem_alloc(sizeof(type_list)); + + if (new_element == NULL) + die(1); + + new_element->data = type_duplicate(data); + new_element->next = NULL; + + /* move to the end of the list */ + while (item->next != NULL) + item = item->next; + + item->next = new_element; + } +} + + +/* + Returns the number of elements in the list +*/ +int type_list_length(type_list *item) +{ + int counter = 0; + + if (item->data == NULL) + return counter; + + do + { + item = item->next; + counter ++; + } while (item != NULL); + + return counter; +} + + +/* + Returns the index (starting with one) of the first + item in the list1 different than the parameetr in the list2, + 0 if the lists are equal, or -1 if the list1 is shorter than + the list2 and all elements in the list1 correspond to the first + n elements in the list2. +*/ +int type_list_different_parameter(type_list *list1, type_list *list2) +{ + int counter = 1; + + while (list1 != NULL) + { + if ((list2 == NULL) + || (list1->data == NULL) + || (list2->data == NULL) + || (!type_equal(list1->data, list2->data))) + { + if ((list2 != NULL) + && (list1->data == NULL) + && (list2->data == NULL)) + return 0; + + return counter; + } + + counter ++; + list1 = list1->next; + list2 = list2->next; + } + + if (list2 != NULL) + return -1; + + return 0; +} + +/* + Same as the previous function, except that if the list1 element + can be casted into list2 element, it is OK !!! +*/ +int type_list_different_parameter_cast(type_list *list1, type_list *list2) +{ + int counter = 1; + + while (list1 != NULL) + { + if ((list2 == NULL) + || (list1->data == NULL) + || (list2->data == NULL) + || (type_equal_cast(list1->data, list2->data) == 0) + || (type_equal_cast(list1->data, list2->data) == 2)) + { + if ((list2 != NULL) + && (list1->data == NULL) + && (list2->data == NULL)) + return 0; + + return counter; + } + + counter ++; + list1 = list1->next; + list2 = list2->next; + } + + if (list2 != NULL) + return -1; + + return 0; +} + +/* + Same as the above, but compares interval base types against the types; + this is used when checking array dimensions +*/ +int type_list_different_parameter_array(type_list *real_types, type_list *interval_types) +{ + int counter = 1; + + while (real_types != NULL) + { + if ((interval_types == NULL) + || (real_types->data == NULL) + || (interval_types->data == NULL) + || (real_types->data->type_class != interval_types->data->interval_base_type)) + { + return counter; + } + + counter ++; + real_types = real_types->next; + interval_types = interval_types->next; + } + + if (interval_types != NULL) + return -1; + + return 0; +} diff --git a/MPC.3.5.LINUX/structures/type_list.h b/MPC.3.5.LINUX/structures/type_list.h new file mode 100644 index 0000000..1c97655 --- /dev/null +++ b/MPC.3.5.LINUX/structures/type_list.h @@ -0,0 +1,28 @@ +/******************************************************************** + + type_list.h - functions to work with typelists + + Niksa Orlic, 2004-04-28 + +********************************************************************/ + + + +struct type_list_struct +{ + struct type_list_struct *next; + struct type_struct *data; +}; + +typedef struct type_list_struct type_list; + +type_list *type_list_create(); +void type_list_destroy(type_list*); + +type_list *type_list_duplicate(type_list*); +void type_list_append(type_list*, struct type_struct*); +int type_list_length(type_list*); + +int type_list_different_parameter(type_list*, type_list*); +int type_list_different_parameter_array(type_list*, type_list*); +int type_list_different_parameter_cast(type_list*, type_list*); diff --git a/MPC.3.5.LINUX/structures/unit.c b/MPC.3.5.LINUX/structures/unit.c new file mode 100644 index 0000000..f09ce5e --- /dev/null +++ b/MPC.3.5.LINUX/structures/unit.c @@ -0,0 +1,75 @@ +/******************************************************************** + + block.h - structures and functions used to hold program + block descriptions + + Niksa Orlic, 2005-03-30 + +********************************************************************/ + +#include "../util/strings.h" +#include "../util/error.h" +//#include "../util/message.h" +#include "../classgen/bytecode.h" +#include "type_list.h" +#include "string_list.h" +#include "type.h" +#include "identifier.h" +#include "name_table.h" +#include "block.h" +#include "unit.h" +#include "../classgen/preverify.h" + +#include "../util/memory.h" + +#include +#include +#include + +#include "../classgen/constant_pool.h" +#include "../classgen/classgen.h" + + +/* + Create an empty unit from the given name. +*/ +unit* unit_create(string *unit_name) +{ + unit *new_unit; + new_unit = (unit*)mem_alloc(sizeof(unit)); + + if (new_unit == NULL) + return NULL; + + new_unit->unit_name = unit_name; + new_unit->names = name_table_create(); + new_unit->is_library = 0; + + return new_unit; +} + +/* + Destroy a unit. +*/ +void unit_destroy(unit *old_unit) +{ + string_destroy(old_unit->unit_name); + + mem_free(old_unit); +} + + +/* + Duplicate a unit. +*/ +unit* unit_duplicate(unit *item) +{ + unit *new_item; + new_item = (unit*) mem_alloc(sizeof(unit)); + + new_item->names = item->names; + new_item->unit_name = string_duplicate(item->unit_name); + new_item->is_library = item->is_library; + + return new_item; +} \ No newline at end of file diff --git a/MPC.3.5.LINUX/structures/unit.h b/MPC.3.5.LINUX/structures/unit.h new file mode 100644 index 0000000..156840c --- /dev/null +++ b/MPC.3.5.LINUX/structures/unit.h @@ -0,0 +1,21 @@ +/******************************************************************** + + unit.h - structures and functions used to hold unit + descriptions + + Niksa Orlic, 2005-03-30 + +********************************************************************/ + +struct unit_struct +{ + name_table *names; + string *unit_name; + int is_library; /* set to 1 if it is an external library, or 0 if it is a plain unit */ +}; + +typedef struct unit_struct unit; + +unit* unit_create(string*); +void unit_destroy(unit*); +unit* unit_duplicate(unit*); \ No newline at end of file diff --git a/MPC.3.5.LINUX/util/error.c b/MPC.3.5.LINUX/util/error.c new file mode 100644 index 0000000..64d101b --- /dev/null +++ b/MPC.3.5.LINUX/util/error.c @@ -0,0 +1,203 @@ +/******************************************************************** + + error.c - implementation of error-handling routines + + Niksa Orlic, 2004-04-19 + +********************************************************************/ + +#include +#include + +extern char msgstr[1024]; +extern char *source_file_name; +extern int linenum; + +char locbuf[1024]; +short int error_count = 0; +long int last_error_linenum = -1; +int new_linenum = 0; +short int warning_count = 0; + + +char *msg(int i){ + switch(i) + { + // General messages + case 1: return "Out of memory"; + case 2: return "Too many errors"; + case 3: return "Cannot create record file"; + case 4: return "Cannot create class file"; + case 5: return "Cannot open source file"; + case 6: return "Serious error occured, stopping compilation"; + case 7: return "Cannot create binary symbol file"; + case 10: return "Internal error #010"; + case 11: return "Internal error #011"; + case 12: return "Internal error #012"; + case 13: return "Internal error #013"; + case 14: return "Internal error #014"; + case 15: return "Internal error #015"; + case 16: return "Internal error #016"; + case 17: return "Internal error #017"; + case 18: return "Internal error #018"; + case 19: return "Internal error #019"; + case 20: return "Internal error #020"; + case 21: return "Internal error #021"; + case 22: return "Internal error #022"; + case 23: return "Internal error #023"; + case 24: return "Internal error #024"; + case 25: return "Internal error #025"; + case 26: return "Internal error #026 memory"; + // Scanner errors + case 100: return "unknown character \'%s\', ignored"; + case 101: return "newline in string constant"; + case 102: return "error in preprocessor statement"; + // Parser errors + case 200: return "character \'%s\' expected, \'%s\' found"; + case 201: return "unexpected text \'%s\' after program end"; + case 202: return "identifier (name) expected"; + case 203: return "keyword \'%s\' expected, \'%s\' found"; + case 204: return "unexpected token \'%s\'"; + case 205: return "operator \'=\' expected, \'%s\' found"; + case 206: return "constant expected"; + case 207: return "unexpected end of file found"; + case 208: return "error in parameter list on token \'%s\'"; + case 209: return "operator \':=\' expected, \'%s\' found"; + case 210: return "\'packed\' arrays not supported; ordinary array are used"; + case 211: return "sets are not supported in this version"; + case 212: return "enumerated types are not supported in this version"; + case 213: return "operator \'..\' expected, \'%s\' found"; + case 214: return "keyword \'end\' expected, \'%s\' found"; + case 215: return "\'with\' is not supported in this version"; + case 216: return "keyword \'then\' expected, \'%s\' found"; + case 217: return "constant of type integer or char expected"; + case 218: return "operator \':=\' expected"; + case 219: return "\'break\' statemnt found outside of do-while, repeat-until or for loop"; + case 220: return "compiler does ot support the \'finalization\' part of the unit"; + case 221: return "procedures and functions may not contain body inside unit interface part"; + // Semantic errors + case 400: return "identifier \'%s\' already defined"; + case 401: return "method was already declared as forward"; + case 402: return "a %s with the same name was declared as forward"; + case 403: return "parameter list is shorter than the list in previous forward declaration"; + case 404: return "parameter list differs on element %s from the list in previous forward declaration"; + case 405: return "return type is different than the return type declared in the previous forward declaration"; + case 406: return "unknown type \'%s\'"; + case 407: return "%s type expected"; + case 408: return "integer, char or string type expected"; + case 409: return "constant of type %s expected, %s found"; + case 410: return "\'%s\' is not a constant"; + case 411: return "integer or char type expected"; + case 412: return "%s type expected, %s type found"; + case 413: return "wrong type in interval definition"; + case 414: return "\'%s\' is not a constant"; + case 415: return "type name or integer/char constant expected, \'%s\' found"; + case 416: return "error in interval definition"; + case 417: return "operand is wrong type"; + case 418: return "name \'%s\' already exists in a record declaration"; + case 419: return "procedure/function takes 0 arguments, brackets must be left out"; + case 420: return "procedure/function takes more than 0 arguments, '(' expected"; + case 421: return "parameter list is too short"; + case 422: return "error on parameter %s"; + case 423: return "left and right operands to \':=\' must have the same type"; + case 424: return "\'.\' operator can only be used on record types"; + case 425: return "the record does not contain element named \'%s\'"; + case 426: return "\'[\' operator can only be used on array types"; + case 427: return "error in array dimensions (array has %s dimensions, %s are specified)"; + case 428: return "identifier \'%s\' is not procedure, function, variable or unit name"; + case 429: return "identifier \'%s\' is not constant, function or variable name"; + case 430: return "only interval types can be used for array indexes"; + case 431: return "nested functions or procedures are not supported"; + case 432: return "function \'%s\' cannot be called from here; procedure call or assignement expected"; + case 433: return "\'run\' is reserved name and cannot be used as a function or procedure name"; + case 434: return "only string, character, integer or boolean can be appended to string"; + case 435: return "files are not supported in this version"; + case 436: return "variable parameters are not supported and are ignored"; + case 437: return "invalid interval"; + case 438: return "interval too large"; + case 439: return "only integer type can be used as string index"; + case 440: return "variables of interval type are not supported"; + case 441: return "only forward declaration supplied; the implementation is missing"; + case 442: return "case statement is not supported in this version"; + case 443: return "a value cannot be asigned to an array. This is a limitation of MIDletPascal"; + case 444: return "unknown identifier"; + case 445: return "name of the procedure/function has already been taken by another identifier"; + case 446: return "arrays in records (\'%s\') are not implemented. This is a limitation of MIDletPascal"; + case 447: return "unknown record element \'%s\'"; + case 448: return "failed to load \'%s\' library/unit"; + case 449: return "error reading external library file"; + case 450: return "could not load library/unit \'%s\' because identifier of the same name already exists"; + case 451: return "serious internal error in library"; + case 452: return "library/unit contains a method with an incorrect argument type"; + case 453: return "library/unit does not contain function \'%s\'"; + case 454: return "unit name must contain at least 2 characters"; + case 455: return "library/unit does not contain type \'%s\'"; + case 456: return "iterator used in for-loop must not be defined inside a library/unit"; + case 457: return "identifier \'%s\' is not a procedure or variable name"; + case 458: return "identifier \'%s\' is not a function, variable or constant name"; + case 459: return "identifier \'%s\' found in more units; use syntax 'unit_name'.'identifier' to resolve ambiguity"; + case 460: return "inlined label \'%d\' (offs:%d) not found"; + case 461: return "inlined label \'%d\' (offs:%d) already defined"; + case 462: return "inlined label \'%d\' (offs:%d) tableswitch / loookupswitch"; + case 463: return "keyword \'%s\' is not allowed here."; + case 464: return "use bytecode/end instead of inline() which might be deprecated"; + } +} + + +/* + Terminate the program and output the error message +*/ + +void die(int i) +{ + sprintf(msgstr,"Fatal error: %s\n", msg(i)); + compileMSG(); + compile_terminate(); +} + + +/* + Add an error message, if the total number of errors exceeds 100, + die +*/ +void add_error_message(int num, char *additional_data1, char *additional_data2) +{ + if (new_linenum==0) + new_linenum=linenum; + if (new_linenum != last_error_linenum) { + // j-a-s-d + if (num < 100) + sprintf(locbuf, "[Compiler Error] %s(%d): E%d %s\n", source_file_name, new_linenum, num, msg(num)); + else + sprintf(locbuf, "[Pascal Error] %s(%d): E%d %s\n", source_file_name, new_linenum, num, msg(num)); + + sprintf(msgstr, locbuf, additional_data1, additional_data2); + compileMSG(); + error_count ++; + if (error_count > 100) + die(2); + last_error_linenum = new_linenum; + } + new_linenum=0; +} + + +/* + Add warning message, if the total number of errors exceeds 100, + die +*/ +void add_warning_message(int num, char *additional_data1, char *additional_data2) +{ + if (new_linenum==0) + new_linenum=linenum; + // j-a-s-d + sprintf(locbuf, "[Pascal Warning] %s(%d): W%d %s\n", source_file_name, new_linenum, num, msg(num)); + + sprintf(msgstr, locbuf, additional_data1, additional_data2); + compileMSG(); + warning_count ++; + if (warning_count > 100) + die(2); + new_linenum=0; +} diff --git a/MPC.3.5.LINUX/util/error.h b/MPC.3.5.LINUX/util/error.h new file mode 100644 index 0000000..2620e6b --- /dev/null +++ b/MPC.3.5.LINUX/util/error.h @@ -0,0 +1,24 @@ +/******************************************************************** + + error.h - declaration of error-handling routines + + Niksa Orlic, 2004-04-19 + +********************************************************************/ + +/* + Terminate the program and output the error message +*/ +void die(int i/*char *message*/); + + +/* + Adds an error message +*/ +char *msg(int i); + +void add_error_message(/*char *message, long int linenum,*/ int num, + char *additional_data1, char *additional_data2); + +void add_warning_message(/*char *message, long int linenum,*/ int num, + char *additional_data1, char *additional_data2); diff --git a/MPC.3.5.LINUX/util/memory.c b/MPC.3.5.LINUX/util/memory.c new file mode 100644 index 0000000..6c233a4 --- /dev/null +++ b/MPC.3.5.LINUX/util/memory.c @@ -0,0 +1,213 @@ +/******************************************************************** + + memory.c - memory handling routines + + Niksa Orlic, 2005-03-22 + +********************************************************************/ + +#include +#include + +#include "memory.h" +#include "error.h" +//#include "message.h" + +#define SLOWLIST 1 + +static memory_object* memory_object_list_begin = NULL; +static memory_object* memory_object_list_end = NULL; + + +/* + Initialize the list of memory objects +*/ +void mem_init() +{ + memory_object_list_begin = (memory_object*)malloc(sizeof(memory_object)); + memory_object_list_begin->next = NULL; + memory_object_list_begin->prev = NULL; + memory_object_list_begin->data = NULL; + memory_object_list_end = memory_object_list_begin; +} + +/* + Clean up the list of memory objects +*/ +void mem_close() +{ + memory_object *it = memory_object_list_begin; + memory_object *old_object; + + while (it != NULL) + { + old_object = it; + it = it->next; +#if SLOWLIST + if (old_object->data != NULL) + free(old_object->data); + free(old_object); +#else + mem_free(old_object); +#endif + } +} + +/* + Allocate the new block of memory and append it into the list +*/ +void* mem_alloc(size_t s) +{ +#if SLOWLIST + memory_object *wrapper = (memory_object*)malloc(sizeof(memory_object)); +#else + memory_object *wrapper = (memory_object*)malloc(sizeof(memory_object) + s); +#endif + if (wrapper == NULL) + return NULL; + +#if SLOWLIST + wrapper->data = malloc(s); + if (wrapper->data == NULL) + return NULL; +#else + wrapper->data = (char*)wrapper + sizeof(memory_object); +#endif + + wrapper->next = NULL; + wrapper->prev = memory_object_list_end; + memory_object_list_end->next = wrapper; + memory_object_list_end = wrapper; + + if (memory_object_list_end == NULL) + die(26); + + return wrapper->data; +} + + +/* + Reallocate the new block of memory and append it into the list +*/ +void* mem_realloc(char* old_block, int s) +{ + memory_object *wrapper; + memory_object *prev, *next; + + void *new_block; + + prev = next = NULL; + +#if SLOWLIST + /* find the block */ + { + memory_object *it = memory_object_list_begin; + + while (it != NULL) + { + if (it->data == old_block) + { + break; + } + + it = it->next; + } + + it->data = realloc(it->data, s); + + return it->data; + } +#else + prev = ((memory_object*)(old_block - sizeof(memory_object)))->prev; + next = ((memory_object*)(old_block - sizeof(memory_object)))->next; + + new_block = realloc(old_block - sizeof(memory_object), sizeof(memory_object) + s); + + if (new_block == NULL) + { + mem_free(old_block); + return NULL; + } + + if ((old_block - sizeof(memory_object)) == new_block) + return old_block; + + wrapper = (memory_object*) new_block; + + if (prev != NULL) + prev->next = wrapper; + wrapper->prev = prev; + + if (next != NULL) + next->prev = wrapper; + wrapper->next = next; + + mem_free(old_block); + + return wrapper->data; +#endif +} + +/* + Free the block of memory +*/ +void mem_free(char* old_block) +{ + memory_object *prev, *next; + + prev = next = NULL; + + if (old_block == NULL) + return; + +#if SLOWLIST + /* find the block */ + { + memory_object *it = memory_object_list_begin; + + while (it != NULL) + { + if (it->data == old_block) + { + prev = it->prev; + next = it->next; + + if (prev == NULL) + { + int a = 1; + } + + free(old_block); + free(it); + + break; + } + + it = it->next; + } + + if (it == NULL) + return; + } +#else + prev = ((memory_object*)(old_block - sizeof(memory_object)))->prev; + next = ((memory_object*)(old_block - sizeof(memory_object)))->next; + + free(old_block - sizeof(memory_object)); +#endif + + if (prev != NULL) + prev->next = next; + + if (next != NULL) + next->prev = prev; + + if (next == NULL) + memory_object_list_end = prev; + + if (memory_object_list_end == NULL) + { + int a = 1; + } + +} \ No newline at end of file diff --git a/MPC.3.5.LINUX/util/memory.h b/MPC.3.5.LINUX/util/memory.h new file mode 100644 index 0000000..5e7552f --- /dev/null +++ b/MPC.3.5.LINUX/util/memory.h @@ -0,0 +1,30 @@ +/******************************************************************** + + memory.h - memory handling routines + + Niksa Orlic, 2005-03-22 + +********************************************************************/ + +struct memory_object_struct +{ + struct memory_object_struct *next; + struct memory_object_struct *prev; + char *data; +}; + +typedef struct memory_object_struct memory_object; + +void mem_init(); +void mem_close(); + +void* mem_alloc(size_t); + +// j-a-s-d +#ifdef __GNUC__ +void* mem_realloc(char*, int); +void mem_free(char*); +#else +void* mem_realloc(void*, int); +void mem_free(void*); +#endif diff --git a/MPC.3.5.LINUX/util/strings.c b/MPC.3.5.LINUX/util/strings.c new file mode 100644 index 0000000..252cd93 --- /dev/null +++ b/MPC.3.5.LINUX/util/strings.c @@ -0,0 +1,201 @@ +/******************************************************************** + + strings.c - implementation of a string-handling routines + + Niksa Orlic, 2004-04-19 + +********************************************************************/ + +#include "error.h" +#include "strings.h" +#include "memory.h" + +#include +#include + +/* + Create an empty string +*/ +string* string_create() +{ + string *new_string; + new_string = (string*) mem_alloc(sizeof(string)); + + if (new_string == NULL) + die(1); + + new_string->cstr = (char*) mem_alloc(sizeof(char) * 16); + + if (new_string->cstr == NULL) + die(1); + + new_string->cstr[0] = '\0'; + + new_string->length = 0; + new_string->allocated = 16; + + return new_string; +} + + +/* + Create a copy of the string +*/ +string* string_duplicate(string *str) +{ + string *new_string; + new_string = (string*) mem_alloc(sizeof(string)); + + if (new_string == NULL) + die(1); + + new_string->cstr = (char*) mem_alloc(sizeof(char) * (str->allocated)); + + if (new_string->cstr == NULL) + die(1); + + memcpy(new_string->cstr, str->cstr, str->length + 1); /* also copy the terminating NULL character */ + + new_string->allocated = str->allocated; + new_string->length = str->length; + + return new_string; +} + + +/* + Create a string from a C-style string +*/ +string* string_from_cstr(char *cstr) +{ + string *new_string; + new_string = (string*) mem_alloc(sizeof(string)); + + if (new_string == NULL) + die(1); + + new_string->cstr = (char*) mem_alloc((strlen(cstr)+5) * sizeof(char)); + + if (new_string->cstr == NULL) + die(1); + + strcpy(new_string->cstr, cstr); + + new_string->allocated = strlen(cstr) + 5; + new_string->length = strlen(cstr); + + return new_string; +} + + +/* + Free all memory used by the string +*/ +void string_destroy(string *str) +{ + mem_free(str->cstr); + mem_free(str); +} + + +/* + Empties the given string +*/ +void string_empty(string *str) +{ + str->length = 0; + str->cstr[0] = '\0'; +} + + +/* + Append the second string to the first string +*/ +void string_append(string *str1, string *str2) +{ + if (str1->length + str2->length + 1 >= str1->allocated) + { + str1->cstr = (char*) mem_realloc(str1->cstr, sizeof(char)*(str1->length + str2->length + 1)); + + if (str1->cstr == NULL) + die(1); + + str1->allocated = str1->length + str2->length + 1; + } + + memcpy(str1->cstr + str1->length, + str2->cstr, + str2->length); + + str1->length = str1->length + str2->length; + + str1->cstr[str1->length] = '\0'; +} + + +/* + Append the C-style string to the string +*/ +void string_append_cstr(string *str1, char *cstr2) +{ + short int cstr2_length; + + if (str1 == NULL) + str1 = string_create(); + + cstr2_length = strlen(cstr2); + + if (str1->length + cstr2_length + 1 >= str1->allocated) + { + str1->cstr = (char*) mem_realloc(str1->cstr, sizeof(char)*(str1->length + cstr2_length + 1)); + + if (str1->cstr == NULL) + die(1); + + str1->allocated = str1->length + cstr2_length + 1; + } + + memcpy(str1->cstr + str1->length, + cstr2, + cstr2_length); + + str1->length = str1->length + cstr2_length; + + str1->cstr[str1->length] = '\0'; +} + + +/* + Get the C-style string from a given string +*/ +char *string_get_cstr(string *str) +{ + return str->cstr; +} + + +/* + Get the string length +*/ +short int string_length(string *str) +{ + return str->length; +} + +/* + Translate the string into lowercase +*/ +void lowercase(char *cstr) +{ + int i = 0; + + while (cstr[i] != 0) + { + if ((cstr[i] >= 'A') && (cstr[i] <= 'Z')) + { + cstr[i] = cstr[i] | (char) 0x20; + } + + i++; + } +} \ No newline at end of file diff --git a/MPC.3.5.LINUX/util/strings.h b/MPC.3.5.LINUX/util/strings.h new file mode 100644 index 0000000..d81da14 --- /dev/null +++ b/MPC.3.5.LINUX/util/strings.h @@ -0,0 +1,76 @@ +/******************************************************************** + + strings.h - declaration of a string-handling routines + + Niksa Orlic, 2004-04-19 + +********************************************************************/ + +struct string_struct +{ + char *cstr; + short int length; + short int allocated; +}; + +typedef struct string_struct string; + + +/* + Create an empty string +*/ +string* string_create(); + + +/* + Create a copy of the string +*/ +string* string_duplicate(string*); + + +/* + Create a string from a C-style string +*/ +string* string_from_cstr(char *cstr); + + +/* + Free all memory used by the string +*/ +void string_destroy(string*); + + +/* + Empties the given string +*/ +void string_empty(string*); + + +/* + Append the second string to the first string +*/ +void string_append(string*, string*); + + +/* + Append the C-style string to the string +*/ +void string_append_cstr(string*, char*); + + +/* + Get the C-style string from a given string +*/ +char* string_get_cstr(string*); + + +/* + Get the string length +*/ +short int string_length(string*); + + +/* + Translates a string into lower case +*/ +void lowercase(char *); \ No newline at end of file diff --git a/MPS.3.1/F.java b/MPS.3.1/F.java new file mode 100644 index 0000000..a97edca --- /dev/null +++ b/MPS.3.1/F.java @@ -0,0 +1,435 @@ +/* + * Fixed-point aritmetika za MIDletPascal + * */ + +public class F +{ + + private F() + { + } + + // fromInt + public static int fI(int i) + { + return i << 12; + } + + // fromint + public static int fI(int a, int b) + { + StringBuffer s = new StringBuffer(); + s.append(a); + s.append('.'); + s.append(b); + return fI(s.toString(),10); + } + + // fromInt + public static int fI(String s, int radix) + { + int i = 0; + if(s.charAt(0) == '-') + i = 1; + String s1 = "-1"; + int j = s.indexOf('.'); + if(j >= 0) + { + for(s1 = s.substring(j + 1, s.length()); s1.length() < 4; s1 = s1 + "0"); + if(s1.length() > 4) + s1 = s1.substring(0, 4); + } else + { + j = s.length(); + } + int k = Integer.parseInt(s.substring(i, j), radix); + int l = Integer.parseInt(s1, radix) + 1; + int i1 = (k << 12) + (l << 12) / 10000; + if(i == 1) + i1 = -i1; + return i1; + } + + // toString + public static String tS(int i) + { + boolean flag = false; + if(i < 0) + { + flag = true; + i = -i; + } + int j = i >> 12; + int k = 10000 * (i & 0xfff) >> 12; + String s; + for(s = Integer.toString(k); s.length() < 4; s = "0" + s); + return (flag ? "-" : "") + Integer.toString(j) + "." + s; + } + + // toInt + public static int tI(int i) + { + if(i >= 0) + i += 2048; + else + i -= 2048; + return i >> 12; + } + + // div + public static int D(int i, int j) + { + boolean flag = false; + if(j == 4096) + return i; + if((j & 0xfff) == 0) + return i / (j >> 12); + if(i < 0) + { + i = -i; + flag = true; + } + if(j < 0) + { + j = -j; + if(flag) + flag = false; + else + flag = true; + } + byte byte0 = 0; + if(i > 0x64fff) + byte0 = 3; + if(i > 0x3e8fff) + byte0 = 4; + if(i > 0x7dffff) + byte0 = 6; + if(i > 0x1f4ffff) + byte0 = 8; + if(i > 0x7dfffff) + byte0 = 10; + if(byte0 > 0) + { + int k = 2 << byte0 - 1; + i += k; + j += k; + } + int l = (i << 12 - byte0) / (j >> byte0); + return flag ? -l : l; + } + + // mult + public static int M(int i, int j) + { + boolean flag = false; + if((i & 0xfff) == 0) + return (i >> 12) * j; + if((j & 0xfff) == 0) + return i * (j >> 12); + if(i < 0 && j > 0 || i > 0 && j < 0) + flag = true; + if(i < 0) + i = -i; + if(j < 0) + j = -j; + byte byte0 = 0; + if(i > 0x64fff || j > 0x64fff) + byte0 = 2; + if(i > 0x3e8fff || j > 0x3e8fff) + byte0 = 4; + if(i > 0x271ffff || j > 0x271ffff) + byte0 = 6; + if(byte0 > 0) + { + int k = 2 << byte0 - 1; + i += k; + j += k; + } + int l = (i >> 12) * (j >> 12) << 12; + int i1 = (i & 0xfff) * (j & 0xfff) >> 12; + i1 += ((i & 0xfffff000) >> byte0) * ((j & 0xfff) >> byte0) >> 12 - (byte0 << 1); + l = l + i1 + (((i & 0xfff) >> byte0) * ((j & 0xfffff000) >> byte0) >> 12 - (byte0 << 1)); + if(l < 0) + return 0; + else + return flag ? -l : l; + } + + // abs + public static int A(int i) + { + if(i < 0) + return -i; + else + return i; + } + + // sqrt + public static int S(int i, int j) + { + if(i < 0) + return 0; + if(i == 0) + return 0; + int k = i + 4096 >> 1; + for(int l = 0; l < j; l++) + k = k + D(i, k) >> 1; + + if(k < 0) + return 0; + else + return k; + } + + // sqrt + public static int S(int i) + { + byte byte0 = 8; + if(i > 0x64000) + byte0 = 12; + if(i > 0x3e8000) + byte0 = 16; + return S(i, byte0); + } + + // sin + public static int s(int i) + { + int j = 0; + for(; i < 0; i += 25736); + if(i > 25736) + i %= 25736; + int k = (i * 10) / 714; + if(i != 0 && i != 6434 && i != 12868 && i != 19302 && i != 25736) + j = (i * 100) / 714 - k * 10; + if(k <= 90) + return sin_lookup(k, j); + if(k <= 180) + return sin_lookup(180 - k, j); + if(k <= 270) + return -sin_lookup(k - 180, j); + else + return -sin_lookup(360 - k, j); + } + + private static int sin_lookup(int i, int j) + { + if(j > 0 && j < 10 && i < 90) + return SIN_TABLE[i] + ((SIN_TABLE[i + 1] - SIN_TABLE[i]) / 10) * j; + else + return SIN_TABLE[i]; + } + + // cos + public static int C(int i) + { + return s(i + 6435); + } + + public static int tan(int i) + { + int j = D(s(i), C(i)); + return j; + } + + public static int cot(int i) + { + int j = D(fI(1), tan(i)); + return j; + } + + // asin + public static int AS(int i) + { + boolean flag = false; + if(i < 0) + flag = true; + if(A(i) > 4096) + return 0; + i = A(i); + int j = 0; + int k = SIN_TABLE.length; + for(int l = 0; l < SIN_TABLE.length; l++) + { + int i1 = A(i - SIN_TABLE[l]); + if(i1 < k) + { + k = i1; + j = l; + } + } + + if(flag) + return -(j * 72); + else + return j * 72; + } + + // acos + public static int AC(int i) + { + return 6434 - AS(i); + } + + // exp + public static int e(int i) + { + int j = A(i) >> 12; + if(j > 13) + return 0; + int ai[] = { + 4096, 11134, 30266, 0x1415e, 0x36992, 0x9469c, 0x1936dc, 0x448a21, 0xba4f54, 0x1fa7158, + 0x560a774, 0xe9e2244, 0x27bc2ca9, 0x6c02d646 + }; + int k = ai[j]; + int l = A(i) & 0xfff; + if(l > 0) + { + int i1 = 0; + int j1 = 4096; + int k1 = 1; + for(int l1 = 0; l1 < 6; l1++) + { + i1 += j1 / k1; + j1 = M(j1, l); + k1 *= l1 + 1; + } + + k = M(k, i1); + } + if(i < 0) + return D(4096, k); + else + return k; + } + + public static int log(int i) + { + if(i <= 0) + return 0; + int j = 0; + boolean flag = false; + int l; + for(l = 0; i > 8192; l++) + i >>= 1; + + int i1 = l * 2839; + int j1 = 0; + i -= 4096; + for(int k1 = 1; k1 < 11; k1++) + { + int k; + if(j == 0) + k = i; + else + k = M(j, i); + if(k == 0) + break; + j1 += ((k1 % 2 != 0 ? 1 : -1) * k) / k1; + j = k; + } + + return i1 + j1; + } + + public static int log10(int i) + { + return D(log(i), log(2)); + } + + // pow + public static int p(int i, int j) + { + boolean flag = false; + int k = 1; + if(j < 0) + { + flag = true; + j = -j; + } + if(A(i) < 4096 && j > 12288) + { + k = e(M(log(i), j)); + } else + { + k = pi(i, j >> 12); + if((j & 0xfff) != 0) + k = M(k, e(M(log(i), j & 0xfff))); + } + if(flag) + return D(4096, k); + else + return k; + } + + private static int pi(int i, int j) + { + int k = 4096; + if(i == 0) + return 0; + for(int l = 0; l < j; l++) + k = M(k, i); + + if(k < 0) + return 0; + else + return k; + } + + // to degrees + public static int tD(int i) + { + return 180*D(i, PI); + } + + // to radians + public static int tR(int i) + { + return M(i/180, PI); + } + + public static int atan(int i) + { + return AC(D(fI(1), S(1+M(i, i)))); + } + + public static int atan2(int y, int x) + { + int res; + if (x == 0) + { + if (y == 0) + return 0; + if (y > 0) + return PI/2; + return -PI/2; + } + + if (x>0) + return atan(D(y,x)); + + res = PI - atan(A(D(y,x))); + + if (y>=0) + return res; + return -res; + } + + public static final int MAX_VALUE = 0x7fffffff; + public static final int MIN_VALUE = 0x80000001; + public static final int E = 11134; + public static final int PI = 12868; + private static final int SIN_TABLE[] = { + 0, 71, 142, 214, 285, 357, 428, 499, 570, 641, + 711, 781, 851, 921, 990, 1060, 1128, 1197, 1265, 1333, + 1400, 1468, 1534, 1600, 1665, 1730, 1795, 1859, 1922, 1985, + 2048, 2109, 2170, 2230, 2290, 2349, 2407, 2464, 2521, 2577, + 2632, 2686, 2740, 2793, 2845, 2896, 2946, 2995, 3043, 3091, + 3137, 3183, 3227, 3271, 3313, 3355, 3395, 3434, 3473, 3510, + 3547, 3582, 3616, 3649, 3681, 3712, 3741, 3770, 3797, 3823, + 3849, 3872, 3895, 3917, 3937, 3956, 3974, 3991, 4006, 4020, + 4033, 4045, 4056, 4065, 4073, 4080, 4086, 4090, 4093, 4095, + 4096 + }; + +} diff --git a/MPS.3.1/FS.java b/MPS.3.1/FS.java new file mode 100644 index 0000000..7849d0e --- /dev/null +++ b/MPS.3.1/FS.java @@ -0,0 +1,230 @@ +/* + * This class is used when Forms support is needeed + * */ +import javax.microedition.lcdui.*; + +public class FS +{ + /* add a textfiled into the form */ + public static int Lj(String label, String text, + int maxSize, int constraints) + { + try + { + return FW.F.append(new TextField(label, text, maxSize, constraints)); + } + catch (Exception E) + { + return -1; + } + } + + /* add gauge */ + public static int Lj(String label, int interactive, + int maxValue, int initialValue) + { + try + { + boolean inter = true; + if (interactive == 0) + inter = false; + // j-a-s-d: avoid AV false alarm + return FW.F.append(new Gauge(label, inter, maxValue, initialValue)); + } + catch (Exception E) + { + return -1; + } + } + + /* add choice group */ + public static int Lj(String label, int type) + { + try + { + ChoiceGroup cg = new ChoiceGroup(label, type); + return FW.F.append(cg); + } + catch (Exception E) + { + return -1; + } + } + + /* get int value from gauge */ + public static int Lja(int itemNum) + { + try + { + Item it = FW.F.get(itemNum); + Gauge g = (Gauge)it; + return g.getValue(); + } + catch(Exception e) + { + return -1; + } + } + + /* set value to gauge */ + public static void Lja(int itemNum, int value) + { + try + { + Item it = FW.F.get(itemNum); + Gauge g = (Gauge)it; + g.setValue(value); + } + catch(Exception e) + { + return; + } + } + + /* get text from textfield */ + public static String ja(int itemNum) + { + try + { + Item it = FW.F.get(itemNum); + TextField tf = (TextField)it; + return tf.getString(); + } + catch(Exception e) + { + return ""; + } + } + + /* set text of field */ + public static void ja(int itemNum, String text) + { + try + { + Item it = FW.F.get(itemNum); + TextField tf = (TextField)it; + tf.setString(text); + } + catch(Exception e) + { + return; + } + } + + /* choice group append item (string, null) */ + public static int I(int itemNum, String text) + { + try + { + ChoiceGroup cg = (ChoiceGroup)FW.F.get(itemNum); + return cg.append(text, null); + } + catch(Exception e) + { + return -1; + } + } + + /* choice group append item (string, image) */ + public static int I(int itemNum, String text, Image image) + { + try + { + ChoiceGroup cg = (ChoiceGroup)FW.F.get(itemNum); + return cg.append(text, image); + } + catch(Exception e) + { + return -1; + } + } + + /* choice is selected item */ + public static int L(int itemNum, int entryNum) + { + try + { + ChoiceGroup cg = (ChoiceGroup)FW.F.get(itemNum); + if (cg.isSelected(entryNum)) + return -1; + else + return 0; + } + catch(Exception e) + { + return -1; + } + } + + /* choice get selected item */ + public static int L(int itemNum) + { + try + { + ChoiceGroup cg = (ChoiceGroup)FW.F.get(itemNum); + return cg.getSelectedIndex(); + } + catch(Exception e) + { + return -1; + } + } + + /* formAddDateField */ + public static int dd(String title, int type) + { + try + { + DateField df = new DateField(title, type); + return FW.F.append(df); + } + catch (Exception e) + { + return -1; + } + } + + /* formSetDate */ + public static void dd(int index, int time) + { + try + { + DateField df = (DateField)FW.F.get(index); + df.setDate(new java.util.Date(((long)time) * 1000)); + } + catch (Exception e) + { + return; + } + } + + /* formGetDate*/ + public static int dd(int index) + { + try + { + DateField df = (DateField)FW.F.get(index); + return (int) (df.getDate().getTime() / 1000); + } + catch (Exception e) + { + return -1; + } + } + + /* getFormTitle*/ + public static String gft() + { + try + { + String title = FW.F.getTitle(); + if (title == null) + title = ""; + return title; + } + catch (Exception e) + { + return ""; + } + } +}; diff --git a/MPS.3.1/FW.java b/MPS.3.1/FW.java new file mode 100644 index 0000000..d302e8b --- /dev/null +++ b/MPS.3.1/FW.java @@ -0,0 +1,95 @@ +/* + * This is the framework file for the MIDLetPascal generated MIDlets + * The Pascal code is compiled into java class called M. + * */ +import javax.microedition.midlet.*; +import javax.microedition.lcdui.*; + +public class FW extends MIDlet implements CommandListener +{ + public static FW fw = null; + public M m = null; + public boolean threadStarted = false; + public Display display; + public static int MP; // MidletPaused + + // command & forms support + public static Form F; + public static Displayable CD; + public static Command LC; + public static List L; + public static Alert A; + public static TextBox TB; + + public void startApp() + { + MP = 0; + + display = Display.getDisplay(this); + + fw = this; + + LC = null; + + if (m == null) + { + m = new M(); + + M.T = m; + M.I = Image.createImage(m.getWidth(), m.getHeight()); + M.G = M.I.getGraphics(); + M.KC = 0; + L = new List("", List.IMPLICIT); + A = new Alert("", "", null, AlertType.INFO); + TB = new TextBox("", "", 2, TextField.ANY); + display.setCurrent(m); + CD = m; + try + { + m.setCommandListener(this); + } catch (Exception e) + { + // do nothing, this catches the exception for NokiaAPI FullCanvas + } + F = new Form(""); + F.setCommandListener(this); + } + else + { + m.repaint(); + m.serviceRepaints(); + } + + if (! threadStarted) + { + new Thread(m).start(); + threadStarted = true; + } + } + + public void pauseApp() + { + MP = -1; + } + + + public void destroyApp(boolean unconditional) + { + m = null; + M.I = null; + M.G = null; + CD = null; + TB = null; + F = null; + A = null; + L = null; + fw = null; + LC = null; + notifyDestroyed(); + } + + public void commandAction(Command c, Displayable item) { + LC = c; + } + +} diff --git a/MPS.3.1/H.java b/MPS.3.1/H.java new file mode 100644 index 0000000..8b7b353 --- /dev/null +++ b/MPS.3.1/H.java @@ -0,0 +1,155 @@ +// The HTTP class for the MIDletPascal +import javax.microedition.io.*; +import java.io.*; + +public class H +{ + public HttpConnection c = null; + public OutputStream o = null; + public InputStream i = null; + + // open a http connection + public int L(String url) + { + try + { + c = (HttpConnection)Connector.open(url); + o = c.openOutputStream(); + return -1; + } + catch(Exception e) + { + c = null; + return 0; + } + } + + // return true if the connection is open + public int L() + { + if (c != null) + return -1; + return 0; + } + + // close the connection + public void c() + { + try + { + if (i != null) + { + i.close(); + i = null; + } + if (o != null) + { + o.close(); + o = null; + } + c.close(); + c = null; + } + catch(Exception e) + { + c = null; + } + } + + // add http header + public void L(String header, String value) + { + try + { + c.setRequestProperty(header, value); + } + catch(Exception e) + {} + } + + // setRequestMethod : + // HEAD, POST, GET bi trebalo rijesiti kao string konstante + public void c(String method) + { + try + { + c.setRequestMethod(method); + } + catch(Exception e) + {} + } + + // get header field + public String i(String header) + { + try + { + String value; + value = c.getHeaderField(header); + + if (value == null) + value = ""; + + return value; + } + catch(Exception e) + { + return ""; + } + } + + // set message text + public int o(String message) + { + try + { + o.write(message.getBytes()); + + return -1; + } + catch(Exception e) + { + o = null; + return 0; + } + } + + // getresponse code + // ovaj takodjer otvara konekciju i ceka dok se ne odgovori + public int o() + { + try + { + int code; + code = c.getResponseCode(); + i = c.openInputStream(); + return code; + } + catch(Exception e) + { + return -1; + } + } + + // read the input data from the connection + public String j() + { + try + { + StringBuffer retval = new StringBuffer(); + int c; + + while ((c=i.read()) != -1) + { + retval.append((char)(char)c); + } + + return retval.toString(); + } + catch(Exception e) + { + return ""; + } + } + +}; diff --git a/MPS.3.1/P.java b/MPS.3.1/P.java new file mode 100644 index 0000000..4c33830 --- /dev/null +++ b/MPS.3.1/P.java @@ -0,0 +1,101 @@ +/* + * The player class used for playing the music. + * */ + +import javax.microedition.media.*; + +public class P +{ + public static Player p = null; + + /* load music player */ + public static int a(String resource, String type) + { + try + { + if (p != null) + { + p.close(); + } + p = Manager.createPlayer(FW.fw.getClass().getResourceAsStream(resource), type); + p.realize(); + p.prefetch(); + } + catch (Exception e) + { + return 0; + } + + return -1; + } + + /* play */ + public static int a() + { + try + { + if (p == null) + return 0; + + p.start(); + } + catch (Exception e) + { + return 0; + } + + return -1; + } + + /* stops playing the music */ + public static void b() + { + try + { + if (p != null) + { + p.stop(); + } + } + catch (Exception e) + {} + } + + /* set loop count, -1 indefinitely */ + public static int a(int x) + { + try + { + if (p != null) + { + if (p.getState() == Player.STARTED) + return 0; + p.setLoopCount(x); + return -1; + } + + } catch (Exception e) + { + return 0; + } + return 0; + } + + /* get duration time in milliseconds */ + public static int c() + { + try + { + if (p != null) + { + return (int)(p.getDuration() / 1000); + } + else return -1; + } + catch (Exception e) + { + return -1; + } + } + +} diff --git a/MPS.3.1/README.txt b/MPS.3.1/README.txt new file mode 100644 index 0000000..83d9c74 --- /dev/null +++ b/MPS.3.1/README.txt @@ -0,0 +1,9 @@ +For building this stubs, just call the java compiler and then the preverifier in the regular way. + +For example, assumbing you have both in the path, the WTK is in C:\WTK25, and that you have a subdirectory called "bin" to hold the preverified class output, for building the SM class you can do: + +javac -g:none -classpath c:\WTK25\lib\midpapi10.jar;c:\WTK25\lib\cldcapi10.jar;c:\WTK25\lib\wma11.jar -source 1.3 -target 1.1 SM.java +preverify1.1 -nofp -nofinalize -nonative -classpath c:\WTK25\lib\midpapi10.jar;c:\WTK25\lib\cldcapi10.jar;c:\WTK25\lib\wma11.jar -d "bin" "SM" + +Enjoy, +Javier Santo Domingo diff --git a/MPS.3.1/RS.java b/MPS.3.1/RS.java new file mode 100644 index 0000000..a87ea9a --- /dev/null +++ b/MPS.3.1/RS.java @@ -0,0 +1,125 @@ +// this is the class to implement record store functionality +// for MIDletPascal +import javax.microedition.rms.*; + +public class RS +{ + // open record store + public static RecordStore j(String name) + { + try + { + return RecordStore.openRecordStore(name, true); + } + catch(Exception e) + { + return null; + } + } + + + // closes record store + public static void L(RecordStore rs) + { + try + { + rs.closeRecordStore(); + } + catch(Exception e) + { + } + } + + // deletes a record store + public static void L(String name) + { + try + { + RecordStore.deleteRecordStore(name); + } + catch(Exception e) + { + } + } + + // deletes a record from a record store + public static void L(RecordStore rs, int id) + { + try + { + rs.deleteRecord(id); + } + catch(Exception e) + { + } + } + + // adds a record + public static int L(RecordStore rs, String data) + { + try + { + return rs.addRecord(data.getBytes(), 0, data.length()); + } + catch(Exception e) + { + return -1; + } + } + + // sets a data in the entry + public static void L(RecordStore rs, String data, int id) + { + try + { + rs.setRecord(id, data.getBytes(), 0, data.getBytes().length); + } + catch (Exception e) + {} + } + + // returns the next record ID + public static int Lja(RecordStore rs) + { + try + { + return rs.getNextRecordID(); + } + catch (Exception e) + { + return -1; + } + } + + // read the data from the record store + public static String j(RecordStore rs, int id) + { + try + { + byte[] res; + res = rs.getRecord(id); + + if (res == null) + return ""; + + return new String(res); + } + catch(Exception e) + { + return ""; + } + } + + // return the number of records in the record store + public static int j(RecordStore rs) + { + try + { + return rs.getNumRecords(); + } + catch(Exception e) + { + return 0; + } + } +}; diff --git a/MPS.3.1/Real.java b/MPS.3.1/Real.java new file mode 100644 index 0000000..c6a131f --- /dev/null +++ b/MPS.3.1/Real.java @@ -0,0 +1,6020 @@ + + + + + + +/** + * Java integer implementation of 63-bit precision floating point. + *
Version 1.13 + * + *

Copyright 2003-2009 Roar Lauritzsen + * + *

+ * + *

General notes + *

    + * + *
  • Real objects are not immutable, like Java + * Double or BigDecimal. This means that you + * should not think of a Real object as a "number", but rather + * as a "register holding a number". This design choice is done to encourage + * object reuse and limit garbage production for more efficient execution on + * e.g. a limited MIDP device. The design choice is reflected in the API, + * where an operation like {@link #add(Real) add} does not return a new + * object containing the result (as with {@link + * java.math.BigDecimal#add(java.math.BigDecimal) BigDecimal}), but rather + * adds the argument to the object itself, and returns nothing. + * + *
  • This library implements infinities and NaN (Not-a-Number) following + * the IEEE 754 logic. If an operation produces a result larger (in + * magnitude) than the largest representable number, a value representing + * positive or negative infinity is generated. If an operation produces a + * result smaller than the smallest representable number, a positive or + * negative zero is generated. If an operation is undefined, a NaN value is + * produced. Abnormal numbers are often fine to use in further + * calculations. In most cases where the final result would be meaningful, + * abnormal numbers accomplish this, e.g. atan(1/0)=π/2. In most cases + * where the final result is not meaningful, a NaN will be produced. + * No exception is ever (deliberately) thrown. + * + *
  • Error bounds listed under Method Detail + * are calculated using William Rossi's rossi.dfp.dfp at 40 decimal digits + * accuracy. Error bounds are for "typical arguments" and may increase when + * results approach zero or + * infinity. The abbreviation {@link Math#ulp(double) ULP} means Unit in the + * Last Place. An error bound of ½ ULP means that the result is correctly + * rounded. The relative execution time listed under each method is the + * average from running on SonyEricsson T610 (R3C), K700i, and Nokia 6230i. + * + *
  • The library is not thread-safe. Static Real objects are + * used extensively as temporary values to avoid garbage production and the + * overhead of new. To make the library thread-safe, references + * to all these static objects must be replaced with code that instead + * allocates new Real objects in their place. + * + *
  • There is one bug that occurs again and again and is really difficult + * to debug. Although the pre-calculated constants are declared static + * final, Java cannot really protect the contents of the objects in + * the same way as consts are protected in C/C++. Consequently, + * you can accidentally change these values if you send them into a function + * that modifies its arguments. If you were to modify {@link #ONE Real.ONE} + * for instance, many of the succeeding calculations would be wrong because + * the same variable is used extensively in the internal calculations of + * Real.java. + * + *
+ */ +public final class Real +{ + /** + * The mantissa of a Real. To maintain numbers in a + * normalized state and to preserve the integrity of abnormal numbers, it + * is discouraged to modify the inner representation of a + * Real directly. + * + *

The number represented by a Real equals:
+ *      -1sign · mantissa · 2-62 · 2exponent-0x40000000 + * + *

The normalized mantissa of a finite Real must be + * between 0x4000000000000000L and + * 0x7fffffffffffffffL. Using a denormalized + * Real in any operation other than {@link + * #normalize()} may produce undefined results. The mantissa of zero and + * of an infinite value is 0x0000000000000000L. + * + *

The mantissa of a NaN is any nonzero value. However, it is + * recommended to use the value 0x4000000000000000L. Any + * other values are reserved for future extensions. + */ + public long mantissa; + /** + * The exponent of a Real. To maintain numbers in a + * normalized state and to preserve the integrity of abnormal numbers, it + * is discouraged to modify the inner representation of a + * Real directly. + * + *

The exponent of a finite Real must be between + * 0x00000000 and 0x7fffffff. The exponent of + * zero 0x00000000. + * + *

The exponent of an infinite value and of a NaN is any negative + * value. However, it is recommended to use the value + * 0x80000000. Any other values are reserved for future + * extensions. + */ + public int exponent; + /** + * The sign of a Real. To maintain numbers in a normalized + * state and to preserve the integrity of abnormal numbers, it is + * discouraged to modify the inner representation of a Real + * directly. + * + *

The sign of a finite, zero or infinite Real is 0 for + * positive values and 1 for negative values. Any other values may produce + * undefined results. + * + *

The sign of a NaN is ignored. However, it is recommended to use the + * value 0. Any other values are reserved for future + * extensions. + */ + public byte sign; + /** + * Set to false during numerical algorithms to favor accuracy + * over prettyness. This flag is initially set to true. + * + *

The flag controls the operation of a subtraction of two + * almost-identical numbers that differ only in the last three bits of the + * mantissa. With this flag enabled, the result of such a subtraction is + * rounded down to zero. Probabilistically, this is the correct course of + * action in an overwhelmingly large percentage of calculations. + * However, certain numerical algorithms such as differentiation depend + * on keeping maximum accuracy during subtraction. + * + *

Note, that because of magicRounding, + * a.sub(b) may produce zero even though + * a.equalTo(b) returns false. This must be + * considered e.g. when trying to avoid division by zero. + */ + public static boolean magicRounding = true; + /** + * A Real constant holding the exact value of 0. Among other + * uses, this value is used as a result when a positive underflow occurs. + */ + public static final Real ZERO = new Real(0,0x00000000,0x0000000000000000L); + /** + * A Real constant holding the exact value of 1. + */ + public static final Real ONE = new Real(0,0x40000000,0x4000000000000000L); + /** + * A Real constant holding the exact value of 2. + */ + public static final Real TWO = new Real(0,0x40000001,0x4000000000000000L); + /** + * A Real constant holding the exact value of 3. + */ + public static final Real THREE= new Real(0,0x40000001,0x6000000000000000L); + /** + * A Real constant holding the exact value of 5. + */ + public static final Real FIVE = new Real(0,0x40000002,0x5000000000000000L); + /** + * A Real constant holding the exact value of 10. + */ + public static final Real TEN = new Real(0,0x40000003,0x5000000000000000L); + /** + * A Real constant holding the exact value of 100. + */ + public static final Real HUNDRED=new Real(0,0x40000006,0x6400000000000000L); + /** + * A Real constant holding the exact value of 1/2. + */ + public static final Real HALF = new Real(0,0x3fffffff,0x4000000000000000L); + /** + * A Real constant that is closer than any other to 1/3. + */ + public static final Real THIRD= new Real(0,0x3ffffffe,0x5555555555555555L); + /** + * A Real constant that is closer than any other to 1/10. + */ + public static final Real TENTH= new Real(0,0x3ffffffc,0x6666666666666666L); + /** + * A Real constant that is closer than any other to 1/100. + */ + public static final Real PERCENT=new Real(0,0x3ffffff9,0x51eb851eb851eb85L); + /** + * A Real constant that is closer than any other to the + * square root of 2. + */ + public static final Real SQRT2= new Real(0,0x40000000,0x5a827999fcef3242L); + /** + * A Real constant that is closer than any other to the + * square root of 1/2. + */ + public static final Real SQRT1_2=new Real(0,0x3fffffff,0x5a827999fcef3242L); + /** + * A Real constant that is closer than any other to 2π. + */ + public static final Real PI2 = new Real(0,0x40000002,0x6487ed5110b4611aL); + /** + * A Real constant that is closer than any other to π, the + * ratio of the circumference of a circle to its diameter. + */ + public static final Real PI = new Real(0,0x40000001,0x6487ed5110b4611aL); + /** + * A Real constant that is closer than any other to π/2. + */ + public static final Real PI_2 = new Real(0,0x40000000,0x6487ed5110b4611aL); + /** + * A Real constant that is closer than any other to π/4. + */ + public static final Real PI_4 = new Real(0,0x3fffffff,0x6487ed5110b4611aL); + /** + * A Real constant that is closer than any other to π/8. + */ + public static final Real PI_8 = new Real(0,0x3ffffffe,0x6487ed5110b4611aL); + /** + * A Real constant that is closer than any other to e, + * the base of the natural logarithms. + */ + public static final Real E = new Real(0,0x40000001,0x56fc2a2c515da54dL); + /** + * A Real constant that is closer than any other to the + * natural logarithm of 2. + */ + public static final Real LN2 = new Real(0,0x3fffffff,0x58b90bfbe8e7bcd6L); + /** + * A Real constant that is closer than any other to the + * natural logarithm of 10. + */ + public static final Real LN10 = new Real(0,0x40000001,0x49aec6eed554560bL); + /** + * A Real constant that is closer than any other to the + * base-2 logarithm of e. + */ + public static final Real LOG2E= new Real(0,0x40000000,0x5c551d94ae0bf85eL); + /** + * A Real constant that is closer than any other to the + * base-10 logarithm of e. + */ + public static final Real LOG10E=new Real(0,0x3ffffffe,0x6f2dec549b9438cbL); + /** + * A Real constant holding the maximum non-infinite positive + * number = 4.197e323228496. + */ + public static final Real MAX = new Real(0,0x7fffffff,0x7fffffffffffffffL); + /** + * A Real constant holding the minimum non-zero positive + * number = 2.383e-323228497. + */ + public static final Real MIN = new Real(0,0x00000000,0x4000000000000000L); + /** + * A Real constant holding the value of NaN (not-a-number). + * This value is always used as a result to signal an invalid operation. + */ + public static final Real NAN = new Real(0,0x80000000,0x4000000000000000L); + /** + * A Real constant holding the value of positive infinity. + * This value is always used as a result to signal a positive overflow. + */ + public static final Real INF = new Real(0,0x80000000,0x0000000000000000L); + /** + * A Real constant holding the value of negative infinity. + * This value is always used as a result to signal a negative overflow. + */ + public static final Real INF_N= new Real(1,0x80000000,0x0000000000000000L); + /** + * A Real constant holding the value of negative zero. This + * value is used as a result e.g. when a negative underflow occurs. + */ + public static final Real ZERO_N=new Real(1,0x00000000,0x0000000000000000L); + /** + * A Real constant holding the exact value of -1. + */ + public static final Real ONE_N= new Real(1,0x40000000,0x4000000000000000L); + private static final int clz_magic = 0x7c4acdd; + private static final byte[] clz_tab = + { 31,22,30,21,18,10,29, 2,20,17,15,13, 9, 6,28, 1, + 23,19,11, 3,16,14, 7,24,12, 4, 8,25, 5,26,27, 0 }; + /** + * Creates a new Real with a value of zero. + */ + public Real() { + } + /** + * Creates a new Real, assigning the value of another + * Real. See {@link #assign(Real)}. + * + * @param a the Real to assign. + */ + public Real(Real a) { + { this.mantissa = a.mantissa; this.exponent = a.exponent; this.sign = a.sign; }; + } + /** + * Creates a new Real, assigning the value of an integer. See + * {@link #assign(int)}. + * + * @param a the int to assign. + */ + public Real(int a) { + assign(a); + } + /** + * Creates a new Real, assigning the value of a long + * integer. See {@link #assign(long)}. + * + * @param a the long to assign. + */ + public Real(long a) { + assign(a); + } + /** + * Creates a new Real, assigning the value encoded in a + * String using base-10. See {@link #assign(String)}. + * + * @param a the String to assign. + */ + public Real(String a) { + assign(a,10); + } + /** + * Creates a new Real, assigning the value encoded in a + * String using the specified number base. See {@link + * #assign(String,int)}. + * + * @param a the String to assign. + * @param base the number base of a. Valid base values are 2, + * 8, 10 and 16. + */ + public Real(String a, int base) { + assign(a,base); + } + /** + * Creates a new Real, assigning a value by directly setting + * the fields of the internal representation. The arguments must represent + * a valid, normalized Real. This is the fastest way of + * creating a constant value. See {@link #assign(int,int,long)}. + * + * @param s {@link #sign} bit, 0 for positive sign, 1 for negative sign + * @param e {@link #exponent} + * @param m {@link #mantissa} + */ + public Real(int s, int e, long m) { + { this.sign=(byte)s; this.exponent=e; this.mantissa=m; }; + } + /** + * Creates a new Real, assigning the value previously encoded + * into twelve consecutive bytes in a byte array using {@link + * #toBytes(byte[],int) toBytes}. See {@link #assign(byte[],int)}. + * + * @param data byte array to decode into this Real. + * @param offset offset to start encoding from. The bytes + * data[offset]...data[offset+11] will be + * read. + */ + public Real(byte [] data, int offset) { + assign(data,offset); + } + /** + * Assigns this Real the value of another Real. + * + *

+ * Equivalent double code: + * this = a; + *
Error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 0.3 + *
+ * + * @param a the Real to assign. + */ + public void assign(Real a) { + if (a == null) { + makeZero(); + return; + } + sign = a.sign; + exponent = a.exponent; + mantissa = a.mantissa; + } + /** + * Assigns this Real the value of an integer. + * All integer values can be represented without loss of accuracy. + * + *

+ * Equivalent double code: + * this = (double)a; + *
Error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 0.6 + *
+ * + * @param a the int to assign. + */ + public void assign(int a) { + if (a==0) { + makeZero(); + return; + } + sign = 0; + if (a<0) { + sign = 1; + a = -a; // Also works for 0x80000000 + } + // Normalize int + int t=a; t|=t>>1; t|=t>>2; t|=t>>4; t|=t>>8; t|=t>>16; + t = clz_tab[(t*clz_magic)>>>27]-1; + exponent = 0x4000001E-t; + mantissa = ((long)a)<<(32+t); + } + /** + * Assigns this Real the value of a signed long integer. + * All long values can be represented without loss of accuracy. + * + *

+ * Equivalent double code: + * this = (double)a; + *
Error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 1.0 + *
+ * + * @param a the long to assign. + */ + public void assign(long a) { + sign = 0; + if (a<0) { + sign = 1; + a = -a; // Also works for 0x8000000000000000 + } + exponent = 0x4000003E; + mantissa = a; + normalize(); + } + /** + * Assigns this Real a value encoded in a String + * using base-10, as specified in {@link #assign(String,int)}. + * + *

+ * Equivalent double code: + * this = Double.{@link Double#valueOf(String) valueOf}(a); + *
Approximate error bound: + * ½-1 ULPs + *
+ * Execution time relative to add:   + * + * 80 + *
+ * + * @param a the String to assign. + */ + public void assign(String a) { + assign(a,10); + } + /** + * Assigns this Real a value encoded in a String + * using the specified number base. The string is parsed as follows: + * + *

    + *
  • If the string is null or an empty string, zero is + * assigned. + *
  • Leading spaces are ignored. + *
  • An optional sign, '+', '-' or '/', where '/' precedes a negative + * two's-complement number, reading: "an infinite number of 1-bits + * preceding the number". + *
  • Optional digits preceding the radix, in the specified base. + *
      + *
    • In base-2, allowed digits are '01'. + *
    • In base-8, allowed digits are '01234567'. + *
    • In base-10, allowed digits are '0123456789'. + *
    • In base-16, allowed digits are '0123456789ABCDEF'. +
    + *
  • An optional radix character, '.' or ','. + *
  • Optional digits following the radix. + *
  • The following spaces are ignored. + *
  • An optional exponent indicator, 'e'. If not base-16, or after a + * space, 'E' is also accepted. + *
  • An optional sign, '+' or '-'. + *
  • Optional exponent digits in base-10. + *
+ * + *

Valid examples:
+ *     base-2: "-.110010101e+5"
+ *     base-8: "+5462E-99"
+ *     base-10: "  3,1415927"
+ *     base-16: "/FFF800C.CCCE e64" + * + *

The number is parsed until the end of the string or an unknown + * character is encountered, then silently returns even if the whole + * string has not been parsed. Please note that specifying an + * excessive number of digits in base-10 may in fact decrease the + * accuracy of the result because of the extra multiplications performed. + * + *

+ *
+ * Equivalent double code: + * this = Double.{@link Double#valueOf(String) valueOf}(a); + * // Works only for base-10 + *
+ * Approximate error bound: + * base-10 + * ½-1 ULPs + *
2/8/16 + * ½ ULPs + *
+ * Execution time relative to add:   + * base-2 + * 54 + *
base-8 + * 60 + *
base-10 + * 80 + *
base-16   + * 60 + *
+ * + * @param a the String to assign. + * @param base the number base of a. Valid base values are + * 2, 8, 10 and 16. + */ + public void assign(String a, int base) { + if (a==null || a.length()==0) { + assign(ZERO); + return; + } + atof(a,base); + } + /** + * Assigns this Real a value by directly setting the fields + * of the internal representation. The arguments must represent a valid, + * normalized Real. This is the fastest way of assigning a + * constant value. + * + *

+ * Equivalent double code: + * this = (1-2*s) * m * + * Math.{@link Math#pow(double,double) + * pow}(2.0,e-0x400000e3); + *
Error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 0.3 + *
+ * + * @param s {@link #sign} bit, 0 for positive sign, 1 for negative sign + * @param e {@link #exponent} + * @param m {@link #mantissa} + */ + public void assign(int s, int e, long m) { + sign = (byte)s; + exponent = e; + mantissa = m; + } + /** + * Assigns this Real a value previously encoded into into + * twelve consecutive bytes in a byte array using {@link + * #toBytes(byte[],int) toBytes}. + * + *

+ * Error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 1.2 + *
+ * + * @param data byte array to decode into this Real. + * @param offset offset to start encoding from. The bytes + * data[offset]...data[offset+11] will be + * read. + */ + public void assign(byte [] data, int offset) { + sign = (byte)((data[offset+4]>>7)&1); + exponent = (((data[offset ]&0xff)<<24)+ + ((data[offset +1]&0xff)<<16)+ + ((data[offset +2]&0xff)<<8)+ + ((data[offset +3]&0xff))); + mantissa = (((long)(data[offset+ 4]&0x7f)<<56)+ + ((long)(data[offset+ 5]&0xff)<<48)+ + ((long)(data[offset+ 6]&0xff)<<40)+ + ((long)(data[offset+ 7]&0xff)<<32)+ + ((long)(data[offset+ 8]&0xff)<<24)+ + ((long)(data[offset+ 9]&0xff)<<16)+ + ((long)(data[offset+10]&0xff)<< 8)+ + ( (data[offset+11]&0xff))); + } + /** + * Encodes an accurate representation of this Real value into + * twelve consecutive bytes in a byte array. Can be decoded using {@link + * #assign(byte[],int)}. + * + *

+ * Execution time relative to add:   + * + * 1.2 + *
+ * + * @param data byte array to save this Real in. + * @param offset offset to start encoding to. The bytes + * data[offset]...data[offset+11] will be + * written. + */ + public void toBytes(byte [] data, int offset) { + data[offset ] = (byte)(exponent>>24); + data[offset+ 1] = (byte)(exponent>>16); + data[offset+ 2] = (byte)(exponent>>8); + data[offset+ 3] = (byte)(exponent); + data[offset+ 4] = (byte)((sign<<7)+(mantissa>>56)); + data[offset+ 5] = (byte)(mantissa>>48); + data[offset+ 6] = (byte)(mantissa>>40); + data[offset+ 7] = (byte)(mantissa>>32); + data[offset+ 8] = (byte)(mantissa>>24); + data[offset+ 9] = (byte)(mantissa>>16); + data[offset+10] = (byte)(mantissa>>8); + data[offset+11] = (byte)(mantissa); + } + /** + * Assigns this Real the value corresponding to a given bit + * representation. The argument is considered to be a representation of a + * floating-point value according to the IEEE 754 floating-point "single + * format" bit layout. + * + *

+ * Equivalent float code: + * this = Float.{@link Float#intBitsToFloat(int) + * intBitsToFloat}(bits); + *
Error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 0.6 + *
+ * + * @param bits a float value encoded in an int. + */ + public void assignFloatBits(int bits) { + sign = (byte)(bits>>>31); + exponent = (bits>>23)&0xff; + mantissa = (long)(bits&0x007fffff)<<39; + if (exponent == 0 && mantissa == 0) + return; // Valid zero + if (exponent == 0 && mantissa != 0) { + // Degenerate small float + exponent = 0x40000000-126; + normalize(); + return; + } + if (exponent <= 254) { + // Normal IEEE 754 float + exponent += 0x40000000-127; + mantissa |= 1L<<62; + return; + } + if (mantissa == 0) + makeInfinity(sign); + else + makeNan(); + } + /** + * Assigns this Real the value corresponding to a given bit + * representation. The argument is considered to be a representation of a + * floating-point value according to the IEEE 754 floating-point "double + * format" bit layout. + * + *

+ * Equivalent double code: + * this = Double.{@link Double#longBitsToDouble(long) + * longBitsToDouble}(bits); + *
Error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 0.6 + *
+ * + * @param bits a double value encoded in a long. + */ + public void assignDoubleBits(long bits) { + sign = (byte)((bits>>63)&1); + exponent = (int)((bits>>52)&0x7ff); + mantissa = (bits&0x000fffffffffffffL)<<10; + if (exponent == 0 && mantissa == 0) + return; // Valid zero + if (exponent == 0 && mantissa != 0) { + // Degenerate small float + exponent = 0x40000000-1022; + normalize(); + return; + } + if (exponent <= 2046) { + // Normal IEEE 754 float + exponent += 0x40000000-1023; + mantissa |= 1L<<62; + return; + } + if (mantissa == 0) + makeInfinity(sign); + else + makeNan(); + } + /** + * Returns a representation of this Real according to the + * IEEE 754 floating-point "single format" bit layout. + * + *

+ * Equivalent float code: + * Float.{@link Float#floatToIntBits(float) + * floatToIntBits}(this) + *
+ * Execution time relative to add:   + * + * 0.7 + *
+ * + * @return the bits that represent the floating-point number. + */ + public int toFloatBits() { + if ((this.exponent < 0 && this.mantissa != 0)) + return 0x7fffffff; // nan + int e = exponent-0x40000000+127; + long m = mantissa; + // Round properly! + m += 1L<<38; + if (m<0) { + m >>>= 1; + e++; + if (exponent < 0) // Overflow + return (sign<<31)|0x7f800000; // inf + } + if ((this.exponent < 0 && this.mantissa == 0) || e > 254) + return (sign<<31)|0x7f800000; // inf + if ((this.exponent == 0 && this.mantissa == 0) || e < -22) + return (sign<<31); // zero + if (e <= 0) // Degenerate small float + return (sign<<31)|((int)(m>>>(40-e))&0x007fffff); + // Normal IEEE 754 float + return (sign<<31)|(e<<23)|((int)(m>>>39)&0x007fffff); + } + /** + * Returns a representation of this Real according to the + * IEEE 754 floating-point "double format" bit layout. + * + *

+ * Equivalent double code: + * Double.{@link Double#doubleToLongBits(double) + * doubleToLongBits}(this) + *
+ * Execution time relative to add:   + * + * 0.7 + *
+ * + * @return the bits that represent the floating-point number. + */ + public long toDoubleBits() { + if ((this.exponent < 0 && this.mantissa != 0)) + return 0x7fffffffffffffffL; // nan + int e = exponent-0x40000000+1023; + long m = mantissa; + // Round properly! + m += 1L<<9; + if (m<0) { + m >>>= 1; + e++; + if (exponent < 0) + return ((long)sign<<63)|0x7ff0000000000000L; // inf + } + if ((this.exponent < 0 && this.mantissa == 0) || e > 2046) + return ((long)sign<<63)|0x7ff0000000000000L; // inf + if ((this.exponent == 0 && this.mantissa == 0) || e < -51) + return ((long)sign<<63); // zero + if (e <= 0) // Degenerate small double + return ((long)sign<<63)|((m>>>(11-e))&0x000fffffffffffffL); + // Normal IEEE 754 double + return ((long)sign<<63)|((long)e<<52)|((m>>>10)&0x000fffffffffffffL); + } + /** + * Makes this Real the value of positive zero. + * + *

+ * Equivalent double code: + * this = 0; + *
+ * Execution time relative to add:   + * + * 0.2 + *
+ */ + public void makeZero() { + sign = 0; + mantissa = 0; + exponent = 0; + } + /** + * Makes this Real the value of zero with the specified sign. + * + *

+ * Equivalent double code: + * this = 0.0 * (1-2*s); + *
+ * Execution time relative to add:   + * + * 0.2 + *
+ * + * @param s sign bit, 0 to make a positive zero, 1 to make a negative zero + */ + public void makeZero(int s) { + sign = (byte)s; + mantissa = 0; + exponent = 0; + } + /** + * Makes this Real the value of infinity with the specified + * sign. + * + *

+ * Equivalent double code: + * this = Double.{@link Double#POSITIVE_INFINITY POSITIVE_INFINITY} + * * (1-2*s); + *
+ * Execution time relative to add:   + * + * 0.3 + *
+ * + * @param s sign bit, 0 to make positive infinity, 1 to make negative + * infinity + */ + public void makeInfinity(int s) { + sign = (byte)s; + mantissa = 0; + exponent = 0x80000000; + } + /** + * Makes this Real the value of Not-a-Number (NaN). + * + *

+ * Equivalent double code: + * this = Double.{@link Double#NaN NaN}; + *
+ * Execution time relative to add:   + * + * 0.3 + *
+ */ + public void makeNan() { + sign = 0; + mantissa = 0x4000000000000000L; + exponent = 0x80000000; + } + /** + * Returns true if the value of this Real is + * zero, false otherwise. + * + *

+ * Equivalent double code: + * (this == 0) + *
+ * Execution time relative to add:   + * + * 0.3 + *
+ * + * @return true if the value represented by this object is + * zero, false otherwise. + */ + public boolean isZero() { + return (exponent == 0 && mantissa == 0); + } + /** + * Returns true if the value of this Real is + * infinite, false otherwise. + * + *

+ * Equivalent double code: + * Double.{@link Double#isInfinite(double) isInfinite}(this) + *
+ * Execution time relative to add:   + * + * 0.3 + *
+ * + * @return true if the value represented by this object is + * infinite, false if it is finite or NaN. + */ + public boolean isInfinity() { + return (exponent < 0 && mantissa == 0); + } + /** + * Returns true if the value of this Real is + * Not-a-Number (NaN), false otherwise. + * + *

+ * Equivalent double code: + * Double.{@link Double#isNaN(double) isNaN}(this) + *
+ * Execution time relative to add:   + * + * 0.3 + *
+ * + * @return true if the value represented by this object is + * NaN, false otherwise. + */ + public boolean isNan() { + return (exponent < 0 && mantissa != 0); + } + /** + * Returns true if the value of this Real is + * finite, false otherwise. + * + *

+ * Equivalent double code: + * (!Double.{@link Double#isNaN(double) isNaN}(this) && + * !Double.{@link Double#isInfinite(double) + * isInfinite}(this)) + *
+ * Execution time relative to add:   + * + * 0.3 + *
+ * + * @return true if the value represented by this object is + * finite, false if it is infinite or NaN. + */ + public boolean isFinite() { + // That is, non-infinite and non-nan + return (exponent >= 0); + } + /** + * Returns true if the value of this Real is + * finite and nonzero, false otherwise. + * + *

+ * Equivalent double code: + * (!Double.{@link Double#isNaN(double) isNaN}(this) && + * !Double.{@link Double#isInfinite(double) isInfinite}(this) && + * (this!=0)) + *
+ * Execution time relative to add:   + * + * 0.3 + *
+ * + * @return true if the value represented by this object is + * finite and nonzero, false if it is infinite, NaN or + * zero. + */ + public boolean isFiniteNonZero() { + // That is, non-infinite and non-nan and non-zero + return (exponent >= 0 && mantissa != 0); + } + /** + * Returns true if the value of this Real is + * negative, false otherwise. + * + *

+ * Equivalent double code: + * (this < 0) + *
+ * Execution time relative to add:   + * + * 0.3 + *
+ * + * @return true if the value represented by this object + * is negative, false if it is positive or NaN. + */ + public boolean isNegative() { + return sign!=0; + } + /** + * Calculates the absolute value. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#abs(double) abs}(this); + *
Error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 0.2 + *
+ */ + public void abs() { + sign = 0; + } + /** + * Negates this Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = -this; + *
Error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 0.2 + *
+ */ + public void neg() { + if (!(this.exponent < 0 && this.mantissa != 0)) + sign ^= 1; + } + /** + * Copies the sign from a. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#abs(double) + * abs}(this)*Math.{@link Math#signum(double) signum}(a); + *
Error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 0.2 + *
+ * + * @param a the Real to copy the sign from. + */ + public void copysign(Real a) { + if ((this.exponent < 0 && this.mantissa != 0) || (a.exponent < 0 && a.mantissa != 0)) { + makeNan(); + return; + } + sign = a.sign; + } + /** + * Readjusts the mantissa of this Real. The exponent is + * adjusted accordingly. This is necessary when the mantissa has been + * {@link #mantissa modified directly} for some purpose and may be + * denormalized. The normalized mantissa of a finite Real + * must have bit 63 cleared and bit 62 set. Using a denormalized + * Real in any other operation may produce undefined + * results. + * + *

+ * Error bound: + * ½ ULPs + *
+ * Execution time relative to add:   + * + * 0.7 + *
+ */ + public void normalize() { + if ((this.exponent >= 0)) { + if (mantissa > 0) + { + int clz = 0; + int t = (int)(mantissa>>>32); + if (t == 0) { clz = 32; t = (int)mantissa; } + t|=t>>1; t|=t>>2; t|=t>>4; t|=t>>8; t|=t>>16; + clz += clz_tab[(t*clz_magic)>>>27]-1; + mantissa <<= clz; + exponent -= clz; + if (exponent < 0) // Underflow + makeZero(sign); + } + else if (mantissa < 0) + { + mantissa = (mantissa+1)>>>1; + exponent ++; + if (mantissa == 0) { // Ooops, it was 0xffffffffffffffffL + mantissa = 0x4000000000000000L; + exponent ++; + } + if (exponent < 0) // Overflow + makeInfinity(sign); + } + else // mantissa == 0 + { + exponent = 0; + } + } + } + /** + * Readjusts the mantissa of a Real with extended + * precision. The exponent is adjusted accordingly. This is necessary when + * the mantissa has been {@link #mantissa modified directly} for some + * purpose and may be denormalized. The normalized mantissa of a finite + * Real must have bit 63 cleared and bit 62 set. Using a + * denormalized Real in any other operation may + * produce undefined results. + * + *

+ * Approximate error bound: + * 2-64 ULPs (i.e. of a normal precision Real) + *
+ * Execution time relative to add:   + * + * 0.7 + *
+ * + * @param extra the extra 64 bits of mantissa of this extended precision + * Real. + * @return the extra 64 bits of mantissa of the resulting extended + * precision Real. + */ + public long normalize128(long extra) { + if (!(this.exponent >= 0)) + return 0; + if (mantissa == 0) { + if (extra == 0) { + exponent = 0; + return 0; + } + mantissa = extra; + extra = 0; + exponent -= 64; + if (exponent < 0) { // Underflow + makeZero(sign); + return 0; + } + } + if (mantissa < 0) { + extra = (mantissa<<63)+(extra>>>1); + mantissa >>>= 1; + exponent ++; + if (exponent < 0) { // Overflow + makeInfinity(sign); + return 0; + } + return extra; + } + int clz = 0; + int t = (int)(mantissa>>>32); + if (t == 0) { clz = 32; t = (int)mantissa; } + t|=t>>1; t|=t>>2; t|=t>>4; t|=t>>8; t|=t>>16; + clz += clz_tab[(t*clz_magic)>>>27]-1; + if (clz == 0) + return extra; + mantissa = (mantissa<>>(64-clz)); + extra <<= clz; + exponent -= clz; + if (exponent < 0) { // Underflow + makeZero(sign); + return 0; + } + return extra; + } + /** + * Rounds an extended precision Real to the nearest + * Real of normal precision. Replaces the contents of this + * Real with the result. + * + *

+ * Error bound: + * ½ ULPs + *
+ * Execution time relative to add:   + * + * 1.0 + *
+ * + * @param extra the extra 64 bits of mantissa of this extended precision + * Real. + */ + public void roundFrom128(long extra) { + mantissa += (extra>>63)&1; + normalize(); + } + /** + * Returns true if this Java object is the same + * object as a. Since a Real should be + * thought of as a "register holding a number", this method compares the + * object references, not the contents of the two objects. + * This is very different from {@link #equalTo(Real)}. + * + * @param a the object to compare to this. + * @return true if this object is the same as a. + */ + public boolean equals(Object a) { + return this==a; + } + private int compare(Real a) { + // Compare of normal floats, zeros, but not nan or equal-signed inf + if ((this.exponent == 0 && this.mantissa == 0) && (a.exponent == 0 && a.mantissa == 0)) + return 0; + if (sign != a.sign) + return a.sign-sign; + int s = (this.sign==0) ? 1 : -1; + if ((this.exponent < 0 && this.mantissa == 0)) + return s; + if ((a.exponent < 0 && a.mantissa == 0)) + return -s; + if (exponent != a.exponent) + return exponenttrue if this Real is equal to + * a. + * If the numbers are incomparable, i.e. the values are infinities of + * the same sign or any of them is NaN, false is always + * returned. This method must not be confused with {@link #equals(Object)}. + * + *

+ * Equivalent double code: + * (this == a) + *
+ * Execution time relative to add:   + * + * 1.0 + *
+ * + * @param a the Real to compare to this. + * @return true if the value represented by this object is + * equal to the value represented by a. false + * otherwise, or if the numbers are incomparable. + */ + public boolean equalTo(Real a) { + if (invalidCompare(a)) + return false; + return compare(a) == 0; + } + /** + * Returns true if this Real is equal to + * the integer a. + * + *

+ * Equivalent double code: + * (this == a) + *
+ * Execution time relative to add:   + * + * 1.7 + *
+ * + * @param a the int to compare to this. + * @return true if the value represented by this object is + * equal to the integer a. false + * otherwise. + */ + public boolean equalTo(int a) { + tmp0.assign(a); + return equalTo(tmp0); + } + /** + * Returns true if this Real is not equal to + * a. + * If the numbers are incomparable, i.e. the values are infinities of + * the same sign or any of them is NaN, false is always + * returned. + * This distinguishes notEqualTo(a) from the expression + * !equalTo(a). + * + *

+ * Equivalent double code: + * (this != a) + *
+ * Execution time relative to add:   + * + * 1.0 + *
+ * + * @param a the Real to compare to this. + * @return true if the value represented by this object is not + * equal to the value represented by a. false + * otherwise, or if the numbers are incomparable. + */ + public boolean notEqualTo(Real a) { + if (invalidCompare(a)) + return false; + return compare(a) != 0; + } + /** + * Returns true if this Real is not equal to + * the integer a. + * If this Real is NaN, false is always + * returned. + * This distinguishes notEqualTo(a) from the expression + * !equalTo(a). + * + *

+ * Equivalent double code: + * (this != a) + *
+ * Execution time relative to add:   + * + * 1.7 + *
+ * + * @param a the int to compare to this. + * @return true if the value represented by this object is not + * equal to the integer a. false + * otherwise, or if this Real is NaN. + */ + public boolean notEqualTo(int a) { + tmp0.assign(a); + return notEqualTo(tmp0); + } + /** + * Returns true if this Real is less than + * a. + * If the numbers are incomparable, i.e. the values are infinities of + * the same sign or any of them is NaN, false is always + * returned. + * + *

+ * Equivalent double code: + * (this < a) + *
+ * Execution time relative to add:   + * + * 1.0 + *
+ * + * @param a the Real to compare to this. + * @return true if the value represented by this object is + * less than the value represented by a. + * false otherwise, or if the numbers are incomparable. + */ + public boolean lessThan(Real a) { + if (invalidCompare(a)) + return false; + return compare(a) < 0; + } + /** + * Returns true if this Real is less than + * the integer a. + * If this Real is NaN, false is always + * returned. + * + *

+ * Equivalent double code: + * (this < a) + *
+ * Execution time relative to add:   + * + * 1.7 + *
+ * + * @param a the int to compare to this. + * @return true if the value represented by this object is + * less than the integer a. false otherwise, + * or if this Real is NaN. + */ + public boolean lessThan(int a) { + tmp0.assign(a); + return lessThan(tmp0); + } + /** + * Returns true if this Real is less than or + * equal to a. + * If the numbers are incomparable, i.e. the values are infinities of + * the same sign or any of them is NaN, false is always + * returned. + * + *

+ * Equivalent double code: + * (this <= a) + *
+ * Execution time relative to add:   + * + * 1.0 + *
+ * + * @param a the Real to compare to this. + * @return true if the value represented by this object is + * less than or equal to the value represented by a. + * false otherwise, or if the numbers are incomparable. + */ + public boolean lessEqual(Real a) { + if (invalidCompare(a)) + return false; + return compare(a) <= 0; + } + /** + * Returns true if this Real is less than or + * equal to the integer a. + * If this Real is NaN, false is always + * returned. + * + *

+ * Equivalent double code: + * (this <= a) + *
+ * Execution time relative to add:   + * + * 1.7 + *
+ * + * @param a the int to compare to this. + * @return true if the value represented by this object is + * less than or equal to the integer a. false + * otherwise, or if this Real is NaN. + */ + public boolean lessEqual(int a) { + tmp0.assign(a); + return lessEqual(tmp0); + } + /** + * Returns true if this Real is greater than + * a. + * If the numbers are incomparable, i.e. the values are infinities of + * the same sign or any of them is NaN, false is always + * returned. + * + *

+ * Equivalent double code: + * (this > a) + *
+ * Execution time relative to add:   + * + * 1.0 + *
+ * + * @param a the Real to compare to this. + * @return true if the value represented by this object is + * greater than the value represented by a. + * false otherwise, or if the numbers are incomparable. + */ + public boolean greaterThan(Real a) { + if (invalidCompare(a)) + return false; + return compare(a) > 0; + } + /** + * Returns true if this Real is greater than + * the integer a. + * If this Real is NaN, false is always + * returned. + * + *

+ * Equivalent double code: + * (this > a) + *
+ * Execution time relative to add:   + * + * 1.7 + *
+ * + * @param a the int to compare to this. + * @return true if the value represented by this object is + * greater than the integer a. + * false otherwise, or if this Real is NaN. + */ + public boolean greaterThan(int a) { + tmp0.assign(a); + return greaterThan(tmp0); + } + /** + * Returns true if this Real is greater than + * or equal to a. + * If the numbers are incomparable, i.e. the values are infinities of + * the same sign or any of them is NaN, false is always + * returned. + * + *

+ * Equivalent double code: + * (this >= a) + *
+ * Execution time relative to add:   + * + * 1.0 + *
+ * + * @param a the Real to compare to this. + * @return true if the value represented by this object is + * greater than or equal to the value represented by a. + * false otherwise, or if the numbers are incomparable. + */ + public boolean greaterEqual(Real a) { + if (invalidCompare(a)) + return false; + return compare(a) >= 0; + } + /** + * Returns true if this Real is greater than + * or equal to the integer a. + * If this Real is NaN, false is always + * returned. + * + *

+ * Equivalent double code: + * (this >= a) + *
+ * Execution time relative to add:   + * + * 1.7 + *
+ * + * @param a the int to compare to this. + * @return true if the value represented by this object is + * greater than or equal to the integer a. + * false otherwise, or if this Real is NaN. + */ + public boolean greaterEqual(int a) { + tmp0.assign(a); + return greaterEqual(tmp0); + } + /** + * Returns true if the absolute value of this + * Real is less than the absolute value of + * a. + * If the numbers are incomparable, i.e. the values are both infinite + * or any of them is NaN, false is always returned. + * + *

+ * Equivalent double code: + * (Math.{@link Math#abs(double) abs}(this) < + * Math.{@link Math#abs(double) abs}(a)) + *
+ * Execution time relative to add:   + * + * 0.5 + *
+ * + * @param a the Real to compare to this. + * @return true if the absolute of the value represented by + * this object is less than the absolute of the value represented by + * a. + * false otherwise, or if the numbers are incomparable. + */ + public boolean absLessThan(Real a) { + if ((this.exponent < 0 && this.mantissa != 0) || (a.exponent < 0 && a.mantissa != 0) || (this.exponent < 0 && this.mantissa == 0)) + return false; + if ((a.exponent < 0 && a.mantissa == 0)) + return true; + if (exponent != a.exponent) + return exponentReal by 2 to the power of n. + * Replaces the contents of this Real with the result. + * This operation is faster than normal multiplication since it only + * involves adding to the exponent. + * + *

+ * Equivalent double code: + * this *= Math.{@link Math#pow(double,double) pow}(2.0,n); + *
Error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 0.3 + *
+ * + * @param n the integer argument. + */ + public void scalbn(int n) { + if (!(this.exponent >= 0 && this.mantissa != 0)) + return; + exponent += n; + if (exponent < 0) { + if (n<0) + makeZero(sign); // Underflow + else + makeInfinity(sign); // Overflow + } + } + /** + * Calculates the next representable neighbour of this Real + * in the direction towards a. + * Replaces the contents of this Real with the result. + * If the two values are equal, nothing happens. + * + *

+ * Equivalent double code: + * this += Math.{@link Math#ulp(double) ulp}(this)*Math.{@link + * Math#signum(double) signum}(a-this); + *
Error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 0.8 + *
+ * + * @param a the Real argument. + */ + public void nextafter(Real a) { + if ((this.exponent < 0 && this.mantissa != 0) || (a.exponent < 0 && a.mantissa != 0)) { + makeNan(); + return; + } + if ((this.exponent < 0 && this.mantissa == 0) && (a.exponent < 0 && a.mantissa == 0) && sign == a.sign) + return; + int dir = -compare(a); + if (dir == 0) + return; + if ((this.exponent == 0 && this.mantissa == 0)) { + { this.mantissa = MIN.mantissa; this.exponent = MIN.exponent; this.sign = MIN.sign; }; + sign = (byte)(dir<0 ? 1 : 0); + return; + } + if ((this.exponent < 0 && this.mantissa == 0)) { + { this.mantissa = MAX.mantissa; this.exponent = MAX.exponent; this.sign = MAX.sign; }; + sign = (byte)(dir<0 ? 0 : 1); + return; + } + if ((this.sign==0) ^ dir<0) { + mantissa ++; + } else { + if (mantissa == 0x4000000000000000L) { + mantissa <<= 1; + exponent--; + } + mantissa --; + } + normalize(); + } + /** + * Calculates the largest (closest to positive infinity) + * Real value that is less than or equal to this + * Real and is equal to a mathematical integer. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#floor(double) floor}(this); + *
Approximate error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 0.5 + *
+ */ + public void floor() { + if (!(this.exponent >= 0 && this.mantissa != 0)) + return; + if (exponent < 0x40000000) { + if ((this.sign==0)) + makeZero(sign); + else { + exponent = ONE.exponent; + mantissa = ONE.mantissa; + // sign unchanged! + } + return; + } + int shift = 0x4000003e-exponent; + if (shift <= 0) + return; + if ((this.sign!=0)) + mantissa += ((1L<Real value that is greater than or equal to this + * Real and is equal to a mathematical integer. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#ceil(double) ceil}(this); + *
Approximate error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 1.8 + *
+ */ + public void ceil() { + neg(); + floor(); + neg(); + } + /** + * Rounds this Real value to the closest value that is equal + * to a mathematical integer. If two Real values that are + * mathematical integers are equally close, the result is the integer + * value with the largest magnitude (positive or negative). Replaces the + * contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#rint(double) rint}(this); + *
Approximate error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 1.3 + *
+ */ + public void round() { + if (!(this.exponent >= 0 && this.mantissa != 0)) + return; + if (exponent < 0x3fffffff) { + makeZero(sign); + return; + } + int shift = 0x4000003e-exponent; + if (shift <= 0) + return; + mantissa += 1L<<(shift-1); // Bla-bla, this works almost + mantissa &= ~((1L<Real value to the closest value towards + * zero that is equal to a mathematical integer. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = (double)((long)this); + *
Approximate error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 1.2 + *
+ */ + public void trunc() { + if (!(this.exponent >= 0 && this.mantissa != 0)) + return; + if (exponent < 0x40000000) { + makeZero(sign); + return; + } + int shift = 0x4000003e-exponent; + if (shift <= 0) + return; + mantissa &= ~((1L<Real by subtracting + * the closest value towards zero that is equal to a mathematical integer. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this -= (double)((long)this); + *
Approximate error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 1.2 + *
+ */ + public void frac() { + if (!(this.exponent >= 0 && this.mantissa != 0) || exponent < 0x40000000) + return; + int shift = 0x4000003e-exponent; + if (shift <= 0) { + makeZero(sign); + return; + } + mantissa &= ((1L<Real value to the closest int + * value towards zero. + * + *

If the value of this Real is too large, {@link + * Integer#MAX_VALUE} is returned. However, if the value of this + * Real is too small, -Integer.MAX_VALUE is + * returned, not {@link Integer#MIN_VALUE}. This is done to ensure that + * the sign will be correct if you calculate + * -this.toInteger(). A NaN is converted to 0. + * + *

+ * Equivalent double code: + * (int)this + *
Approximate error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 0.6 + *
+ * + * @return an int representation of this Real. + */ + public int toInteger() { + if ((this.exponent == 0 && this.mantissa == 0) || (this.exponent < 0 && this.mantissa != 0)) + return 0; + if ((this.exponent < 0 && this.mantissa == 0)) { + return ((this.sign==0)) ? 0x7fffffff : 0x80000001; + // 0x80000001, so that you can take -x.toInteger() + } + if (exponent < 0x40000000) + return 0; + int shift = 0x4000003e-exponent; + if (shift < 32) { + return ((this.sign==0)) ? 0x7fffffff : 0x80000001; + // 0x80000001, so that you can take -x.toInteger() + } + return (this.sign==0) ? + (int)(mantissa>>>shift) : -(int)(mantissa>>>shift); + } + /** + * Converts this Real value to the closest long + * value towards zero. + * + *

If the value of this Real is too large, {@link + * Long#MAX_VALUE} is returned. However, if the value of this + * Real is too small, -Long.MAX_VALUE is + * returned, not {@link Long#MIN_VALUE}. This is done to ensure that the + * sign will be correct if you calculate -this.toLong(). + * A NaN is converted to 0. + * + *

+ * Equivalent double code: + * (long)this + *
Approximate error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 0.5 + *
+ * + * @return a long representation of this Real. + */ + public long toLong() { + if ((this.exponent == 0 && this.mantissa == 0) || (this.exponent < 0 && this.mantissa != 0)) + return 0; + if ((this.exponent < 0 && this.mantissa == 0)) { + return ((this.sign==0))? 0x7fffffffffffffffL:0x8000000000000001L; + // 0x8000000000000001L, so that you can take -x.toLong() + } + if (exponent < 0x40000000) + return 0; + int shift = 0x4000003e-exponent; + if (shift < 0) { + return ((this.sign==0))? 0x7fffffffffffffffL:0x8000000000000001L; + // 0x8000000000000001L, so that you can take -x.toLong() + } + return (this.sign==0) ? (mantissa>>>shift) : -(mantissa>>>shift); + } + /** + * Returns true if the value of this Real + * represents a mathematical integer. If the value is too large to + * determine if it is an integer, true is returned. + * + *

+ * Equivalent double code: + * (this == (long)this) + *
+ * Execution time relative to add:   + * + * 0.6 + *
+ * + * @return true if the value represented by this object + * represents a mathematical integer, false otherwise. + */ + public boolean isIntegral() { + if ((this.exponent < 0 && this.mantissa != 0)) + return false; + if ((this.exponent == 0 && this.mantissa == 0) || (this.exponent < 0 && this.mantissa == 0)) + return true; + if (exponent < 0x40000000) + return false; + int shift = 0x4000003e-exponent; + if (shift <= 0) + return true; + return (mantissa&((1L<true if the mathematical integer represented + * by this Real is odd. You must first determine + * that the value is actually an integer using {@link + * #isIntegral()}. If the value is too large to determine if the + * integer is odd, false is returned. + * + *

+ * Equivalent double code: + * ((((long)this)&1) == 1) + *
+ * Execution time relative to add:   + * + * 0.6 + *
+ * + * @return true if the mathematical integer represented by + * this Real is odd, false otherwise. + */ + public boolean isOdd() { + if (!(this.exponent >= 0 && this.mantissa != 0) || + exponent < 0x40000000 || exponent > 0x4000003e) + return false; + int shift = 0x4000003e-exponent; + return ((mantissa>>>shift)&1) != 0; + } + /** + * Exchanges the contents of this Real and a. + * + *

+ * Equivalent double code: + * tmp=this; this=a; a=tmp; + *
Error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 0.5 + *
+ * + * @param a the Real to exchange with this. + */ + public void swap(Real a) { + long tmpMantissa=mantissa; mantissa=a.mantissa; a.mantissa=tmpMantissa; + int tmpExponent=exponent; exponent=a.exponent; a.exponent=tmpExponent; + byte tmpSign =sign; sign =a.sign; a.sign =tmpSign; + } + // Temporary values used by functions (to avoid "new" inside functions) + private static Real tmp0 = new Real(); // tmp for basic functions + private static Real recipTmp = new Real(); + private static Real recipTmp2 = new Real(); + private static Real sqrtTmp = new Real(); + private static Real expTmp = new Real(); + private static Real expTmp2 = new Real(); + private static Real expTmp3 = new Real(); + private static Real tmp1 = new Real(); + private static Real tmp2 = new Real(); + private static Real tmp3 = new Real(); + private static Real tmp4 = new Real(); + private static Real tmp5 = new Real(); + /** + * Calculates the sum of this Real and a. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this += a; + *
Error bound: + * ½ ULPs + *
+ * Execution time relative to add:   + * + * «« 1.0 »» + *
+ * + * @param a the Real to add to this. + */ + public void add(Real a) { + if ((this.exponent < 0 && this.mantissa != 0) || (a.exponent < 0 && a.mantissa != 0)) { + makeNan(); + return; + } + if ((this.exponent < 0 && this.mantissa == 0) || (a.exponent < 0 && a.mantissa == 0)) { + if ((this.exponent < 0 && this.mantissa == 0) && (a.exponent < 0 && a.mantissa == 0) && sign != a.sign) + makeNan(); + else + makeInfinity((this.exponent < 0 && this.mantissa == 0) ? sign : a.sign); + return; + } + if ((this.exponent == 0 && this.mantissa == 0) || (a.exponent == 0 && a.mantissa == 0)) { + if ((this.exponent == 0 && this.mantissa == 0)) + { this.mantissa = a.mantissa; this.exponent = a.exponent; this.sign = a.sign; }; + if ((this.exponent == 0 && this.mantissa == 0)) + sign=0; + return; + } + byte s; + int e; + long m; + if (exponent > a.exponent || + (exponent == a.exponent && mantissa>=a.mantissa)) + { + s = a.sign; + e = a.exponent; + m = a.mantissa; + } else { + s = sign; + e = exponent; + m = mantissa; + sign = a.sign; + exponent = a.exponent; + mantissa = a.mantissa; + } + int shift = exponent-e; + if (shift>=64) + return; + if (sign == s) { + mantissa += m>>>shift; + if (mantissa >= 0 && shift>0 && ((m>>>(shift-1))&1) != 0) + mantissa ++; // We don't need normalization, so round now + if (mantissa < 0) { + // Simplified normalize() + mantissa = (mantissa+1)>>>1; + exponent ++; + if (exponent < 0) { // Overflow + makeInfinity(sign); + return; + } + } + } else { + if (shift>0) { + // Shift mantissa up to increase accuracy + mantissa <<= 1; + exponent --; + shift --; + } + m = -m; + mantissa += m>>shift; + if (mantissa >= 0 && shift>0 && ((m>>>(shift-1))&1) != 0) + mantissa ++; // We don't need to shift down, so round now + if (mantissa < 0) { + // Simplified normalize() + mantissa = (mantissa+1)>>>1; + exponent ++; // Can't overflow + } else if (shift==0) { + // Operands have equal exponents => many bits may be cancelled + // Magic rounding: if result of subtract leaves only a few bits + // standing, the result should most likely be 0... + if (magicRounding && mantissa > 0 && mantissa <= 7) { + // If arguments were integers <= 2^63-1, then don't + // do the magic rounding anyway. + // This is a bit "post mortem" investigation but it happens + // so seldom that it's no problem to spend the extra time. + m = -m; + if (exponent == 0x4000003c || exponent == 0x4000003d || + (exponent == 0x4000003e && mantissa+m > 0)) { + long mask = (1<<(0x4000003e-exponent))-1; + if ((mantissa & mask) != 0 || (m & mask) != 0) + mantissa = 0; + } else + mantissa = 0; + } + normalize(); + } // else... if (shift>=1 && mantissa>=0) it should be a-ok + } + if ((this.exponent == 0 && this.mantissa == 0)) + sign=0; + } + /** + * Calculates the sum of this Real and the integer + * a. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this += a; + *
Error bound: + * ½ ULPs + *
+ * Execution time relative to add:   + * + * 1.8 + *
+ * + * @param a the int to add to this. + */ + public void add(int a) { + tmp0.assign(a); + add(tmp0); + } + /** + * Calculates the sum of this Real and a with + * extended precision. Replaces the contents of this Real + * with the result. Returns the extra mantissa of the extended precision + * result. + * + *

An extra 64 bits of mantissa is added to both arguments for extended + * precision. If any of the arguments are not of extended precision, use + * 0 for the extra mantissa. + * + *

Extended prevision can be useful in many situations. For instance, + * when accumulating a lot of very small values it is advantageous for the + * accumulator to have extended precision. To convert the extended + * precision value back to a normal Real for further + * processing, use {@link #roundFrom128(long)}. + * + *

+ * Equivalent double code: + * this += a; + *
Approximate error bound: + * 2-62 ULPs (i.e. of a normal precision Real) + *
+ * Execution time relative to add:   + * + * 2.0 + *
+ * + * @param extra the extra 64 bits of mantissa of this extended precision + * Real. + * @param a the Real to add to this. + * @param aExtra the extra 64 bits of mantissa of the extended precision + * value a. + * @return the extra 64 bits of mantissa of the resulting extended + * precision Real. + */ + public long add128(long extra, Real a, long aExtra) { + if ((this.exponent < 0 && this.mantissa != 0) || (a.exponent < 0 && a.mantissa != 0)) { + makeNan(); + return 0; + } + if ((this.exponent < 0 && this.mantissa == 0) || (a.exponent < 0 && a.mantissa == 0)) { + if ((this.exponent < 0 && this.mantissa == 0) && (a.exponent < 0 && a.mantissa == 0) && sign != a.sign) + makeNan(); + else + makeInfinity((this.exponent < 0 && this.mantissa == 0) ? sign : a.sign); + return 0; + } + if ((this.exponent == 0 && this.mantissa == 0) || (a.exponent == 0 && a.mantissa == 0)) { + if ((this.exponent == 0 && this.mantissa == 0)) { + { this.mantissa = a.mantissa; this.exponent = a.exponent; this.sign = a.sign; }; + extra = aExtra; + } + if ((this.exponent == 0 && this.mantissa == 0)) + sign=0; + return extra; + } + byte s; + int e; + long m; + long x; + if (exponent > a.exponent || + (exponent == a.exponent && mantissa>a.mantissa) || + (exponent == a.exponent && mantissa==a.mantissa && + (extra>>>1)>=(aExtra>>>1))) + { + s = a.sign; + e = a.exponent; + m = a.mantissa; + x = aExtra; + } else { + s = sign; + e = exponent; + m = mantissa; + x = extra; + sign = a.sign; + exponent = a.exponent; + mantissa = a.mantissa; + extra = aExtra; + } + int shift = exponent-e; + if (shift>=127) + return extra; + if (shift>=64) { + x = m>>>(shift-64); + m = 0; + } else if (shift>0) { + x = (x>>>shift)+(m<<(64-shift)); + m >>>= shift; + } + extra >>>= 1; + x >>>= 1; + if (sign == s) { + extra += x; + mantissa += (extra>>63)&1; + mantissa += m; + } else { + extra -= x; + mantissa -= (extra>>63)&1; + mantissa -= m; + // Magic rounding: if result of subtract leaves only a few bits + // standing, the result should most likely be 0... + if (mantissa == 0 && extra > 0 && extra <= 0x1f) + extra = 0; + } + extra <<= 1; + extra = normalize128(extra); + if ((this.exponent == 0 && this.mantissa == 0)) + sign=0; + return extra; + } + /** + * Calculates the difference between this Real and + * a. + * Replaces the contents of this Real with the result. + * + *

(To achieve extended precision subtraction, it is enough to call + * a.{@link #neg() neg}() before calling {@link + * #add128(long,Real,long) add128}(extra,a,aExtra), since only + * the sign bit of a need to be changed.) + * + *

+ * Equivalent double code: + * this -= a; + *
Error bound: + * ½ ULPs + *
+ * Execution time relative to add:   + * + * 2.0 + *
+ * + * @param a the Real to subtract from this. + */ + public void sub(Real a) { + tmp0.mantissa = a.mantissa; + tmp0.exponent = a.exponent; + tmp0.sign = (byte)(a.sign^1); + add(tmp0); + } + /** + * Calculates the difference between this Real and the + * integer a. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this -= a; + *
Error bound: + * ½ ULPs + *
+ * Execution time relative to add:   + * + * 2.4 + *
+ * + * @param a the int to subtract from this. + */ + public void sub(int a) { + tmp0.assign(a); + sub(tmp0); + } + /** + * Calculates the product of this Real and a. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this *= a; + *
Error bound: + * ½ ULPs + *
+ * Execution time relative to add:   + * + * 1.3 + *
+ * + * @param a the Real to multiply to this. + */ + public void mul(Real a) { + if ((this.exponent < 0 && this.mantissa != 0) || (a.exponent < 0 && a.mantissa != 0)) { + makeNan(); + return; + } + sign ^= a.sign; + if ((this.exponent == 0 && this.mantissa == 0) || (a.exponent == 0 && a.mantissa == 0)) { + if ((this.exponent < 0 && this.mantissa == 0) || (a.exponent < 0 && a.mantissa == 0)) + makeNan(); + else + makeZero(sign); + return; + } + if ((this.exponent < 0 && this.mantissa == 0) || (a.exponent < 0 && a.mantissa == 0)) { + makeInfinity(sign); + return; + } + long a0 = mantissa & 0x7fffffff; + long a1 = mantissa >>> 31; + long b0 = a.mantissa & 0x7fffffff; + long b1 = a.mantissa >>> 31; + mantissa = a1*b1; + // If we're going to need normalization, we don't want to round twice + int round = (mantissa<0) ? 0 : 0x40000000; + mantissa += ((a0*b1 + a1*b0 + ((a0*b0)>>>31) + round)>>>31); + int aExp = a.exponent; + exponent += aExp-0x40000000; + if (exponent < 0) { + if (exponent == -1 && aExp < 0x40000000 && mantissa < 0) { + // Not underflow after all, it will be corrected in the + // normalization below + } else { + if (aExp < 0x40000000) + makeZero(sign); // Underflow + else + makeInfinity(sign); // Overflow + return; + } + } + // Simplified normalize() + if (mantissa < 0) { + mantissa = (mantissa+1)>>>1; + exponent ++; + if (exponent < 0) // Overflow + makeInfinity(sign); + } + } + /** + * Calculates the product of this Real and the integer + * a. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this *= a; + *
Error bound: + * ½ ULPs + *
+ * Execution time relative to add:   + * + * 1.3 + *
+ * + * @param a the int to multiply to this. + */ + public void mul(int a) { + if ((this.exponent < 0 && this.mantissa != 0)) + return; + if (a<0) { + sign ^= 1; + a = -a; + } + if ((this.exponent == 0 && this.mantissa == 0) || a==0) { + if ((this.exponent < 0 && this.mantissa == 0)) + makeNan(); + else + makeZero(sign); + return; + } + if ((this.exponent < 0 && this.mantissa == 0)) + return; + // Normalize int + int t=a; t|=t>>1; t|=t>>2; t|=t>>4; t|=t>>8; t|=t>>16; + t = clz_tab[(t*clz_magic)>>>27]; + exponent += 0x1F-t; + a <<= t; + if (exponent < 0) { + makeInfinity(sign); // Overflow + return; + } + long a0 = mantissa & 0x7fffffff; + long a1 = mantissa >>> 31; + long b0 = a & 0xffffffffL; + mantissa = a1*b0; + // If we're going to need normalization, we don't want to round twice + int round = (mantissa<0) ? 0 : 0x40000000; + mantissa += ((a0*b0 + round)>>>31); + // Simplified normalize() + if (mantissa < 0) { + mantissa = (mantissa+1)>>>1; + exponent ++; + if (exponent < 0) // Overflow + makeInfinity(sign); + } + } + /** + * Calculates the product of this Real and a with + * extended precision. + * Replaces the contents of this Real with the result. + * Returns the extra mantissa of the extended precision result. + * + *

An extra 64 bits of mantissa is added to both arguments for + * extended precision. If any of the arguments are not of extended + * precision, use 0 for the extra mantissa. See also {@link + * #add128(long,Real,long)}. + * + *

+ * Equivalent double code: + * this *= a; + *
Approximate error bound: + * 2-60 ULPs + *
+ * Execution time relative to add:   + * + * 3.1 + *
+ * + * @param extra the extra 64 bits of mantissa of this extended precision + * Real. + * @param a the Real to multiply to this. + * @param aExtra the extra 64 bits of mantissa of the extended precision + * value a. + * @return the extra 64 bits of mantissa of the resulting extended + * precision Real. + */ + public long mul128(long extra, Real a, long aExtra) { + if ((this.exponent < 0 && this.mantissa != 0) || (a.exponent < 0 && a.mantissa != 0)) { + makeNan(); + return 0; + } + sign ^= a.sign; + if ((this.exponent == 0 && this.mantissa == 0) || (a.exponent == 0 && a.mantissa == 0)) { + if ((this.exponent < 0 && this.mantissa == 0) || (a.exponent < 0 && a.mantissa == 0)) + makeNan(); + else + makeZero(sign); + return 0; + } + if ((this.exponent < 0 && this.mantissa == 0) || (a.exponent < 0 && a.mantissa == 0)) { + makeInfinity(sign); + return 0; + } + int aExp = a.exponent; + exponent += aExp-0x40000000; + if (exponent < 0) { + if (aExp < 0x40000000) + makeZero(sign); // Underflow + else + makeInfinity(sign); // Overflow + return 0; + } + long ffffffffL = 0xffffffffL; + long a0 = extra & ffffffffL; + long a1 = extra >>> 32; + long a2 = mantissa & ffffffffL; + long a3 = mantissa >>> 32; + long b0 = aExtra & ffffffffL; + long b1 = aExtra >>> 32; + long b2 = a.mantissa & ffffffffL; + long b3 = a.mantissa >>> 32; + a0 = ((a3*b0>>>2)+ + (a2*b1>>>2)+ + (a1*b2>>>2)+ + (a0*b3>>>2)+ + 0x60000000)>>>28; + //(a2*b0>>>34)+(a1*b1>>>34)+(a0*b2>>>34)+0x08000000)>>>28; + a1 *= b3; + b0 = a2*b2; + b1 *= a3; + a0 += ((a1<<2)&ffffffffL) + ((b0<<2)&ffffffffL) + ((b1<<2)&ffffffffL); + a1 = (a0>>>32) + (a1>>>30) + (b0>>>30) + (b1>>>30); + a0 &= ffffffffL; + a2 *= b3; + b2 *= a3; + a1 += ((a2<<2)&ffffffffL) + ((b2<<2)&ffffffffL); + extra = (a1<<32) + a0; + mantissa = ((a3*b3)<<2) + (a1>>>32) + (a2>>>30) + (b2>>>30); + extra = normalize128(extra); + return extra; + } + private void mul10() { + if (!(this.exponent >= 0 && this.mantissa != 0)) + return; + mantissa += (mantissa+2)>>>2; + exponent += 3; + if (mantissa < 0) { + mantissa = (mantissa+1)>>>1; + exponent++; + } + if (exponent < 0) + makeInfinity(sign); // Overflow + } + /** + * Calculates the square of this Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = this*this; + *
Error bound: + * ½ ULPs + *
+ * Execution time relative to add:   + * + * 1.1 + *
+ */ + public void sqr() { + sign = 0; + if (!(this.exponent >= 0 && this.mantissa != 0)) + return; + int e = exponent; + exponent += exponent-0x40000000; + if (exponent < 0) { + if (e < 0x40000000) + makeZero(sign); // Underflow + else + makeInfinity(sign); // Overflow + return; + } + long a0 = mantissa&0x7fffffff; + long a1 = mantissa>>>31; + mantissa = a1*a1; + // If we're going to need normalization, we don't want to round twice + int round = (mantissa<0) ? 0 : 0x40000000; + mantissa += ((((a0*a1)<<1) + ((a0*a0)>>>31) + round)>>>31); + // Simplified normalize() + if (mantissa < 0) { + mantissa = (mantissa+1)>>>1; + exponent ++; + if (exponent < 0) // Overflow + makeInfinity(sign); + } + } + private static long ldiv(long a, long b) { + // Calculate (a<<63)/b, where a<2**64, b<2**63, b<=a and a<2*b The + // result will always be 63 bits, leading to a 3-stage radix-2**21 + // (very high radix) algorithm, as described here: + // S.F. Oberman and M.J. Flynn, "Division Algorithms and + // Implementations," IEEE Trans. Computers, vol. 46, no. 8, + // pp. 833-854, Aug 1997 Section 4: "Very High Radix Algorithms" + int bInv24; // Approximate 1/b, never more than 24 bits + int aHi24; // High 24 bits of a (sometimes 25 bits) + int next21; // The next 21 bits of result, possibly 1 less + long q; // Resulting quotient: round((a<<63)/b) + // Preparations + bInv24 = (int)(0x400000000000L/((b>>>40)+1)); + aHi24 = (int)(a>>32)>>>8; + a <<= 20; // aHi24 and a overlap by 4 bits + // Now perform the division + next21 = (int)(((long)aHi24*(long)bInv24)>>>26); + a -= next21*b; // Bits above 2**64 will always be cancelled + // No need to remove remainder, this will be cared for in next block + q = next21; + aHi24 = (int)(a>>32)>>>7; + a <<= 21; + // Two more almost identical blocks... + next21 = (int)(((long)aHi24*(long)bInv24)>>>26); + a -= next21*b; + q = (q<<21)+next21; + aHi24 = (int)(a>>32)>>>7; + a <<= 21; + next21 = (int)(((long)aHi24*(long)bInv24)>>>26); + a -= next21*b; + q = (q<<21)+next21; + // Remove final remainder + if (a<0 || a>=b) { q++; a -= b; } + a <<= 1; + // Round correctly + if (a<0 || a>=b) q++; + return q; + } + /** + * Calculates the quotient of this Real and a. + * Replaces the contents of this Real with the result. + * + *

(To achieve extended precision division, call + * aExtra=a.{@link #recip128(long) recip128}(aExtra) before + * calling {@link #mul128(long,Real,long) + * mul128}(extra,a,aExtra).) + * + *

+ * Equivalent double code: + * this /= a; + *
Error bound: + * ½ ULPs + *
+ * Execution time relative to add:   + * + * 2.6 + *
+ * + * @param a the Real to divide this with. + */ + public void div(Real a) { + if ((this.exponent < 0 && this.mantissa != 0) || (a.exponent < 0 && a.mantissa != 0)) { + makeNan(); + return; + } + sign ^= a.sign; + if ((this.exponent < 0 && this.mantissa == 0)) { + if ((a.exponent < 0 && a.mantissa == 0)) + makeNan(); + return; + } + if ((a.exponent < 0 && a.mantissa == 0)) { + makeZero(sign); + return; + } + if ((this.exponent == 0 && this.mantissa == 0)) { + if ((a.exponent == 0 && a.mantissa == 0)) + makeNan(); + return; + } + if ((a.exponent == 0 && a.mantissa == 0)) { + makeInfinity(sign); + return; + } + exponent += 0x40000000-a.exponent; + if (mantissa < a.mantissa) { + mantissa <<= 1; + exponent--; + } + if (exponent < 0) { + if (a.exponent >= 0x40000000) + makeZero(sign); // Underflow + else + makeInfinity(sign); // Overflow + return; + } + if (a.mantissa == 0x4000000000000000L) + return; + mantissa = ldiv(mantissa,a.mantissa); + } + /** + * Calculates the quotient of this Real and the integer + * a. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this /= a; + *
Error bound: + * ½ ULPs + *
+ * Execution time relative to add:   + * + * 2.6 + *
+ * + * @param a the int to divide this with. + */ + public void div(int a) { + if ((this.exponent < 0 && this.mantissa != 0)) + return; + if (a<0) { + sign ^= 1; + a = -a; + } + if ((this.exponent < 0 && this.mantissa == 0)) + return; + if ((this.exponent == 0 && this.mantissa == 0)) { + if (a==0) + makeNan(); + return; + } + if (a==0) { + makeInfinity(sign); + return; + } + long denom = a & 0xffffffffL; + long remainder = mantissa%denom; + mantissa /= denom; + // Normalizing mantissa and scaling remainder accordingly + int clz = 0; + int t = (int)(mantissa>>>32); + if (t == 0) { clz = 32; t = (int)mantissa; } + t|=t>>1; t|=t>>2; t|=t>>4; t|=t>>8; t|=t>>16; + clz += clz_tab[(t*clz_magic)>>>27]-1; + mantissa <<= clz; + remainder <<= clz; + exponent -= clz; + // Final division, correctly rounded + remainder = (remainder+denom/2)/denom; + mantissa += remainder; + if (exponent < 0) // Underflow + makeZero(sign); + } + /** + * Calculates the quotient of a and this Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = a/this; + *
Error bound: + * ½ ULPs + *
+ * Execution time relative to add:   + * + * 3.1 + *
+ * + * @param a the Real to be divided by this. + */ + public void rdiv(Real a) { + { recipTmp.mantissa = a.mantissa; recipTmp.exponent = a.exponent; recipTmp.sign = a.sign; }; + recipTmp.div(this); + { this.mantissa = recipTmp.mantissa; this.exponent = recipTmp.exponent; this.sign = recipTmp.sign; }; + } + /** + * Calculates the quotient of the integer a and this + * Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = a/this; + *
Error bound: + * ½ ULPs + *
+ * Execution time relative to add:   + * + * 3.9 + *
+ * + * @param a the int to be divided by this. + */ + public void rdiv(int a) { + tmp0.assign(a); + rdiv(tmp0); + } + /** + * Calculates the reciprocal of this Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = 1/this; + *
Error bound: + * ½ ULPs + *
+ * Execution time relative to add:   + * + * 2.3 + *
+ */ + public void recip() { + if ((this.exponent < 0 && this.mantissa != 0)) + return; + if ((this.exponent < 0 && this.mantissa == 0)) { + makeZero(sign); + return; + } + if ((this.exponent == 0 && this.mantissa == 0)) { + makeInfinity(sign); + return; + } + exponent = 0x80000000-exponent; + if (mantissa == 0x4000000000000000L) { + if (exponent < 0) + makeInfinity(sign); // Overflow + return; + } + exponent--; + mantissa = ldiv(0x8000000000000000L,mantissa); + } + /** + * Calculates the reciprocal of this Real with + * extended precision. + * Replaces the contents of this Real with the result. + * Returns the extra mantissa of the extended precision result. + * + *

An extra 64 bits of mantissa is added for extended precision. + * If the argument is not of extended precision, use 0 + * for the extra mantissa. See also {@link #add128(long,Real,long)}. + * + *

+ * Equivalent double code: + * this = 1/this; + *
Approximate error bound: + * 2-60 ULPs + *
+ * Execution time relative to add:   + * + * 17 + *
+ * + * @param extra the extra 64 bits of mantissa of this extended precision + * Real. + * @return the extra 64 bits of mantissa of the resulting extended + * precision Real. + */ + public long recip128(long extra) { + if ((this.exponent < 0 && this.mantissa != 0)) + return 0; + if ((this.exponent < 0 && this.mantissa == 0)) { + makeZero(sign); + return 0; + } + if ((this.exponent == 0 && this.mantissa == 0)) { + makeInfinity(sign); + return 0; + } + byte s = sign; + sign = 0; + // Special case, simple power of 2 + if (mantissa == 0x4000000000000000L && extra == 0) { + exponent = 0x80000000-exponent; + if (exponent<0) // Overflow + makeInfinity(s); + return 0; + } + // Normalize exponent + int exp = 0x40000000-exponent; + exponent = 0x40000000; + // Save -A + { recipTmp.mantissa = this.mantissa; recipTmp.exponent = this.exponent; recipTmp.sign = this.sign; }; + long recipTmpExtra = extra; + recipTmp.neg(); + // First establish approximate result (actually 63 bit accurate) + recip(); + // Perform one Newton-Raphson iteration + // Xn+1 = Xn + Xn*(1-A*Xn) + { recipTmp2.mantissa = this.mantissa; recipTmp2.exponent = this.exponent; recipTmp2.sign = this.sign; }; + extra = mul128(0,recipTmp,recipTmpExtra); + extra = add128(extra,ONE,0); + extra = mul128(extra,recipTmp2,0); + extra = add128(extra,recipTmp2,0); + // Fix exponent + scalbn(exp); + // Fix sign + if (!isNan()) + sign = s; + return extra; + } + /** + * Calculates the mathematical integer that is less than or equal to + * this Real divided by a. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#floor(double) floor}(this/a); + *
Error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 22 + *
+ * + * @param a the Real argument. + */ + public void divf(Real a) { + if ((this.exponent < 0 && this.mantissa != 0) || (a.exponent < 0 && a.mantissa != 0)) { + makeNan(); + return; + } + if ((this.exponent < 0 && this.mantissa == 0)) { + if ((a.exponent < 0 && a.mantissa == 0)) + makeNan(); + return; + } + if ((a.exponent < 0 && a.mantissa == 0)) { + makeZero(sign); + return; + } + if ((this.exponent == 0 && this.mantissa == 0)) { + if ((a.exponent == 0 && a.mantissa == 0)) + makeNan(); + return; + } + if ((a.exponent == 0 && a.mantissa == 0)) { + makeInfinity(sign); + return; + } + { tmp0.mantissa = a.mantissa; tmp0.exponent = a.exponent; tmp0.sign = a.sign; }; // tmp0 should be free + // Perform same division as with mod, and don't round up + long extra = tmp0.recip128(0); + extra = mul128(0,tmp0,extra); + if (((tmp0.sign!=0) && (extra < 0 || extra > 0x1f)) || + (!(tmp0.sign!=0) && extra < 0 && extra > 0xffffffe0)) + { + // For accurate floor() + mantissa++; + normalize(); + } + floor(); + } + private void modInternal(/*long thisExtra,*/ Real a, long aExtra) { + { tmp0.mantissa = a.mantissa; tmp0.exponent = a.exponent; tmp0.sign = a.sign; }; // tmp0 should be free + long extra = tmp0.recip128(aExtra); + extra = tmp0.mul128(extra,this,0/*thisExtra*/); // tmp0 == this/a + if (tmp0.exponent > 0x4000003e) { + // floor() will be inaccurate + makeZero(a.sign); // What else can be done? makeNan? + return; + } + if (((tmp0.sign!=0) && (extra < 0 || extra > 0x1f)) || + (!(tmp0.sign!=0) && extra < 0 && extra > 0xffffffe0)) + { + // For accurate floor() with a bit of "magical rounding" + tmp0.mantissa++; + tmp0.normalize(); + } + tmp0.floor(); + tmp0.neg(); // tmp0 == -floor(this/a) + extra = tmp0.mul128(0,a,aExtra); + extra = add128(0/*thisExtra*/,tmp0,extra); + roundFrom128(extra); + } + /** + * Calculates the value of this Real modulo a. + * Replaces the contents of this Real with the result. + * The modulo in this case is defined as the remainder after subtracting + * a multiplied by the mathematical integer that is less than + * or equal to this Real divided by a. + * + *

+ * Equivalent double code: + * this = this - + * a*Math.{@link Math#floor(double) floor}(this/a); + *
Error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 27 + *
+ * + * @param a the Real argument. + */ + public void mod(Real a) { + if ((this.exponent < 0 && this.mantissa != 0) || (a.exponent < 0 && a.mantissa != 0)) { + makeNan(); + return; + } + if ((this.exponent < 0 && this.mantissa == 0)) { + makeNan(); + return; + } + if ((this.exponent == 0 && this.mantissa == 0)) { + if ((a.exponent == 0 && a.mantissa == 0)) + makeNan(); + else + sign = a.sign; + return; + } + if ((a.exponent < 0 && a.mantissa == 0)) { + if (sign != a.sign) + makeInfinity(a.sign); + return; + } + if ((a.exponent == 0 && a.mantissa == 0)) { + makeZero(a.sign); + return; + } + modInternal(a,0); + } + /** + * Calculates the logical AND of this Real and + * a. + * Replaces the contents of this Real with the result. + * + *

Semantics of bitwise logical operations exactly mimic those of + * Java's bitwise integer operators. In these operations, the + * internal binary representation of the numbers are used. If the + * values represented by the operands are not mathematical + * integers, the fractional bits are also included in the operation. + * + *

Negative numbers are interpreted as two's-complement, + * generalized to real numbers: Negating the number inverts all + * bits, including an infinite number of 1-bits before the radix + * point and an infinite number of 1-bits after the radix point. The + * infinite number of 1-bits after the radix is rounded upwards + * producing an infinite number of 0-bits, until the first 0-bit is + * encountered which will be switched to a 1 (rounded or not, these + * two forms are mathematically equivalent). For example, the number + * "1" negated, becomes (in binary form) + * ...1111110.111111.... Rounding of the infinite + * number of 1's after the radix gives the number + * ...1111111.000000..., which is exactly the way we + * usually see "-1" as two's-complement. + * + *

This method calculates a negative value if and only + * if this and a are both negative. + * + *

+ * Equivalent int code: + * this &= a; + *
Error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 1.5 + *
+ * + * @param a the Real argument + */ + public void and(Real a) { + if ((this.exponent < 0 && this.mantissa != 0) || (a.exponent < 0 && a.mantissa != 0)) { + makeNan(); + return; + } + if ((this.exponent == 0 && this.mantissa == 0) || (a.exponent == 0 && a.mantissa == 0)) { + makeZero(); + return; + } + if ((this.exponent < 0 && this.mantissa == 0) || (a.exponent < 0 && a.mantissa == 0)) { + if (!(this.exponent < 0 && this.mantissa == 0) && (this.sign!=0)) { + { this.mantissa = a.mantissa; this.exponent = a.exponent; this.sign = a.sign; }; + } else if (!(a.exponent < 0 && a.mantissa == 0) && (a.sign!=0)) + ; // ASSIGN(this,this) + else if ((this.exponent < 0 && this.mantissa == 0) && (a.exponent < 0 && a.mantissa == 0) && + (this.sign!=0) && (a.sign!=0)) + ; // makeInfinity(1) + else + makeZero(); + return; + } + byte s; + int e; + long m; + if (exponent >= a.exponent) { + s = a.sign; + e = a.exponent; + m = a.mantissa; + } else { + s = sign; + e = exponent; + m = mantissa; + sign = a.sign; + exponent = a.exponent; + mantissa = a.mantissa; + } + int shift = exponent-e; + if (shift>=64) { + if (s == 0) + makeZero(sign); + return; + } + if (s != 0) + m = -m; + if ((this.sign!=0)) + mantissa = -mantissa; + mantissa &= m>>shift; + sign = 0; + if (mantissa < 0) { + mantissa = -mantissa; + sign = 1; + } + normalize(); + } + /** + * Calculates the logical OR of this Real and + * a. + * Replaces the contents of this Real with the result. + * + *

See {@link #and(Real)} for an explanation of the + * interpretation of a Real in bitwise operations. + * This method calculates a negative value if and only + * if either this or a is negative. + * + *

+ * Equivalent int code: + * this |= a; + *
Error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 1.6 + *
+ * + * @param a the Real argument + */ + public void or(Real a) { + if ((this.exponent < 0 && this.mantissa != 0) || (a.exponent < 0 && a.mantissa != 0)) { + makeNan(); + return; + } + if ((this.exponent == 0 && this.mantissa == 0) || (a.exponent == 0 && a.mantissa == 0)) { + if ((this.exponent == 0 && this.mantissa == 0)) + { this.mantissa = a.mantissa; this.exponent = a.exponent; this.sign = a.sign; }; + return; + } + if ((this.exponent < 0 && this.mantissa == 0) || (a.exponent < 0 && a.mantissa == 0)) { + if (!(this.exponent < 0 && this.mantissa == 0) && (this.sign!=0)) + ; // ASSIGN(this,this); + else if (!(a.exponent < 0 && a.mantissa == 0) && (a.sign!=0)) { + { this.mantissa = a.mantissa; this.exponent = a.exponent; this.sign = a.sign; }; + } else + makeInfinity(sign | a.sign); + return; + } + byte s; + int e; + long m; + if (((this.sign!=0) && exponent <= a.exponent) || + ((a.sign==0) && exponent >= a.exponent)) + { + s = a.sign; + e = a.exponent; + m = a.mantissa; + } else { + s = sign; + e = exponent; + m = mantissa; + sign = a.sign; + exponent = a.exponent; + mantissa = a.mantissa; + } + int shift = exponent-e; + if (shift>=64 || shift<=-64) + return; + if (s != 0) + m = -m; + if ((this.sign!=0)) + mantissa = -mantissa; + if (shift>=0) + mantissa |= m>>shift; + else + mantissa |= m<<(-shift); + sign = 0; + if (mantissa < 0) { + mantissa = -mantissa; + sign = 1; + } + normalize(); + } + /** + * Calculates the logical XOR of this Real and + * a. + * Replaces the contents of this Real with the result. + * + *

See {@link #and(Real)} for an explanation of the + * interpretation of a Real in bitwise operations. + * This method calculates a negative value if and only + * if exactly one of this and a is negative. + * + *

The operation NOT has been omitted in this library + * because it cannot be generalized to fractional numbers. If this + * Real represents a mathematical integer, the + * operation NOT can be calculated as "this XOR -1", + * which is equivalent to "this XOR + * /FFFFFFFF.0000". + * + *

+ * Equivalent int code: + * this ^= a; + *
Error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 1.5 + *
+ * + * @param a the Real argument + */ + public void xor(Real a) { + if ((this.exponent < 0 && this.mantissa != 0) || (a.exponent < 0 && a.mantissa != 0)) { + makeNan(); + return; + } + if ((this.exponent == 0 && this.mantissa == 0) || (a.exponent == 0 && a.mantissa == 0)) { + if ((this.exponent == 0 && this.mantissa == 0)) + { this.mantissa = a.mantissa; this.exponent = a.exponent; this.sign = a.sign; }; + return; + } + if ((this.exponent < 0 && this.mantissa == 0) || (a.exponent < 0 && a.mantissa == 0)) { + makeInfinity(sign ^ a.sign); + return; + } + byte s; + int e; + long m; + if (exponent >= a.exponent) { + s = a.sign; + e = a.exponent; + m = a.mantissa; + } else { + s = sign; + e = exponent; + m = mantissa; + sign = a.sign; + exponent = a.exponent; + mantissa = a.mantissa; + } + int shift = exponent-e; + if (shift>=64) + return; + if (s != 0) + m = -m; + if ((this.sign!=0)) + mantissa = -mantissa; + mantissa ^= m>>shift; + sign = 0; + if (mantissa < 0) { + mantissa = -mantissa; + sign = 1; + } + normalize(); + } + /** + * Calculates the value of this Real AND NOT + * a. The opeation is read as "bit clear". + * Replaces the contents of this Real with the result. + * + *

See {@link #and(Real)} for an explanation of the + * interpretation of a Real in bitwise operations. + * This method calculates a negative value if and only + * if this is negative and not a is negative. + * + *

+ * Equivalent int code: + * this &= ~a; + *
Error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 1.5 + *
+ * + * @param a the Real argument + */ + public void bic(Real a) { + if ((this.exponent < 0 && this.mantissa != 0) || (a.exponent < 0 && a.mantissa != 0)) { + makeNan(); + return; + } + if ((this.exponent == 0 && this.mantissa == 0) || (a.exponent == 0 && a.mantissa == 0)) + return; + if ((this.exponent < 0 && this.mantissa == 0) || (a.exponent < 0 && a.mantissa == 0)) { + if (!(this.exponent < 0 && this.mantissa == 0)) { + if ((this.sign!=0)) + if ((a.sign!=0)) + makeInfinity(0); + else + makeInfinity(1); + } else if ((a.sign!=0)) { + if ((a.exponent < 0 && a.mantissa == 0)) + makeInfinity(0); + else + makeZero(); + } + return; + } + int shift = exponent-a.exponent; + if (shift>=64 || (shift<=-64 && (this.sign==0))) + return; + long m = a.mantissa; + if ((a.sign!=0)) + m = -m; + if ((this.sign!=0)) + mantissa = -mantissa; + if (shift<0) { + if ((this.sign!=0)) { + if (shift<=-64) + mantissa = ~m; + else + mantissa = (mantissa>>(-shift)) & ~m; + exponent = a.exponent; + } else + mantissa &= ~(m<<(-shift)); + } else + mantissa &= ~(m>>shift); + sign = 0; + if (mantissa < 0) { + mantissa = -mantissa; + sign = 1; + } + normalize(); + } + private int compare(int a) { + tmp0.assign(a); + return compare(tmp0); + } + /** + * Calculates the square root of this Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#sqrt(double) sqrt}(this); + *
Approximate error bound: + * 1 ULPs + *
+ * Execution time relative to add:   + * + * 19 + *
+ */ + public void sqrt() { + /* + * Adapted from: + * Cephes Math Library Release 2.2: December, 1990 + * Copyright 1984, 1990 by Stephen L. Moshier + * + * sqrtl.c + * + * long double sqrtl(long double x); + */ + if ((this.exponent < 0 && this.mantissa != 0)) + return; + if ((this.exponent == 0 && this.mantissa == 0)) { + sign=0; + return; + } + if ((this.sign!=0)) { + makeNan(); + return; + } + if ((this.exponent < 0 && this.mantissa == 0)) + return; + // Save X + { recipTmp.mantissa = this.mantissa; recipTmp.exponent = this.exponent; recipTmp.sign = this.sign; }; + // normalize to range [0.5, 1) + int e = exponent-0x3fffffff; + exponent = 0x3fffffff; + // quadratic approximation, relative error 6.45e-4 + { recipTmp2.mantissa = this.mantissa; recipTmp2.exponent = this.exponent; recipTmp2.sign = this.sign; }; + { sqrtTmp.sign=(byte)1; sqrtTmp.exponent=0x3ffffffd; sqrtTmp.mantissa=0x68a7e193370ff21bL; };//-0.2044058315473477195990 + mul(sqrtTmp); + { sqrtTmp.sign=(byte)0; sqrtTmp.exponent=0x3fffffff; sqrtTmp.mantissa=0x71f1e120690deae8L; };//0.89019407351052789754347 + add(sqrtTmp); + mul(recipTmp2); + { sqrtTmp.sign=(byte)0; sqrtTmp.exponent=0x3ffffffe; sqrtTmp.mantissa=0x5045ee6baf28677aL; };//0.31356706742295303132394 + add(sqrtTmp); + // adjust for odd powers of 2 + if ((e&1) != 0) + mul(SQRT2); + // calculate exponent + exponent += e>>1; + // Newton iteratios: + // Yn+1 = (Yn + X/Yn)/2 + for (int i=0; i<3; i++) { + { recipTmp2.mantissa = recipTmp.mantissa; recipTmp2.exponent = recipTmp.exponent; recipTmp2.sign = recipTmp.sign; }; + recipTmp2.div(this); + add(recipTmp2); + scalbn(-1); + } + } + /** + * Calculates the reciprocal square root of this Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = 1/Math.{@link Math#sqrt(double) sqrt}(this); + *
Approximate error bound: + * 1 ULPs + *
+ * Execution time relative to add:   + * + * 21 + *
+ */ + public void rsqrt() { + sqrt(); + recip(); + } + /** + * Calculates the cube root of this Real. + * Replaces the contents of this Real with the result. + * The cube root of a negative value is the negative of the cube + * root of that value's magnitude. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#cbrt(double) cbrt}(this); + *
Approximate error bound: + * 2 ULPs + *
+ * Execution time relative to add:   + * + * 32 + *
+ */ + public void cbrt() { + if (!(this.exponent >= 0 && this.mantissa != 0)) + return; + byte s = sign; + sign = 0; + // Calculates recipocal cube root of normalized Real, + // not zero, nan or infinity + final long start = 0x5120000000000000L; + // Save -A + { recipTmp.mantissa = this.mantissa; recipTmp.exponent = this.exponent; recipTmp.sign = this.sign; }; + recipTmp.neg(); + // First establish approximate result + mantissa = start-(mantissa>>>2); + int expRmd = exponent==0 ? 2 : (exponent-1)%3; + exponent = 0x40000000-(exponent-0x40000000-expRmd)/3; + normalize(); + if (expRmd>0) { + { recipTmp2.sign=(byte)0; recipTmp2.exponent=0x3fffffff; recipTmp2.mantissa=0x6597fa94f5b8f20bL; }; // cbrt(1/2) + mul(recipTmp2); + if (expRmd>1) + mul(recipTmp2); + } + // Now perform Newton-Raphson iteration + // Xn+1 = (4*Xn - A*Xn**4)/3 + for (int i=0; i<4; i++) { + { recipTmp2.mantissa = this.mantissa; recipTmp2.exponent = this.exponent; recipTmp2.sign = this.sign; }; + sqr(); + sqr(); + mul(recipTmp); + recipTmp2.scalbn(2); + add(recipTmp2); + mul(THIRD); + } + recip(); + if (!(this.exponent < 0 && this.mantissa != 0)) + sign = s; + } + /** + * Calculates the n'th root of this Real. + * Replaces the contents of this Real with the result. + * For odd integer n, the n'th root of a negative value is the + * negative of the n'th root of that value's magnitude. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#pow(double,double) + * pow}(this,1/a); + *
Approximate error bound: + * 2 ULPs + *
+ * Execution time relative to add:   + * + * 110 + *
+ * + * @param n the Real argument. + */ + public void nroot(Real n) { + if ((n.exponent < 0 && n.mantissa != 0)) { + makeNan(); + return; + } + if (n.compare(THREE)==0) { + cbrt(); // Most probable application of nroot... + return; + } else if (n.compare(TWO)==0) { + sqrt(); // Also possible, should be optimized like this + return; + } + boolean negative = false; + if ((this.sign!=0) && n.isIntegral() && n.isOdd()) { + negative = true; + abs(); + } + { tmp2.mantissa = n.mantissa; tmp2.exponent = n.exponent; tmp2.sign = n.sign; }; // Copy to temporary location in case of x.nroot(x) + tmp2.recip(); + pow(tmp2); + if (negative) + neg(); + } + /** + * Calculates sqrt(this*this+a*a). + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#hypot(double,double) + * hypot}(this,a); + *
Approximate error bound: + * 1 ULPs + *
+ * Execution time relative to add:   + * + * 24 + *
+ * + * @param a the Real argument. + */ + public void hypot(Real a) { + { tmp1.mantissa = a.mantissa; tmp1.exponent = a.exponent; tmp1.sign = a.sign; }; // Copy to temporary location in case of x.hypot(x) + tmp1.sqr(); + sqr(); + add(tmp1); + sqrt(); + } + private void exp2Internal(long extra) { + if ((this.exponent < 0 && this.mantissa != 0)) + return; + if ((this.exponent < 0 && this.mantissa == 0)) { + if ((this.sign!=0)) + makeZero(0); + return; + } + if ((this.exponent == 0 && this.mantissa == 0)) { + { this.mantissa = ONE.mantissa; this.exponent = ONE.exponent; this.sign = ONE.sign; }; + return; + } + // Extract integer part + { expTmp.mantissa = this.mantissa; expTmp.exponent = this.exponent; expTmp.sign = this.sign; }; + expTmp.add(HALF); + expTmp.floor(); + int exp = expTmp.toInteger(); + if (exp > 0x40000000) { + makeInfinity(sign); + return; + } + if (exp < -0x40000000) { + makeZero(sign); + return; + } + // Subtract integer part (this is where we need the extra accuracy) + expTmp.neg(); + add128(extra,expTmp,0); + /* + * Adapted from: + * Cephes Math Library Release 2.7: May, 1998 + * Copyright 1984, 1991, 1998 by Stephen L. Moshier + * + * exp2l.c + * + * long double exp2l(long double x); + */ + // Now -0.5e raised to the power of this Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#exp(double) exp}(this); + *
Approximate error bound: + * 1 ULPs + *
+ * Execution time relative to add:   + * + * 31 + *
+ */ + public void exp() { + { expTmp.sign=(byte)0; expTmp.exponent=0x40000000; expTmp.mantissa=0x5c551d94ae0bf85dL; }; // log2(e) + long extra = mul128(0,expTmp,0xdf43ff68348e9f44L); + exp2Internal(extra); + } + /** + * Calculates 2 raised to the power of this Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#exp(double) exp}(this * + * Math.{@link Math#log(double) log}(2)); + *
Approximate error bound: + * 1 ULPs + *
+ * Execution time relative to add:   + * + * 27 + *
+ */ + public void exp2() { + exp2Internal(0); + } + /** + * Calculates 10 raised to the power of this Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#exp(double) exp}(this * + * Math.{@link Math#log(double) log}(10)); + *
Approximate error bound: + * 1 ULPs + *
+ * Execution time relative to add:   + * + * 31 + *
+ */ + public void exp10() { + { expTmp.sign=(byte)0; expTmp.exponent=0x40000001; expTmp.mantissa=0x6a4d3c25e68dc57fL; }; // log2(10) + long extra = mul128(0,expTmp,0x2495fb7fa6d7eda6L); + exp2Internal(extra); + } + private int lnInternal() + { + if ((this.exponent < 0 && this.mantissa != 0)) + return 0; + if ((this.sign!=0)) { + makeNan(); + return 0; + } + if ((this.exponent == 0 && this.mantissa == 0)) { + makeInfinity(1); + return 0; + } + if ((this.exponent < 0 && this.mantissa == 0)) + return 0; + /* + * Adapted from: + * Cephes Math Library Release 2.7: May, 1998 + * Copyright 1984, 1990, 1998 by Stephen L. Moshier + * + * logl.c + * + * long double logl(long double x); + */ + // normalize to range [0.5, 1) + int e = exponent-0x3fffffff; + exponent = 0x3fffffff; + // rational appriximation + // log(1+x) = x - x²/2 + x³ P(x)/Q(x) + if (this.compare(SQRT1_2) < 0) { + e--; + exponent++; + } + sub(ONE); + { expTmp2.mantissa = this.mantissa; expTmp2.exponent = this.exponent; expTmp2.sign = this.sign; }; + // P(x) + { this.sign=(byte)0; this.exponent=0x3ffffff1; this.mantissa=0x5ef0258ace5728ddL; };//4.5270000862445199635215E-5 + mul(expTmp2); + { expTmp3.sign=(byte)0; expTmp3.exponent=0x3ffffffe; expTmp3.mantissa=0x7fa06283f86a0ce8L; };//0.4985410282319337597221 + add(expTmp3); + mul(expTmp2); + { expTmp3.sign=(byte)0; expTmp3.exponent=0x40000002; expTmp3.mantissa=0x69427d1bd3e94ca1L; };//6.5787325942061044846969 + add(expTmp3); + mul(expTmp2); + { expTmp3.sign=(byte)0; expTmp3.exponent=0x40000004; expTmp3.mantissa=0x77a5ce2e32e7256eL; };//29.911919328553073277375 + add(expTmp3); + mul(expTmp2); + { expTmp3.sign=(byte)0; expTmp3.exponent=0x40000005; expTmp3.mantissa=0x79e63ae1b0cd4222L; };//60.949667980987787057556 + add(expTmp3); + mul(expTmp2); + { expTmp3.sign=(byte)0; expTmp3.exponent=0x40000005; expTmp3.mantissa=0x7239d65d1e6840d6L; };//57.112963590585538103336 + add(expTmp3); + mul(expTmp2); + { expTmp3.sign=(byte)0; expTmp3.exponent=0x40000004; expTmp3.mantissa=0x502880b6660c265fL; };//20.039553499201281259648 + add(expTmp3); + // Q(x) + { expTmp.mantissa = expTmp2.mantissa; expTmp.exponent = expTmp2.exponent; expTmp.sign = expTmp2.sign; }; + { expTmp3.sign=(byte)0; expTmp3.exponent=0x40000003; expTmp3.mantissa=0x7880d67a40f8dc5cL; };//15.062909083469192043167 + expTmp.add(expTmp3); + expTmp.mul(expTmp2); + { expTmp3.sign=(byte)0; expTmp3.exponent=0x40000006; expTmp3.mantissa=0x530c2d4884d25e18L; };//83.047565967967209469434 + expTmp.add(expTmp3); + expTmp.mul(expTmp2); + { expTmp3.sign=(byte)0; expTmp3.exponent=0x40000007; expTmp3.mantissa=0x6ee19643f3ed5776L; };//221.76239823732856465394 + expTmp.add(expTmp3); + expTmp.mul(expTmp2); + { expTmp3.sign=(byte)0; expTmp3.exponent=0x40000008; expTmp3.mantissa=0x4d465177242295efL; };//309.09872225312059774938 + expTmp.add(expTmp3); + expTmp.mul(expTmp2); + { expTmp3.sign=(byte)0; expTmp3.exponent=0x40000007; expTmp3.mantissa=0x6c36c4f923819890L; };//216.42788614495947685003 + expTmp.add(expTmp3); + expTmp.mul(expTmp2); + { expTmp3.sign=(byte)0; expTmp3.exponent=0x40000005; expTmp3.mantissa=0x783cc111991239a3L; };//60.118660497603843919306 + expTmp.add(expTmp3); + div(expTmp); + { expTmp3.mantissa = expTmp2.mantissa; expTmp3.exponent = expTmp2.exponent; expTmp3.sign = expTmp2.sign; }; + expTmp3.sqr(); + mul(expTmp3); + mul(expTmp2); + expTmp3.scalbn(-1); + sub(expTmp3); + add(expTmp2); + return e; + } + /** + * Calculates the natural logarithm (base-e) of this + * Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#log(double) log}(this); + *
Approximate error bound: + * 2 ULPs + *
+ * Execution time relative to add:   + * + * 51 + *
+ */ + public void ln() { + int exp = lnInternal(); + expTmp.assign(exp); + expTmp.mul(LN2); + add(expTmp); + } + /** + * Calculates the base-2 logarithm of this Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#log(double) log}(this)/Math.{@link + * Math#log(double) log}(2); + *
Approximate error bound: + * 1 ULPs + *
+ * Execution time relative to add:   + * + * 51 + *
+ */ + public void log2() { + int exp = lnInternal(); + mul(LOG2E); + add(exp); + } + /** + * Calculates the base-10 logarithm of this Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#log10(double) log10}(this); + *
Approximate error bound: + * 2 ULPs + *
+ * Execution time relative to add:   + * + * 53 + *
+ */ + public void log10() { + int exp = lnInternal(); + expTmp.assign(exp); + expTmp.mul(LN2); + add(expTmp); + mul(LOG10E); + } + /** + * Calculates the closest power of 10 that is less than or equal to this + * Real. + * Replaces the contents of this Real with the result. + * The base-10 exponent of the result is returned. + * + *

+ * Equivalent double code: + * int exp = (int)(Math.{@link Math#floor(double) + * floor}(Math.{@link Math#log10(double) log10}(this))); + *
this = Math.{@link Math#pow(double,double) pow}(10, exp);
+ * return exp;
+ *
Error bound: + * ½ ULPs + *
+ * Execution time relative to add:   + * + * 3.6 + *
+ * + * @return the base-10 exponent + */ + public int lowPow10() { + if (!(this.exponent >= 0 && this.mantissa != 0)) + return 0; + { tmp2.mantissa = this.mantissa; tmp2.exponent = this.exponent; tmp2.sign = this.sign; }; + // Approximate log10 using exponent only + int e = exponent - 0x40000000; + if (e<0) // it's important to achieve floor(exponent*ln2/ln10) + e = -(int)(((-e)*0x4d104d43L+((1L<<32)-1)) >> 32); + else + e = (int)(e*0x4d104d43L >> 32); + // Now, e < log10(this) < e+1 + { this.mantissa = TEN.mantissa; this.exponent = TEN.exponent; this.sign = TEN.sign; }; + pow(e); + if ((this.exponent == 0 && this.mantissa == 0)) { // A *really* small number, then + { tmp3.mantissa = TEN.mantissa; tmp3.exponent = TEN.exponent; tmp3.sign = TEN.sign; }; + tmp3.pow(e+1); + } else { + { tmp3.mantissa = this.mantissa; tmp3.exponent = this.exponent; tmp3.sign = this.sign; }; + tmp3.mul10(); + } + if (tmp3.compare(tmp2) <= 0) { + // First estimate of log10 was too low + e++; + { this.mantissa = tmp3.mantissa; this.exponent = tmp3.exponent; this.sign = tmp3.sign; }; + } + return e; + } + /** + * Calculates the value of this Real raised to the power of + * a. + * Replaces the contents of this Real with the result. + * + *

Special cases: + *

    + *
  • if a is 0.0 or -0.0 then result is 1.0 + *
  • if a is NaN then result is NaN + *
  • if this is NaN and a is not zero then result is NaN + *
  • if a is 1.0 then result is this + *
  • if |this| > 1.0 and a is +Infinity then result is +Infinity + *
  • if |this| < 1.0 and a is -Infinity then result is +Infinity + *
  • if |this| > 1.0 and a is -Infinity then result is +0 + *
  • if |this| < 1.0 and a is +Infinity then result is +0 + *
  • if |this| = 1.0 and a is ±Infinity then result is NaN + *
  • if this = +0 and a > 0 then result is +0 + *
  • if this = +0 and a < 0 then result is +Inf + *
  • if this = -0 and a > 0, and odd integer then result is -0 + *
  • if this = -0 and a < 0, and odd integer then result is -Inf + *
  • if this = -0 and a > 0, not odd integer then result is +0 + *
  • if this = -0 and a < 0, not odd integer then result is +Inf + *
  • if this = +Inf and a > 0 then result is +Inf + *
  • if this = +Inf and a < 0 then result is +0 + *
  • if this = -Inf and a not integer then result is NaN + *
  • if this = -Inf and a > 0, and odd integer then result is -Inf + *
  • if this = -Inf and a > 0, not odd integer then result is +Inf + *
  • if this = -Inf and a < 0, and odd integer then result is -0 + *
  • if this = -Inf and a < 0, not odd integer then result is +0 + *
  • if this < 0 and a not integer then result is NaN + *
  • if this < 0 and a odd integer then result is -(|this|a) + *
  • if this < 0 and a not odd integer then result is |this|a + *
  • else result is exp(ln(this)*a) + *
+ * + *

+ * Equivalent double code: + * this = Math.{@link Math#pow(double,double) pow}(this, a); + *
Approximate error bound: + * 2 ULPs + *
+ * Execution time relative to add:   + * + * 110 + *
+ * + * @param a the Real argument. + */ + public void pow(Real a) { + if ((a.exponent == 0 && a.mantissa == 0)) { + { this.mantissa = ONE.mantissa; this.exponent = ONE.exponent; this.sign = ONE.sign; }; + return; + } + if ((this.exponent < 0 && this.mantissa != 0) || (a.exponent < 0 && a.mantissa != 0)) { + makeNan(); + return; + } + if (a.compare(ONE)==0) + return; + if ((a.exponent < 0 && a.mantissa == 0)) { + { tmp1.mantissa = this.mantissa; tmp1.exponent = this.exponent; tmp1.sign = this.sign; }; + tmp1.abs(); + int test = tmp1.compare(ONE); + if (test>0) { + if ((a.sign==0)) + makeInfinity(0); + else + makeZero(); + } else if (test<0) { + if ((a.sign!=0)) + makeInfinity(0); + else + makeZero(); + } else { + makeNan(); + } + return; + } + if ((this.exponent == 0 && this.mantissa == 0)) { + if ((this.sign==0)) { + if ((a.sign==0)) + makeZero(); + else + makeInfinity(0); + } else { + if (a.isIntegral() && a.isOdd()) { + if ((a.sign==0)) + makeZero(1); + else + makeInfinity(1); + } else { + if ((a.sign==0)) + makeZero(); + else + makeInfinity(0); + } + } + return; + } + if ((this.exponent < 0 && this.mantissa == 0)) { + if ((this.sign==0)) { + if ((a.sign==0)) + makeInfinity(0); + else + makeZero(); + } else { + if (a.isIntegral()) { + if (a.isOdd()) { + if ((a.sign==0)) + makeInfinity(1); + else + makeZero(1); + } else { + if ((a.sign==0)) + makeInfinity(0); + else + makeZero(); + } + } else { + makeNan(); + } + } + return; + } + if (a.isIntegral() && a.exponent <= 0x4000001e) { + pow(a.toInteger()); + return; + } + byte s=0; + if ((this.sign!=0)) { + if (a.isIntegral()) { + if (a.isOdd()) + s = 1; + } else { + makeNan(); + return; + } + sign = 0; + } + { tmp1.mantissa = a.mantissa; tmp1.exponent = a.exponent; tmp1.sign = a.sign; }; + if (tmp1.exponent <= 0x4000001e) { + // For increased accuracy, exponentiate with integer part of + // exponent by successive squaring + // (I really don't know why this works) + { tmp2.mantissa = tmp1.mantissa; tmp2.exponent = tmp1.exponent; tmp2.sign = tmp1.sign; }; + tmp2.floor(); + { tmp3.mantissa = this.mantissa; tmp3.exponent = this.exponent; tmp3.sign = this.sign; }; + tmp3.pow(tmp2.toInteger()); + tmp1.sub(tmp2); + } else { + { tmp3.mantissa = ONE.mantissa; tmp3.exponent = ONE.exponent; tmp3.sign = ONE.sign; }; + } + // Do log2 and maintain accuracy + int e = lnInternal(); + { tmp2.sign=(byte)0; tmp2.exponent=0x40000000; tmp2.mantissa=0x5c551d94ae0bf85dL; }; // log2(e) + long extra = mul128(0,tmp2,0xdf43ff68348e9f44L); + tmp2.assign(e); + extra = add128(extra,tmp2,0); + // Do exp2 of this multiplied by (fractional part of) exponent + extra = tmp1.mul128(0,this,extra); + tmp1.exp2Internal(extra); + { this.mantissa = tmp1.mantissa; this.exponent = tmp1.exponent; this.sign = tmp1.sign; }; + mul(tmp3); + if (!(this.exponent < 0 && this.mantissa != 0)) + sign = s; + } + /** + * Calculates the value of this Real raised to the power of + * the integer a. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#pow(double,double) pow}(this, a); + *
Error bound: + * ½ ULPs + *
+ * Execution time relative to add:   + * + * 84 + *
+ * + * @param a the integer argument. + */ + public void pow(int a) { + // Calculate power of integer by successive squaring + boolean recp=false; + if (a < 0) { + a = -a; // Also works for 0x80000000 + recp = true; + } + long extra = 0, expTmpExtra = 0; + { expTmp.mantissa = this.mantissa; expTmp.exponent = this.exponent; expTmp.sign = this.sign; }; + { this.mantissa = ONE.mantissa; this.exponent = ONE.exponent; this.sign = ONE.sign; }; + for (; a!=0; a>>>=1) { + if ((a & 1) != 0) + extra = mul128(extra,expTmp,expTmpExtra); + expTmpExtra = expTmp.mul128(expTmpExtra,expTmp,expTmpExtra); + } + if (recp) + extra = recip128(extra); + roundFrom128(extra); + } + private void sinInternal() { + /* + * Adapted from: + * Cephes Math Library Release 2.7: May, 1998 + * Copyright 1985, 1990, 1998 by Stephen L. Moshier + * + * sinl.c + * + * long double sinl(long double x); + */ + // XReal. + * Replaces the contents of this Real with the result. + * The input value is treated as an angle measured in radians. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#sin(double) sin}(this); + *
Approximate error bound: + * 1 ULPs + *
+ * Execution time relative to add:   + * + * 28 + *
+ */ + public void sin() { + if (!(this.exponent >= 0 && this.mantissa != 0)) { + if (!(this.exponent == 0 && this.mantissa == 0)) + makeNan(); + return; + } + // Since sin(-x) = -sin(x) we can make sure that x > 0 + boolean negative = false; + if ((this.sign!=0)) { + abs(); + negative = true; + } + // Then reduce the argument to the range of 0 < x < pi*2 + if (this.compare(PI2) > 0) + modInternal(PI2,0x62633145c06e0e69L); + // Since sin(pi*2 - x) = -sin(x) we can reduce the range 0 < x < pi + if (this.compare(PI) > 0) { + sub(PI2); + neg(); + negative = !negative; + } + // Since sin(x) = sin(pi - x) we can reduce the range to 0 < x < pi/2 + if (this.compare(PI_2) > 0) { + sub(PI); + neg(); + } + // Since sin(x) = cos(pi/2 - x) we can reduce the range to 0 < x < pi/4 + if (this.compare(PI_4) > 0) { + sub(PI_2); + neg(); + cosInternal(); + } else { + sinInternal(); + } + if (negative) + neg(); + if ((this.exponent == 0 && this.mantissa == 0)) + abs(); // Remove confusing "-" + } + /** + * Calculates the trigonometric cosine of this Real. + * Replaces the contents of this Real with the result. + * The input value is treated as an angle measured in radians. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#cos(double) cos}(this); + *
Approximate error bound: + * 1 ULPs + *
+ * Execution time relative to add:   + * + * 37 + *
+ */ + public void cos() { + if ((this.exponent == 0 && this.mantissa == 0)) { + { this.mantissa = ONE.mantissa; this.exponent = ONE.exponent; this.sign = ONE.sign; }; + return; + } + if ((this.sign!=0)) + abs(); + if (this.compare(PI_4) < 0) { + cosInternal(); + } else { + add(PI_2); + sin(); + } + } + /** + * Calculates the trigonometric tangent of this Real. + * Replaces the contents of this Real with the result. + * The input value is treated as an angle measured in radians. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#tan(double) tan}(this); + *
Approximate error bound: + * 2 ULPs + *
+ * Execution time relative to add:   + * + * 70 + *
+ */ + public void tan() { + { tmp4.mantissa = this.mantissa; tmp4.exponent = this.exponent; tmp4.sign = this.sign; }; + tmp4.cos(); + sin(); + div(tmp4); + } + /** + * Calculates the trigonometric arc sine of this Real, + * in the range -π/2 to π/2. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#asin(double) asin}(this); + *
Approximate error bound: + * 3 ULPs + *
+ * Execution time relative to add:   + * + * 68 + *
+ */ + public void asin() { + { tmp1.mantissa = this.mantissa; tmp1.exponent = this.exponent; tmp1.sign = this.sign; }; + sqr(); + neg(); + add(ONE); + rsqrt(); + mul(tmp1); + atan(); + } + /** + * Calculates the trigonometric arc cosine of this Real, + * in the range 0.0 to π. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#acos(double) acos}(this); + *
Approximate error bound: + * 2 ULPs + *
+ * Execution time relative to add:   + * + * 67 + *
+ */ + public void acos() { + boolean negative = (this.sign!=0); + abs(); + { tmp1.mantissa = this.mantissa; tmp1.exponent = this.exponent; tmp1.sign = this.sign; }; + sqr(); + neg(); + add(ONE); + sqrt(); + div(tmp1); + atan(); + if (negative) { + neg(); + add(PI); + } + } + /** + * Calculates the trigonometric arc tangent of this Real, + * in the range -π/2 to π/2. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#atan(double) atan}(this); + *
Approximate error bound: + * 2 ULPs + *
+ * Execution time relative to add:   + * + * 37 + *
+ */ + public void atan() { + /* + * Adapted from: + * Cephes Math Library Release 2.7: May, 1998 + * Copyright 1984, 1990, 1998 by Stephen L. Moshier + * + * atanl.c + * + * long double atanl(long double x); + */ + if ((this.exponent == 0 && this.mantissa == 0) || (this.exponent < 0 && this.mantissa != 0)) + return; + if ((this.exponent < 0 && this.mantissa == 0)) { + byte s = sign; + { this.mantissa = PI_2.mantissa; this.exponent = PI_2.exponent; this.sign = PI_2.sign; }; + sign = s; + return; + } + byte s = sign; + sign = 0; + // range reduction + boolean addPI_2 = false; + boolean addPI_4 = false; + { tmp1.mantissa = SQRT2.mantissa; tmp1.exponent = SQRT2.exponent; tmp1.sign = SQRT2.sign; }; + tmp1.add(ONE); + if (this.compare(tmp1) > 0) { + addPI_2 = true; + recip(); + neg(); + } else { + tmp1.sub(TWO); + if (this.compare(tmp1) > 0) { + addPI_4 = true; + { tmp1.mantissa = this.mantissa; tmp1.exponent = this.exponent; tmp1.sign = this.sign; }; + tmp1.add(ONE); + sub(ONE); + div(tmp1); + } + } + // Now |X|Real divided by x, in the range -π + * to π. The signs of both arguments are used to determine the + * quadrant of the result. Replaces the contents of this + * Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#atan2(double,double) + * atan2}(this,x); + *
Approximate error bound: + * 2 ULPs + *
+ * Execution time relative to add:   + * + * 48 + *
+ * + * @param x the Real argument. + */ + public void atan2(Real x) { + if ((this.exponent < 0 && this.mantissa != 0) || (x.exponent < 0 && x.mantissa != 0) || ((this.exponent < 0 && this.mantissa == 0) && (x.exponent < 0 && x.mantissa == 0))) { + makeNan(); + return; + } + if ((this.exponent == 0 && this.mantissa == 0) && (x.exponent == 0 && x.mantissa == 0)) + return; + byte s = sign; + byte s2 = x.sign; + sign = 0; + x.sign = 0; + div(x); + atan(); + if (s2 != 0) { + neg(); + add(PI); + } + sign = s; + } + /** + * Calculates the hyperbolic sine of this Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#sinh(double) sinh}(this); + *
Approximate error bound: + * 2 ULPs + *
+ * Execution time relative to add:   + * + * 67 + *
+ */ + public void sinh() { + { tmp1.mantissa = this.mantissa; tmp1.exponent = this.exponent; tmp1.sign = this.sign; }; + tmp1.neg(); + tmp1.exp(); + exp(); + sub(tmp1); + scalbn(-1); + } + /** + * Calculates the hyperbolic cosine of this Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#cosh(double) cosh}(this); + *
Approximate error bound: + * 2 ULPs + *
+ * Execution time relative to add:   + * + * 66 + *
+ */ + public void cosh() { + { tmp1.mantissa = this.mantissa; tmp1.exponent = this.exponent; tmp1.sign = this.sign; }; + tmp1.neg(); + tmp1.exp(); + exp(); + add(tmp1); + scalbn(-1); + } + /** + * Calculates the hyperbolic tangent of this Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#tanh(double) tanh}(this); + *
Approximate error bound: + * 2 ULPs + *
+ * Execution time relative to add:   + * + * 70 + *
+ */ + public void tanh() { + { tmp1.mantissa = this.mantissa; tmp1.exponent = this.exponent; tmp1.sign = this.sign; }; + tmp1.neg(); + tmp1.exp(); + exp(); + { tmp2.mantissa = this.mantissa; tmp2.exponent = this.exponent; tmp2.sign = this.sign; }; + tmp2.add(tmp1); + sub(tmp1); + div(tmp2); + } + /** + * Calculates the hyperbolic arc sine of this Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * none + *
Approximate error bound: + * 2 ULPs + *
+ * Execution time relative to add:   + * + * 77 + *
+ */ + public void asinh() { + if (!(this.exponent >= 0 && this.mantissa != 0)) + return; + // Use symmetry to prevent underflow error for very large negative + // values + byte s = sign; + sign = 0; + { tmp1.mantissa = this.mantissa; tmp1.exponent = this.exponent; tmp1.sign = this.sign; }; + tmp1.sqr(); + tmp1.add(ONE); + tmp1.sqrt(); + add(tmp1); + ln(); + if (!(this.exponent < 0 && this.mantissa != 0)) + sign = s; + } + /** + * Calculates the hyperbolic arc cosine of this Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * none + *
Approximate error bound: + * 2 ULPs + *
+ * Execution time relative to add:   + * + * 75 + *
+ */ + public void acosh() { + { tmp1.mantissa = this.mantissa; tmp1.exponent = this.exponent; tmp1.sign = this.sign; }; + tmp1.sqr(); + tmp1.sub(ONE); + tmp1.sqrt(); + add(tmp1); + ln(); + } + /** + * Calculates the hyperbolic arc tangent of this Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * none + *
Approximate error bound: + * 2 ULPs + *
+ * Execution time relative to add:   + * + * 57 + *
+ */ + public void atanh() { + { tmp1.mantissa = this.mantissa; tmp1.exponent = this.exponent; tmp1.sign = this.sign; }; + tmp1.neg(); + tmp1.add(ONE); + add(ONE); + div(tmp1); + ln(); + scalbn(-1); + } + /** + * Calculates the factorial of this Real. + * Replaces the contents of this Real with the result. + * The definition is generalized to all real numbers (not only integers), + * by using the fact that (n!)={@link #gamma() gamma}(n+1). + * + *

+ * Equivalent double code: + * none + *
Approximate error bound: + * 15 ULPs + *
+ * Execution time relative to add:   + * + * 8-190 + *
+ */ + public void fact() { + if (!(this.exponent >= 0)) + return; + if (!this.isIntegral() || this.compare(ZERO)<0 || this.compare(200)>0) + { + // x<0, x>200 or not integer: fact(x) = gamma(x+1) + add(ONE); + gamma(); + return; + } + { tmp1.mantissa = this.mantissa; tmp1.exponent = this.exponent; tmp1.sign = this.sign; }; + { this.mantissa = ONE.mantissa; this.exponent = ONE.exponent; this.sign = ONE.sign; }; + while (tmp1.compare(ONE) > 0) { + mul(tmp1); + tmp1.sub(ONE); + } + } + /** + * Calculates the gamma function for this Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * none + *
Approximate error bound: + * 100+ ULPs + *
+ * Execution time relative to add:   + * + * 190 + *
+ */ + public void gamma() { + if (!(this.exponent >= 0)) + return; + // x<0: gamma(-x) = -pi/(x*gamma(x)*sin(pi*x)) + boolean negative = (this.sign!=0); + abs(); + { tmp1.mantissa = this.mantissa; tmp1.exponent = this.exponent; tmp1.sign = this.sign; }; + // xn: gamma(x) = exp((x-1/2)*ln(x) - x + ln(2*pi)/2 + 1/12x - 1/360x³ + // + 1/1260x**5 - 1/1680x**7+1/1188x**9) + { tmp3.mantissa = this.mantissa; tmp3.exponent = this.exponent; tmp3.sign = this.sign; }; // x + { tmp4.mantissa = this.mantissa; tmp4.exponent = this.exponent; tmp4.sign = this.sign; }; + tmp4.sqr(); // x² + // (x-1/2)*ln(x)-x + ln(); { tmp5.mantissa = tmp3.mantissa; tmp5.exponent = tmp3.exponent; tmp5.sign = tmp3.sign; }; tmp5.sub(HALF); mul(tmp5); sub(tmp3); + // + ln(2*pi)/2 + { tmp5.sign=(byte)0; tmp5.exponent=0x3fffffff; tmp5.mantissa=0x759fc72192fad29aL; }; add(tmp5); + // + 1/12x + tmp5.assign( 12); tmp5.mul(tmp3); tmp5.recip(); add(tmp5); tmp3.mul(tmp4); + // - 1/360x³ + tmp5.assign( 360); tmp5.mul(tmp3); tmp5.recip(); sub(tmp5); tmp3.mul(tmp4); + // + 1/1260x**5 + tmp5.assign(1260); tmp5.mul(tmp3); tmp5.recip(); add(tmp5); tmp3.mul(tmp4); + // - 1/1680x**7 + tmp5.assign(1680); tmp5.mul(tmp3); tmp5.recip(); sub(tmp5); tmp3.mul(tmp4); + // + 1/1188x**9 + tmp5.assign(1188); tmp5.mul(tmp3); tmp5.recip(); add(tmp5); + exp(); + if (divide) + div(tmp2); + if (negative) { + { tmp5.mantissa = tmp1.mantissa; tmp5.exponent = tmp1.exponent; tmp5.sign = tmp1.sign; }; // sin() uses tmp1 + // -pi/(x*gamma(x)*sin(pi*x)) + mul(tmp5); + tmp5.scalbn(-1); tmp5.frac(); tmp5.mul(PI2); // Fixes integer inaccuracy + tmp5.sin(); mul(tmp5); recip(); mul(PI); neg(); + } + } + private void erfc1Internal() { + // 3 5 7 9 + // 2 / x x x x // erfc(x) = 1 - ------ | x - --- + ---- - ---- + ---- - ... | + // sqrt(pi)\ 3 2!*5 3!*7 4!*9 / + // + long extra=0,tmp1Extra,tmp2Extra,tmp3Extra,tmp4Extra; + { tmp1.mantissa = this.mantissa; tmp1.exponent = this.exponent; tmp1.sign = this.sign; }; tmp1Extra = 0; + { tmp2.mantissa = this.mantissa; tmp2.exponent = this.exponent; tmp2.sign = this.sign; }; + tmp2Extra = tmp2.mul128(0,tmp2,0); + tmp2.neg(); + { tmp3.mantissa = ONE.mantissa; tmp3.exponent = ONE.exponent; tmp3.sign = ONE.sign; }; tmp3Extra = 0; + int i=1; + do { + tmp1Extra = tmp1.mul128(tmp1Extra,tmp2,tmp2Extra); + tmp4.assign(i); + tmp3Extra = tmp3.mul128(tmp3Extra,tmp4,0); + tmp4.assign(2*i+1); + tmp4Extra = tmp4.mul128(0,tmp3,tmp3Extra); + tmp4Extra = tmp4.recip128(tmp4Extra); + tmp4Extra = tmp4.mul128(tmp4Extra,tmp1,tmp1Extra); + extra = add128(extra,tmp4,tmp4Extra); + i++; + } while (exponent - tmp4.exponent < 128); + { tmp1.sign=(byte)1; tmp1.exponent=0x40000000; tmp1.mantissa=0x48375d410a6db446L; }; // -2/sqrt(pi) + extra = mul128(extra,tmp1,0xb8ea453fb5ff61a2L); + extra = add128(extra,ONE,0); + roundFrom128(extra); + } + private void erfc2Internal() { + // -x² -1 + // e x / 1 3 3*5 3*5*7 // erfc(x) = -------- | 1 - --- + ------ - ------ + ------ - ... | + // sqrt(pi) \ 2x² 2 3 4 / + // (2x²) (2x²) (2x²) + // Calculate iteration stop criteria + { tmp1.mantissa = this.mantissa; tmp1.exponent = this.exponent; tmp1.sign = this.sign; }; + tmp1.sqr(); + { tmp2.sign=(byte)0; tmp2.exponent=0x40000000; tmp2.mantissa=0x5c3811b4bfd0c8abL; }; // 1/0.694 + tmp2.mul(tmp1); + tmp2.sub(HALF); + int digits = tmp2.toInteger(); // number of accurate digits = x*x/0.694-0.5 + if (digits > 64) + digits = 64; + tmp1.scalbn(1); + int dxq = tmp1.toInteger()+1; + { tmp1.mantissa = this.mantissa; tmp1.exponent = this.exponent; tmp1.sign = this.sign; }; + recip(); + { tmp2.mantissa = this.mantissa; tmp2.exponent = this.exponent; tmp2.sign = this.sign; }; + { tmp3.mantissa = this.mantissa; tmp3.exponent = this.exponent; tmp3.sign = this.sign; }; + tmp3.sqr(); + tmp3.neg(); + tmp3.scalbn(-1); + { this.mantissa = ONE.mantissa; this.exponent = ONE.exponent; this.sign = ONE.sign; }; + { tmp4.mantissa = ONE.mantissa; tmp4.exponent = ONE.exponent; tmp4.sign = ONE.sign; }; + int i=1; + do { + tmp4.mul(2*i-1); + tmp4.mul(tmp3); + add(tmp4); + i++; + } while (tmp4.exponent-0x40000000>-(digits+2) && 2*i-1Real. + * Replaces the contents of this Real with the result. + * + *

The complementary error function is defined as the integral from + * x to infinity of 2/√π ·e-t² dt. It is + * related to the error function, erf, by the formula + * erfc(x)=1-erf(x). + * + *

+ * Equivalent double code: + * none + *
Approximate error bound: + * 219 ULPs + *
+ * Execution time relative to add:   + * + * 80-4900 + *
+ */ + public void erfc() { + if ((this.exponent < 0 && this.mantissa != 0)) + return; + if ((this.exponent == 0 && this.mantissa == 0)) { + { this.mantissa = ONE.mantissa; this.exponent = ONE.exponent; this.sign = ONE.sign; }; + return; + } + if ((this.exponent < 0 && this.mantissa == 0) || toInteger()>27281) { + if ((this.sign!=0)) { + { this.mantissa = TWO.mantissa; this.exponent = TWO.exponent; this.sign = TWO.sign; }; + } else + makeZero(0); + return; + } + byte s = sign; + sign = 0; + { tmp1.sign=(byte)0; tmp1.exponent=0x40000002; tmp1.mantissa=0x570a3d70a3d70a3dL; }; // 5.44 + if (this.lessThan(tmp1)) + erfc1Internal(); + else + erfc2Internal(); + if (s != 0) { + neg(); + add(TWO); + } + } + /** + * Calculates the inverse complementary error function for this + * Real. + * Replaces the contents of this Real with the result. + * + *

+ * Equivalent double code: + * none + *
Approximate error bound: + * 219 ULPs + *
+ * Execution time relative to add:   + * + * 240-5100 + *
+ */ + public void inverfc() { + if ((this.exponent < 0 && this.mantissa != 0) || (this.sign!=0) || this.greaterThan(TWO)) { + makeNan(); + return; + } + if ((this.exponent == 0 && this.mantissa == 0)) { + makeInfinity(0); + return; + } + if (this.equalTo(TWO)) { + makeInfinity(1); + return; + } + int sign = ONE.compare(this); + if (sign==0) { + makeZero(); + return; + } + if (sign<0) { + neg(); + add(TWO); + } + // Using invphi to calculate inverfc, like this + // inverfc(x) = -invphi(x/2)/(sqrt(2)) + scalbn(-1); + // Inverse Phi Algorithm (phi(Z)=P, so invphi(P)=Z) + // ------------------------------------------------ + // Part 1: Numerical Approximation Method for Inverse Phi + // This accepts input of P and outputs approximate Z as Y + // Source:Odeh & Evans. 1974. AS 70. Applied Statistics. + // R = sqrt(Ln(1/(Q²))) + { tmp1.mantissa = this.mantissa; tmp1.exponent = this.exponent; tmp1.sign = this.sign; }; + tmp1.ln(); + tmp1.mul(-2); + tmp1.sqrt(); + // Y = -(R+((((P4*R+P3)*R+P2)*R+P1)*R+P0)/((((Q4*R+Q3)*R*Q2)*R+Q1)*R+Q0)) + { tmp2.sign=(byte)1; tmp2.exponent=0x3ffffff1; tmp2.mantissa=0x5f22bb0fb4698674L; }; // P4=-0.0000453642210148 + tmp2.mul(tmp1); + { tmp3.sign=(byte)1; tmp3.exponent=0x3ffffffa; tmp3.mantissa=0x53a731ce1ea0be15L; }; // P3=-0.0204231210245 + tmp2.add(tmp3); + tmp2.mul(tmp1); + { tmp3.sign=(byte)1; tmp3.exponent=0x3ffffffe; tmp3.mantissa=0x579d2d719fc517f3L; }; // P2=-0.342242088547 + tmp2.add(tmp3); + tmp2.mul(tmp1); + tmp2.add(-1); // P1=-1 + tmp2.mul(tmp1); + { tmp3.sign=(byte)1; tmp3.exponent=0x3ffffffe; tmp3.mantissa=0x527dd3193bc8dd4cL; }; // P0=-0.322232431088 + tmp2.add(tmp3); + { tmp3.sign=(byte)0; tmp3.exponent=0x3ffffff7; tmp3.mantissa=0x7e5b0f681d161e7dL; }; // Q4=0.0038560700634 + tmp3.mul(tmp1); + { tmp4.sign=(byte)0; tmp4.exponent=0x3ffffffc; tmp4.mantissa=0x6a05ccf9917da0a8L; }; // Q3=0.103537752850 + tmp3.add(tmp4); + tmp3.mul(tmp1); + { tmp4.sign=(byte)0; tmp4.exponent=0x3fffffff; tmp4.mantissa=0x43fb32c0d3c14ec4L; }; // Q2=0.531103462366 + tmp3.add(tmp4); + tmp3.mul(tmp1); + { tmp4.sign=(byte)0; tmp4.exponent=0x3fffffff; tmp4.mantissa=0x4b56a41226f4ba95L; }; // Q1=0.588581570495 + tmp3.add(tmp4); + tmp3.mul(tmp1); + { tmp4.sign=(byte)0; tmp4.exponent=0x3ffffffc; tmp4.mantissa=0x65bb9a7733dd5062L; }; // Q0=0.0993484626060 + tmp3.add(tmp4); + tmp2.div(tmp3); + tmp1.add(tmp2); + tmp1.neg(); + { sqrtTmp.mantissa = tmp1.mantissa; sqrtTmp.exponent = tmp1.exponent; sqrtTmp.sign = tmp1.sign; }; // sqrtTmp and tmp5 not used by erfc() and exp() + // Part 2: Refine to accuracy of erfc Function + // This accepts inputs Y and P (from above) and outputs Z + // (Using Halley's third order method for finding roots of equations) + // Q = erfc(-Y/sqrt(2))/2-P + { tmp5.mantissa = sqrtTmp.mantissa; tmp5.exponent = sqrtTmp.exponent; tmp5.sign = sqrtTmp.sign; }; + tmp5.mul(SQRT1_2); + tmp5.neg(); + tmp5.erfc(); + tmp5.scalbn(-1); + tmp5.sub(this); + // R = Q*sqrt(2*pi)*e^(Y²/2) + { tmp3.mantissa = sqrtTmp.mantissa; tmp3.exponent = sqrtTmp.exponent; tmp3.sign = sqrtTmp.sign; }; + tmp3.sqr(); + tmp3.scalbn(-1); + tmp3.exp(); + tmp5.mul(tmp3); + { tmp3.sign=(byte)0; tmp3.exponent=0x40000001; tmp3.mantissa=0x50364c7fd89c1659L; }; // sqrt(2*pi) + tmp5.mul(tmp3); + // Z = Y-R/(1+R*Y/2) + { this.mantissa = sqrtTmp.mantissa; this.exponent = sqrtTmp.exponent; this.sign = sqrtTmp.sign; }; + mul(tmp5); + scalbn(-1); + add(ONE); + rdiv(tmp5); + neg(); + add(sqrtTmp); + // calculate inverfc(x) = -invphi(x/2)/(sqrt(2)) + mul(SQRT1_2); + if (sign>0) + neg(); + } + //************************************************************************* + // Calendar conversions taken from + // http://www.fourmilab.ch/documents/calendar/ + private static int floorDiv(int a, int b) { + if (a>=0) + return a/b; + return -((-a+b-1)/b); + } + private static int floorMod(int a, int b) { + if (a>=0) + return a%b; + return a+((-a+b-1)/b)*b; + } + private static boolean leap_gregorian(int year) { + return ((year % 4) == 0) && + (!(((year % 100) == 0) && ((year % 400) != 0))); + } + // GREGORIAN_TO_JD -- Determine Julian day number from Gregorian + // calendar date -- Except that we use 1/1-0 as day 0 + private static int gregorian_to_jd(int year, int month, int day) { + return ((366 - 1) + + (365 * (year - 1)) + + (floorDiv(year - 1, 4)) + + (-floorDiv(year - 1, 100)) + + (floorDiv(year - 1, 400)) + + ((((367 * month) - 362) / 12) + + ((month <= 2) ? 0 : (leap_gregorian(year) ? -1 : -2)) + day)); + } + // JD_TO_GREGORIAN -- Calculate Gregorian calendar date from Julian + // day -- Except that we use 1/1-0 as day 0 + private static int jd_to_gregorian(int jd) { + int wjd, depoch, quadricent, dqc, cent, dcent, quad, dquad, + yindex, year, yearday, leapadj, month, day; + wjd = jd; + depoch = wjd - 366; + quadricent = floorDiv(depoch, 146097); + dqc = floorMod(depoch, 146097); + cent = floorDiv(dqc, 36524); + dcent = floorMod(dqc, 36524); + quad = floorDiv(dcent, 1461); + dquad = floorMod(dcent, 1461); + yindex = floorDiv(dquad, 365); + year = (quadricent * 400) + (cent * 100) + (quad * 4) + yindex; + if (!((cent == 4) || (yindex == 4))) + year++; + yearday = wjd - gregorian_to_jd(year, 1, 1); + leapadj = ((wjd < gregorian_to_jd(year, 3, 1)) ? 0 + : (leap_gregorian(year) ? 1 : 2)); + month = floorDiv(((yearday + leapadj) * 12) + 373, 367); + day = (wjd - gregorian_to_jd(year, month, 1)) + 1; + return (year*100+month)*100+day; + } + /** + * Converts this Real from "hours" to "days, hours, + * minutes and seconds". + * Replaces the contents of this Real with the result. + * + *

The format converted to is encoded into the digits of the + * number (in decimal form): + * "DDDDhh.mmss". Here "DDDD," is number + * of days, "hh" is hours (0-23), "mm" is + * minutes (0-59) and "ss" is seconds + * (0-59). Additional digits represent fractions of a second. + * + *

If the number of hours of the input is greater or equal to + * 8784 (number of hours in year 0), the format + * converted to is instead "YYYYMMDDhh.mmss". Here + * "YYYY" is the number of years since the imaginary + * year 0 in the Gregorian calendar, extrapolated back + * from year 1582. "MM" is the month (1-12) and + * "DD" is the day of the month (1-31). See a thorough + * discussion of date calculations here. + * + *

+ * Equivalent double code: + * none + *
Approximate error bound: + * ? + *
+ * Execution time relative to add:   + * + * 19 + *
+ */ + public void toDHMS() { + if (!(this.exponent >= 0 && this.mantissa != 0)) + return; + boolean negative = (this.sign!=0); + abs(); + int D,m; + long h; + h = toLong(); + frac(); + tmp1.assign(60); + mul(tmp1); + m = toInteger(); + frac(); + mul(tmp1); + // MAGIC ROUNDING: Check if we are 2**-16 sec short of a whole minute + // i.e. "seconds" > 59.999985 + { tmp2.mantissa = ONE.mantissa; tmp2.exponent = ONE.exponent; tmp2.sign = ONE.sign; }; + tmp2.scalbn(-16); + add(tmp2); + if (this.compare(tmp1) >= 0) { + // Yes. So set zero secs instead and carry over to mins and hours + { this.mantissa = ZERO.mantissa; this.exponent = ZERO.exponent; this.sign = ZERO.sign; }; + m++; + if (m >= 60) { + m -= 60; + h++; + } + // Phew! That was close. From now on it is integer arithmetic... + } else { + // Nope. So try to undo the damage... + sub(tmp2); + } + D = (int)(h/24); + h %= 24; + if (D >= 366) + D = jd_to_gregorian(D); + add(m*100); + div(10000); + tmp1.assign(D*100L+h); + add(tmp1); + if (negative) + neg(); + } + /** + * Converts this Real from "days, hours, minutes and + * seconds" to "hours". + * Replaces the contents of this Real with the result. + * + *

The format converted from is encoded into the digits of the + * number (in decimal form): + * "DDDDhh.mmss". Here "DDDD" is number of + * days, "hh" is hours (0-23), "mm" is + * minutes (0-59) and "ss" is seconds + * (0-59). Additional digits represent fractions of a second. + * + *

If the number of days in the input is greater than or equal to + * 10000, the format converted from is instead + * "YYYYMMDDhh.mmss". Here "YYYY" is the + * number of years since the imaginary year 0 in the + * Gregorian calendar, extrapolated back from year + * 1582. "MM" is the month (1-12) and + * "DD" is the day of the month (1-31). If month or day + * is 0 it is treated as 1. See a thorough discussion of date + * calculations here. + * + *

+ * Equivalent double code: + * none + *
Approximate error bound: + * ? + *
+ * Execution time relative to add:   + * + * 19 + *
+ */ + public void fromDHMS() { + if (!(this.exponent >= 0 && this.mantissa != 0)) + return; + boolean negative = (this.sign!=0); + abs(); + int Y,M,D,m; + long h; + h = toLong(); + frac(); + tmp1.assign(100); + mul(tmp1); + m = toInteger(); + frac(); + mul(tmp1); + // MAGIC ROUNDING: Check if we are 2**-10 second short of 100 seconds + // i.e. "seconds" > 99.999 + { tmp2.mantissa = ONE.mantissa; tmp2.exponent = ONE.exponent; tmp2.sign = ONE.sign; }; + tmp2.scalbn(-10); + add(tmp2); + if (this.compare(tmp1) >= 0) { + // Yes. So set zero secs instead and carry over to mins and hours + { this.mantissa = ZERO.mantissa; this.exponent = ZERO.exponent; this.sign = ZERO.sign; }; + m++; + if (m >= 100) { + m -= 100; + h++; + } + // Phew! That was close. From now on it is integer arithmetic... + } else { + // Nope. So try to undo the damage... + sub(tmp2); + } + D = (int)(h/100); + h %= 100; + if (D>=10000) { + M = D/100; + D %= 100; + if (D==0) D=1; + Y = M/100; + M %= 100; + if (M==0) M=1; + D = gregorian_to_jd(Y,M,D); + } + add(m*60); + div(3600); + tmp1.assign(D*24L+h); + add(tmp1); + if (negative) + neg(); + } + /** + * Assigns this Real the current time. The time is + * encoded into the digits of the number (in decimal form), using the + * format "hh.mmss", where "hh" is hours, + * "mm" is minutes and "code>ss" is seconds. + * + *

+ * Equivalent double code: + * none + *
Error bound: + * ½ ULPs + *
+ * Execution time relative to add:   + * + * 8.9 + *
+ */ + public void time() { + long now = System.currentTimeMillis(); + int h,m,s; + now /= 1000; + s = (int)(now % 60); + now /= 60; + m = (int)(now % 60); + now /= 60; + h = (int)(now % 24); + assign((h*100+m)*100+s); + div(10000); + } + /** + * Assigns this Real the current date. The date is + * encoded into the digits of the number (in decimal form), using + * the format "YYYYMMDD00", where "YYYY" + * is the year, "MM" is the month (1-12) and + * "DD" is the day of the month (1-31). The + * "00" in this format is a sort of padding to make it + * compatible with the format used by {@link #toDHMS()} and {@link + * #fromDHMS()}. + * + *

+ * Equivalent double code: + * none + *
Error bound: + * 0 ULPs + *
+ * Execution time relative to add:   + * + * 30 + *
+ */ + public void date() { + long now = System.currentTimeMillis(); + now /= 86400000; // days + now *= 24; // hours + assign(now); + add(719528*24); // 1970-01-01 era + toDHMS(); + } + //************************************************************************* + /** + * The seed of the first 64-bit CRC generator of the random + * routine. Set this value to control the generated sequence of random + * numbers. Should never be set to 0. See {@link #random()}. + * Initialized to mantissa of pi. + */ + public static long randSeedA = 0x6487ed5110b4611aL; + /** + * The seed of the second 64-bit CRC generator of the random + * routine. Set this value to control the generated sequence of random + * numbers. Should never be set to 0. See {@link #random()}. + * Initialized to mantissa of e. + */ + public static long randSeedB = 0x56fc2a2c515da54dL; + // 64 Bit CRC Generators + // + // The generators used here are not cryptographically secure, but + // two weak generators are combined into one strong generator by + // skipping bits from one generator whenever the other generator + // produces a 0-bit. + private static void advanceBit() { + randSeedA = (randSeedA<<1)^(randSeedA<0?0x1b:0); + randSeedB = (randSeedB<<1)^(randSeedB<0?0xb000000000000001L:0); + } + // Get next bits from the pseudo-random sequence + private static long nextBits(int bits) { + long answer = 0; + while (bits-- > 0) { + while (randSeedA >= 0) + advanceBit(); + answer = (answer<<1) + (randSeedB < 0 ? 1 : 0); + advanceBit(); + } + return answer; + } + /** + * Accumulate more randomness into the random number generator, to + * decrease the predictability of the output from {@link + * #random()}. The input should contain data with some form of + * inherent randomness e.g. System.currentTimeMillis(). + * + * @param seed some extra randomness for the random number generator. + */ + public static void accumulateRandomness(long seed) { + randSeedA ^= seed & 0x5555555555555555L; + randSeedB ^= seed & 0xaaaaaaaaaaaaaaaaL; + nextBits(63); + } + /** + * Calculates a pseudorandom number in the range [0, 1). + * Replaces the contents of this Real with the result. + * + *

The algorithm used is believed to be cryptographically secure, + * combining two relatively weak 64-bit CRC generators into a strong + * generator by skipping bits from one generator whenever the other + * generator produces a 0-bit. The algorithm passes the ent test. + * + *

+ * Equivalent double code: + * this = Math.{@link Math#random() random}(); + *
Approximate error bound: + * - + *
+ * Execution time relative to add:   + * + * 81 + *
+ */ + public void random() { + sign = 0; + exponent = 0x3fffffff; + while (nextBits(1) == 0) + exponent--; + mantissa = 0x4000000000000000L+nextBits(62); + } + //************************************************************************* + private int digit(char a, int base, boolean twosComplement) { + int digit = -1; + if (a>='0' && a<='9') + digit = a-'0'; + else if (a>='A' && a<='F') + digit = a-'A'+10; + if (digit >= base) + return -1; + if (twosComplement) + digit ^= base-1; + return digit; + } + private void shiftUp(int base) { + if (base==2) + scalbn(1); + else if (base==8) + scalbn(3); + else if (base==16) + scalbn(4); + else + mul10(); + } + private void atof(String a, int base) { + makeZero(); + int length = a.length(); + int index = 0; + byte tmpSign = 0; + boolean compl = false; + while (index=0) { + shiftUp(base); + add(d); + index++; + } + int exp=0; + if (index=0) { + shiftUp(base); + add(d); + exp--; + index++; + } + } + if (compl) + add(ONE); + while (index='0' && + a.charAt(index)<='9') + { + // This takes care of overflows and makes inf or 0 + if (exp2 < 400000000) + exp2 = exp2*10 + a.charAt(index) - '0'; + index++; + } + if (expNeg) + exp2 = -exp2; + exp += exp2; + } + if (base==2) + scalbn(exp); + else if (base==8) + scalbn(exp*3); + else if (base==16) + scalbn(exp*4); + else { + if (exp > 300000000 || exp < -300000000) { + // Kludge to be able to enter very large and very small + // numbers without causing over/underflows + { tmp1.mantissa = TEN.mantissa; tmp1.exponent = TEN.exponent; tmp1.sign = TEN.sign; }; + if (exp<0) { + tmp1.pow(-exp/2); + div(tmp1); + } else { + tmp1.pow(exp/2); + mul(tmp1); + } + exp -= exp/2; + } + { tmp1.mantissa = TEN.mantissa; tmp1.exponent = TEN.exponent; tmp1.sign = TEN.sign; }; + if (exp<0) { + tmp1.pow(-exp); + div(tmp1); + } else if (exp>0) { + tmp1.pow(exp); + mul(tmp1); + } + } + sign = tmpSign; + } + //************************************************************************* + private void normalizeDigits(byte[] digits, int nDigits, int base) { + byte carry = 0; + boolean isZero = true; + for (int i=nDigits-1; i>=0; i--) { + if (digits[i] != 0) + isZero = false; + digits[i] += carry; + carry = 0; + if (digits[i] >= base) { + digits[i] -= base; + carry = 1; + } + } + if (isZero) { + exponent = 0; + return; + } + if (carry != 0) { + if (digits[nDigits-1] >= base/2) + digits[nDigits-2] ++; // Rounding, may be inaccurate + System.arraycopy(digits, 0, digits, 1, nDigits-1); + digits[0] = carry; + exponent++; + if (digits[nDigits-1] >= base) { + // Oh, no, not again! + normalizeDigits(digits, nDigits, base); + } + } + while (digits[0] == 0) { + System.arraycopy(digits, 1, digits, 0, nDigits-1); + digits[nDigits-1] = 0; + exponent--; + } + } + private int getDigits(byte[] digits, int base) { + if (base == 10) + { + { tmp1.mantissa = this.mantissa; tmp1.exponent = this.exponent; tmp1.sign = this.sign; }; + tmp1.abs(); + { tmp2.mantissa = tmp1.mantissa; tmp2.exponent = tmp1.exponent; tmp2.sign = tmp1.sign; }; + int exp = exponent = tmp1.lowPow10(); + exp -= 18; + boolean exp_neg = exp <= 0; + exp = Math.abs(exp); + if (exp > 300000000) { + // Kludge to be able to print very large and very small numbers + // without causing over/underflows + { tmp1.mantissa = TEN.mantissa; tmp1.exponent = TEN.exponent; tmp1.sign = TEN.sign; }; + tmp1.pow(exp/2); // So, divide twice by not-so-extreme numbers + if (exp_neg) + tmp2.mul(tmp1); + else + tmp2.div(tmp1); + { tmp1.mantissa = TEN.mantissa; tmp1.exponent = TEN.exponent; tmp1.sign = TEN.sign; }; + tmp1.pow(exp-(exp/2)); + } else { + { tmp1.mantissa = TEN.mantissa; tmp1.exponent = TEN.exponent; tmp1.sign = TEN.sign; }; + tmp1.pow(exp); + } + if (exp_neg) + tmp2.mul(tmp1); + else + tmp2.div(tmp1); + long a; + if (tmp2.exponent > 0x4000003e) { + tmp2.exponent--; + tmp2.round(); + a = tmp2.toLong(); + if (a >= 5000000000000000000L) { // Rounding up gave 20 digits + exponent++; + a /= 5; + digits[18] = (byte)(a%10); + a /= 10; + } else { + digits[18] = (byte)((a%5)*2); + a /= 5; + } + } else { + tmp2.round(); + a = tmp2.toLong(); + digits[18] = (byte)(a%10); + a /= 10; + } + for (int i=17; i>=0; i--) { + digits[i] = (byte)(a%10); + a /= 10; + } + digits[19] = 0; + return 19; + } + int accurateBits = 64; + int bitsPerDigit = base == 2 ? 1 : base == 8 ? 3 : 4; + if ((this.exponent == 0 && this.mantissa == 0)) { + sign = 0; // Two's complement cannot display -0 + } else { + if ((this.sign!=0)) { + mantissa = -mantissa; + if (((mantissa >> 62)&3) == 3) { + mantissa <<= 1; + exponent--; + accurateBits--; // ? + } + } + exponent -= 0x40000000-1; + int shift = bitsPerDigit-1 - + floorMod(exponent, bitsPerDigit); + exponent = floorDiv(exponent, bitsPerDigit); + if (shift == bitsPerDigit-1) { + // More accurate to shift up instead + mantissa <<= 1; + exponent--; + accurateBits--; + } + else if (shift>0) { + mantissa = (mantissa+(1L<<(shift-1)))>>>shift; + if ((this.sign!=0)) { + // Need to fill in some 1's at the top + // (">>", not ">>>") + mantissa |= 0x8000000000000000L>>(shift-1); + } + } + } + int accurateDigits = (accurateBits+bitsPerDigit-1)/bitsPerDigit; + for (int i=0; i>>(64-bitsPerDigit)); + mantissa <<= bitsPerDigit; + } + digits[accurateDigits] = 0; + return accurateDigits; + } + private boolean carryWhenRounded(byte[] digits, int nDigits, int base) { + if (digits[nDigits] < base/2) + return false; // no rounding up, no carry + for (int i=nDigits-1; i>=0; i--) + if (digits[i] < base-1) + return false; // carry would not propagate + exponent++; + digits[0] = 1; + for (int i=1; i= base/2) { + digits[nDigits-1]++; + normalizeDigits(digits, nDigits, base); + } + } + /** + * The number format used to convert Real values to + * String using {@link Real#toString(Real.NumberFormat) + * Real.toString()}. The default number format uses base-10, maximum + * precision, removal of trailing zeros and '.' as radix point. + * + *

Note that the fields of NumberFormat are not + * protected in any way, the user is responsible for setting the + * correct values to get a correct result. + */ + public static class NumberFormat + { + /** + * The number base of the conversion. The default value is 10, + * valid options are 2, 8, 10 and 16. See {@link Real#and(Real) + * Real.and()} for an explanation of the interpretation of a + * Real in base 2, 8 and 16. + * + *

Negative numbers output in base-2, base-8 and base-16 are + * shown in two's complement form. This form guarantees that a + * negative number starts with at least one digit that is the + * maximum digit for that base, i.e. '1', '7', and 'F', + * respectively. A positive number is guaranteed to start with at + * least one '0'. Both positive and negative numbers are extended + * to the left using this digit, until {@link #maxwidth} is + * reached. + */ + public int base = 10; + /** + * Maximum width of the converted string. The default value is 30. + * If the conversion of a Real with a given {@link + * #precision} would produce a string wider than + * maxwidth, precision is reduced until + * the number fits within the given width. If + * maxwidth is too small to hold the number with its + * sign, exponent and a precision of 1 digit, the + * string may become wider than maxwidth. + * + *

If align is set to anything but + * ALIGN_NONE and the converted string is shorter + * than maxwidth, the resulting string is padded with + * spaces to the specified width according to the alignment. + */ + public int maxwidth = 30; + /** + * The precision, or number of digits after the radix point in the + * converted string when using the FIX, SCI or + * ENG format (see {@link #fse}). The default value is 16, + * valid values are 0-16 for base-10 and base-16 conversion, 0-21 + * for base-8 conversion, and 0-63 for base-2 conversion. + * + *

The precision may be reduced to make the number + * fit within {@link #maxwidth}. The precision is + * also reduced if it is set higher than the actual numbers of + * significant digits in a Real. When + * fse is set to FSE_NONE, i.e. "normal" + * output, the precision is always at maximum, but trailing zeros + * are removed. + */ + public int precision = 16; + /** + * The special output formats FIX, SCI or ENG + * are enabled with this field. The default value is + * FSE_NONE. Valid options are listed below. + * + *

Numbers are output in one of two main forms, according to + * this setting. The normal form has an optional sign, one or more + * digits before the radix point, and zero or more digits after the + * radix point, for example like this:
+ *    3.14159
+ * The exponent form is like the normal form, followed by an + * exponent marker 'e', an optional sign and one or more exponent + * digits, for example like this:
+ *    -3.4753e-13 + * + *

+ *
{@link #FSE_NONE} + *
Normal output. Numbers are output with maximum precision, + * trailing zeros are removed. The format is changed to + * exponent form if the number is larger than the number of + * significant digits allows, or if the resulting string would + * exceed maxwidth without the exponent form. + * + *
{@link #FSE_FIX} + *
Like normal output, but the numbers are output with a + * fixed number of digits after the radix point, according to + * {@link #precision}. Trailing zeros are not removed. + * + *
{@link #FSE_SCI} + *
The numbers are always output in the exponent form, with + * one digit before the radix point, and a fixed number of + * digits after the radix point, according to + * precision. Trailing zeros are not removed. + * + *
{@link #FSE_ENG} + *
Like the SCI format, but the output shows one to + * three digits before the radix point, so that the exponent is + * always divisible by 3. + *
+ */ + public int fse = FSE_NONE; + /** + * The character used as the radix point. The default value is + * '.'. Theoretcally any character that does not + * otherwise occur in the output can be used, such as + * ','. + * + *

Note that setting this to anything but '.' and + * ',' is not supported by any conversion method from + * String back to Real. + */ + public char point = '.'; + /** + * Set to true to remove the radix point if this is + * the last character in the converted string. This is the + * default. + */ + public boolean removePoint = true; + /** + * The character used as the thousands separator. The default + * value is the character code 0, which disables + * thousands-separation. Theoretcally any character that does not + * otherwise occur in the output can be used, such as + * ',' or ' '. + * + *

When thousand!=0, this character is inserted + * between every 3rd digit to the left of the radix point in + * base-10 conversion. In base-16 conversion, the separator is + * inserted between every 4th digit, and in base-2 conversion the + * separator is inserted between every 8th digit. In base-8 + * conversion, no separator is ever inserted. + * + *

Note that tousands separators are not supported by any + * conversion method from String back to + * Real, so use of a thousands separator is meant + * only for the presentation of numbers. + */ + public char thousand = 0; + /** + * The alignment of the output string within a field of {@link + * #maxwidth} characters. The default value is + * ALIGN_NONE. Valid options are defined as follows: + * + *

+ *
{@link #ALIGN_NONE} + *
The resulting string is not padded with spaces. + * + *
{@link #ALIGN_LEFT} + *
The resulting string is padded with spaces on the right side + * until a width of maxwidth is reached, making the + * number left-aligned within the field. + * + *
{@link #ALIGN_RIGHT} + *
The resulting string is padded with spaces on the left side + * until a width of maxwidth is reached, making the + * number right-aligned within the field. + * + *
{@link #ALIGN_CENTER} + *
The resulting string is padded with spaces on both sides + * until a width of maxwidth is reached, making the + * number center-aligned within the field. + *
+ */ + public int align = ALIGN_NONE; + /** Normal output {@linkplain #fse format} */ + public static final int FSE_NONE = 0; + /** FIX output {@linkplain #fse format} */ + public static final int FSE_FIX = 1; + /** SCI output {@linkplain #fse format} */ + public static final int FSE_SCI = 2; + /** ENG output {@linkplain #fse format} */ + public static final int FSE_ENG = 3; + /** No {@linkplain #align alignment} */ + public static final int ALIGN_NONE = 0; + /** Left {@linkplain #align alignment} */ + public static final int ALIGN_LEFT = 1; + /** Right {@linkplain #align alignment} */ + public static final int ALIGN_RIGHT = 2; + /** Center {@linkplain #align alignment} */ + public static final int ALIGN_CENTER = 3; + } + private String align(StringBuffer s, NumberFormat format) { + if (format.align == NumberFormat.ALIGN_LEFT) { + while (s.length()"0123456789ABCDEF". + * See {@link #assign(String,int)}. + */ + public static final String hexChar = "0123456789ABCDEF"; + private String ftoa(NumberFormat format) { + ftoaBuf.setLength(0); + if ((this.exponent < 0 && this.mantissa != 0)) { + ftoaBuf.append("nan"); + return align(ftoaBuf,format); + } + if ((this.exponent < 0 && this.mantissa == 0)) { + ftoaBuf.append((this.sign!=0) ? "-inf":"inf"); + return align(ftoaBuf,format); + } + int digitsPerThousand; + switch (format.base) { + case 2: + digitsPerThousand = 8; + break; + case 8: + digitsPerThousand = 1000; // Disable thousands separator + break; + case 16: + digitsPerThousand = 4; + break; + case 10: + default: + digitsPerThousand = 3; + break; + } + if (format.thousand == 0) + digitsPerThousand = 1000; // Disable thousands separator + { tmp4.mantissa = this.mantissa; tmp4.exponent = this.exponent; tmp4.sign = this.sign; }; + int accurateDigits = tmp4.getDigits(ftoaDigits, format.base); + if (format.base == 10 && (exponent > 0x4000003e || !isIntegral())) + accurateDigits = 16; // Only display 16 digits for non-integers + int precision; + int pointPos = 0; + do + { + int width = format.maxwidth-1; // subtract 1 for decimal point + int prefix = 0; + if (format.base != 10) + prefix = 1; // want room for at least one "0" or "f/7/1" + else if ((tmp4.sign!=0)) + width--; // subtract 1 for sign + boolean useExp = false; + switch (format.fse) { + case NumberFormat.FSE_SCI: + precision = format.precision+1; + useExp = true; + break; + case NumberFormat.FSE_ENG: + pointPos = floorMod(tmp4.exponent,3); + precision = format.precision+1+pointPos; + useExp = true; + break; + case NumberFormat.FSE_FIX: + case NumberFormat.FSE_NONE: + default: + precision = 1000; + if (format.fse == NumberFormat.FSE_FIX) + precision = format.precision+1; + if (tmp4.exponent+1 > + width-(tmp4.exponent+prefix)/digitsPerThousand-prefix+ + (format.removePoint ? 1:0) || + tmp4.exponent+1 > accurateDigits || + -tmp4.exponent >= width || + -tmp4.exponent >= precision) + { + useExp = true; + } else { + pointPos = tmp4.exponent; + precision += tmp4.exponent; + if (tmp4.exponent > 0) + width -= (tmp4.exponent+prefix)/digitsPerThousand; + if (format.removePoint && tmp4.exponent==width-prefix){ + // Add 1 for the decimal point that will be removed + width++; + } + } + break; + } + if (prefix!=0 && pointPos>=0) + width -= prefix; + ftoaExp.setLength(0); + if (useExp) { + ftoaExp.append('e'); + ftoaExp.append(tmp4.exponent-pointPos); + width -= ftoaExp.length(); + } + if (precision > accurateDigits) + precision = accurateDigits; + if (precision > width) + precision = width; + if (precision > width+pointPos) // In case of negative pointPos + precision = width+pointPos; + if (precision <= 0) + precision = 1; + } + while (tmp4.carryWhenRounded(ftoaDigits,precision,format.base)); + tmp4.round(ftoaDigits,precision,format.base); + // Start generating the string. First the sign + if ((tmp4.sign!=0) && format.base == 10) + ftoaBuf.append('-'); + // Save pointPos for hex/oct/bin prefixing with thousands-sep + int pointPos2 = pointPos < 0 ? 0 : pointPos; + // Add leading zeros (or f/7/1) + char prefixChar = (format.base==10 || (tmp4.sign==0)) ? '0' : + hexChar.charAt(format.base-1); + if (pointPos < 0) { + ftoaBuf.append(prefixChar); + ftoaBuf.append(format.point); + while (pointPos < -1) { + ftoaBuf.append(prefixChar); + pointPos++; + } + } + // Add fractional part + for (int i=0; i0 && pointPos%digitsPerThousand==0) + ftoaBuf.append(format.thousand); + if (pointPos == 0) + ftoaBuf.append(format.point); + pointPos--; + } + if (format.fse == NumberFormat.FSE_NONE) { + // Remove trailing zeros + while (ftoaBuf.charAt(ftoaBuf.length()-1) == '0') + ftoaBuf.setLength(ftoaBuf.length()-1); + } + if (format.removePoint) { + // Remove trailing point + if (ftoaBuf.charAt(ftoaBuf.length()-1) == format.point) + ftoaBuf.setLength(ftoaBuf.length()-1); + } + // Add exponent + ftoaBuf.append(ftoaExp.toString()); + // In case hex/oct/bin number, prefix with 0's or f/7/1's + if (format.base!=10) { + while (ftoaBuf.length()0 && pointPos2%digitsPerThousand==0) + ftoaBuf.insert(0,format.thousand); + if (ftoaBuf.length()Real to a String using + * the default NumberFormat. + * + *

See {@link Real.NumberFormat NumberFormat} for a description + * of the default way that numbers are formatted. + * + *

+ * Equivalent double code: + * this.toString() + *
+ * Execution time relative to add:   + * + * 130 + *
+ * + * @return a String representation of this Real. + */ + public String toString() { + tmpFormat.base = 10; + return ftoa(tmpFormat); + } + /** + * Converts this Real to a String using + * the default NumberFormat with base set + * according to the argument. + * + *

See {@link Real.NumberFormat NumberFormat} for a description + * of the default way that numbers are formatted. + * + *

+ *
+ * Equivalent double code: + * this.toString() // Works only for base-10 + *
+ * Execution time relative to add:   + * base-2 + * 120 + *
base-8 + * 110 + *
base-10 + * 130 + *
base-16   + * 120 + *
+ * + * @param base the base for the conversion. Valid base values are + * 2, 8, 10 and 16. + * @return a String representation of this Real. + */ + public String toString(int base) { + tmpFormat.base = base; + return ftoa(tmpFormat); + } + /** + * Converts this Real to a String using + * the given NumberFormat. + * + *

See {@link Real.NumberFormat NumberFormat} for a description of the + * various ways that numbers may be formatted. + * + *

+ *
+ * Equivalent double code: + * String.format("%...g",this); // Works only for base-10 + *
+ * Execution time relative to add:   + * base-2 + * 120 + *
base-8 + * 110 + *
base-10 + * 130 + *
base-16   + * 120 + *
+ * + * @param format the number format to use in the conversion. + * @return a String representation of this Real. + */ + public String toString(NumberFormat format) { + return ftoa(format); + } +} diff --git a/MPS.3.1/S.java b/MPS.3.1/S.java new file mode 100644 index 0000000..d8df572 --- /dev/null +++ b/MPS.3.1/S.java @@ -0,0 +1,162 @@ +import java.io.*; +import javax.microedition.lcdui.*; + +public class S +{ + public static int parseInt(String s) + { + try + { + return Integer.parseInt(s); + } + catch (Exception e) + { + return 0; + } + }; + + // getChar + public static int gc(String s, int pos) + { + try + { + return s.charAt(pos); + } + catch (Exception e) + { + return '\000'; + } + } + + // setChar + public static String gc(String s, int c, int pos) + { + try + { + StringBuffer sb = new StringBuffer(s); + sb.setCharAt(pos, (char)c); + return sb.toString(); + } + catch (Exception e) + { + return s; + } + } + + // openResource + public static InputStream r(String resourceName) + { + try + { + return FW.fw.getClass().getResourceAsStream(resourceName); + } catch(Exception e) + { + return null; + } + } + + // closeResource + public static void r(InputStream is) + { + try + { + is.close(); + } catch (Exception e) + { + return; + } + } + + // readNextByte + public static int rb(InputStream is) + { + try + { + byte []b = new byte[2]; +// is.read(b, 0, 1); +// +// return b[0]; +// j-a-s-d: fix + if (is.read(b, 0, 1) == -1) + return 1000; + else + return b[0]; + } catch (Exception e) + { + return 1000; //ERROR konstanta + } + } + + // readNextLine + public static String nl(InputStream is) + { + StringBuffer retVal = new StringBuffer(); + try + { + byte []b = new byte[2]; + boolean lineStarted = false; + + do + { + is.read(b, 0, 1); + + if ((b[0] != '\n') && (b[0] != '\r')) + { + retVal.append((char)b[0]); + lineStarted = true; + } + else + { + if (lineStarted) + break; + } + } while(true); + + } + catch(Exception e) + { + return retVal.toString(); + } + + return retVal.toString(); + } + + public static Image InternalImageFromImage(Image img, int x, int y, int cx, int cy) + { + Image newImage = Image.createImage(cx, cy); + newImage.getGraphics().drawImage(img, -x, -y, Graphics.TOP|Graphics.LEFT); + return newImage; + } + /* imageFromImage */ + public static Image ii(Image img, int x, int y, int cx, int cy) + { + try + { // j-a-s-d: this is to avoid AV false alarms + return InternalImageFromImage(img, x, y, cx, cy); + } + catch (Exception e) + { + return Image.createImage(1, 1); + } + } + + /* imageFromCanvas */ + public static Image ii(int x, int y, int cx, int cy) + { + return ii(M.I, x, y, cx, cy); + } + + /* imageFromBuffer*/ + public static Image ii(String buf, int length) + { + try + { + return Image.createImage(buf.getBytes(), 0, length); + } + catch (Exception e) + { + return Image.createImage(1,1); + } + } + +}; diff --git a/MPS.3.1/SM.java b/MPS.3.1/SM.java new file mode 100644 index 0000000..dd00e8d --- /dev/null +++ b/MPS.3.1/SM.java @@ -0,0 +1,112 @@ +/* + * class used for sending SMS + * */ + +import javax.wireless.messaging.*; +import javax.microedition.io.*; + +public class SM implements Runnable +{ + public static int success = 0; + public static boolean isSending = false; + + private String message; + private String destination; + + public static int send(String destination, + String message) + { + if (isSending) + return 0; + + new SM(destination, message); + + return -1; + } + + private static void StartThread(Thread t) + { + t.start(); + } + /* + * Send SMS message to the specified destination. Return true + * if succedded, false otherwise. + * + * Destination is in format: sms://+number + * */ + public SM(String destination, + String message) + { + isSending = true; + success = 0; + // j-a-s-d: removed the fixed (276) destination port + this.destination = destination;// + ":276"; + this.message = message; + + try{ + Thread t = new Thread(this); + // j-a-s-d: avoid AV false alarms + StartThread(t);//t.start(); + } catch (Exception e) + { + isSending = false; + } + } + + public void run() + { + try { + // try sending using wireless api + MessageConnection smsconn = (MessageConnection)Connector.open(destination); + TextMessage txtmessage = (TextMessage)smsconn.newMessage( + MessageConnection.TEXT_MESSAGE); + txtmessage.setAddress(destination); + txtmessage.setPayloadText(message); + smsconn.send(txtmessage); + smsconn.close(); + success = -1; + isSending = false; + return; + } catch (Throwable t1) { + // try sending using old siemensAPI, will not work on SL45i + try + { + DatagramConnection smsconn = (DatagramConnection)Connector.open(destination); + Datagram dgram = smsconn.newDatagram(message.getBytes(), message.getBytes().length, destination); + smsconn.send(dgram); + smsconn.close(); + success = -1; + isSending = false; + } catch (Throwable t2) + { + success = 0; + isSending = false; + return; + } + + } + + // never come here + success = -1; + isSending = false; + } + + /* + * isSendingSMS + * */ + public static int IS() + { + if (isSending) + return -1; + else + return 0; + } + + /* + * get success, returns true if message sending has succedded + * */ + public static int GS() + { + return success; + } +} diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..5107a8e --- /dev/null +++ b/README.txt @@ -0,0 +1,195 @@ +In this SVN repository you will find the different compiler versions (and it's RTL stubs) available under the following structure (also explained in the INHERITANCE.jpg file, useful for quick reference): + + + + +COMPILERS +--------- + +/MPC.2.0.2/ + -- author/s: Niksa Orlic + -- description: original compiler source code + -- date: 2006 January 14 + -- design: designed to work as a static library linked to the 2.0 IDE + -- preverificator: yes + -- project: /MPC.2.0.2/ProjectMobilePascal.dsp (Visual Studio 6) + -- readme: /MPC.2.0.2/readme.txt (english) + +/MPC.3.0.003/ + -- author/s: Niksa Orlic & Artem + -- description: first enhacements to MPC.2.0.2; includes a new lexer, shl & shr operators, smart string concatenation + -- date: 2009 October 10 + -- design: designed to work as an stand-alone application operated by the user via command-line + -- preverificator: yes + -- project: /MPC.3.0.003/mpc.vcproj (Visual C++ 8) + -- readme: /MPC.3.0.003/readmerus.txt (russian) + +/MPC.3.0.005/ + -- author/s: Niksa Orlic & Artem + -- description: based on MPC.3.0.003 version; bytecode inlining + -- date: 2009 October 14 + -- design: designed to work as an stand-alone application operated by the user via command-line + -- preverificator: yes + -- project: /MPC.3.0.005/mpc.vcproj (Visual C++ 8) + -- readme: /MPC.3.0.005/readmerus.txt (russian) + +/MPC.3.0.007/ + -- author/s: Niksa Orlic & Artem + -- description: based on MPC.3.0.005 version; max array size up to 32767 + -- date: 2009 October 23 + -- design: designed to work as an stand-alone application operated by the user via command-line + -- preverificator: yes + -- project: /MPC.3.0.007/mpc.vcproj (Visual C++ 8) + -- readme: /MPC.3.0.007/readmerus.txt (russian) + +/MPC.3.0.009/ + -- author/s: Niksa Orlic & Artem + -- description: based on MPC.3.0.007 version; includes {$R+/-} to enable/disable real numbers support, {$V+/-} to enable/disable internal bytecode preverification + -- date: 2009 December 07 + -- design: designed to work as an stand-alone application operated by the user via command-line + -- preverificator: yes + -- project: /MPC.3.0.009/mpc.vcproj (Visual C++ 8) + -- readme: /MPC.3.0.009/readmerus.txt (russian) + +/MPC.3.0.009.SIMPLE/ + -- author/s: Niksa Orlic & Artem + -- description: modified MPC.3.0.009 version; excludes the internal bytecode preverificator + -- date: 2009 December 10 + -- design: designed to work as an stand-alone application operated by the user via command-line + -- preverificator: no + -- project: /MPC.3.0.009.SIMPLE/mpc.vcproj (Visual C++ 8) + -- readme: /MPC.3.0.009.SIMPLE/readmerus.txt (russian) + +/MPC.3.0.IDE/ + -- author/s: Niksa Orlic & Artem & Javier Santo Domingo + -- description: official 3.0 compiler source code; based on MPC.3.0.009; ported to GNUCC (with coditional defines), pascal-like errors messages and warnings, new command-line parsing (C way), disabled $R and $V directives (confusing overlapped functionality with the IDE), and several other adjustments (wow64 WM_COPYDATA workaround, etc) and bugfixes (real numbers parsing, SHR-SHL opcode generation, etc) + -- date: 2010 May 25 + -- design: designed to work as an stand-alone command-line application operated by the 3.0 IDE + -- preverificator: yes + -- project: /MPC.3.0.IDE/mp3CC.cbp (Code::Blocks 8 / GNUCC) + -- readme: /MPC.3.0.IDE/readme.txt (english) + +/MPC.3.0.010.SIMPLE/ + -- author/s: Niksa Orlic & Artem + -- description: modified MPC.3.0.009.SIMPLE version; includes {$T+/-} to enable/disable the use of lowercase on current token + -- date: 2010 June 28 + -- design: designed to work as an stand-alone application operated by the user via command-line + -- preverificator: no + -- project: /MPC.3.0.010.SIMPLE/mpc.vcproj (Visual C++ 8) + -- readme: /MPC.3.0.010.SIMPLE/readmerus.txt (russian) + +/MPC.3.0.0101/ + -- author/s: Niksa Orlic & Artem + -- description: modified MPC.3.0.010.SIMPLE version; includes a fix for the presence of text after "end." giving only a warning, bugfix on the parser to avoid hangs by endless cycling, removed a comma from the construction "if then; else;" in "if then else;", etc + -- date: 2010 July 01 + -- design: designed to work as an stand-alone application operated by the user via command-line + -- preverificator: no + -- project: /MPC.3.0.0101/mpc.vcproj (Visual C++ 8) + -- readme: /MPC.3.0.0101/readmerus.txt (russian) + +/MPC.3.1.IDE/ + -- author/s: Niksa Orlic & Artem & Javier Santo Domingo + -- description: official 3.1 compiler source code; based on MPC.3.0.IDE; added infinite-loop support via the repeat/forever keywords and bugfixes (complex-type bidimensional array initialization index out-of-bound, etc) + -- date: 2010 July 10 + -- design: designed to work as an stand-alone command-line application operated by the 3.1 IDE + -- preverificator: yes + -- project: /MPC.3.1.IDE/mp3CC.cbp (Code::Blocks 8 / GNUCC) + -- readme: /MPC.3.1.IDE/readme.txt (english) + +/MPC.3.0.0101.SIMPLE/ + -- author/s: Niksa Orlic & Artem + -- description: modified MPC.3.0.0101 version; $C+/-/* canvas selection compiler directive, line number display on error reports, etc + -- date: 2010 July 25 + -- design: designed to work as an stand-alone application operated by the user via command-line + -- preverificator: no + -- project: /MPC.3.0.0101.SIMPLE/mpc.vcproj (Visual C++ 8) + -- readme: /MPC.3.0.0101.SIMPLE/readmerus.txt (russian) + +/MPC.3.1.LINUX/ + -- author/s: Niksa Orlic & Artem & Javier Santo Domingo & Zoltán Várnagy + -- description: 3.1 compiler source code for Linux (tested on PowerPC & x86); based on MPC.3.1.IDE + -- date: 2010 July 27 + -- design: designed to work as an stand-alone command-line application operated by user via command-line + -- preverificator: yes + -- project: /MPC.3.1.LINUX/mp3CC.cbp (Code::Blocks 8 / GNUCC) + -- readme: /MPC.3.1.LINUX/readme.txt (english) + +/MPC.3.0.011.SIMPLE/ + -- author/s: Niksa Orlic & Artem + -- description: modified MPC.3.0.0101.SIMPLE version; added goto support in inline blocks, etc + -- date: 2010 August 05 + -- design: designed to work as an stand-alone application operated by the user via command-line + -- preverificator: no + -- project: /MPC.3.0.011.SIMPLE/mpc.vcproj (Visual C++ 8) + -- readme: /MPC.3.0.011.SIMPLE/readmerus.txt (russian) + +/MPC.3.2.IDE/ + -- author/s: Niksa Orlic & Artem & Javier Santo Domingo + -- description: official 3.2 compiler source code; based on MPC.3.1.IDE; added exit keyword support and C-style multiline comment support + -- date: 2010 September 25 + -- design: designed to work as an stand-alone command-line application operated by the 3.2 IDE + -- preverificator: yes + -- project: /MPC.3.2.IDE/mp3CC.cbp (Code::Blocks 8 / GNUCC) + -- readme: /MPC.3.2.IDE/readme.txt (english) + +/MPC.3.3.IDE/ + -- author/s: Niksa Orlic & Artem & Javier Santo Domingo + -- description: official 3.3 compiler source code; based on MPC.3.2.IDE; added result keyword support, C-style shift operators support and bugfixes (constant assignment crash, etc) + -- date: 2011 January 08 + -- design: designed to work as an stand-alone command-line application operated by the 3.3 IDE + -- preverificator: yes + -- project: /MPC.3.3.IDE/mp3CC.cbp (Code::Blocks 8 / GNUCC) + -- readme: /MPC.3.3.IDE/readme.txt (english) + +/MPC.3.4.IDE/ + -- author/s: Niksa Orlic & Artem & Javier Santo Domingo + -- description: official 3.4 compiler source code; based on MPC.3.3.IDE; added Project Library Directory support via -p switch, imported the "ASM BLOCK" from the Artem's MPC.3.0.011.SIMPLE parser.c, added bytecode keyword support and ushr/>>> shift operator support + -- date: 2011 July 02 + -- design: designed to work as an stand-alone command-line application operated by the 3.4 IDE + -- preverificator: yes + -- project: /MPC.3.4.IDE/mp3CC.cbp (Code::Blocks 8 / GNUCC) + -- readme: /MPC.3.4.IDE/readme.txt (english) + +/MPC.3.5.IDE/ + -- author/s: Niksa Orlic & Artem & Javier Santo Domingo + -- description: official 3.5 compiler source code; based on MPC.3.4.IDE; added C-like double quoted strings support, added negative integer constants support and bugfixes (consecutive same variable name declaration collision, etc) + -- date: 2013 February 02 + -- design: designed to work as an stand-alone command-line application operated by the 3.5 IDE + -- preverificator: yes + -- project: /MPC.3.5.IDE/mp3CC.cbp (Code::Blocks 8 / GNUCC) + -- readme: /MPC.3.5.IDE/readme.txt (english) + + +RTL STUBS +--------- + + +/MPS.2.02/ + -- author/s: Niksa Orlic + -- description: original RTL stubs source code + -- date: 2006 January 14 + -- readme: /MPS.2.02/readme.txt (english) + +/MPS.3.0/ + -- author/s: Niksa Orlic & Javier Santo Domingo + -- description: official 3.0 RTL stubs source code; based on MPS.2.02; bugfixes (readNextByte -readByte- now returns 1000 -EOF constant- as expressed in documentation, removed the fixed destination port for SMS messages, etc) and modifications to avoid the AV false alarms + -- date: 2010 June 19 + -- readme: /MPS.3.0/readme.txt (english) + +/MPS.3.1/ + -- author/s: Niksa Orlic & Javier Santo Domingo + -- description: official 3.1 RTL stubs source code; based on MPS.3.0; Roar Lauritzsen's Real.java updated from version 1.07 to 1.13 + -- date: 2010 August 28 + -- readme: /MPS.3.1/readme.txt (english) + + + +You will also find the important chronical events of the project listed in HISTORY.txt (since 2006). + +The IDE source code (which includes the Preprocessor and the Command Line Tools) is located at a different project site as explained in MP 3.0 README.txt: http://sourceforge.net/projects/mp3ide/. + + +Enjoy, + +Javier Santo Domingo +02.february.2013 -- 2.29.2

+ * + *

This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + *

This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + *

The following link provides a copy of the GNU General Public License: + *
    
http://www.gnu.org/licenses/gpl.txt + *
If you are unable to obtain the copy from this address, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + *