We saw in the previous recipe how binary operators can be handled. A language may also have some unary operator, operating on 1 operand. In this recipe, we will see how to handle unary operators.
The first step is to define a unary operator in the TOY language. A simple unary NOT operator (!
) can serve as a good example; let's see one definition:
def unary!(v) if v then 0 else 1;
If the value v
is equal to 1
, then 0
is returned. If the value is 0
, 1
is returned as the output.
Do the following steps:
enum
token for the unary operator in the toy.cpp
file:enum Token_Type { … … BINARY_TOKEN, UNARY_TOKEN }
static int get_token() { … … if (Identifier_string == "in") return IN_TOKEN; if (Identifier_string == "binary") return BINARY_TOKEN; if (Identifier_string == "unary") return UNARY_TOKEN; … … }
class ExprUnaryAST : public BaseAST { char Opcode; BaseAST *Operand; public: ExprUnaryAST(char opcode, BaseAST *operand) : Opcode(opcode), Operand(operand) {} virtual Value *Codegen(); };
static BaseAST *unary_parser() { if (!isascii(Current_token) || Current_token == '(' || Current_token == ',') return Base_Parser(); int Op = Current_token; next_token(); if (ExprAST *Operand = unary_parser()) return new ExprUnaryAST(Opc, Operand); return 0; }
unary_parser()
function from the binary operator parser:static BaseAST *binary_op_parser(int Old_Prec, BaseAST *LHS) { while (1) { int Operator_Prec = getBinOpPrecedence(); if (Operator_Prec < Old_Prec) return LHS; int BinOp = Current_token; next_token(); BaseAST *RHS = unary_parser(); if (!RHS) return 0; int Next_Prec = getBinOpPrecedence(); if (Operator_Prec < Next_Prec) { RHS = binary_op_parser(Operator_Prec + 1, RHS); if (RHS == 0) return 0; } LHS = new BinaryAST(std::to_string(BinOp), LHS, RHS); } }
unary_parser()
function from the expression parser:static BaseAST *expression_parser() { BaseAST *LHS = unary_parser(); if (!LHS) return 0; return binary_op_parser(0, LHS); }
static FunctionDeclAST* func_decl_parser() { std::string Function_Name = Identifier_string; unsigned Kind = 0; unsigned BinaryPrecedence = 30; switch (Current_token) { default: return 0; case IDENTIFIER_TOKEN: Function_Name = Identifier_string; Kind = 0; next_token(); break; case UNARY_TOKEN: next_token(); if (!isascii(Current_token)) return0; Function_Name = "unary"; Function_Name += (char)Current_token; Kind = 1; next_token(); break; case BINARY_TOKEN: next_token(); if (!isascii(Current_token)) return 0; Function_Name = "binary"; Function_Name += (char)Current_token; Kind = 2; next_token(); if (Current_token == NUMERIC_TOKEN) { if (Numeric_Val < 1 || Numeric_Val > 100) return 0; BinaryPrecedence = (unsigned)Numeric_Val; next_token(); } break; } if (Current_token ! = '(') { printf("error in function declaration"); return 0; } std::vector<std::string> Function_Argument_Names; while(next_token() == IDENTIFIER_TOKEN) Function_Argument_Names.push_back(Identifier_string); if(Current_token != ')') { printf("Expected ')' "); return 0; } next_token(); if (Kind && Function_Argument_Names.size() != Kind) return 0; return new FunctionDeclAST(Function_Name, Function_Arguments_Names, Kind !=0, BinaryPrecedence); }
Codegen()
function for the unary operator:Value *ExprUnaryAST::Codegen() { Value *OperandV = Operand->Codegen(); if (OperandV == 0) return 0; Function *F = TheModule->getFunction(std::string("unary")+Opcode); if (F == 0) return 0; return Builder.CreateCall(F, OperandV, "unop"); }
Do the following steps:
toy.cpp
file:$ g++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core ` -O3 -o toy
$ vi example
def unary!(v) if v then 0 else 1;
$ ./toy example
The output should be as shown:
; ModuleID = 'my compiler' target datalayout = "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128" define i32 @"unary!"(i32 %v) { entry: %ifcond = icmp eq i32 %v, 0 %. = select i1 %ifcond, i32 1, i32 0 ret i32 %. }
The unary operator defined by the user will be parsed, and IR will be generated for it. In the case you just saw, if the unary operand is not zero then the result is 0
. If the operand is zero, then the result is 1
.
18.118.0.145