/Users/lyon/j4p/src/javassist/compiler/CodeGen.java
|
1 /*
2 * Javassist, a Java-bytecode translator toolkit.
3 * Copyright (C) 1999-2003 Shigeru Chiba. All Rights Reserved.
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. Alternatively, the contents of this file may be used under
8 * the terms of the GNU Lesser General Public License Version 2.1 or later.
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 */
15
16 package javassist.compiler;
17
18 import java.util.ArrayList;
19
20 import javassist.compiler.ast.*;
21 import javassist.bytecode.*;
22
23 /* The code generator is implemeted by three files:
24 * CodeGen.java, MemberCodeGen.java, and JvstCodeGen.
25 * I just wanted to split a big file into three smaller ones.
26 */
27
28 public abstract class CodeGen extends Visitor implements Opcode, TokenId {
29 static final String javaLangObject = "java.lang.Object";
30 static final String jvmJavaLangObject = "java/lang/Object";
31
32 static final String javaLangString = "java.lang.String";
33 static final String jvmJavaLangString = "java/lang/String";
34
35 protected Bytecode bytecode;
36 private int tempVar;
37
38 /**
39 * true if the last visited node is a return statement.
40 */
41 protected boolean hasReturned;
42
43 /**
44 * Must be true if compilation is for a static method.
45 */
46 public boolean inStaticMethod;
47
48 protected ArrayList breakList, continueList;
49
50 /* The following fields are used by atXXX() methods
51 * for returning the type of the compiled expression.
52 */
53 protected int exprType; // VOID, NULL, CLASS, BOOLEAN, INT, ...
54 protected int arrayDim;
55 protected String className; // JVM-internal representation
56
57 public CodeGen(Bytecode b) {
58 bytecode = b;
59 tempVar = -1;
60 hasReturned = false;
61 inStaticMethod = false;
62 breakList = null;
63 continueList = null;
64 }
65
66 protected static void fatal() throws CompileError {
67 throw new CompileError("fatal");
68 }
69
70 public static boolean is2word(int type, int dim) {
71 return dim == 0 && (type == DOUBLE || type == LONG);
72 }
73
74 public int getMaxLocals() {
75 return bytecode.getMaxLocals();
76 }
77
78 public void setMaxLocals(int n) {
79 bytecode.setMaxLocals(n);
80 }
81
82 protected void incMaxLocals(int size) {
83 bytecode.incMaxLocals(size);
84 }
85
86 /**
87 * Returns a local variable that single or double words can be
88 * stored in.
89 */
90 protected int getTempVar() {
91 if (tempVar < 0) {
92 tempVar = getMaxLocals();
93 incMaxLocals(2);
94 }
95
96 return tempVar;
97 }
98
99 protected int getLocalVar(Declarator d) {
100 int v = d.getLocalVar();
101 if (v < 0) {
102 v = getMaxLocals(); // delayed variable allocation.
103 d.setLocalVar(v);
104 incMaxLocals(1);
105 }
106
107 return v;
108 }
109
110 /**
111 * Returns the JVM-internal representation of this class name.
112 */
113 protected abstract String getThisName();
114
115 /**
116 * Returns the JVM-internal representation of this super class name.
117 */
118 protected abstract String getSuperName() throws CompileError;
119
120 /* Converts a class name into a JVM-internal representation.
121 *
122 * It may also expand a simple class name to java.lang.*.
123 * For example, this converts Object into java/lang/Object.
124 */
125 protected abstract String resolveClassName(ASTList name)
126 throws CompileError;
127
128 /* Expands a simple class name to java.lang.*.
129 * For example, this converts Object into java/lang/Object.
130 */
131 protected abstract String resolveClassName(String jvmClassName)
132 throws CompileError;
133
134 /**
135 * @param name the JVM-internal representation.
136 * name is not exapnded to java.lang.*.
137 */
138 protected static String toJvmArrayName(String name, int dim) {
139 if (name == null)
140 return null;
141
142 if (dim == 0)
143 return name;
144 else {
145 StringBuffer sbuf = new StringBuffer();
146 int d = dim;
147 while (d-- > 0)
148 sbuf.append('[');
149
150 sbuf.append('L');
151 sbuf.append(name);
152 sbuf.append(';');
153
154 return sbuf.toString();
155 }
156 }
157
158 protected static String toJvmTypeName(int type, int dim) {
159 char c = 'I';
160 switch (type) {
161 case BOOLEAN:
162 c = 'Z';
163 break;
164 case BYTE:
165 c = 'B';
166 break;
167 case CHAR:
168 c = 'C';
169 break;
170 case SHORT:
171 c = 'S';
172 break;
173 case INT:
174 c = 'I';
175 break;
176 case LONG:
177 c = 'J';
178 break;
179 case FLOAT:
180 c = 'F';
181 break;
182 case DOUBLE:
183 c = 'D';
184 break;
185 case VOID:
186 c = 'V';
187 break;
188 }
189
190 StringBuffer sbuf = new StringBuffer();
191 while (dim-- > 0)
192 sbuf.append('[');
193
194 sbuf.append(c);
195 return sbuf.toString();
196 }
197
198 protected static int jvmTypeNameToExprType(char type) {
199 switch (type) {
200 case 'Z':
201 return BOOLEAN;
202 case 'B':
203 return BYTE;
204 case 'C':
205 return CHAR;
206 case 'S':
207 return SHORT;
208 case 'I':
209 return INT;
210 case 'J':
211 return LONG;
212 case 'F':
213 return FLOAT;
214 case 'D':
215 return DOUBLE;
216 case 'V':
217 return VOID;
218 default :
219 return CLASS;
220 }
221 }
222
223 public void atASTList(ASTList n) throws CompileError {
224 fatal();
225 }
226
227 public void atPair(Pair n) throws CompileError {
228 fatal();
229 }
230
231 public void atSymbol(Symbol n) throws CompileError {
232 fatal();
233 }
234
235 public void atFieldDecl(FieldDecl field) throws CompileError {
236 field.getInit().accept(this);
237 }
238
239 public void atMethodDecl(MethodDecl method) throws CompileError {
240 ASTList mods = method.getModifiers();
241 setMaxLocals(1);
242 while (mods != null) {
243 Keyword k = (Keyword) mods.head();
244 mods = mods.tail();
245 if (k.get() == STATIC) {
246 setMaxLocals(0);
247 inStaticMethod = true;
248 }
249 }
250
251 ASTList params = method.getParams();
252 while (params != null) {
253 atDeclarator((Declarator) params.head());
254 params = params.tail();
255 }
256
257 Stmnt s = method.getBody();
258 atMethodBody(s, method.isConstructor(),
259 method.getReturn().getType() == VOID);
260 }
261
262 /**
263 * @param isCons true if super() must be called.
264 * false if the method is a class initializer.
265 */
266 public void atMethodBody(Stmnt s, boolean isCons, boolean isVoid)
267 throws CompileError {
268 if (s == null)
269 return;
270
271 if (isCons && needsSuperCall(s))
272 insertDefaultSuperCall();
273
274 hasReturned = false;
275 s.accept(this);
276 if (!hasReturned)
277 if (isVoid) {
278 bytecode.addOpcode(Opcode.RETURN);
279 hasReturned = true;
280 } else
281 throw new CompileError("no return statement");
282 }
283
284 private boolean needsSuperCall(Stmnt body) throws CompileError {
285 if (body.getOperator() == BLOCK)
286 body = (Stmnt) body.head();
287
288 if (body != null && body.getOperator() == EXPR) {
289 ASTree expr = body.head();
290 if (expr != null && expr instanceof Expr
291 && ((Expr) expr).getOperator() == CALL) {
292 ASTree target = ((Expr) expr).head();
293 if (target instanceof Keyword) {
294 int token = ((Keyword) target).get();
295 return token != THIS && token != SUPER;
296 }
297 }
298 }
299
300 return true;
301 }
302
303 protected abstract void insertDefaultSuperCall() throws CompileError;
304
305 public void atStmnt(Stmnt st) throws CompileError {
306 if (st == null)
307 return; // empty
308
309 int op = st.getOperator();
310 if (op == EXPR) {
311 ASTree expr = st.getLeft();
312 if (expr instanceof AssignExpr)
313 atAssignExpr((AssignExpr) expr, false);
314 else if (isPlusPlusExpr(expr)) {
315 Expr e = (Expr) expr;
316 atPlusPlus(e.getOperator(), e.oprand1(), e, false);
317 } else {
318 expr.accept(this);
319 if (is2word(exprType, arrayDim))
320 bytecode.addOpcode(POP2);
321 else if (exprType != VOID)
322 bytecode.addOpcode(POP);
323 }
324 } else if (op == DECL || op == BLOCK) {
325 ASTList list = st;
326 while (list != null) {
327 ASTree h = list.head();
328 list = list.tail();
329 if (h != null)
330 h.accept(this);
331 }
332 } else if (op == IF)
333 atIfStmnt(st);
334 else if (op == WHILE || op == DO)
335 atWhileStmnt(st, op == WHILE);
336 else if (op == FOR)
337 atForStmnt(st);
338 else if (op == BREAK || op == CONTINUE)
339 atBreakStmnt(st, op == BREAK);
340 else if (op == TokenId.RETURN)
341 atReturnStmnt(st);
342 else if (op == THROW)
343 atThrowStmnt(st);
344 else if (op == TRY)
345 atTryStmnt(st);
346 else {
347 // LABEL, SWITCH label stament might be null?.
348 hasReturned = false;
349 throw new CompileError(
350 "sorry, not supported statement: TokenId " + op);
351 }
352 }
353
354 private void atIfStmnt(Stmnt st) throws CompileError {
355 ASTree expr = st.head();
356 Stmnt thenp = (Stmnt) st.tail().head();
357 Stmnt elsep = (Stmnt) st.tail().tail().head();
358 booleanExpr(false, expr);
359 int pc = bytecode.currentPc();
360 int pc2 = 0;
361 bytecode.addIndex(0); // correct later
362
363 hasReturned = false;
364 if (thenp != null)
365 thenp.accept(this);
366
367 boolean thenHasReturned = hasReturned;
368 hasReturned = false;
369
370 if (elsep != null && !thenHasReturned) {
371 bytecode.addOpcode(Opcode.GOTO);
372 pc2 = bytecode.currentPc();
373 bytecode.addIndex(0);
374 }
375
376 bytecode.write16bit(pc, bytecode.currentPc() - pc + 1);
377
378 if (elsep != null) {
379 elsep.accept(this);
380 if (!thenHasReturned)
381 bytecode.write16bit(pc2, bytecode.currentPc() - pc2 + 1);
382
383 hasReturned = thenHasReturned && hasReturned;
384 }
385 }
386
387 private void atWhileStmnt(Stmnt st, boolean notDo) throws CompileError {
388 ArrayList prevBreakList = breakList;
389 ArrayList prevContList = continueList;
390 breakList = new ArrayList();
391 continueList = new ArrayList();
392
393 ASTree expr = st.head();
394 Stmnt body = (Stmnt) st.tail();
395
396 int pc = 0;
397 if (notDo) {
398 bytecode.addOpcode(Opcode.GOTO);
399 pc = bytecode.currentPc();
400 bytecode.addIndex(0);
401 }
402
403 int pc2 = bytecode.currentPc();
404 if (body != null)
405 body.accept(this);
406
407 int pc3 = bytecode.currentPc();
408 if (notDo)
409 bytecode.write16bit(pc, pc3 - pc + 1);
410
411 boolean alwaysBranch = booleanExpr(true, expr);
412 bytecode.addIndex(pc2 - bytecode.currentPc() + 1);
413
414 patchGoto(breakList, bytecode.currentPc());
415 patchGoto(continueList, pc3);
416 continueList = prevContList;
417 breakList = prevBreakList;
418 hasReturned = alwaysBranch;
419 }
420
421 private void patchGoto(ArrayList list, int targetPc) {
422 int n = list.size();
423 for (int i = 0; i < n; ++i) {
424 int pc = ((Integer) list.get(i)).intValue();
425 bytecode.write16bit(pc, targetPc - pc + 1);
426 }
427 }
428
429 private void atForStmnt(Stmnt st) throws CompileError {
430 ArrayList prevBreakList = breakList;
431 ArrayList prevContList = continueList;
432 breakList = new ArrayList();
433 continueList = new ArrayList();
434
435 Stmnt init = (Stmnt) st.head();
436 ASTList p = st.tail();
437 ASTree expr = p.head();
438 p = p.tail();
439 Stmnt update = (Stmnt) p.head();
440 Stmnt body = (Stmnt) p.tail();
441
442 if (init != null)
443 init.accept(this);
444
445 int pc = bytecode.currentPc();
446 int pc2 = 0;
447 if (expr != null) {
448 booleanExpr(false, expr);
449 pc2 = bytecode.currentPc();
450 bytecode.addIndex(0);
451 }
452
453 if (body != null)
454 body.accept(this);
455
456 int pc3 = bytecode.currentPc();
457 if (update != null)
458 update.accept(this);
459
460 bytecode.addOpcode(Opcode.GOTO);
461 bytecode.addIndex(pc - bytecode.currentPc() + 1);
462
463 int pc4 = bytecode.currentPc();
464 if (expr != null)
465 bytecode.write16bit(pc2, pc4 - pc2 + 1);
466
467 patchGoto(breakList, pc4);
468 patchGoto(continueList, pc3);
469 continueList = prevContList;
470 breakList = prevBreakList;
471 hasReturned = false;
472 }
473
474 private void atBreakStmnt(Stmnt st, boolean notCont)
475 throws CompileError {
476 if (st.head() != null)
477 throw new CompileError(
478 "sorry, not support labeled break or continue");
479
480 bytecode.addOpcode(Opcode.GOTO);
481 Integer pc = new Integer(bytecode.currentPc());
482 bytecode.addIndex(0);
483 if (notCont)
484 breakList.add(pc);
485 else
486 continueList.add(pc);
487 }
488
489 protected void atReturnStmnt(Stmnt st) throws CompileError {
490 atReturnStmnt2(st.getLeft());
491 }
492
493 protected final void atReturnStmnt2(ASTree result) throws CompileError {
494 int op;
495 if (result == null)
496 op = Opcode.RETURN;
497 else {
498 result.accept(this);
499 if (arrayDim > 0)
500 op = ARETURN;
501 else {
502 int type = exprType;
503 if (type == DOUBLE)
504 op = DRETURN;
505 else if (type == FLOAT)
506 op = FRETURN;
507 else if (type == LONG)
508 op = LRETURN;
509 else if (isRefType(type))
510 op = ARETURN;
511 else
512 op = IRETURN;
513 }
514 }
515
516 bytecode.addOpcode(op);
517 hasReturned = true;
518 }
519
520 private void atThrowStmnt(Stmnt st) throws CompileError {
521 ASTree e = st.getLeft();
522 e.accept(this);
523 if (exprType != CLASS || arrayDim > 0)
524 throw new CompileError("bad throw statement");
525
526 bytecode.addOpcode(ATHROW);
527 hasReturned = true;
528 }
529
530 protected void atTryStmnt(Stmnt st) throws CompileError {
531 hasReturned = false;
532 }
533
534 private static boolean isPlusPlusExpr(ASTree expr) {
535 if (expr instanceof Expr) {
536 int op = ((Expr) expr).getOperator();
537 return op == PLUSPLUS || op == MINUSMINUS;
538 }
539
540 return false;
541 }
542
543 public void atDeclarator(Declarator d) throws CompileError {
544 d.setLocalVar(getMaxLocals());
545 d.setClassName(resolveClassName(d.getClassName()));
546
547 int size;
548 if (is2word(d.getType(), d.getArrayDim()))
549 size = 2;
550 else
551 size = 1;
552
553 incMaxLocals(size);
554
555 /* NOTE: Array initializers has not been supported.
556 */
557 ASTree init = d.getInitializer();
558 if (init != null)
559 atVariableAssign(null, '=', null, d, init, false);
560 }
561
562 public abstract void atNewExpr(NewExpr n) throws CompileError;
563
564 public void atAssignExpr(AssignExpr expr) throws CompileError {
565 atAssignExpr(expr, true);
566 }
567
568 protected void atAssignExpr(AssignExpr expr, boolean doDup)
569 throws CompileError {
570 // =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, >>>=
571 int op = expr.getOperator();
572 ASTree left = expr.oprand1();
573 ASTree right = expr.oprand2();
574 if (left instanceof Variable)
575 atVariableAssign(expr, op, (Variable) left,
576 ((Variable) left).getDeclarator(),
577 right, doDup);
578 else {
579 if (left instanceof Expr) {
580 Expr e = (Expr) left;
581 if (e.getOperator() == ARRAY) {
582 atArrayAssign(expr, op, (Expr) left, right, doDup);
583 return;
584 }
585 }
586
587 atFieldAssign(expr, op, left, right, doDup);
588 }
589 }
590
591 protected static void badAssign(Expr expr) throws CompileError {
592 String msg;
593 if (expr == null)
594 msg = "incompatible type for assignment";
595 else
596 msg = "incompatible type for " + expr.getName();
597
598 throw new CompileError(msg);
599 }
600
601 /* op is either =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, or >>>=.
602 *
603 * expr and var can be null.
604 */
605 private void atVariableAssign(Expr expr, int op, Variable var,
606 Declarator d, ASTree right,
607 boolean doDup) throws CompileError {
608 int varType = d.getType();
609 int varArray = d.getArrayDim();
610 String varClass = d.getClassName();
611 int varNo = getLocalVar(d);
612
613 if (op != '=')
614 atVariable(var);
615
616 atAssignCore(expr, op, right, varType, varArray, varClass);
617
618 if (doDup)
619 if (is2word(varType, varArray))
620 bytecode.addOpcode(DUP2);
621 else
622 bytecode.addOpcode(DUP);
623
624 if (varArray > 0)
625 bytecode.addAstore(varNo);
626 else if (varType == DOUBLE)
627 bytecode.addDstore(varNo);
628 else if (varType == FLOAT)
629 bytecode.addFstore(varNo);
630 else if (varType == LONG)
631 bytecode.addLstore(varNo);
632 else if (isRefType(varType))
633 bytecode.addAstore(varNo);
634 else
635 bytecode.addIstore(varNo);
636
637 exprType = varType;
638 arrayDim = varArray;
639 className = varClass;
640 }
641
642 private void atArrayAssign(Expr expr, int op, Expr array,
643 ASTree right, boolean doDup) throws CompileError {
644 arrayAccess(array.oprand1(), array.oprand2());
645
646 if (op != '=') {
647 bytecode.addOpcode(DUP2);
648 bytecode.addOpcode(getArrayReadOp(exprType, arrayDim));
649 }
650
651 int aType = exprType;
652 int aDim = arrayDim;
653 String cname = className;
654
655 atAssignCore(expr, op, right, aType, aDim, cname);
656
657 if (doDup)
658 if (is2word(aType, aDim))
659 bytecode.addOpcode(DUP2_X2);
660 else
661 bytecode.addOpcode(DUP_X2);
662
663 bytecode.addOpcode(getArrayWriteOp(aType, aDim));
664 exprType = aType;
665 arrayDim = aDim;
666 className = cname;
667 }
668
669 protected abstract void atFieldAssign(Expr expr, int op, ASTree left,
670 ASTree right, boolean doDup) throws CompileError;
671
672 protected void atAssignCore(Expr expr, int op, ASTree right,
673 int type, int dim, String cname)
674 throws CompileError {
675 right.accept(this);
676 if (invalidDim(exprType, arrayDim, className, type, dim, cname, false)
677 || (op != '=' && dim > 0))
678 badAssign(expr);
679
680 if (op == PLUS_E && dim == 0 && type == CLASS)
681 atStringConcatExpr(expr, type, dim, cname);
682 else if (op != '=') {
683 int token = assignOps[op - MOD_E];
684 int k = lookupBinOp(token);
685 if (k < 0)
686 fatal();
687
688 atArithBinExpr(expr, token, k, type);
689 }
690
691 if (op != '=' || (dim == 0 && !isRefType(type)))
692 atNumCastExpr(exprType, type);
693
694 // type check should be done here.
695 }
696
697 private boolean invalidDim(int srcType, int srcDim, String srcClass,
698 int destType, int destDim, String destClass,
699 boolean isCast) {
700 if (srcDim != destDim)
701 if (srcType == NULL)
702 return false;
703 else if (destDim == 0 && destType == CLASS
704 && jvmJavaLangObject.equals(destClass))
705 return false;
706 else if (isCast && srcDim == 0 && srcType == CLASS
707 && jvmJavaLangObject.equals(srcClass))
708 return false;
709 else
710 return true;
711
712 return false;
713 }
714
715 public void atCondExpr(CondExpr expr) throws CompileError {
716 booleanExpr(false, expr.condExpr());
717 int pc = bytecode.currentPc();
718 bytecode.addIndex(0); // correct later
719 expr.thenExpr().accept(this);
720 bytecode.addOpcode(Opcode.GOTO);
721 int pc2 = bytecode.currentPc();
722 bytecode.addIndex(0);
723 bytecode.write16bit(pc, bytecode.currentPc() - pc + 1);
724 expr.elseExpr().accept(this);
725 bytecode.write16bit(pc2, bytecode.currentPc() - pc2 + 1);
726 }
727
728 private final int[] binOp = {
729 '+', DADD, FADD, LADD, IADD,
730 '-', DSUB, FSUB, LSUB, ISUB,
731 '*', DMUL, FMUL, LMUL, IMUL,
732 '/', DDIV, FDIV, LDIV, IDIV,
733 '%', DREM, FREM, LREM, IREM,
734 '|', NOP, NOP, LOR, IOR,
735 '^', NOP, NOP, LXOR, IXOR,
736 '&', NOP, NOP, LAND, IAND,
737 LSHIFT, NOP, NOP, LSHL, ISHL,
738 RSHIFT, NOP, NOP, LSHR, ISHR,
739 ARSHIFT, NOP, NOP, LUSHR, IUSHR};
740
741 private int lookupBinOp(int token) {
742 int[] code = binOp;
743 int s = code.length;
744 for (int k = 0; k < s; k = k + 5)
745 if (code[k] == token)
746 return k;
747
748 return -1;
749 }
750
751 public void atBinExpr(BinExpr expr) throws CompileError {
752 int token = expr.getOperator();
753
754 /* arithmetic operators: +, -, *, /, %, |, ^, &, <<, >>, >>>
755 */
756 int k = lookupBinOp(token);
757 if (k >= 0) {
758 expr.oprand1().accept(this);
759 int type1 = exprType;
760 int dim1 = arrayDim;
761 String cname1 = className;
762 expr.oprand2().accept(this);
763 if (dim1 != arrayDim)
764 throw new CompileError("incompatible array types");
765
766 if (token == '+' && dim1 == 0
767 && (type1 == CLASS || exprType == CLASS))
768 atStringConcatExpr(expr, type1, dim1, cname1);
769 else
770 atArithBinExpr(expr, token, k, type1);
771
772 return;
773 }
774
775 /* equation: &&, ||, ==, !=, <=, >=, <, >
776 */
777 booleanExpr(true, expr);
778 bytecode.addIndex(7);
779 bytecode.addIconst(0); // false
780 bytecode.addOpcode(Opcode.GOTO);
781 bytecode.addIndex(4);
782 bytecode.addIconst(1); // true
783 }
784
785 /* arrayDim values of the two oprands must be equal.
786 * If an oprand type is not a numeric type, this method
787 * throws an exception.
788 */
789 private void atArithBinExpr(Expr expr, int token,
790 int index, int type1) throws CompileError {
791 if (arrayDim != 0)
792 badTypes(expr);
793
794 int type2 = exprType;
795 if (token == LSHIFT || token == RSHIFT || token == ARSHIFT)
796 if (type2 == INT || type2 == SHORT
797 || type2 == CHAR || type2 == BYTE)
798 exprType = type1;
799 else
800 badTypes(expr);
801 else
802 convertOprandTypes(type1, type2, expr);
803
804 int p = typePrecedence(exprType);
805 if (p >= 0) {
806 int op = binOp[index + p + 1];
807 if (op != NOP) {
808 if (p == P_INT)
809 exprType = INT; // type1 may be BYTE, ...
810
811 bytecode.addOpcode(op);
812 return;
813 }
814 }
815
816 badTypes(expr);
817 }
818
819 private void atStringConcatExpr(Expr expr, int type1, int dim1,
820 String cname1) throws CompileError {
821 int type2 = exprType;
822 int dim2 = arrayDim;
823 boolean type2Is2 = is2word(type2, dim2);
824 boolean type2IsString
825 = (type2 == CLASS && jvmJavaLangString.equals(className));
826
827 if (type2Is2)
828 convToString(type2, dim2);
829
830 if (is2word(type1, dim1)) {
831 bytecode.addOpcode(DUP_X2);
832 bytecode.addOpcode(POP);
833 } else
834 bytecode.addOpcode(SWAP);
835
836 convToString(type1, dim1);
837 bytecode.addOpcode(SWAP);
838
839 if (!type2Is2 && !type2IsString)
840 convToString(type2, dim2);
841
842 bytecode.addInvokevirtual(javaLangString, "concat",
843 "(Ljava/lang/String;)Ljava/lang/String;");
844 exprType = CLASS;
845 arrayDim = 0;
846 className = jvmJavaLangString;
847 }
848
849 private void convToString(int type, int dim) throws CompileError {
850 final String method = "valueOf";
851
852 if (isRefType(type) || dim > 0)
853 bytecode.addInvokestatic(javaLangString, method,
854 "(Ljava/lang/Object;)Ljava/lang/String;");
855 else if (type == DOUBLE)
856 bytecode.addInvokestatic(javaLangString, method,
857 "(D)Ljava/lang/String;");
858 else if (type == FLOAT)
859 bytecode.addInvokestatic(javaLangString, method,
860 "(F)Ljava/lang/String;");
861 else if (type == LONG)
862 bytecode.addInvokestatic(javaLangString, method,
863 "(J)Ljava/lang/String;");
864 else if (type == BOOLEAN)
865 bytecode.addInvokestatic(javaLangString, method,
866 "(Z)Ljava/lang/String;");
867 else if (type == CHAR)
868 bytecode.addInvokestatic(javaLangString, method,
869 "(C)Ljava/lang/String;");
870 else if (type == VOID)
871 throw new CompileError("void type expression");
872 else /* INT, BYTE, SHORT */
873 bytecode.addInvokestatic(javaLangString, method,
874 "(I)Ljava/lang/String;");
875 }
876
877 /* Produces the opcode to branch if the condition is true.
878 * The oprand is not produced.
879 *
880 * @return true if the compiled code is GOTO (always branch).
881 */
882 private boolean booleanExpr(boolean branchIf, ASTree expr)
883 throws CompileError {
884 boolean isAndAnd;
885 int op = getCompOperator(expr);
886 if (op == EQ) { // ==, !=, ...
887 BinExpr bexpr = (BinExpr) expr;
888 int type1 = compileOprands(bexpr);
889 compareExpr(branchIf, bexpr.getOperator(), type1, bexpr);
890 } else if (op == '!')
891 booleanExpr(!branchIf, ((Expr) expr).oprand1());
892 else if ((isAndAnd = (op == ANDAND)) || op == OROR) {
893 BinExpr bexpr = (BinExpr) expr;
894 booleanExpr(!isAndAnd, bexpr.oprand1());
895 int pc = bytecode.currentPc();
896 bytecode.addIndex(0); // correct later
897
898 booleanExpr(isAndAnd, bexpr.oprand2());
899 bytecode.write16bit(pc, bytecode.currentPc() - pc + 3);
900 if (branchIf != isAndAnd) {
901 bytecode.addIndex(6); // skip GOTO instruction
902 bytecode.addOpcode(Opcode.GOTO);
903 }
904 } else if (isAlwaysBranch(expr, branchIf)) {
905 bytecode.addOpcode(Opcode.GOTO);
906 return true; // always branch
907 } else { // others
908 expr.accept(this);
909 bytecode.addOpcode(branchIf ? IFNE : IFEQ);
910 }
911
912 exprType = BOOLEAN;
913 arrayDim = 0;
914 return false;
915 }
916
917
918 private static boolean isAlwaysBranch(ASTree expr, boolean branchIf) {
919 if (expr instanceof Keyword) {
920 int t = ((Keyword) expr).get();
921 return branchIf ? t == TRUE : t == FALSE;
922 }
923
924 return false;
925 }
926
927 private static int getCompOperator(ASTree expr) throws CompileError {
928 if (expr instanceof Expr) {
929 Expr bexpr = (Expr) expr;
930 int token = bexpr.getOperator();
931 if (token == '!')
932 return '!';
933 else if ((bexpr instanceof BinExpr)
934 && token != OROR && token != ANDAND
935 && token != '&' && token != '|')
936 return EQ; // ==, !=, ...
937 else
938 return token;
939 }
940
941 return ' '; // others
942 }
943
944 private int compileOprands(BinExpr expr) throws CompileError {
945 expr.oprand1().accept(this);
946 int type1 = exprType;
947 int dim1 = arrayDim;
948 expr.oprand2().accept(this);
949 if (dim1 != arrayDim)
950 throw new CompileError("incompatible array types");
951
952 return type1;
953 }
954
955 private final int ifOp[] = {EQ, IF_ICMPEQ, IF_ICMPNE,
956 NEQ, IF_ICMPNE, IF_ICMPEQ,
957 LE, IF_ICMPLE, IF_ICMPGT,
958 GE, IF_ICMPGE, IF_ICMPLT,
959 '<', IF_ICMPLT, IF_ICMPGE,
960 '>', IF_ICMPGT, IF_ICMPLE};
961
962 private final int ifOp2[] = {EQ, IFEQ, IFNE,
963 NEQ, IFNE, IFEQ,
964 LE, IFLE, IFGT,
965 GE, IFGE, IFLT,
966 '<', IFLT, IFGE,
967 '>', IFGT, IFLE};
968
969 /* Produces the opcode to branch if the condition is true.
970 * The oprands are not produced.
971 *
972 * Parameter expr - compare expression ==, !=, <=, >=, <, >
973 */
974 private void compareExpr(boolean branchIf,
975 int token, int type1, BinExpr expr)
976 throws CompileError {
977 if (arrayDim == 0)
978 convertOprandTypes(type1, exprType, expr);
979
980 int p = typePrecedence(exprType);
981 if (p == P_OTHER || arrayDim > 0)
982 if (token == EQ)
983 bytecode.addOpcode(branchIf ? IF_ACMPEQ : IF_ACMPNE);
984 else if (token == NEQ)
985 bytecode.addOpcode(branchIf ? IF_ACMPNE : IF_ACMPEQ);
986 else
987 badTypes(expr);
988 else if (p == P_INT) {
989 int op[] = ifOp;
990 for (int i = 0; i < op.length; i += 3)
991 if (op[i] == token) {
992 bytecode.addOpcode(op[i + (branchIf ? 1 : 2)]);
993 return;
994 }
995
996 badTypes(expr);
997 } else {
998 if (p == P_DOUBLE)
999 if (token == '<' || token == LE)
1000 bytecode.addOpcode(DCMPG);
1001 else
1002 bytecode.addOpcode(DCMPL);
1003 else if (p == P_FLOAT)
1004 if (token == '<' || token == LE)
1005 bytecode.addOpcode(FCMPG);
1006 else
1007 bytecode.addOpcode(FCMPL);
1008 else if (p == P_LONG)
1009 bytecode.addOpcode(LCMP); // 1: >, 0: =, -1: <
1010 else
1011 fatal();
1012
1013 int[] op = ifOp2;
1014 for (int i = 0; i < op.length; i += 3)
1015 if (op[i] == token) {
1016 bytecode.addOpcode(op[i + (branchIf ? 1 : 2)]);
1017 return;
1018 }
1019
1020 badTypes(expr);
1021 }
1022 }
1023
1024 protected static void badTypes(Expr expr) throws CompileError {
1025 throw new CompileError("invalid types for " + expr.getName());
1026 }
1027
1028 private static final int P_DOUBLE = 0;
1029 private static final int P_FLOAT = 1;
1030 private static final int P_LONG = 2;
1031 private static final int P_INT = 3;
1032 private static final int P_OTHER = -1;
1033
1034 protected static boolean isRefType(int type) {
1035 return type == CLASS || type == NULL;
1036 }
1037
1038 private static int typePrecedence(int type) {
1039 if (type == DOUBLE)
1040 return P_DOUBLE;
1041 else if (type == FLOAT)
1042 return P_FLOAT;
1043 else if (type == LONG)
1044 return P_LONG;
1045 else if (isRefType(type))
1046 return P_OTHER;
1047 else if (type == VOID)
1048 return P_OTHER; // this is wrong, but ...
1049 else
1050 return P_INT; // BOOLEAN, BYTE, CHAR, SHORT, INT
1051 }
1052
1053 private static final int[] castOp = {
1054 /* D F L I */
1055 /* double */ NOP, D2F, D2L, D2I,
1056 /* float */ F2D, NOP, F2L, F2I,
1057 /* long */ L2D, L2F, NOP, L2I,
1058 /* other */ I2D, I2F, I2L, NOP};
1059
1060 /* do implicit type conversion.
1061 * arrayDim values of the two oprands must be zero.
1062 */
1063 private void convertOprandTypes(int type1, int type2, Expr expr)
1064 throws CompileError {
1065 boolean rightStrong;
1066 int type1_p = typePrecedence(type1);
1067 int type2_p = typePrecedence(type2);
1068
1069 if (type2_p < 0 && type1_p < 0) // not primitive types
1070 return;
1071
1072 if (type2_p < 0 || type1_p < 0) // either is not a primitive type
1073 badTypes(expr);
1074
1075 int op, result_type;
1076 if (type1_p <= type2_p) {
1077 rightStrong = false;
1078 exprType = type1;
1079 op = castOp[type2_p * 4 + type1_p];
1080 result_type = type1_p;
1081 } else {
1082 rightStrong = true;
1083 op = castOp[type1_p * 4 + type2_p];
1084 result_type = type2_p;
1085 }
1086
1087 if (rightStrong) {
1088 if (result_type == P_DOUBLE || result_type == P_LONG) {
1089 if (type1_p == P_DOUBLE || type1_p == P_LONG)
1090 bytecode.addOpcode(DUP2_X2);
1091 else
1092 bytecode.addOpcode(DUP2_X1);
1093
1094 bytecode.addOpcode(POP2);
1095 bytecode.addOpcode(op);
1096 bytecode.addOpcode(DUP2_X2);
1097 bytecode.addOpcode(POP2);
1098 } else if (result_type == P_FLOAT) {
1099 if (type1_p == P_LONG) {
1100 bytecode.addOpcode(DUP_X2);
1101 bytecode.addOpcode(POP);
1102 } else
1103 bytecode.addOpcode(SWAP);
1104
1105 bytecode.addOpcode(op);
1106 bytecode.addOpcode(SWAP);
1107 } else
1108 fatal();
1109 } else if (op != NOP)
1110 bytecode.addOpcode(op);
1111 }
1112
1113 public void atCastExpr(CastExpr expr) throws CompileError {
1114 String cname = resolveClassName(expr.getClassName());
1115 String toClass = checkCastExpr(expr, cname);
1116 int srcType = exprType;
1117 exprType = expr.getType();
1118 arrayDim = expr.getArrayDim();
1119 className = cname;
1120 if (toClass == null)
1121 atNumCastExpr(srcType, exprType); // built-in type
1122 else
1123 bytecode.addCheckcast(toClass);
1124 }
1125
1126 public void atInstanceOfExpr(InstanceOfExpr expr) throws CompileError {
1127 String cname = resolveClassName(expr.getClassName());
1128 String toClass = checkCastExpr(expr, cname);
1129 bytecode.addInstanceof(toClass);
1130 exprType = BOOLEAN;
1131 arrayDim = 0;
1132 }
1133
1134 private String checkCastExpr(CastExpr expr, String name)
1135 throws CompileError {
1136 final String msg = "invalid cast";
1137 ASTree oprand = expr.getOprand();
1138 int dim = expr.getArrayDim();
1139 int type = expr.getType();
1140 oprand.accept(this);
1141 int srcType = exprType;
1142 if (invalidDim(srcType, arrayDim, className, type, dim, name, true)
1143 || srcType == VOID || type == VOID)
1144 throw new CompileError(msg);
1145
1146 if (type == CLASS) {
1147 if (!isRefType(srcType))
1148 throw new CompileError(msg);
1149
1150 return toJvmArrayName(name, dim);
1151 } else if (dim > 0)
1152 return toJvmTypeName(type, dim);
1153 else
1154 return null; // built-in type
1155 }
1156
1157 void atNumCastExpr(int srcType, int destType)
1158 throws CompileError {
1159 if (srcType == destType)
1160 return;
1161
1162 int op, op2;
1163 int stype = typePrecedence(srcType);
1164 int dtype = typePrecedence(destType);
1165 if (0 <= stype && stype < 3)
1166 op = castOp[stype * 4 + dtype];
1167 else
1168 op = NOP;
1169
1170 if (destType == DOUBLE)
1171 op2 = I2D;
1172 else if (destType == FLOAT)
1173 op2 = I2F;
1174 else if (destType == LONG)
1175 op2 = I2L;
1176 else if (destType == SHORT)
1177 op2 = I2S;
1178 else if (destType == CHAR)
1179 op2 = I2C;
1180 else if (destType == BYTE)
1181 op2 = I2B;
1182 else
1183 op2 = NOP;
1184
1185 if (op != NOP)
1186 bytecode.addOpcode(op);
1187
1188 if (op == NOP || op == L2I || op == F2I || op == D2I)
1189 if (op2 != NOP)
1190 bytecode.addOpcode(op2);
1191 }
1192
1193 public void atExpr(Expr expr) throws CompileError {
1194 // method call, array access, member access,
1195 // (unary) +, (unary) -, ++, --, !, ~
1196
1197 int token = expr.getOperator();
1198 ASTree oprand = expr.oprand1();
1199 if (token == CALL) // method call
1200 atMethodCall(expr);
1201 else if (token == '.')
1202 if (((Symbol) expr.oprand2()).get().equals("length"))
1203 atArrayLength(expr);
1204 else
1205 atFieldRead(expr);
1206 else if (token == MEMBER) { // field read
1207 if (!atClassObject(expr)) // .class
1208 atFieldRead(expr);
1209 } else if (token == ARRAY)
1210 atArrayRead(oprand, expr.oprand2());
1211 else if (token == PLUSPLUS || token == MINUSMINUS)
1212 atPlusPlus(token, oprand, expr, true);
1213 else if (token == '!') {
1214 booleanExpr(false, expr);
1215 bytecode.addIndex(7);
1216 bytecode.addIconst(1);
1217 bytecode.addOpcode(Opcode.GOTO);
1218 bytecode.addIndex(4);
1219 bytecode.addIconst(0);
1220 } else {
1221 expr.oprand1().accept(this);
1222 int type = typePrecedence(exprType);
1223 if (arrayDim > 0)
1224 badType(expr);
1225
1226 if (token == '-') {
1227 if (type == P_DOUBLE)
1228 bytecode.addOpcode(DNEG);
1229 else if (type == P_FLOAT)
1230 bytecode.addOpcode(FNEG);
1231 else if (type == P_LONG)
1232 bytecode.addOpcode(LNEG);
1233 else if (type == P_INT) {
1234 bytecode.addOpcode(INEG);
1235 exprType = INT; // type may be BYTE, ...
1236 } else
1237 badType(expr);
1238 } else if (token == '~') {
1239 if (type == P_INT) {
1240 bytecode.addIconst(-1);
1241 bytecode.addOpcode(IXOR);
1242 exprType = INT; // type may be BYTE. ...
1243 } else if (type == P_LONG) {
1244 bytecode.addLconst(-1);
1245 bytecode.addOpcode(LXOR);
1246 } else
1247 badType(expr);
1248
1249 } else if (token == '+') {
1250 if (type == P_OTHER)
1251 badType(expr);
1252
1253 // do nothing. ignore.
1254 } else
1255 fatal();
1256 }
1257 }
1258
1259 protected static void badType(Expr expr) throws CompileError {
1260 throw new CompileError("invalid type for " + expr.getName());
1261 }
1262
1263 protected abstract void atMethodCall(Expr expr) throws CompileError;
1264
1265 protected abstract void atFieldRead(ASTree expr) throws CompileError;
1266
1267 public boolean atClassObject(Expr expr) throws CompileError {
1268 if (!((Symbol) expr.oprand2()).get().equals("class"))
1269 return false;
1270
1271 if (resolveClassName((ASTList) expr.oprand1()) == null)
1272 return false;
1273
1274 throw new CompileError(".class is not supported");
1275 }
1276
1277 public void atArrayLength(Expr expr) throws CompileError {
1278 expr.oprand1().accept(this);
1279 if (arrayDim == 0)
1280 throw new CompileError(".length applied to a non array");
1281
1282 bytecode.addOpcode(ARRAYLENGTH);
1283 exprType = INT;
1284 arrayDim = 0;
1285 }
1286
1287 public void atArrayRead(ASTree array, ASTree index)
1288 throws CompileError {
1289 int op;
1290 arrayAccess(array, index);
1291 bytecode.addOpcode(getArrayReadOp(exprType, arrayDim));
1292 }
1293
1294 protected void arrayAccess(ASTree array, ASTree index)
1295 throws CompileError {
1296 array.accept(this);
1297 int type = exprType;
1298 int dim = arrayDim;
1299 if (dim == 0)
1300 throw new CompileError("bad array access");
1301
1302 String cname = className;
1303
1304 index.accept(this);
1305 if (typePrecedence(exprType) != P_INT || arrayDim > 0)
1306 throw new CompileError("bad array index");
1307
1308 exprType = type;
1309 arrayDim = dim - 1;
1310 className = cname;
1311 }
1312
1313 protected static int getArrayReadOp(int type, int dim) {
1314 int op;
1315 if (dim > 0)
1316 return AALOAD;
1317
1318 switch (type) {
1319 case DOUBLE:
1320 return DALOAD;
1321 case FLOAT:
1322 return FALOAD;
1323 case LONG:
1324 return LALOAD;
1325 case INT:
1326 return IALOAD;
1327 case SHORT:
1328 return SALOAD;
1329 case CHAR:
1330 return CALOAD;
1331 case BYTE:
1332 case BOOLEAN:
1333 return BALOAD;
1334 default :
1335 return AALOAD;
1336 }
1337 }
1338
1339 protected static int getArrayWriteOp(int type, int dim) {
1340 int op;
1341 if (dim > 0)
1342 return AASTORE;
1343
1344 switch (type) {
1345 case DOUBLE:
1346 return DASTORE;
1347 case FLOAT:
1348 return FASTORE;
1349 case LONG:
1350 return LASTORE;
1351 case INT:
1352 return IASTORE;
1353 case CHAR:
1354 return CASTORE;
1355 case BYTE:
1356 case BOOLEAN:
1357 return BASTORE;
1358 default :
1359 return AASTORE;
1360 }
1361 }
1362
1363 private void atPlusPlus(int token, ASTree oprand, Expr expr,
1364 boolean doDup) throws CompileError {
1365 boolean isPost = oprand == null; // ++i or i++?
1366 if (isPost)
1367 oprand = expr.oprand2();
1368
1369 if (oprand instanceof Variable) {
1370 Declarator d = ((Variable) oprand).getDeclarator();
1371 int t = exprType = d.getType();
1372 arrayDim = d.getArrayDim();
1373 int var = getLocalVar(d);
1374 if (arrayDim > 0)
1375 badType(expr);
1376
1377 if (t == DOUBLE) {
1378 bytecode.addDload(var);
1379 if (doDup && isPost)
1380 bytecode.addOpcode(DUP2);
1381
1382 bytecode.addDconst(1.0);
1383 bytecode.addOpcode(token == PLUSPLUS ? DADD : DSUB);
1384 if (doDup && !isPost)
1385 bytecode.addOpcode(DUP2);
1386
1387 bytecode.addDstore(var);
1388 } else if (t == LONG) {
1389 bytecode.addLload(var);
1390 if (doDup && isPost)
1391 bytecode.addOpcode(DUP2);
1392
1393 bytecode.addLconst((long) 1);
1394 bytecode.addOpcode(token == PLUSPLUS ? LADD : LSUB);
1395 if (doDup && !isPost)
1396 bytecode.addOpcode(DUP2);
1397
1398 bytecode.addLstore(var);
1399 } else if (t == FLOAT) {
1400 bytecode.addFload(var);
1401 if (doDup && isPost)
1402 bytecode.addOpcode(DUP);
1403
1404 bytecode.addFconst(1.0f);
1405 bytecode.addOpcode(token == PLUSPLUS ? FADD : FSUB);
1406 if (doDup && !isPost)
1407 bytecode.addOpcode(DUP);
1408
1409 bytecode.addFstore(var);
1410 } else if (t == BYTE || t == CHAR || t == SHORT || t == INT) {
1411 if (doDup && isPost)
1412 bytecode.addIload(var);
1413
1414 bytecode.addOpcode(IINC);
1415 bytecode.add(var);
1416 bytecode.add(token == PLUSPLUS ? 1 : -1);
1417
1418 if (doDup && !isPost)
1419 bytecode.addIload(var);
1420 } else
1421 badType(expr);
1422 } else {
1423 if (oprand instanceof Expr) {
1424 Expr e = (Expr) oprand;
1425 if (e.getOperator() == ARRAY) {
1426 atArrayPlusPlus(token, isPost, e, doDup);
1427 return;
1428 }
1429 }
1430
1431 atFieldPlusPlus(token, isPost, oprand, expr, doDup);
1432 }
1433 }
1434
1435 public void atArrayPlusPlus(int token, boolean isPost,
1436 Expr expr, boolean doDup) throws CompileError {
1437 arrayAccess(expr.oprand1(), expr.oprand2());
1438 int t = exprType;
1439 int dim = arrayDim;
1440 if (dim > 0)
1441 badType(expr);
1442
1443 bytecode.addOpcode(DUP2);
1444 bytecode.addOpcode(getArrayReadOp(t, arrayDim));
1445 int dup_code = is2word(t, dim) ? DUP2_X2 : DUP_X2;
1446 atPlusPlusCore(dup_code, doDup, token, isPost, expr);
1447 bytecode.addOpcode(getArrayWriteOp(t, dim));
1448 }
1449
1450 protected void atPlusPlusCore(int dup_code, boolean doDup,
1451 int token, boolean isPost,
1452 Expr expr) throws CompileError {
1453 int t = exprType;
1454
1455 if (doDup && isPost)
1456 bytecode.addOpcode(dup_code);
1457
1458 if (t == INT || t == BYTE || t == CHAR || t == SHORT) {
1459 bytecode.addIconst(1);
1460 bytecode.addOpcode(token == PLUSPLUS ? IADD : ISUB);
1461 exprType = INT;
1462 } else if (t == LONG) {
1463 bytecode.addLconst((long) 1);
1464 bytecode.addOpcode(token == PLUSPLUS ? LADD : LSUB);
1465 } else if (t == FLOAT) {
1466 bytecode.addFconst(1.0f);
1467 bytecode.addOpcode(token == PLUSPLUS ? FADD : FSUB);
1468 } else if (t == DOUBLE) {
1469 bytecode.addDconst(1.0);
1470 bytecode.addOpcode(token == PLUSPLUS ? DADD : DSUB);
1471 } else
1472 badType(expr);
1473
1474 if (doDup && !isPost)
1475 bytecode.addOpcode(dup_code);
1476 }
1477
1478 protected abstract void atFieldPlusPlus(int token, boolean isPost,
1479 ASTree oprand, Expr expr, boolean doDup) throws CompileError;
1480
1481 public abstract void atMember(Member n) throws CompileError;
1482
1483 public void atVariable(Variable v) throws CompileError {
1484 Declarator d = v.getDeclarator();
1485 exprType = d.getType();
1486 arrayDim = d.getArrayDim();
1487 className = d.getClassName();
1488 int var = getLocalVar(d);
1489
1490 if (arrayDim > 0)
1491 bytecode.addAload(var);
1492 else
1493 switch (exprType) {
1494 case CLASS:
1495 bytecode.addAload(var);
1496 break;
1497 case LONG:
1498 bytecode.addLload(var);
1499 break;
1500 case FLOAT:
1501 bytecode.addFload(var);
1502 break;
1503 case DOUBLE:
1504 bytecode.addDload(var);
1505 break;
1506 default : // BOOLEAN, BYTE, CHAR, SHORT, INT
1507 bytecode.addIload(var);
1508 break;
1509 }
1510 }
1511
1512 public void atKeyword(Keyword k) throws CompileError {
1513 arrayDim = 0;
1514 int token = k.get();
1515 switch (token) {
1516 case TRUE:
1517 bytecode.addIconst(1);
1518 exprType = BOOLEAN;
1519 break;
1520 case FALSE:
1521 bytecode.addIconst(0);
1522 exprType = BOOLEAN;
1523 break;
1524 case NULL:
1525 bytecode.addOpcode(ACONST_NULL);
1526 exprType = NULL;
1527 break;
1528 case THIS:
1529 case SUPER:
1530 if (inStaticMethod)
1531 throw new CompileError("not-available: "
1532 + (token == THIS ? "this" : "super"));
1533
1534 bytecode.addAload(0);
1535 exprType = CLASS;
1536 if (token == THIS)
1537 className = getThisName();
1538 else
1539 className = getSuperName();
1540 break;
1541 default :
1542 fatal();
1543 }
1544 }
1545
1546 public void atStringL(StringL s) throws CompileError {
1547 exprType = CLASS;
1548 arrayDim = 0;
1549 className = "java/lang/String";
1550 bytecode.addLdc(s.get());
1551 }
1552
1553 public void atIntConst(IntConst i) throws CompileError {
1554 arrayDim = 0;
1555 long value = i.get();
1556 int type = i.getType();
1557 if (type == IntConstant || type == CharConstant) {
1558 exprType = (type == IntConstant ? INT : CHAR);
1559 bytecode.addIconst((int) value);
1560 } else {
1561 exprType = LONG;
1562 bytecode.addLconst(value);
1563 }
1564 }
1565
1566 public void atDoubleConst(DoubleConst d) throws CompileError {
1567 arrayDim = 0;
1568 if (d.getType() == DoubleConstant) {
1569 exprType = DOUBLE;
1570 bytecode.addDconst(d.get());
1571 } else {
1572 exprType = FLOAT;
1573 bytecode.addFconst((float) d.get());
1574 }
1575 }
1576 }
1577