aboutsummaryrefslogtreecommitdiffstats
path: root/examples/Kaleidoscope/MCJIT/initial/toy.cpp
diff options
context:
space:
mode:
authorStephen Hines <srhines@google.com>2015-04-01 18:49:24 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2015-04-01 18:49:26 +0000
commit3fa16bd6062e23bcdb82ed4dd965674792e6b761 (patch)
tree9348fc507292f7e8715d22d64ce5a32131b4f875 /examples/Kaleidoscope/MCJIT/initial/toy.cpp
parentbeed47390a60f6f0c77532b3d3f76bb47ef49423 (diff)
parentebe69fe11e48d322045d5949c83283927a0d790b (diff)
downloadexternal_llvm-3fa16bd6062e23bcdb82ed4dd965674792e6b761.zip
external_llvm-3fa16bd6062e23bcdb82ed4dd965674792e6b761.tar.gz
external_llvm-3fa16bd6062e23bcdb82ed4dd965674792e6b761.tar.bz2
Merge "Update aosp/master LLVM for rebase to r230699."
Diffstat (limited to 'examples/Kaleidoscope/MCJIT/initial/toy.cpp')
-rw-r--r--examples/Kaleidoscope/MCJIT/initial/toy.cpp250
1 files changed, 125 insertions, 125 deletions
diff --git a/examples/Kaleidoscope/MCJIT/initial/toy.cpp b/examples/Kaleidoscope/MCJIT/initial/toy.cpp
index 2c1b297..dd35358 100644
--- a/examples/Kaleidoscope/MCJIT/initial/toy.cpp
+++ b/examples/Kaleidoscope/MCJIT/initial/toy.cpp
@@ -6,9 +6,9 @@
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
-#include "llvm/PassManager.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Transforms/Scalar.h"
#include <cctype>
@@ -32,14 +32,14 @@ enum Token {
// primary
tok_identifier = -4, tok_number = -5,
-
+
// control
tok_if = -6, tok_then = -7, tok_else = -8,
tok_for = -9, tok_in = -10,
-
+
// operators
tok_binary = -11, tok_unary = -12,
-
+
// var definition
tok_var = -13
};
@@ -88,11 +88,11 @@ static int gettok() {
// Comment until end of line.
do LastChar = getchar();
while (LastChar != EOF && LastChar != '\n' && LastChar != '\r');
-
+
if (LastChar != EOF)
return gettok();
}
-
+
// Check for end of file. Don't eat the EOF.
if (LastChar == EOF)
return tok_eof;
@@ -136,7 +136,7 @@ class UnaryExprAST : public ExprAST {
char Opcode;
ExprAST *Operand;
public:
- UnaryExprAST(char opcode, ExprAST *operand)
+ UnaryExprAST(char opcode, ExprAST *operand)
: Opcode(opcode), Operand(operand) {}
virtual Value *Codegen();
};
@@ -146,7 +146,7 @@ class BinaryExprAST : public ExprAST {
char Op;
ExprAST *LHS, *RHS;
public:
- BinaryExprAST(char op, ExprAST *lhs, ExprAST *rhs)
+ BinaryExprAST(char op, ExprAST *lhs, ExprAST *rhs)
: Op(op), LHS(lhs), RHS(rhs) {}
virtual Value *Codegen();
};
@@ -189,7 +189,7 @@ public:
VarExprAST(const std::vector<std::pair<std::string, ExprAST*> > &varnames,
ExprAST *body)
: VarNames(varnames), Body(body) {}
-
+
virtual Value *Codegen();
};
@@ -204,19 +204,19 @@ public:
PrototypeAST(const std::string &name, const std::vector<std::string> &args,
bool isoperator = false, unsigned prec = 0)
: Name(name), Args(args), isOperator(isoperator), Precedence(prec) {}
-
+
bool isUnaryOp() const { return isOperator && Args.size() == 1; }
bool isBinaryOp() const { return isOperator && Args.size() == 2; }
-
+
char getOperatorName() const {
assert(isUnaryOp() || isBinaryOp());
return Name[Name.size()-1];
}
-
+
unsigned getBinaryPrecedence() const { return Precedence; }
-
+
Function *Codegen();
-
+
void CreateArgumentAllocas(Function *F);
};
@@ -227,7 +227,7 @@ class FunctionAST {
public:
FunctionAST(PrototypeAST *proto, ExprAST *body)
: Proto(proto), Body(body) {}
-
+
Function *Codegen();
};
@@ -251,7 +251,7 @@ static std::map<char, int> BinopPrecedence;
static int GetTokPrecedence() {
if (!isascii(CurTok))
return -1;
-
+
// Make sure it's a declared binop.
int TokPrec = BinopPrecedence[CurTok];
if (TokPrec <= 0) return -1;
@@ -270,12 +270,12 @@ static ExprAST *ParseExpression();
/// ::= identifier '(' expression* ')'
static ExprAST *ParseIdentifierExpr() {
std::string IdName = IdentifierStr;
-
+
getNextToken(); // eat identifier.
-
+
if (CurTok != '(') // Simple variable ref.
return new VariableExprAST(IdName);
-
+
// Call.
getNextToken(); // eat (
std::vector<ExprAST*> Args;
@@ -295,7 +295,7 @@ static ExprAST *ParseIdentifierExpr() {
// Eat the ')'.
getNextToken();
-
+
return new CallExprAST(IdName, Args);
}
@@ -311,7 +311,7 @@ static ExprAST *ParseParenExpr() {
getNextToken(); // eat (.
ExprAST *V = ParseExpression();
if (!V) return 0;
-
+
if (CurTok != ')')
return Error("expected ')'");
getNextToken(); // eat ).
@@ -321,26 +321,26 @@ static ExprAST *ParseParenExpr() {
/// ifexpr ::= 'if' expression 'then' expression 'else' expression
static ExprAST *ParseIfExpr() {
getNextToken(); // eat the if.
-
+
// condition.
ExprAST *Cond = ParseExpression();
if (!Cond) return 0;
-
+
if (CurTok != tok_then)
return Error("expected then");
getNextToken(); // eat the then
-
+
ExprAST *Then = ParseExpression();
if (Then == 0) return 0;
-
+
if (CurTok != tok_else)
return Error("expected else");
-
+
getNextToken();
-
+
ExprAST *Else = ParseExpression();
if (!Else) return 0;
-
+
return new IfExprAST(Cond, Then, Else);
}
@@ -350,24 +350,24 @@ static ExprAST *ParseForExpr() {
if (CurTok != tok_identifier)
return Error("expected identifier after for");
-
+
std::string IdName = IdentifierStr;
getNextToken(); // eat identifier.
-
+
if (CurTok != '=')
return Error("expected '=' after for");
getNextToken(); // eat '='.
-
-
+
+
ExprAST *Start = ParseExpression();
if (Start == 0) return 0;
if (CurTok != ',')
return Error("expected ',' after for start value");
getNextToken();
-
+
ExprAST *End = ParseExpression();
if (End == 0) return 0;
-
+
// The step value is optional.
ExprAST *Step = 0;
if (CurTok == ',') {
@@ -375,18 +375,18 @@ static ExprAST *ParseForExpr() {
Step = ParseExpression();
if (Step == 0) return 0;
}
-
+
if (CurTok != tok_in)
return Error("expected 'in' after for");
getNextToken(); // eat 'in'.
-
+
ExprAST *Body = ParseExpression();
if (Body == 0) return 0;
return new ForExprAST(IdName, Start, End, Step, Body);
}
-/// varexpr ::= 'var' identifier ('=' expression)?
+/// varexpr ::= 'var' identifier ('=' expression)?
// (',' identifier ('=' expression)?)* 'in' expression
static ExprAST *ParseVarExpr() {
getNextToken(); // eat the var.
@@ -396,7 +396,7 @@ static ExprAST *ParseVarExpr() {
// At least one variable name is required.
if (CurTok != tok_identifier)
return Error("expected identifier after var");
-
+
while (1) {
std::string Name = IdentifierStr;
getNextToken(); // eat identifier.
@@ -405,29 +405,29 @@ static ExprAST *ParseVarExpr() {
ExprAST *Init = 0;
if (CurTok == '=') {
getNextToken(); // eat the '='.
-
+
Init = ParseExpression();
if (Init == 0) return 0;
}
-
+
VarNames.push_back(std::make_pair(Name, Init));
-
+
// End of var list, exit loop.
if (CurTok != ',') break;
getNextToken(); // eat the ','.
-
+
if (CurTok != tok_identifier)
return Error("expected identifier list after var");
}
-
+
// At this point, we have to have 'in'.
if (CurTok != tok_in)
return Error("expected 'in' keyword after 'var'");
getNextToken(); // eat 'in'.
-
+
ExprAST *Body = ParseExpression();
if (Body == 0) return 0;
-
+
return new VarExprAST(VarNames, Body);
}
@@ -457,7 +457,7 @@ static ExprAST *ParseUnary() {
// If the current token is not an operator, it must be a primary expr.
if (!isascii(CurTok) || CurTok == '(' || CurTok == ',')
return ParsePrimary();
-
+
// If this is a unary operator, read it.
int Opc = CurTok;
getNextToken();
@@ -472,20 +472,20 @@ static ExprAST *ParseBinOpRHS(int ExprPrec, ExprAST *LHS) {
// If this is a binop, find its precedence.
while (1) {
int TokPrec = GetTokPrecedence();
-
+
// If this is a binop that binds at least as tightly as the current binop,
// consume it, otherwise we are done.
if (TokPrec < ExprPrec)
return LHS;
-
+
// Okay, we know this is a binop.
int BinOp = CurTok;
getNextToken(); // eat binop
-
+
// Parse the unary expression after the binary operator.
ExprAST *RHS = ParseUnary();
if (!RHS) return 0;
-
+
// If BinOp binds less tightly with RHS than the operator after RHS, let
// the pending operator take RHS as its LHS.
int NextPrec = GetTokPrecedence();
@@ -493,7 +493,7 @@ static ExprAST *ParseBinOpRHS(int ExprPrec, ExprAST *LHS) {
RHS = ParseBinOpRHS(TokPrec+1, RHS);
if (RHS == 0) return 0;
}
-
+
// Merge LHS/RHS.
LHS = new BinaryExprAST(BinOp, LHS, RHS);
}
@@ -505,7 +505,7 @@ static ExprAST *ParseBinOpRHS(int ExprPrec, ExprAST *LHS) {
static ExprAST *ParseExpression() {
ExprAST *LHS = ParseUnary();
if (!LHS) return 0;
-
+
return ParseBinOpRHS(0, LHS);
}
@@ -515,10 +515,10 @@ static ExprAST *ParseExpression() {
/// ::= unary LETTER (id)
static PrototypeAST *ParsePrototype() {
std::string FnName;
-
+
unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary.
unsigned BinaryPrecedence = 30;
-
+
switch (CurTok) {
default:
return ErrorP("Expected function name in prototype");
@@ -544,7 +544,7 @@ static PrototypeAST *ParsePrototype() {
FnName += (char)CurTok;
Kind = 2;
getNextToken();
-
+
// Read the precedence if present.
if (CurTok == tok_number) {
if (NumVal < 1 || NumVal > 100)
@@ -554,23 +554,23 @@ static PrototypeAST *ParsePrototype() {
}
break;
}
-
+
if (CurTok != '(')
return ErrorP("Expected '(' in prototype");
-
+
std::vector<std::string> ArgNames;
while (getNextToken() == tok_identifier)
ArgNames.push_back(IdentifierStr);
if (CurTok != ')')
return ErrorP("Expected ')' in prototype");
-
+
// success.
getNextToken(); // eat ')'.
-
+
// Verify right number of names for operator.
if (Kind && ArgNames.size() != Kind)
return ErrorP("Invalid number of operands for operator");
-
+
return new PrototypeAST(FnName, ArgNames, Kind != 0, BinaryPrecedence);
}
@@ -670,14 +670,14 @@ private:
class HelpingMemoryManager : public SectionMemoryManager
{
- HelpingMemoryManager(const HelpingMemoryManager&) LLVM_DELETED_FUNCTION;
- void operator=(const HelpingMemoryManager&) LLVM_DELETED_FUNCTION;
+ HelpingMemoryManager(const HelpingMemoryManager&) = delete;
+ void operator=(const HelpingMemoryManager&) = delete;
public:
HelpingMemoryManager(MCJITHelper *Helper) : MasterHelper(Helper) {}
virtual ~HelpingMemoryManager() {}
- /// This method returns the address of the specified function.
+ /// This method returns the address of the specified function.
/// Our implementation will attempt to find functions in other
/// modules associated with the MCJITHelper to cross link functions
/// from one generated module to another.
@@ -739,9 +739,9 @@ Function *MCJITHelper::getFunction(const std::string FnName) {
// If we don't have a prototype yet, create one.
if (!PF)
- PF = Function::Create(F->getFunctionType(),
- Function::ExternalLinkage,
- FnName,
+ PF = Function::Create(F->getFunctionType(),
+ Function::ExternalLinkage,
+ FnName,
OpenModule);
return PF;
}
@@ -885,11 +885,11 @@ Value *VariableExprAST::Codegen() {
Value *UnaryExprAST::Codegen() {
Value *OperandV = Operand->Codegen();
if (OperandV == 0) return 0;
-
+
Function *F = TheHelper->getFunction(MakeLegalFunctionName(std::string("unary")+Opcode));
if (F == 0)
return ErrorV("Unknown unary operator");
-
+
return Builder.CreateCall(F, OperandV, "unop");
}
@@ -911,11 +911,11 @@ Value *BinaryExprAST::Codegen() {
Builder.CreateStore(Val, Variable);
return Val;
}
-
+
Value *L = LHS->Codegen();
Value *R = RHS->Codegen();
if (L == 0 || R == 0) return 0;
-
+
switch (Op) {
case '+': return Builder.CreateFAdd(L, R, "addtmp");
case '-': return Builder.CreateFSub(L, R, "subtmp");
@@ -928,12 +928,12 @@ Value *BinaryExprAST::Codegen() {
"booltmp");
default: break;
}
-
+
// If it wasn't a builtin binary operator, it must be a user defined one. Emit
// a call to it.
Function *F = TheHelper->getFunction(MakeLegalFunctionName(std::string("binary")+Op));
assert(F && "binary operator not found!");
-
+
Value *Ops[] = { L, R };
return Builder.CreateCall(F, Ops, "binop");
}
@@ -943,7 +943,7 @@ Value *CallExprAST::Codegen() {
Function *CalleeF = TheHelper->getFunction(Callee);
if (CalleeF == 0)
return ErrorV("Unknown function referenced");
-
+
// If argument mismatch error.
if (CalleeF->arg_size() != Args.size())
return ErrorV("Incorrect # arguments passed");
@@ -953,56 +953,56 @@ Value *CallExprAST::Codegen() {
ArgsV.push_back(Args[i]->Codegen());
if (ArgsV.back() == 0) return 0;
}
-
+
return Builder.CreateCall(CalleeF, ArgsV, "calltmp");
}
Value *IfExprAST::Codegen() {
Value *CondV = Cond->Codegen();
if (CondV == 0) return 0;
-
+
// Convert condition to a bool by comparing equal to 0.0.
- CondV = Builder.CreateFCmpONE(CondV,
+ CondV = Builder.CreateFCmpONE(CondV,
ConstantFP::get(getGlobalContext(), APFloat(0.0)),
"ifcond");
-
+
Function *TheFunction = Builder.GetInsertBlock()->getParent();
-
+
// Create blocks for the then and else cases. Insert the 'then' block at the
// end of the function.
BasicBlock *ThenBB = BasicBlock::Create(getGlobalContext(), "then", TheFunction);
BasicBlock *ElseBB = BasicBlock::Create(getGlobalContext(), "else");
BasicBlock *MergeBB = BasicBlock::Create(getGlobalContext(), "ifcont");
-
+
Builder.CreateCondBr(CondV, ThenBB, ElseBB);
-
+
// Emit then value.
Builder.SetInsertPoint(ThenBB);
-
+
Value *ThenV = Then->Codegen();
if (ThenV == 0) return 0;
-
+
Builder.CreateBr(MergeBB);
// Codegen of 'Then' can change the current block, update ThenBB for the PHI.
ThenBB = Builder.GetInsertBlock();
-
+
// Emit else block.
TheFunction->getBasicBlockList().push_back(ElseBB);
Builder.SetInsertPoint(ElseBB);
-
+
Value *ElseV = Else->Codegen();
if (ElseV == 0) return 0;
-
+
Builder.CreateBr(MergeBB);
// Codegen of 'Else' can change the current block, update ElseBB for the PHI.
ElseBB = Builder.GetInsertBlock();
-
+
// Emit merge block.
TheFunction->getBasicBlockList().push_back(MergeBB);
Builder.SetInsertPoint(MergeBB);
PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), 2,
"iftmp");
-
+
PN->addIncoming(ThenV, ThenBB);
PN->addIncoming(ElseV, ElseBB);
return PN;
@@ -1015,7 +1015,7 @@ Value *ForExprAST::Codegen() {
// start = startexpr
// store start -> var
// goto loop
- // loop:
+ // loop:
// ...
// bodyexpr
// ...
@@ -1028,40 +1028,40 @@ Value *ForExprAST::Codegen() {
// store nextvar -> var
// br endcond, loop, endloop
// outloop:
-
+
Function *TheFunction = Builder.GetInsertBlock()->getParent();
// Create an alloca for the variable in the entry block.
AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName);
-
+
// Emit the start code first, without 'variable' in scope.
Value *StartVal = Start->Codegen();
if (StartVal == 0) return 0;
-
+
// Store the value into the alloca.
Builder.CreateStore(StartVal, Alloca);
-
+
// Make the new basic block for the loop header, inserting after current
// block.
BasicBlock *LoopBB = BasicBlock::Create(getGlobalContext(), "loop", TheFunction);
-
+
// Insert an explicit fall through from the current block to the LoopBB.
Builder.CreateBr(LoopBB);
// Start insertion in LoopBB.
Builder.SetInsertPoint(LoopBB);
-
+
// Within the loop, the variable is defined equal to the PHI node. If it
// shadows an existing variable, we have to restore it, so save it now.
AllocaInst *OldVal = NamedValues[VarName];
NamedValues[VarName] = Alloca;
-
+
// Emit the body of the loop. This, like any other expr, can change the
// current BB. Note that we ignore the value computed by the body, but don't
// allow an error.
if (Body->Codegen() == 0)
return 0;
-
+
// Emit the step value.
Value *StepVal;
if (Step) {
@@ -1071,52 +1071,52 @@ Value *ForExprAST::Codegen() {
// If not specified, use 1.0.
StepVal = ConstantFP::get(getGlobalContext(), APFloat(1.0));
}
-
+
// Compute the end condition.
Value *EndCond = End->Codegen();
if (EndCond == 0) return EndCond;
-
+
// Reload, increment, and restore the alloca. This handles the case where
// the body of the loop mutates the variable.
Value *CurVar = Builder.CreateLoad(Alloca, VarName.c_str());
Value *NextVar = Builder.CreateFAdd(CurVar, StepVal, "nextvar");
Builder.CreateStore(NextVar, Alloca);
-
+
// Convert condition to a bool by comparing equal to 0.0.
- EndCond = Builder.CreateFCmpONE(EndCond,
+ EndCond = Builder.CreateFCmpONE(EndCond,
ConstantFP::get(getGlobalContext(), APFloat(0.0)),
"loopcond");
-
+
// Create the "after loop" block and insert it.
BasicBlock *AfterBB = BasicBlock::Create(getGlobalContext(), "afterloop", TheFunction);
-
+
// Insert the conditional branch into the end of LoopEndBB.
Builder.CreateCondBr(EndCond, LoopBB, AfterBB);
-
+
// Any new code will be inserted in AfterBB.
Builder.SetInsertPoint(AfterBB);
-
+
// Restore the unshadowed variable.
if (OldVal)
NamedValues[VarName] = OldVal;
else
NamedValues.erase(VarName);
-
+
// for expr always returns 0.0.
return Constant::getNullValue(Type::getDoubleTy(getGlobalContext()));
}
Value *VarExprAST::Codegen() {
std::vector<AllocaInst *> OldBindings;
-
+
Function *TheFunction = Builder.GetInsertBlock()->getParent();
// Register all variables and emit their initializer.
for (unsigned i = 0, e = VarNames.size(); i != e; ++i) {
const std::string &VarName = VarNames[i].first;
ExprAST *Init = VarNames[i].second;
-
+
// Emit the initializer before adding the variable to scope, this prevents
// the initializer from referencing the variable itself, and permits stuff
// like this:
@@ -1129,22 +1129,22 @@ Value *VarExprAST::Codegen() {
} else { // If not specified, use 0.0.
InitVal = ConstantFP::get(getGlobalContext(), APFloat(0.0));
}
-
+
AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName);
Builder.CreateStore(InitVal, Alloca);
// Remember the old variable binding so that we can restore the binding when
// we unrecurse.
OldBindings.push_back(NamedValues[VarName]);
-
+
// Remember this binding.
NamedValues[VarName] = Alloca;
}
-
+
// Codegen the body, now that all vars are in scope.
Value *BodyVal = Body->Codegen();
if (BodyVal == 0) return 0;
-
+
// Pop all our variables from scope.
for (unsigned i = 0, e = VarNames.size(); i != e; ++i)
NamedValues[VarNames[i].first] = OldBindings[i];
@@ -1155,7 +1155,7 @@ Value *VarExprAST::Codegen() {
Function *PrototypeAST::Codegen() {
// Make the function type: double(double,double) etc.
- std::vector<Type*> Doubles(Args.size(),
+ std::vector<Type*> Doubles(Args.size(),
Type::getDoubleTy(getGlobalContext()));
FunctionType *FT = FunctionType::get(Type::getDoubleTy(getGlobalContext()),
Doubles, false);
@@ -1172,26 +1172,26 @@ Function *PrototypeAST::Codegen() {
// Delete the one we just made and get the existing one.
F->eraseFromParent();
F = M->getFunction(Name);
-
+
// If F already has a body, reject this.
if (!F->empty()) {
ErrorF("redefinition of function");
return 0;
}
-
+
// If F took a different number of args, reject.
if (F->arg_size() != Args.size()) {
ErrorF("redefinition of function with different # args");
return 0;
}
}
-
+
// Set names for all arguments.
unsigned Idx = 0;
for (Function::arg_iterator AI = F->arg_begin(); Idx != Args.size();
++AI, ++Idx)
AI->setName(Args[Idx]);
-
+
return F;
}
@@ -1213,19 +1213,19 @@ void PrototypeAST::CreateArgumentAllocas(Function *F) {
Function *FunctionAST::Codegen() {
NamedValues.clear();
-
+
Function *TheFunction = Proto->Codegen();
if (TheFunction == 0)
return 0;
-
+
// If this is an operator, install it.
if (Proto->isBinaryOp())
BinopPrecedence[Proto->getOperatorName()] = Proto->getBinaryPrecedence();
-
+
// Create a new basic block to start insertion into.
BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction);
Builder.SetInsertPoint(BB);
-
+
// Add all arguments to the symbol table and create their allocas.
Proto->CreateArgumentAllocas(TheFunction);
@@ -1238,7 +1238,7 @@ Function *FunctionAST::Codegen() {
return TheFunction;
}
-
+
// Error reading body, remove function.
TheFunction->eraseFromParent();
@@ -1285,7 +1285,7 @@ static void HandleTopLevelExpression() {
if (Function *LF = F->Codegen()) {
// JIT the function, returning a function pointer.
void *FPtr = TheHelper->getPointerToFunction(LF);
-
+
// Cast it to the right type (takes no arguments, returns a double) so we
// can call it as a native function.
double (*FP)() = (double (*)())(intptr_t)FPtr;
@@ -1322,20 +1322,20 @@ static void MainLoop() {
//===----------------------------------------------------------------------===//
/// putchard - putchar that takes a double and returns 0.
-extern "C"
+extern "C"
double putchard(double X) {
putchar((char)X);
return 0;
}
/// printd - printf that takes a double prints it as "%f\n", returning 0.
-extern "C"
+extern "C"
double printd(double X) {
printf("%f", X);
return 0;
}
-extern "C"
+extern "C"
double printlf() {
printf("\n");
return 0;