diff --git a/ast.h b/ast.h index 15e53d6..caeb187 100644 --- a/ast.h +++ b/ast.h @@ -190,10 +190,10 @@ class Call : public Expr { class Index : public Expr { Expr* base; - Expr* idx; + std::vector idxs; public: - Index(Expr* base, Expr* idx) : base(base), idx(idx){}; + Index(Expr* base, std::vector idxs) : base(base), idxs(idxs){}; operator std::string() override { return "index " + std::string(*base); }; bool isLval() const override { return true; } diff --git a/parser.cc b/parser.cc index e9c5729..6d30996 100644 --- a/parser.cc +++ b/parser.cc @@ -273,16 +273,30 @@ TypedVar Parser::typedVar() { Token id = consume(IDENTIFIER, "Expect an identifer for variable"); Type type = {base}; - if (match(1, LEFT_SQUARE)) { + while (match(1, LEFT_SQUARE)) { // parse array type advance(); auto num = consume(NUMBER, "Expect a number literal for array size"); + + int dim = 0; std::stringstream ss(num.lexeme); - ss >> type.arraySize; + ss >> dim; + if (dim <= 0) { + std::cerr << "Invalid size of array at line " << num.line << std::endl; + exit(-1); + } + + type.dims.push_back(dim); + type.isArray = true; consume(RIGHT_SQUARE, "Expect `]` affter array size"); } + if (type.isArray) { + type.arraySize = 1; + for (auto x : type.dims) type.arraySize *= x; + } + return {type, id}; } @@ -465,12 +479,13 @@ Expr* Parser::call() { Expr* Parser::index() { Expr* e = primary(); - if (match(1, LEFT_SQUARE)) { + std::vector idxs; + while (match(1, LEFT_SQUARE)) { advance(); - auto i = expression(); - e = new Index(e, i); + idxs.push_back(expression()); consume(RIGHT_SQUARE, "Expect `]` after indexing"); } + if (!idxs.empty()) e = new Index(e, idxs); return e; } diff --git a/parser.h b/parser.h index f4740f0..5ca88e6 100644 --- a/parser.h +++ b/parser.h @@ -29,7 +29,7 @@ class Parser { BlockStmt* forStmt(); // FOR '(' VAR_DECL EXPRESSION; EXPRESSION ')' STMT WhileStmt* whileStmt(); // WHILE '(' EXPRESSION ')' STMT ReturnStmt* returnStmt(); // RETURN EXPR; - TypedVar typedVar(); // (INT | DOUBLE | CHAR) '*'? ID ('['SIZE']')? + TypedVar typedVar(); // (INT | DOUBLE | CHAR) '*'? ID ('['SIZE']')* VarDecl* varDecl(Type type, Token id); // TYPEDVAR // (EQUAL EXPRESSION)? ; FunDecl* funDecl(Type type, diff --git a/tests/types/2darray b/tests/types/2darray new file mode 100644 index 0000000..3046489 --- /dev/null +++ b/tests/types/2darray @@ -0,0 +1,34 @@ +int putchar(int c); +void printInt(int x) { + if (!x) { + putchar('0'); + return; + } + int a[10]; + int sz = 0; + while (x) { + a[sz] = x%10; + sz++; + x = x/10; + } + for (int i = sz-1; i >= 0; i--) { + putchar(a[i] + '0'); + } + return; +} +int main() { + int a[3][3]; + int c = 0; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) { + a[i][j] = c++; + } + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + printInt(a[i][j]); + putchar(' '); + } + putchar('\n'); + } + return 0; +} diff --git a/tests/types/3darray b/tests/types/3darray new file mode 100644 index 0000000..888653c --- /dev/null +++ b/tests/types/3darray @@ -0,0 +1,35 @@ +int putchar(int c); +void printInt(int x) { + if (!x) { + putchar('0'); + return; + } + int a[10]; + int sz = 0; + while (x) { + a[sz] = x%10; + sz++; + x = x/10; + } + for (int i = sz-1; i >= 0; i--) { + putchar(a[i] + '0'); + } + return; +} +int main() { + int a[3][3][3]; + int c = 0; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 3; k++) { + a[i][j][k] = c++; + } + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) for (int k = 0; k < 3; k++) { + printInt(a[i][j][k]); + putchar(' '); + } + putchar('\n'); + } + return 0; +} diff --git a/type.h b/type.h index 182f56a..15464f9 100644 --- a/type.h +++ b/type.h @@ -1,11 +1,13 @@ #pragma once #include +#include #include "token.h" struct Type { enum class Base { VOID, INT, DOUBLE, CHAR, ARRAY, BOOL, FUNCTION } base; int arraySize; + std::vector dims; bool isArray; bool isPointer; bool operator==(const Type& rhs) const { diff --git a/visitor.cc b/visitor.cc index 2d6cee2..15afaeb 100644 --- a/visitor.cc +++ b/visitor.cc @@ -247,15 +247,28 @@ void CodeGenExprVisitor::visit(Variable* expr) { addr = r.addr; value = l.builder->CreateLoad(l.getType(r.type), r.addr, r.id.c_str()); } + type = r.type; } void CodeGenExprVisitor::visit(Index* expr) { CodeGenExprVisitor ev(scope, l); ev.visit(expr->base); + Type type = ev.getType(); CodeGenExprVisitor ev2(scope, l); - ev2.visit(expr->idx); - auto idx = ev2.getValue(); + llvm::Value* offset = + llvm::Constant::getIntegerValue(l.getInt(), llvm::APInt(32, 0)); + if (expr->idxs.size() != type.dims.size()) abortMsg("invalid array index"); + for (size_t i = 0; i < expr->idxs.size(); i++) { + int factor = 1; + for (size_t j = i + 1; j < type.dims.size(); j++) factor *= type.dims[j]; + + ev2.visit(expr->idxs[i]); + auto factorValue = + llvm::Constant::getIntegerValue(l.getInt(), llvm::APInt(32, factor)); + auto part_offset = l.builder->CreateMul(ev2.getValue(), factorValue); + offset = l.builder->CreateAdd(offset, part_offset); + } auto base = ev.getValue(); - auto ptr = l.builder->CreateGEP(base, idx); + auto ptr = l.builder->CreateGEP(base, offset); value = l.builder->CreateLoad(ptr); addr = static_cast(ptr); } diff --git a/visitor.h b/visitor.h index 19633ce..4aa1b33 100644 --- a/visitor.h +++ b/visitor.h @@ -69,6 +69,8 @@ class CodeGenExprVisitor : public ExprVisitor { llvmWrapper l; llvm::Value* value = nullptr; llvm::AllocaInst* addr = nullptr; + Type type; // only used for array. other type information is passed by + // llvm::Value* public: CodeGenExprVisitor(Scope scope, llvmWrapper l) : scope(scope), l(l){}; @@ -86,6 +88,8 @@ class CodeGenExprVisitor : public ExprVisitor { void visit(Call* expr) override; void visit(Index* expr) override; + Type getType() { return type; } + void setType(Type t) { type = t; } void setValue(llvm::Value* v) { value = v; } void setAddr(llvm::AllocaInst* a) { addr = a; } void setTuple(llvm::Value* v, llvm::AllocaInst* a = nullptr) {