A CIL Tutorial - Department of Computer Science - ETH Zürich

A CIL Tutorial - Department of Computer Science - ETH Zürich A CIL Tutorial - Department of Computer Science - ETH Zürich

29.01.2014 Views

CHAPTER 14. IMPLEMENTING A SIMPLE DSL 122 (L.map (fun a → (a.argVi.vname¢"addr"), Fe (AddrOf(var a.argVi))) al)@ (L.map (fun a → (a.argVi.vname¢"l"), Fl(var a.argVi)) al)@ (L.map (fun a → (a.argGot.vname), Fl(var a.argGot)) al)) The function initArgs generates statements that initialize the global variables for arguments with their default values. let initArgs (al : argument list) : stmt list = L.map (fun a → i2s(Set(var a.argVi, a.argDef, locUnknown))) al The function printHelp generates statements using printf that print the help text for the arguments to standard out. The help text gives the short version, the long version, the default value, and tells whether the argument is mandatory. The statements generated by printHelp will be used in case some checks on the runtime argument values fails. let printHelp (f : file) (al : argument list) : stmt list = let print = findOrCreateFunc f "printf" intType in let s s = mkString s in [i2s(Call(None, v2e print, [s "Improper arguemnts\n"], locUnknown))]@ (L.map (fun a → let af = if a.argFmt ≠ "" then a.argFmt else "%d" in let fmt = if a.argOpt then s ("\t-%s,--%s\t%s ("¢af¢")\n") else s "\t-%s,--%s\t%s (mandatory)\n" in let args = if a.argOpt then [fmt; s a.argShort; s a.argName; s a.argHelp; a.argDef] else [fmt; s a.argShort; s a.argName; s a.argHelp] in i2s (Call(None, v2e print, args, locUnknown)) ) al) @ [mkStmt (Return(Some mone, locUnknown))] The function makeArgChecks generates an if statement that checks two things. First, it checks that all mandatory arguments have been given. Second, it checks that all assertions stipulated by the programmer on the arguments are true. If either of these fails, the statements given by printHelp are used to print the help messages, and exit from the program with a failure code.

CHAPTER 14. IMPLEMENTING A SIMPLE DSL 123 let makeArgChecks (f : file) (al : argument list) : stmt = let got arg a = if a.argOpt then one else v2e a.argGot in let bexp, mexp = L.fold left (fun b a → BinOp(LAnd, b, a.argReq, intType)) one al, L.fold left (fun b a → BinOp(LAnd, b, (got arg a), intType)) one al in mkStmt (If(BinOp(LOr, UnOp(LNot, mexp, intType), UnOp(LNot, bexp, intType), intType), mkBlock (printHelp f al), mkBlock[ ], locUnknown)) If we have found the main function, then the function processFunction inserts the code for processing command line arguments at the top of the function. let processFunction (f : file) (al : argument list) (fd : fundec) (loc : location) : unit = if fd.svar.vname = "main" then fd.sbody.bstmts ← (initArgs al) @ (makeArgStmts f fd al) @ [makeArgChecks f al] @ fd.sbody.bstmts Finally, the function tut14 gathers the argument specications using gatherArguments before calling processFunction, which generates the argument parsing code. let tut14 (f : file) : unit = f | > gatherArguments |> processFunction f |> onlyFunctions |> iterGlobals f; eraseAttrs f 14.2 test/tut14.c This C code demonstrates the language extension we wrote for generating code to process command line arguments. It will accept one argument called boolarg, and another called intarg. ../test/tut14.c # include # include # include // This is where the argument macro is #define'd The boolarg argument can be passed with --boolarg or -b, and its value can be accessed in the program through the global variable boolarg of type int. When not given, the default value is 0 or false.

CHAPTER 14. IMPLEMENTING A SIMPLE DSL 122<br />

(L.map (fun a → (a.argVi.vname¢"addr"), Fe (AddrOf(var a.argVi))) al)@<br />

(L.map (fun a → (a.argVi.vname¢"l"), Fl(var a.argVi)) al)@<br />

(L.map (fun a → (a.argGot.vname), Fl(var a.argGot)) al))<br />

The function initArgs generates statements that initialize the global variables for arguments with<br />

their default values.<br />

let initArgs (al : argument list) : stmt list =<br />

L.map (fun a → i2s(Set(var a.argVi, a.argDef, locUnknown))) al<br />

The function printHelp generates statements using printf that print the help text for the arguments<br />

to standard out. The help text gives the short version, the long version, the default value,<br />

and tells whether the argument is mandatory. The statements generated by printHelp will be used<br />

in case some checks on the runtime argument values fails.<br />

let printHelp (f : file) (al : argument list) : stmt list =<br />

let print = findOrCreateFunc f "printf" intType in<br />

let s s = mkString s in<br />

[i2s(Call(None, v2e print, [s "Improper arguemnts\n"], locUnknown))]@<br />

(L.map (fun a →<br />

let af = if a.argFmt ≠ "" then a.argFmt else "%d" in<br />

let fmt = if a.argOpt<br />

then s ("\t-%s,--%s\t%s ("¢af¢")\n")<br />

else s "\t-%s,--%s\t%s (mandatory)\n"<br />

in<br />

let args = if a.argOpt<br />

then [fmt; s a.argShort; s a.argName; s a.argHelp; a.argDef]<br />

else [fmt; s a.argShort; s a.argName; s a.argHelp]<br />

in<br />

i2s (Call(None, v2e print, args, locUnknown))<br />

) al) @<br />

[mkStmt (Return(Some mone, locUnknown))]<br />

The function makeArgChecks generates an if statement that checks two things. First, it checks that<br />

all mandatory arguments have been given. Second, it checks that all assertions stipulated by the<br />

programmer on the arguments are true. If either <strong>of</strong> these fails, the statements given by printHelp<br />

are used to print the help messages, and exit from the program with a failure code.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!