--[[ Expression Language 1, Abstract Syntax Module CSci 450: Organization of Programming Languages, Fall 2016 H. Conrad Cunningham, Professor Computer and Information Science University of Mississippi 1234567890123456789012345678901234567890123456789012345678901234567890 2016-09-13: Separated as module from Assignment #1 code, added NOP 2016-09-16: Corrected typo 2016-09-21: Removed Min, Max, Set, Let for new base aftr HW1 Added global variables for module names 2016-09-22: Typo correction in comment 2016-10-03: Typo correction in isGt This module encapsulates the representation of Expressions behind constructors and accessors. Other parts of the program access the data structures through these public functions. This design allows the representation to change with few effects on the other parts of the interpreter. This module represents the abstract syntax for Expression Language using Lua array tables as indicated below. Field 1 is a type tag. Other fields are the arguments of the operations. Expr == {NOP, string} -- no operation {INT, number} -- integer value {VAR, string} -- variable name {NEG, Expr} -- negation {ADD, Expr, Expr} -- addition {SUB, Expr, Expr} -- subtraction {MUL, Expr, Expr} -- multiplcation {DIV, Expr, Expr} -- division {EQ, Expr, Expr} -- equality comparison {NE, Expr, Expr} -- inequality comparison {LT, Expr, Expr} -- less than comparion {GT, Expr, Expr} -- greater than comparion {LE, Expr, Expr} -- less or equal comparison {GE, Expr, Expr} -- greater or equal comparison {IF, Expr, Expr, Expr} -- if-then-else expression -- (returns e2 value if e1 true -- otherwise, returns e3 value) Public constructor and type query functions: Nop, isNop -- no operation Int, isInt -- integer number constants Var, isVar -- variable names Neg, isNeg -- negation Add, isAdd -- addition Sub, isSub -- subtraction Mul, isMul -- multiplication UNIMPLEMENTED HW1 Div, isDiv -- division UNIMPLEMENTED HW1 Eq, isEQ -- equality comparison Ne, isNe -- inequality comparison UNIMPLEMENTED HW1 Lt, isLt -- less than comparison UNIMPLEMENTED HW1 Gt, isGt -- greater than comparison UNIMPLEMENTED HW1 Le, isLe -- less or equal comparison UNIMPLEMENTED HW1 Ge, isGe -- greater/equal comparison UNIMPLEMENTED HW1 If, isIf -- if-then-else expression Public operand accessor function: getArg Public string conversion function: exprToString Internal: isExpr, newBinOp, EXPRFIELDS, all type tag constants --]] --[[ Module names varialbes now global local UTILITIES = "utilities" --]] -- Import Utilities module local util = require(UTILITIES) local show_data = util.show_data -- treeConcat, printTree not currently used -- Internal singleton constants to represent Expression type tags local NOP, INT, VAR, NEG, ADD, SUB, MUL, DIV = "Nop", "Int", "Var", "Neg", "Add", "Sub", "Mul", "Div" local EQ, NE, LT, GT, LE, GE, IF = "Eq", "Ne", "Lt", "Gt", "Le", "Ge", "If" -- Internal constant mapping from Expression type tags to -- required number of arguments. -- ADDED Min, Max for HW1 local EXPRFIELDS = { ["Int"] = 1, ["Var"] = 1, ["Neg"] = 1, ["Add"] = 2, ["Sub"] = 2, ["Mul"] = 2, ["Div"] = 2, ["Eq"] = 2, ["Ne"] = 2, ["Lt"] = 2, ["Gt"] = 2, ["Le"] = 2, ["Ge"] = 2, ["If"] = 3, ["Nop"] = 1 } -- Internal query function "isExpr" checks whether the first level of -- the data structure "e" has a valid Expression tag and number of -- arguments. It does not recursively check arguments that are -- Expressions. local function isExpr(e, t) return type(e) == "table" and EXPRFIELDS[e[1]] == #e-1 and (t == nil or e[1] == t) end -- Internal constructor function "newBinOp" builds Expressions for -- operators with two Expression arguments. It is used by other -- constructors. local function newBinOp(tag, e1, e2) if EXPRFIELDS[tag] == 2 and isExpr(e1) and isExpr(e2) then return {tag, e1, e2} else error("Cannot construct binary operator " .. tag .. " with arguments:" .. show_data(e1) .. " and " .. show_data(e2)) end end -- Public accessor function "getArg" returns argument "n" of -- Expression "e". local function getArg(e, n) if 1 <= n and n <= EXPRFIELDS[e[1]] then return e[n+1] else error("Expression argument index " .. n .. " out of range for expression " .. show_data(e)) end end -- Public constructor and type check query functions for Expression -- types. local function Nop(s) return {NOP,s} end local function isNop(e) return isExpr(e, NOP) end local function Int(n) if type(n) == "number" then -- could check integer? coerce? -- check: if type(n) == "number" and n == math.floor(n) then return {INT, n} -- coerce: return {INT, math.floor(n)} else error("Cannot construct Int with nonnumeric argument: " .. show_data(n)) end end local function isInt(e) return isExpr(e, INT) end local function Var(n) if type(n) == "string" then -- other check return {VAR, n} else error("Cannot construct Var called with unsupported name" .. show_data(n)) end end local function isVar(e) return isExpr(e, VAR) end local function Neg(e) if isExpr(e) then return {NEG, e} else error("Cannot construct unary operator Neg with argument: " .. show_data(e)) end end local function isNeg(e) return isExpr(e, NEG) end local function Add(e1, e2) return newBinOp(ADD, e1, e2) end local function isAdd(e) return isExpr(e, ADD) end local function Sub(e1, e2) return newBinOp(SUB, e1, e2) end local function isSub(e) return isExpr(e, SUB) end local function Mul(e1, e2) return newBinOp(MUL, e1, e2) -- implement for HW1 end local function isMul(e) return isExpr(e, MUL) -- implement for HW1 end local function Div(e1, e2) return newBinOp(DIV, e1, e2) -- implement for HW1 end local function isDiv(e) return isExpr(e, DIV) -- implement for HW1 end local function Eq(e1, e2) return newBinOp(EQ, e1, e2) end local function isEq(e) return isExpr(e, EQ) end local function Ne(e1, e2) return newBinOp(NE, e1, e2) -- implement for HW1 end local function isNe(e) return isExpr(e, NE) -- implement for HW1 end local function Lt(e1, e2) return newBinOp(LT, e1, e2) -- implement for HW1 end local function isLt(e) return isExpr(e, LT) -- implement for HW1 end local function Gt(e1, e2) return newBinOp(GT, e1, e2) -- implement for HW1 end local function isGt(e) return isExpr(e, GT) -- implement for HW1 end local function Le(e1, e2) return newBinOp(LE, e1, e2) -- implement for HW1 end local function isLe(e) return isExpr(e, LE) -- implement for HW1 end local function Ge(e1, e2) return newBinOp(GE, e1, e2) -- implement for HW1 end local function isGe(e) return isExpr(e, GE) -- implement for HW1 end local function If(e1, e2, e3) if isExpr(e1) and isExpr(e2) and isExpr(e3) then -- condition? return {IF, e1, e2, e3} else error("Cannot construct ternary operator IF with arguments: " .. show_data(e1) .. " ; " .. show_data(e2) .. " ; " .. show_data(e3)) end end local function isIf(e) return isExpr(e, IF) end -- Public accessor function "exprToString" converts Expression "e" to -- a readable string format. local function exprToString(e) if isInt(e) then return "Int(" .. tostring(getArg(e,1)) .. ")" elseif isVar(e) then return "Var(" .. tostring(getArg(e,1)) .. ")" elseif isNop(e) then return "Nop(" .. tostring(getArg(e,1)) .. ")" elseif isExpr(e) then -- only has Expression arguments local strb = {} for i = 2, EXPRFIELDS[e[1]]+1 do strb[#strb+1] = exprToString(e[i]) end return e[1] .. "( " .. table.concat(strb, ", ") .. " )" else error("Not a valid Expression in exprToString: " .. show_data(e)) end end -- MODULE EXPORT LIST -- not exported: isExpr, EXPRFIELDS, type tag constants, newBinOp return { exprToString = exprToString, getArg = getArg, Int = Int, isInt = isInt, Var = Var, isVar = isVar, Neg = Neg, isNeg = isNeg, Add = Add, isAdd = isAdd, Sub = Sub, isSub = isSub, Mul = Mul, isMul = isMul, -- unimplemented HW1 Div = Div, isDiv = isDiv, -- unimplemented HW1 Eq = Eq, isEq = isEq, Ne = Ne, isNe = isNe, -- unimplemented HW1 Lt = Lt, isLt = isLt, -- unimplemented HW1 Gt = Gt, isGt = isGt, -- unimplemented HW1 Le = Le, isLe = isLe, -- unimplemented HW1 Ge = Ge, isGe = isGe, -- unimplemented HW1 If = If, isIf = isIf, Nop = Nop, isNop = isNop }