* net/loveruby/cflat/compiler/TypeChecker.java: transform pointer arithmetic to normal arithmetic (e.g. ptr+7 => ptr+(7*sizeof(*ptr))).

* net/loveruby/cflat/compiler/TypeChecker.java: int-ptr is invalid.
* net/loveruby/cflat/compiler/CodeGenerator.java: implement pointer arithmetic correctly (e.g. *(ptr+1) for various types work now).
* net/loveruby/cflat/ast/PrefixOpNode.java: inherit UnaryArithmeticOpNode.
* net/loveruby/cflat/ast/SuffixOpNode.java: ditto.
* net/loveruby/cflat/ast/UnaryArithmeticOpNode.java: new file.
* net/loveruby/cflat/ast/CastNode.java: is not assignable.
* net/loveruby/cflat/type/TypeTable.java: new method #pointerSize, #ptrDiffTypeRef.
* net/loveruby/cflat/type/ArrayType.java: fetch pointer size from a TypeTable.
* net/loveruby/cflat/type/ArrayType.java: we can cast any pointers to void*.
* net/loveruby/cflat/type/PointerType.java: ditto.
* net/loveruby/cflat/type/IntegerTypeRef.java (equals): check name equality by #equals, not ==.
* test: test pointer arithmetic.
* test: CastNode does not becomes LHS, do not check it.
* import/string.hb: add mem* functions.


git-svn-id: file:///Users/aamine/c/gitwork/public/cbc/trunk@3979 1b9489fe-b721-0410-924e-b54b9192deb8
This commit is contained in:
Minero Aoki 2008-08-31 10:24:40 +00:00
parent 0229e05728
commit eca722f362
16 changed files with 243 additions and 97 deletions

View File

@ -1,3 +1,45 @@
Sun Aug 31 19:24:30 2008 Minero Aoki <aamine@loveruby.net>
* net/loveruby/cflat/compiler/TypeChecker.java: transform pointer
arithmetic to normal arithmetic (e.g. ptr+7 =>
ptr+(7*sizeof(*ptr))).
* net/loveruby/cflat/compiler/TypeChecker.java: int-ptr is
invalid.
* net/loveruby/cflat/compiler/CodeGenerator.java: implement
pointer arithmetic correctly (e.g. *(ptr+1) for various types work
now).
* net/loveruby/cflat/ast/PrefixOpNode.java: inherit
UnaryArithmeticOpNode.
* net/loveruby/cflat/ast/SuffixOpNode.java: ditto.
* net/loveruby/cflat/ast/UnaryArithmeticOpNode.java: new file.
* net/loveruby/cflat/ast/CastNode.java: is not assignable.
* net/loveruby/cflat/type/TypeTable.java: new method #pointerSize,
#ptrDiffTypeRef.
* net/loveruby/cflat/type/ArrayType.java: fetch pointer size from
a TypeTable.
* net/loveruby/cflat/type/ArrayType.java: we can cast any pointers
to void*.
* net/loveruby/cflat/type/PointerType.java: ditto.
* net/loveruby/cflat/type/IntegerTypeRef.java (equals): check name
equality by #equals, not ==.
* test: test pointer arithmetic.
* test: CastNode does not becomes LHS, do not check it.
* import/string.hb: add mem* functions.
Sun Aug 31 15:17:05 2008 Minero Aoki <aamine@loveruby.net>
* net/loveruby/cflat/ast/Declarations.java: reject duplicated

View File

@ -16,4 +16,7 @@ extern char* strstr(char* str, char* pattern);
extern size_t strspn(char* str, char* accept);
extern size_t strcspn(char* str, char* reject);
extern char* strerror(int errnum);
extern char* strerror_r(int errnum, char* buf, size_t size);
extern char* strerror_r(int errnum, char* buf, size_t len);
extern void* memcpy(void* dest, void* src, size_t len);
extern void* memccpy(void* dest, void* src, int c, size_t len);
extern void* memmove(void* dest, void* src, size_t len);

View File

@ -35,10 +35,6 @@ public class CastNode extends ExprNode {
return expr.isConstant();
}
public boolean isAssignable() {
return expr.isAssignable();
}
public boolean isConstantAddress() {
return expr.isConstantAddress();
}

View File

