Skip to content

Commit ed3e21b

Browse files
committed
Add support for DIM statement
1 parent 683df04 commit ed3e21b

File tree

8 files changed

+167
-28
lines changed

8 files changed

+167
-28
lines changed

ast.cpp

+54
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ std::unique_ptr<ExprAST> StatementAST::parse(const Token& tok, BasicContext* ctx
132132
}
133133
case Token::Let:
134134
return LetAST::parse(tok, ctx);
135+
case Token::Dim:
136+
return DimAST::parse(tok, ctx);
135137
case Token::String: {
136138
const auto& name = tok.strValue;
137139
if (ctx->externFunctions.find(name) != ctx->externFunctions.end()) {
@@ -448,6 +450,56 @@ std::unique_ptr<ExprAST> LetAST::parse(const Token& tok, BasicContext* ctx, bool
448450
return std::make_unique<LetAST>(tok, ctx, name, type, std::move(value), global);
449451
}
450452

453+
std::unique_ptr<ExprAST> DimAST::parse(const Token& tok, BasicContext* ctx) {
454+
Token nameTok = ctx->lexer.lex();
455+
if (nameTok.tag != Token::String && nameTok.tag != Token::Variable) {
456+
throw AssignException(AssignException::NotString);
457+
}
458+
459+
auto nextTok = ctx->lexer.lex();
460+
std::vector<int> dimensions;
461+
VariableType type = Integer;
462+
if (nextTok.tag == Token::LParens) {
463+
nextTok = ctx->lexer.lex();
464+
while (nextTok.tag != Token::RParens) {
465+
if (nextTok.tag == Token::Integer) {
466+
dimensions.push_back(boost::get<int64_t>(nextTok.value));
467+
} else if (nextTok.tag == Token::Comma) {
468+
nextTok = ctx->lexer.lex();
469+
} else {
470+
throw ParseException("Invalid token while parsing dimensions list");
471+
}
472+
nextTok = ctx->lexer.lex();
473+
}
474+
475+
// Consume the RParens
476+
nextTok = ctx->lexer.lex();
477+
}
478+
479+
if (nextTok.tag == Token::As) {
480+
nextTok = ctx->lexer.lex();
481+
switch (nextTok.tag) {
482+
case Token::IntegerType:
483+
type = Integer;
484+
break;
485+
case Token::StringType:
486+
type = String;
487+
break;
488+
case Token::DoubleType:
489+
type = Double;
490+
break;
491+
default:
492+
throw ParseException("Invalid token while parsing variable type");
493+
}
494+
} else {
495+
ctx->lexer.putBack(nextTok);
496+
}
497+
bool global = (ctx->currentFunction == nullptr);
498+
499+
return std::make_unique<DimAST>(
500+
tok, ctx, nameTok.strValue, type, std::move(dimensions), global);
501+
}
502+
451503
std::string lexString(Lexer* lexer) {
452504
auto labelTok = lexer->lex();
453505
std::string gotoName;
@@ -606,6 +658,8 @@ std::unique_ptr<ExprAST> ProtoDefAST::parse(const Token& tok, BasicContext* ctx)
606658
type = Double;
607659
} else if (argTypeTok.tag == Token::StringType) {
608660
type = String;
661+
} else if (argTypeTok.tag == Token::IntegerType) {
662+
type = Integer;
609663
} else {
610664
throw ParseException("Unknown type for argument in extern def");
611665
}

ast.h

+28
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,34 @@ class LetAST : public ExprAST {
256256
llvm::AllocaInst* _alloca;
257257
};
258258

259+
class DimAST : public ExprAST {
260+
public:
261+
DimAST(Token tok,
262+
BasicContext* ctx,
263+
std::string name,
264+
VariableType type,
265+
std::vector<int> dimensions,
266+
bool global)
267+
: ExprAST(std::move(tok), ctx),
268+
_name(std::move(name)),
269+
_type(type),
270+
_dimensions(std::move(dimensions)),
271+
_global(global) {}
272+
273+
llvm::Value* codegen() override;
274+
static std::unique_ptr<ExprAST> parse(const Token& tok, BasicContext* ctx);
275+
276+
llvm::AllocaInst* allocaInst() const;
277+
const std::string& name() const;
278+
279+
private:
280+
std::string _name;
281+
VariableType _type;
282+
std::vector<int> _dimensions;
283+
bool _global;
284+
llvm::AllocaInst* _alloca;
285+
};
286+
259287
class BinaryExprAST : public ExprAST {
260288
public:
261289
BinaryExprAST(Token tok,

cli.cpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,19 @@ Options Options::parseOptions(int argc, char** argv) {
3030
llvm::cl::cat(CompilerCategory),
3131
llvm::cl::init(ObjectCode));
3232

33+
static llvm::cl::opt<bool> verifyModule(
34+
"verify",
35+
llvm::cl::desc("Run verification on module before writing output"),
36+
llvm::cl::cat(CompilerCategory),
37+
llvm::cl::init(true));
38+
3339
llvm::cl::HideUnrelatedOptions(CompilerCategory);
3440

3541
llvm::cl::ParseCommandLineOptions(argc, argv);
3642

37-
3843
return Options{inputFilename.getValue(),
3944
outputFilename.getValue(),
4045
mainFunctionName.getValue(),
41-
outputType.getValue()};
46+
outputType.getValue(),
47+
verifyModule.getValue()};
4248
}

cli.h

+1
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ struct Options {
1212
ObjectCode,
1313
};
1414
OutputType outputType;
15+
bool verifyModule;
1516
static Options parseOptions(int argc, char** argv);
1617
};

codegen.cpp

+61-3
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@ bool BasicContext::codegenAllProtos() {
4444
return true;
4545
}
4646

47-
llvm::Value* makeLiteralDouble(BasicContext* ctx, double val) {
47+
llvm::Constant* makeLiteralDouble(BasicContext* ctx, double val) {
4848
return llvm::ConstantFP::get(ctx->context, llvm::APFloat(val));
4949
}
5050

51-
llvm::Value* makeLiteralInteger(BasicContext* ctx, int64_t val) {
51+
llvm::Constant* makeLiteralInteger(BasicContext* ctx, int64_t val) {
5252
return llvm::ConstantInt::getSigned(ctx->builder.getInt64Ty(), val);
5353
}
5454

@@ -140,6 +140,62 @@ llvm::Value* VariableExprAST::codegen() {
140140
return builder.CreateLoad(it->second, it->first);
141141
}
142142

143+
llvm::Value* DimAST::codegen() {
144+
auto& builder = ctx()->builder;
145+
146+
int numElements = 0;
147+
for (auto dimensions : _dimensions) {
148+
numElements += dimensions + 1;
149+
}
150+
151+
llvm::Constant* initV;
152+
llvm::Type* type = nullptr;
153+
if (_type == Double) {
154+
initV = makeLiteralDouble(ctx(), 0.0);
155+
type = builder.getDoubleTy();
156+
} else if (_type == Integer) {
157+
initV = makeLiteralInteger(ctx(), 0);
158+
type = builder.getInt64Ty();
159+
} else if (_type == String) {
160+
initV = llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(ctx()->context));
161+
type = builder.getInt8PtrTy();
162+
} else {
163+
std::cerr << "Cannot find initial value for variable " << _name << std::endl;
164+
return nullptr;
165+
}
166+
167+
if (numElements > 0) {
168+
type = llvm::ArrayType::get(type, numElements);
169+
initV = llvm::ConstantAggregateZero::get(type);
170+
}
171+
172+
if (_global) {
173+
auto globalPtr = ctx()->module->getOrInsertGlobal(_name, type);
174+
auto global = ctx()->module->getGlobalVariable(_name);
175+
if (!global->hasInitializer()) {
176+
global->setInitializer(initV);
177+
global->setLinkage(llvm::GlobalValue::CommonLinkage);
178+
}
179+
180+
return globalPtr;
181+
}
182+
183+
auto alloc = CreateEntryBlockAlloca(ctx(), _name, type);
184+
185+
_alloca = alloc;
186+
ctx()->namedVariables[_name] = alloc;
187+
188+
return alloc;
189+
}
190+
191+
const std::string& DimAST::name() const {
192+
return _name;
193+
}
194+
195+
llvm::AllocaInst* DimAST::allocaInst() const {
196+
return _alloca;
197+
}
198+
143199
llvm::Value* LetAST::codegen() {
144200
auto& builder = ctx()->builder;
145201

@@ -342,7 +398,9 @@ llvm::Value* GotoAST::codegen() {
342398
return nullptr;
343399
}
344400
builder.CreateBr(static_cast<llvm::BasicBlock*>(labelIt->second.label->value()));
345-
return llvm::ConstantFP::get(builder.getDoubleTy(), 0);
401+
auto newBB = llvm::BasicBlock::Create(ctx()->context, "afterGoto", ctx()->getCurrentFunction());
402+
builder.SetInsertPoint(newBB);
403+
return newBB;
346404
}
347405

348406
llvm::Value* GosubAST::codegen() {

lexer.cpp

+12-22
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,18 @@
1010
using StringToTagMap = std::unordered_map<std::string, Token::Tag>;
1111
const StringToTagMap& stringToTagMap() {
1212
static const StringToTagMap _stringToTag = {
13-
{"AND", Token::And},
14-
{"AS", Token::As},
15-
{"DOUBLE", Token::DoubleType},
16-
{"ELSE", Token::Else},
17-
{"END", Token::End},
18-
{"EXTERN", Token::Extern},
19-
{"FOR", Token::For},
20-
{"FUNCTION", Token::Function},
21-
{"GOSUB", Token::Gosub},
22-
{"GOTO", Token::Goto},
23-
{"IF", Token::If},
24-
{"INPUT", Token::Input},
25-
{"LET", Token::Let},
26-
{"OR", Token::Or},
27-
{"NEXT", Token::Next},
28-
{"PRINT", Token::Print},
29-
{"RETURN", Token::Return},
30-
{"STEP", Token::Step},
31-
{"STRING", Token::StringType},
32-
{"SUB", Token::Sub},
33-
{"THEN", Token::Then},
34-
{"TO", Token::To},
13+
{"AND", Token::And}, {"AS", Token::As},
14+
{"DIM", Token::Dim}, {"DOUBLE", Token::DoubleType},
15+
{"ELSE", Token::Else}, {"END", Token::End},
16+
{"EXTERN", Token::Extern}, {"FOR", Token::For},
17+
{"FUNCTION", Token::Function}, {"GOSUB", Token::Gosub},
18+
{"GOTO", Token::Goto}, {"IF", Token::If},
19+
{"INPUT", Token::Input}, {"INTEGER", Token::IntegerType},
20+
{"LET", Token::Let}, {"OR", Token::Or},
21+
{"NEXT", Token::Next}, {"PRINT", Token::Print},
22+
{"RETURN", Token::Return}, {"STEP", Token::Step},
23+
{"STRING", Token::StringType}, {"SUB", Token::Sub},
24+
{"THEN", Token::Then}, {"TO", Token::To},
3525
};
3626
return _stringToTag;
3727
}

lexer.h

+2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ struct Token {
2323
Sub,
2424
Function,
2525
Variable,
26+
Dim,
2627

28+
IntegerType,
2729
StringType,
2830
DoubleType,
2931

main.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ int main(int argc, char** argv) {
7575
return 1;
7676

7777
llvm::raw_os_ostream errStream(std::cerr);
78-
if (llvm::verifyModule(*ctx.module, &errStream))
78+
if (opts.verifyModule && llvm::verifyModule(*ctx.module, &errStream))
7979
return 1;
8080

8181
std::unique_ptr<llvm::raw_fd_ostream> output;

0 commit comments

Comments
 (0)