Franck Pommereau

done lang/c.py, added README

1 +codanim: Animated code & data structures with LaTeX/beamer
2 +
3 + (C) 2020 Franck Pommereau <franck.pommereau@univ-evry.fr>
4 + This is free software, see file LICENCE
5 +
6 +codanim allows to generate LaTeX/TikZ code to animate source code and
7 +data structures for beamer presentations. So far, it is oriented to
8 +simulate C code, but there is no conceptual limitation for the
9 +simulation of other languages.
10 +
11 +codanim is currently highly experimental and neither well documented
12 +nor well tested. You've been warned.
13 +
14 +## INSTALL
15 +
16 +There is so far no installation procedure. Just copy directory
17 +`codanim` somewhere in your `PYTHONPATH`.
18 +
19 +File `examples/pygments.sty` will be needed to compile the final LaTeX
20 +files. File `examples/tpl.tex` shows how the generated LaTeX code may
21 +be included in a beamer presentation.
22 +
23 +## CONCEPTS
24 +
25 +codanim defines Python classes to simulate the data and control-flow
26 +structures of an imperative language. Data structures are defined in
27 +`codanim.data` and include:
28 +
29 + * `Pointer(data)` a pointer to another data `data`
30 + * `Value(value)` an arbitrary value, initialised to `value`. If
31 + `value` is `None` (the default), the value is considered
32 + uninitialised
33 + * `Array(init, index=[])` an array of values, that is zero-indexed,
34 + and initialised as follows:
35 + * if `init` is an `int`, then it is the length of the array whose
36 + values are all uninitialised
37 + * if `init` is a `list` then is holds the initial values of the
38 + array
39 + `index` is a list of variables identifiers that may be used to
40 + access the array cells (see below)
41 + * `Struct(init)` a structure whose fields and initial values are
42 + defined by `init` that must be a `dict`
43 + * `Heap()` a container for dynamically allocated data that provides
44 + methods `new` and `free` to do so
45 +
46 +Control-flow structures are used to simulate within Python code that
47 +may potentially be written in any imperative language. Doing so, all
48 +the changes that are made to the data structures defined above are
49 +recorded so that they may be latter animated, consistently with the
50 +animation of the code itself. The idea is that source code in the
51 +simulated language is split into corresponding control-flow
52 +structures, and actual computation is done using equivalent Python
53 +code instead of executing the code in the source language.
54 +Control-flow structures are defined in `codanim.flow` and include:
55 +
56 + * `RAW(src='...')` raw code from the simulated language, its
57 + simulation is no-op, but it is rendered highlighted in the final
58 + animation
59 + * `WS(src='...')` just like `RAW` but should be only white spaces (so
60 + that it won't be highlighted)
61 + * `BLOCK(*body)` a group of other structures that are simulated (and
62 + rendered) sequentially
63 + * `STMT(*steps, src='...')` an arbitrary statement that is simulated
64 + by running its`steps` sequentially, each of which being an
65 + arbitrary Python statement that is `exec`ed
66 + * `EXPR(expr, src='...')` an arbitrary Python expression `expr` that
67 + simulate an expression in the simulated language
68 + * `PY(code)` an arbitrary Python statement that need to be executed
69 + but is not rendered in the final animation, just like every
70 + structure that expects no `src='...'` argument
71 + * `ENV(name, value)` a data structure that need to be defined in
72 + order to do the simulation (typically: global or external
73 + variables), and which is stored into variable `name` that can be
74 + used from the Python code of statements and expression
75 + * `DECL(name, init=None, animate=False, src'...')` an actual variable
76 + declaration in the simulated language, that will be executed and
77 + rendered. The execution consists of evaluating `init` that should
78 + be an `EXPR` (or `None`) and assigning its value to `name`. If
79 + `animate` is `True` then the value of the variable will displayed
80 + within a comment just next to the declaration in the final
81 + animation
82 + * `XDECL(*names, src='...')` several uninitialised declarations
83 + * `BREAK` a `break` instruction for loops and switches
84 + * `RETURN(value, src='...')` a return instruction from a function
85 + * `IF(cond, then, otherwise=None, src='...')` simulates an `if` block
86 + with an optional `else` part (called `otherwise` since `else` is a
87 + Python keyword. Argument `cond` should be an `EXPR` instance
88 + * `WHILE(cond, body, src='...')` simulates a `while` loop
89 + * `DO(body, cond, src='...')` simulates a `do/while` loop
90 + * `FOR(init, cont, step, body)` simulates a C-like `for` loop
91 + * `FUNC(body, src='...')` simulates a function
92 + **TODO:** functions calls is not implemented yet, so basically, a
93 + function is so far only a `BLOCK` with source code
94 + * `SWITCH(cond, *cases, src='...')` simulates a C-like switch,
95 + `cases` may be:
96 + * `CASE(value, body)` to simulate a `case` statement
97 + * `DEFAULT()` to simulate a `default` statement
98 +
99 +So, all what you need is to defined some data structures, some
100 +control-flow structures with appropriate `src` arguments (so that code
101 +is rendered in the simulated language), and with appropriate Python
102 +code to simulate the original statements and expressions.
103 +
104 +Writing the control-flow structures may be tedious, so codanim may be
105 +called from the command line to parse actual code to be simulated and
106 +generate the appropriate control-flow structures (in which the Python
107 +code remains to be written). Run `python -m codanim` for help.
108 +
109 +## EXAMPLES
110 +
111 +File `examples/Makefile` can be used to build the PDF for all the
112 +examples. For instance use `make heap.pdf` to build the first example
113 +described below.
114 +
115 +### `examples/heap.py`
116 +
117 +It defines a `Heap` instance and add chained `Struct`s to it. The
118 +final picture is rendered as TikZ code. There is no animation, this is
119 +just the picture of a chained list.
120 +
121 +### `examples/stack-push.py`
122 +
123 +It uses the same kind of linked lists as above, seen as stacks, to
124 +animate a push onto a stack. First the data is defined, then the
125 +control-flow structure. The latter is then simulated and finally, both
126 +code and data structures are rendered for LaTeX/beamer inclusion.
127 +
128 +Note the use of class `Box` that can be used to layout several data
129 +structures.
130 +
131 +### `examples/qs-partition.py` and `examples/qs-main.py`
132 +
133 +The partitioning and main algorithm of a quick-sort. This shows how to
134 +use `Array`, in particular the `index` argument. `qs-main` also shows
135 +how to define custom layout of arrays, as well as auxiliary Python
136 +functions to simulate full C-functions calls in one step.
1 +import argparse, pathlib, importlib, sys
2 +from . import lang as _lang
3 +
4 +languages = {}
5 +
6 +for path in pathlib.Path(_lang.__file__).parent.glob("*.py") :
7 + module_name = path.with_suffix("").name
8 + if module_name == "__init__" :
9 + continue
10 + module = importlib.import_module(f".lang.{module_name}", package="codanim")
11 + languages[module_name.lower()] = module
12 +
13 +class ListLang (argparse.Action) :
14 + def __call__ (self, parser, *l, **k) :
15 + print("Supported languages:")
16 + width = max(len(l) for l in languages) + 4
17 + for lang, module in sorted(languages.items()) :
18 + print((" - {lang:<%s} {help}" % width).format(lang=lang,
19 + help=module.translate.__doc__))
20 + parser.exit(0)
21 +
22 +parser = argparse.ArgumentParser(
23 + prog="codanim",
24 + description="parse code and generate Python stub suitable for codanim")
25 +
26 +parser.add_argument("-l", "--lang",
27 + default=None,
28 + help="language to be parsed (default: guess from file name)")
29 +parser.add_argument("-L", "--list-lang", nargs=0,
30 + action=ListLang,
31 + help="list supported languages")
32 +parser.add_argument("-o", "--output", type=argparse.FileType("w"),
33 + default=sys.stdout,
34 + help="output file")
35 +parser.add_argument("SOURCE", type=argparse.FileType("r"),
36 + help="source file")
37 +args = parser.parse_args()
38 +
39 +if args.lang is None :
40 + args.lang = args.SOURCE.name.rsplit(".")[-1]
41 +
42 +args.lang = args.lang.lower()
43 +
44 +if args.lang not in languages :
45 + parser.error("unsupported language: %r" % args.lang)
46 +
47 +translate = languages[args.lang].translate
48 +
49 +args.output.write(repr(translate(args.SOURCE.read())) + "\n")
...@@ -385,3 +385,13 @@ class Translator (object) : ...@@ -385,3 +385,13 @@ class Translator (object) :
385 return default 385 return default
386 def do_Break (self, node) : 386 def do_Break (self, node) :
387 return flow.BREAK() 387 return flow.BREAK()
388 +
389 +##
390 +## CLI interface
391 +##
392 +
393 +def translate (code) :
394 + "the C language"
395 + a = parse(code)
396 + t = Translator()
397 + return t(a)
......