@ -1,6 +1,6 @@
package net.loveruby.cflat.ast;
public class PrefixOpNode extends UnaryOpNode {
public class PrefixOpNode extends UnaryArithmeticOpNode {
public PrefixOpNode(String op, ExprNode expr) {
super(op, expr);
}

View File

@ -1,6 +1,6 @@
package net.loveruby.cflat.ast;
public class SuffixOpNode extends UnaryOpNode {
public class SuffixOpNode extends UnaryArithmeticOpNode {
public SuffixOpNode(String op, ExprNode expr) {
super(op, expr);
}

View File

@ -0,0 +1,18 @@
package net.loveruby.cflat.ast;
public class UnaryArithmeticOpNode extends UnaryOpNode {
protected long amount;
public UnaryArithmeticOpNode(String op, ExprNode expr) {
super(op, expr);
amount = 1;
}
public long amount() {
return this.amount;
}
public void setAmount(long amount) {
this.amount = amount;
}
}

View File

@ -643,34 +643,38 @@ static public void p(String s) { System.err.println(s); }
}
public void visit(PrefixOpNode node) {
compileIncDec(node.operator(), node.expr());
load(node.expr().type(), node.expr().address(), reg("ax"));
AsmEntity dest = compileLHS2(node.expr());
load(node.expr().type(), dest, reg("ax"));
compileUnaryArithmetic(node, reg("ax"));
save(node.expr().type(), reg("ax"), dest);
}
public void visit(SuffixOpNode node) {
load(node.expr().type(), node.expr().address(), reg("ax"));
compileIncDec(node.operator(), node.expr());
AsmEntity dest = compileLHS2(node.expr());
load(node.expr().type(), dest, reg("ax"));
compileUnaryArithmetic(node, dest);
}
protected void compileIncDec(String op, ExprNode e) {
if (op.equals("++")) {
if (e.type().isInteger()) {
inc(e.type(), e.address());
}
else {
add(imm(e.type().size()), e.address());
}
}
else if (op.equals("--")) {
if (e.type().isInteger()) {
dec(e.type(), e.address());
}
else {
sub(imm(e.type().size()), e.address());
}
protected AsmEntity compileLHS2(ExprNode expr) {
if (expr.isConstantAddress()) {
return expr.address();
}
else {
throw new Error("unknown unary operator: " + op);
compileLHS(expr);
return baseptr();
}
}
protected void compileUnaryArithmetic(UnaryArithmeticOpNode node,
AsmEntity dest) {
if (node.operator().equals("++")) {
add(imm(node.amount()), dest);
}
else if (node.operator().equals("--")) {
sub(imm(node.amount()), dest);
}
else {
throw new Error("unknown unary operator: " + node.operator());
}
}
@ -722,7 +726,6 @@ static public void p(String s) { System.err.println(s); }
save(node.type(), reg("ax"), node.lhs().address());
}
// FIXME: use -4(%edx,%esi,4) addressing
public void visit(ArefNode node) {
if (node.expr().type().isPointerAlike()) {
compile(node.expr());
@ -767,9 +770,8 @@ static public void p(String s) { System.err.println(s); }
}
protected void compileLHS(Node node) {
comment("compileLHS: " + node.getClass().getName() + " {");
comment("compileLHS: " + node.getClass().getSimpleName() + " {");
if (node instanceof VariableNode) {
// FIXME: support static variables
VariableNode n = (VariableNode)node;
lea(n.address(), baseptr());
}
@ -810,33 +812,6 @@ comment("compileLHS: " + node.getClass().getName() + " {");
mov(reg("ax"), baseptr());
pop(reg("ax"));
}
else if (node instanceof PrefixOpNode) {
PrefixOpNode n = (PrefixOpNode)node;
compileLHS(n.expr());
if (n.operator().equals("++")) {
add(imm(n.expr().type().size()), mem(baseptr()));
add(imm(n.expr().type().size()), baseptr());
}
else {
sub(imm(n.expr().type().size()), mem(baseptr()));
sub(imm(n.expr().type().size()), baseptr());
}
}
else if (node instanceof SuffixOpNode) {
SuffixOpNode n = (SuffixOpNode)node;
compileLHS(n.expr());
if (n.operator().equals("++")) {
add(imm(n.expr().type().size()), baseptr());
}
else {
sub(imm(n.expr().type().size()), baseptr());
}
}
else if (node instanceof CastNode) {
CastNode n = (CastNode)node;
compileLHS(n.expr());
// FIXME: cast here
}
else {
throw new Error("wrong type for compileLHS: " + node.getClass().getName());
}

View File

@ -152,10 +152,7 @@ class TypeChecker extends Visitor {
|| node.operator().equals("-")) {
if (node.lhs().type().isPointer()) {
if (! mustBeInteger(node.rhs(), node.operator())) return;
Type t = integralPromotion(node.rhs().type());
if (! t.isSameType(node.rhs().type())) {
node.setRHS(new CastNode(t, node.rhs()));
}
node.setRHS(multiplyPtrBaseSize(node.rhs(), node.lhs()));
return;
}
}
@ -276,14 +273,30 @@ class TypeChecker extends Visitor {
* * integer + integer
* * pointer + integer
* * integer + pointer
* * integer - integer
* * pointer - integer
*/
protected Type expectsSameIntegerOrPointerDiff(BinaryOpNode node) {
if (node.left().type().isPointer()) {
if (node.left().type().isDereferable()) {
if (node.left().type().baseType().isVoid()) {
wrongTypeError(node.left(), node.operator());
return null;
}
mustBeInteger(node.right(), node.operator());
node.setRight(multiplyPtrBaseSize(node.right(), node.left()));
return node.left().type();
}
else if (node.right().type().isPointer()) {
else if (node.right().type().isDereferable()) {
if (node.operator().equals("-")) {
error(node, "invalid operation integer-pointer");
return null;
}
if (node.right().type().baseType().isVoid()) {
wrongTypeError(node.right(), node.operator());
return null;
}
mustBeInteger(node.left(), node.operator());
node.setLeft(multiplyPtrBaseSize(node.left(), node.right()));
return node.right().type();
}
else {
@ -291,6 +304,36 @@ class TypeChecker extends Visitor {
}
}
protected BinaryOpNode multiplyPtrBaseSize(ExprNode expr, ExprNode ptr) {
return new BinaryOpNode(integralPromotedExpr(expr), "*", ptrBaseSize(ptr));
}
protected ExprNode integralPromotedExpr(ExprNode expr) {
Type t = integralPromotion(expr.type());
if (t.isSameType(expr.type())) {
return expr;
}
else {
return new CastNode(t, expr);
}
}
protected IntegerLiteralNode ptrBaseSize(ExprNode ptr) {
return integerLiteral(ptr.location(),
typeTable.ptrDiffTypeRef(),
ptr.type().baseType().size());
}
protected IntegerLiteralNode integerLiteral(Location loc, TypeRef ref, long n) {
IntegerLiteralNode node = new IntegerLiteralNode(loc, ref, n);
bindType(node.typeNode());
return node;
}
protected void bindType(TypeNode t) {
t.setType(typeTable.get(t.typeRef()));
}
// +, -, *, /, %, &, |, ^, <<, >>
// #@@range/expectsSameInteger{
protected Type expectsSameInteger(BinaryOpNode node) {
@ -304,12 +347,12 @@ class TypeChecker extends Visitor {
protected Type expectsComparableScalars(BinaryOpNode node) {
if (! mustBeScalar(node.left(), node.operator())) return null;
if (! mustBeScalar(node.right(), node.operator())) return null;
if (node.left().type().isPointer()) {
if (node.left().type().isDereferable()) {
ExprNode right = forcePointerType(node.left(), node.right());
node.setRight(right);
return node.left().type();
}
if (node.right().type().isPointer()) {
if (node.right().type().isDereferable()) {
ExprNode left = forcePointerType(node.right(), node.left());
node.setLeft(left);
return node.right().type();
@ -371,7 +414,7 @@ class TypeChecker extends Visitor {
expectsScalarLHS(node);
}
protected void expectsScalarLHS(UnaryOpNode node) {
protected void expectsScalarLHS(UnaryArithmeticOpNode node) {
if (node.expr().isParameter()) {
// parameter is always a scalar.
}
@ -388,6 +431,18 @@ class TypeChecker extends Visitor {
if (! node.expr().type().isSameType(opType)) {
node.setOpType(opType);
}
node.setAmount(1);
}
else if (node.expr().type().isDereferable()) {
if (node.expr().type().baseType().isVoid()) {
// We cannot increment/decrement void*
wrongTypeError(node.expr(), node.operator());
return;
}
node.setAmount(node.expr().type().baseType().size());
}
else {
throw new Error("must not happen");
}
}

View File

@ -3,16 +3,17 @@ package net.loveruby.cflat.type;
public class ArrayType extends Type {
protected Type baseType;
protected long length;
protected long pointerSize;
static final protected long undefined = -1;
public ArrayType(Type baseType) {
this.baseType = baseType;
length = undefined;
public ArrayType(Type baseType, long pointerSize) {
this(baseType, undefined, pointerSize);
}
public ArrayType(Type baseType, long length) {
public ArrayType(Type baseType, long length, long pointerSize) {
this.baseType = baseType;
this.length = length;
this.pointerSize = pointerSize;
}
public boolean isArray() { return true; }
@ -32,7 +33,7 @@ public class ArrayType extends Type {
}
public long size() {
return 4; // FIXME: get from TypeTable
return pointerSize;
}
public long allocSize() {
@ -59,6 +60,9 @@ public class ArrayType extends Type {
public boolean isCompatible(Type target) {
if (! target.isDereferable()) return false;
if (target.baseType().isVoid()) {
return true;
}
return baseType.isCompatible(target.baseType())
&& baseType.size() == target.baseType().size();
}

View File

@ -84,7 +84,7 @@ public class IntegerTypeRef extends TypeRef {
public boolean equals(Object other) {
if (! (other instanceof IntegerTypeRef)) return false;
IntegerTypeRef ref = (IntegerTypeRef)other;
return name == ref.name;
return name.equals(ref.name);
}
public String toString() {

View File

@ -35,7 +35,10 @@ public class PointerType extends Type {
public boolean isCompatible(Type other) {
if (! other.isDereferable()) return false;
if (baseType.isVoid() && ! other.baseType().isPointer()) {
if (baseType.isVoid()) {
return true;
}
if (other.baseType().isVoid()) {
return true;
}
return baseType.isCompatible(other.baseType());

View File

@ -70,7 +70,9 @@ public class TypeTable {
}
else if (ref instanceof ArrayTypeRef) {
ArrayTypeRef aref = (ArrayTypeRef)ref;
Type t = new ArrayType(get(aref.baseType()), aref.length());
Type t = new ArrayType(get(aref.baseType()),
aref.length(),
pointerSize);
table.put(aref, t);
return t;
}
@ -86,6 +88,22 @@ public class TypeTable {
return type;
}
public long pointerSize() {
return this.pointerSize;
}
// returns a IntegerTypeRef whose size is equals to pointer.
public TypeRef ptrDiffTypeRef() {
return new IntegerTypeRef(ptrDiffTypeName());
}
protected String ptrDiffTypeName() {
if (signedLong().size == pointerSize) return "long";
if (signedInt().size == pointerSize) return "int";
if (signedShort().size == pointerSize) return "short";
throw new Error("must not happen: integer.size != pointer.size");
}
public Iterator types() {
return table.values().iterator();
}

View File

@ -1,4 +1,5 @@
import stdio;
import string;
int global_x = 0;
int common_x;
@ -13,16 +14,22 @@ main(int argc, char **argv)
int x, y;
static int static_x = 0;
static int scomm_x;
int*[1] ptrs;
int*[2] ptrs;
struct s s;
int* ptr;
int[8] integers;
char[8] buf;
char *p = buf;
memcpy(buf, "Hello", 8);
// local variable
x = 1;
y = 1;
printf("%d", x);
x = 77;
y = 77;
x = y = 2;
printf("%d;%d", x, y);
printf(";%d;%d", x, y);
// parameter
argc = 3;
@ -60,6 +67,16 @@ main(int argc, char **argv)
*ptr++ = 11;
printf(";%d;%d", integers[0], integers[1]);
// local array with pointer arighmetic
*(p + 1) = 'S';
printf(";%c", p[1]);
// local array with pointer arighmetic
ptrs[0] = NULL;
ptrs[1] = &x;
**(ptrs + 1) = 12;
printf(";%d", *ptrs[1]);
puts("");
return 0;
}

View File

@ -1,15 +0,0 @@
import stdio;
int
main(int argc, char **argv)
{
int i;
int* ptr = &i;
(int)i = 666;
printf("%d", i);
*(int*)ptr = 777;
printf(";%d", *ptr);
puts("");
return 0;
}

View File

@ -26,7 +26,38 @@ main(int argc, char **argv)
printf(";%d", i); // 1
i <<= 2;
printf(";%d", i); // 4
puts("");
// pointer diff arithmetic (size=1)
{
char *string = "Hello, World!";
char *p;
p = string;
p += 1;
printf(";%c", *p);
p -= 1;
printf(";%c", *p);
}
// pointer diff arithmetic (size=4)
{
int[4] xs;
int* p;
xs[0] = 75;
xs[1] = 76;
xs[2] = 77;
xs[3] = 78;
p = xs;
p += 1;
printf(";%d", *p);
p -= 1;
printf(";%d", *p);
}
puts("");
return 0;
}

View File

@ -92,8 +92,8 @@ test_09_cmp() {
}
test_10_assign() {
assert_out "2;2;3;4;5;6;7;8;8;9;10;11;777;S" ./assign
assert_out "3;4;3;12;4;1;1;7;5;1;4" ./opassign
assert_out "1;2;2;3;4;5;6;7;8;8;9;10;11;777;S;12" ./assign
assert_out "3;4;3;12;4;1;1;7;5;1;4;e;H;76;75" ./opassign
assert_out "0;1;2;2;3;3;4" ./inc
assert_out "4;3;2;2;1;1;0" ./dec
}
@ -207,7 +207,6 @@ test_23_limits() {
test_24_cast() {
assert_out "25000000" ./cast
assert_out "777;666" ./cast2
assert_out "666;777" ./cast3
}
test_25_block() {