CSCI 2041 Lab12: The OCaml Debugger
- Due: 11:59pm Mon 12/03/2018
- Approximately 0.83% of total grade
- Submit to Canvas
- Lab exercises are open resource/open collaboration. You must submit your own work but you may freely discuss lab topics with other members of the class.
CODE DISTRIBUTION: lab12-code.zip
- Download the code distribution every lab
- See further setup instructions below
CHANGELOG: Empty
1 Rationale
All sane programming environments have debuggers associated with
them that allow line-by-line execution of programs. While OCaml's
debugger is not fancy having only a text-based command line interface,
it is sufficient for most debugging tasks. Among standard features
like breakpoints, single stepping, and printing variable values,
ocamldebug
is a so-called "time-travelling" debugger which allows
reverse execution via backstep
commands. This allows one to hit an
error and simply back up a couple steps to see what program state is
like at the problem point, a rather uncommon feature among debuggers.
This lab covers basic debugger techniques for ocamldebug
applied to
a code base that does lexing, parsing, and evaluation similarly to
previous labs.
Associated Reading / Preparation
- OCaml System Manual: Ch 17 on The Debugger
Grading Policy
- Check-off 30%: Demonstrate to a TA that a student understands answers to questions. This must be done in person in groups of one or two. Check-offs can happen during the lab period of during a TA office hour.
- Submit 70%: Submit required files according to the lab instruction. This can be done at any time and from anywhere with a network connection. Submitting does not require attending lab. All students must submit files even if they were checked off in a group during lab.
See the full policy in the syllabus.
2 Codepack
The codepack for the lab contains the following files:
File | State | Description |
---|---|---|
QUESTIONS.txt |
Edit | Answer questions in the file to complete the lab |
buggy_lpe.ml |
Edit | Problem 1/2 file to analyze and edit |
lpe_main.ml |
Edit | Main function which allows experimentation with expression evaluation |
3 Questions
Analyze the files in the provided codepack and answer the questions
given in QUESTIONS.txt
.
__________________ LAB 12 QUESTIONS __________________ - Name: (FILL THIS in) - NetID: (THE kauf0095 IN kauf0095@umn.edu) Answer the questions below according to the lab specification. Write your answers directly in this text file and submit it to complete the lab. Files `buggy_lpe.ml' and `lpe_main.ml' ====================================== Like previous labs, this lab deals with a lexer, parser, evaluator system for a small language that includes arithmetic and `let/in' expressions. There are some bugs in the basic implementation though. PROBLEM 1: Debugger Basics ========================== (A) ~~~ Compile the two source files together to create an executable. Make sure that debug information is turned on via the `-g' switch as in ,---- | > ocamlc -g buggy_lpe.ml lpe_main.ml | File "buggy_lpe.ml", line 249, characters 5-42: | Warning 10: this expression should have type unit. `---- Note that the warning shown is likely to be shown and will be addressed later in the lab. Run the program as shown which should generate an exception. ,---- | ./a.out 'let x=5 in x+2' `---- Show the results of this exception in the terminal which should be a bit perplexing. While it might be possible to diagnose the problem simply by examining the source code carefully, the remainder of this problem will demonstrate how to use the debugger to gather information that can lead to a fix. (B) ~~~ Start the debugger with the compiled program as in: ,---- | > ocamldebug a.out | OCaml Debugger version 4.xx | | (ocd) `---- Since the `lpe_main.ml' program must take command line arguments, set them using the `set arguments <args>' command as in ,---- | (ocd) set arguments 'let x=5 in x+2' `---- Run the program with the `run' command and copy the results below. (C) ~~~ A major strength of OCaml's debugger is it enables so-called "time-traveling" allowing both forward and backward steps. A standard debugger such as is widely available in C and Java allows only forward steps, not backwards. The technique that enables ocamldebug this is not conceptually not difficult: it simply saves program state occasionally as a 'checkpoint' and when one requests backwards movement, the program position is noted and the program is restarted from the latest checkpoint to the desired moment in time. As an end user, this means on hitting an uncaught excepton, one can simply back up a step to see what is happening using the `backstep' command. Moving forward is a matter of issuing a `step' command. Do some backsteps and steps after hitting the exception from the last part. Paste the results below. (D) ~~~ Next set some *breakpoints* at functions of interest which will stop the debugger from executing when reached. If an uncaught exception has been hit, all of the modules associated with program are already loaded one can use the name of the function to set the breakpoint as in: ,---- | (ocd) break Buggy_lpe.parse_muldiv | Breakpoint 1 at 145252: file buggy_lpe.ml, line 137, characters 3-348 `---- Follow this with the `reverse' command which will run the program in "reverse" until the break point is hit. After hitting it, run the `list' and `backtrace' commands and paste the results below. Breakpoints from the beginning of Programs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When running from the beginning of a program, not all modules are loaded so functions may not be identifiable by name. In this case, set breakpoints at specific source lines like the below where 136 is the source line corresponding to the `parse_muldiv' function. ,---- | (ocd) break @ Buggy_lpe 136 | Loading program... done. | Breakpoint 1 at 145252: file buggy_lpe.ml, line 137, characters 3-348 `---- PROBLEM 2: Debugging the Program ================================ (A) ~~~ After positioning the debugger as indicated above, print the `toks' variable then use the `step' command to step through the execution of `parse_muldiv'. - What token is at the front of the token list? - Does the control flow seem to make sense for parsing a the tokens at the beginning of the token list? - After examining the source code, is the function call sequence appropriate or should changes be made? - Describe the bug that is in the source code and how to fix it. (B) ~~~ After identifying the bug in the parser, make a change to fix it. Quit the debugger (via `quit'), recompile, re-run the program on the problem input to show some progress has been made. Paste your results below and state how the results differ. (C) ~~~ Start the debugger again, set the arguments, and run to the uncaught exception. Backstep and then use `list' to show the source position. The trouble at this point should be apparent: something is wrong with the `varmap'. Unfortunately, the debugger is not equipped to print standard Maps as evidenced by failed attempt to print: ,---- | > ocamldebug a.out | | (ocd) set arguments 'let x=5 in x+2' | (ocd) run | Uncaught exception: Buggy_lpe.EvalError "No variable 'x' bound" | | (ocd) backstep | | (ocd) print varmap | varmap: varval_t Varmap.t = <abstr> `---- This output is hidden behind an abstraction barrier. One can install "printers" which will display data for maps and other more customized types but this is beyond the scope of the lab. Rather, turn your attention to the warning that has been issued on every compilation. Examine the associated code and describe what is being done wrong. (D) ~~~ Fix the evaluation error, recompile, and show that the trouble code now evaluates correctly. Show your corrected lines of code in `buggy_lpe.ml' and the results of running on the input. Optional Extras =============== Another Bug ~~~~~~~~~~~ There is another bug present in `buggy_lpe.ml'. Attempt to diagnose and fix it. Hint: examine the results of the differences between the following two evaluations. ,---- | > ./a.out '10-let x=2*3 in x' | ... | > ./a.out '10-2*3' | ... `---- if/then/else (from lab 11) ~~~~~~~~~~~~~~~~~~~~~~~~~~ Currently the lexer/parser/evaluator does not handle numeric comparisons to produce boolean results such as ,---- | 5 < 2 -> Bool false | if 1+2 > 0 then 8 else 4 -> Int 8 `---- This will be a required part of the final assignment interpreter so it would be an excellent exercise to extend the system to handle these new expression types. - Extend the lexer to include < and >. The = sign is already part of the lexer. - Extend the expression type to include comparison expressions for Less, Greater, Equal with constituent left/right expressions (like arithmetic). - Extend the parser functions with a new function to parse comparisons. This should occur at a lower precedence than arithmetic. - Extend the evaluator to include evaluation cases for comparisons. These should check that their left/right expressions are integers, do the appropriate comparison on the numbers, and return a Bool. You may wish to model them after the arithmetic evaluation code.
4 What to Understand
Ensure that you understand
- Basics of starting the debugger, setting command line arguments, and running programs.
- The capability to run forwards with
step
andrun
or in reverse usingbackstep
andreverse
. - How to set breakpoints and print variable values during debugging sessions.
5 Getting Credit: Submit and Check-off
- Check-off your answers with a TA in person during lab or office hours.
- Submit your completed
QUESTIONS.txt
file to Canvas under the appropriate lab heading. Make sure to paste in any new code and answers you were to write at appropriate locations in the file.