├── COPYRIGHT ├── README.txt ├── lua └── annotations.txt └── luaannotate.lua /COPYRIGHT: -------------------------------------------------------------------------------- 1 | LuaAnnotate License 2 | 3 | Copyright (C) 2010 David Manura 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | =============================================================================== 24 | 25 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | LuaAnnotate - C code comments externally stored but displayed inline. 2 | 3 | LuaAnnotate is a tool for displaying C source file comments inline to 4 | the source but stored in a separate file. The comments are maintained 5 | in a text file (annotate.txt) in the same directory as the C sources. 6 | Displaying the comments inline to the C code can be done in many ways: 7 | 8 | - weaving the comments into the source code as C comments and saving 9 | the result to a temporary file for viewing in any text editor. 10 | - displaying comments as annotations in the SciTE text editor when viewing 11 | the original source files (without altering those source files). 12 | - other possibilities (not implemented) include rendering as HTML 13 | or creating plugins for other text editors. 14 | 15 | The original motivation for this project is to allow Lua users to better 16 | document the Lua source code [2]. The Lua source code is dense 17 | but sparsely commented. It's uncertain whether the original Lua authors 18 | will incorporate generous use of comments in the original upstream 19 | sources, so we need to maintain the comments separately. 20 | This becomes challenging when the upstream sources change 21 | and users themselves may maintain their own set of patches. 22 | The problem with using unified patches here is that the contextual 23 | information contained is more detailed than necessary and its conflict 24 | checking is more strict than necesessary. All the comment data really 25 | needs to say is that a certain identifier corresponds with a certain piece of 26 | documentation, almost in the manner of ctags. Furthermore, if such an 27 | identifier cannot be matched in the source, we don't care that much 28 | --it's just documentation. 29 | 30 | == Project Page == 31 | 32 | For further details, see http://lua-users.org/wiki/LuaAnnotate . 33 | 34 | == Status == 35 | 36 | WARNING: This code is very new and might not be stable yet. 37 | It is usable but you may need to sometimes fix things yourself. 38 | Many additional features could be added too. 39 | 40 | == Example === 41 | 42 | See the "lua\annotations.txt" for an example of an annotations file 43 | for the Lua 5.2.0-alpha sources. To use, copy annotations.txt into 44 | the Lua "src" directory. 45 | 46 | Note: This annotations.txt example currently only documents a few items 47 | in the Lua sources. It should be extended to the extire Lua sources. 48 | Patches are welcome. 49 | 50 | == Command-line Usage (C++ output) == 51 | 52 | Example: 53 | 54 | $ cp lua/annotations.txt ../lua-5.2.0-alpha/src/ 55 | $ lua luaannotate.lua ../lua-5.2.0-alpha/src/luac.c > luac-annotated.c 56 | 57 | == Installation in SciTE == 58 | 59 | First install SciTE . 60 | Version 2.12 and 2.20 work (older versions might not work). 61 | 62 | Install SciTE ExtMan: http://lua-users.org/wiki/SciteExtMan . 63 | 64 | Copy luaannotate.lua into your ExtMan "scite_lua" scripts folder. 65 | 66 | Now when you restart SciTE and load a C file that has an annotations.txt 67 | file in the same directory, SciTE will render the annotations inline to the 68 | source file. 69 | 70 | == LICENSE == 71 | 72 | See COPYRIGHT file. 73 | 74 | == Credits == 75 | 76 | David Manura, original author. 77 | Steve Donovan originally suggested this. 78 | 79 | == Bugs == 80 | 81 | Please report bugs via github 82 | or just "dee em dot el you ae at em ae tee ayche two dot ow ar gee", or 83 | if you prefer neither then append to the wiki page 84 | . 85 | 86 | == References == 87 | 88 | [1] http://www.scintilla.org/SciTE.html 89 | [2] lua-users.org/wiki/LuaSource 90 | -------------------------------------------------------------------------------- /lua/annotations.txt: -------------------------------------------------------------------------------- 1 | # lauxlib.h: 2 | This is the public interface of the "Auxiliary Library". 3 | 4 | # lauxlib.h:luaL_newlib 5 | int luaL_newlib (lua_State *L, const luaL_Reg *l); 6 | [-0, +1, m] 7 | 8 | # lauxlib.h:luaL_argcheck 9 | void luaL_argcheck (lua_State *L, int cond, int narg, const char *extramsg); 10 | [-0, +0, v] 11 | 12 | # lcode.h:getcode 13 | FuncState*, expdesc* -> int 14 | 15 | # llimits.h:MAXSTACK 16 | Note: must fix in byte (lu_byte)--see Proto::maxstacksize. 17 | 18 | # lua.h: 19 | This is the public interface to the core Lua library. 20 | 21 | # lua.h:LUA_VERSION_NUM 22 | This is the number exposed by lua_version(). 23 | Note: 502 mean "5.2". 501 means "5.1" 24 | 25 | # lua.h:LUA_SIGNATURE 26 | Lua bytecode always starts with a signature consisting 27 | of these bytes. Both Lua 5.1 and 5.2 start with this 28 | signature. Some functions like load() determine whether 29 | a file is Lua source code or Lua byte code by looking 30 | for this signature. The \033 (escape) character is not 31 | a valid first character in Lua source code. 32 | 33 | # lua.h:LUA_ERRERR 34 | Note: see also LUA_ERRFILE in lauxlib.h. 35 | 36 | # lua.h:LUA_NUMTAGS 37 | This must always be set to one more than the 38 | maximum LUA_T* value above. 39 | 40 | # lua.h:LUA_MINSTACK 41 | From the reference manual: 42 | Whenever Lua calls C, it ensures that at least 43 | LUA_MINSTACK stack positions are available. 44 | LUA_MINSTACK is defined as 20, so that usually 45 | you do not have to worry about stack space 46 | unless your code has loops pushing elements 47 | onto the stack. 48 | 49 | # lua.h:LUA_RIDX_MAINTHREAD 50 | From the reference manual: At this index the 51 | registry has the main thread of the state. 52 | (The main thread is the one created together 53 | with the state.) 54 | 55 | # lua.h:LUA_RIDX_GLOBALS 56 | From the reference manual: At this index the 57 | registry has the global environment. This is the 58 | C equivalent to the _G global variable. 59 | 60 | # lua.h:LUA_RIDX_LAST 61 | This must always be set to the maximum LUA_RIDX 62 | value above. 63 | 64 | # lua.h:lua_Number 65 | Typically set to double on PCs. 66 | 67 | # lua.h:lua_Integer 68 | Typically set to int (32-bit) on PCs. 69 | 70 | # lua.h:lua_Unsigned 71 | Typically set to unsigned int on PCs. 72 | 73 | # luac.c: 74 | This is the Lua compiler front-end (luac). 75 | 76 | Note: Comments based on Lua 5.2.0-alpha. 77 | 78 | # luac.c:fatal 79 | Utility function to display fatal error message 80 | and exit (without cleanup). 81 | 82 | # luac.c:cannot 83 | Utility function display fatal I/O error 84 | and exit (without cleanup). 85 | 86 | # luac.c:usage 87 | Writes command-line help to standard error 88 | and exit (without cleanup) 89 | 90 | # luac.c:doargs 91 | Parse main's command line arguments. 92 | May exit without cleanup. 93 | 94 | # luac.c:FUNCTION 95 | used by luac.c:reader 96 | 97 | # luac.c:reader 98 | lua_Reader function that outputs Lua source code consisting of 99 | a series of "(function()end)();" repeated by the number of times 100 | in integer *ud. 101 | 102 | This is used to generate the initial bytecode needed by 103 | luac when compiling multiple files (chunks) together. This bytecode 104 | is later patched with the addresses of the real chunks. 105 | 106 | # luac.c:combine 107 | On exit, the top of the stack will contain a function that calls 108 | the previous top-most n values (functions) on the stack. 109 | 110 | This is used to generate the initial bytecode needed by 111 | luac when compiling multiple files (chunks) together. 112 | 113 | # luac.c:writer 114 | lua_Writer function used to dump generated bytecode to a file. 115 | 116 | # luac.c:pmain 117 | Main code, protected by pcall. 118 | 119 | # luac.c:main 120 | Main code, entry point. 121 | 122 | # luac.c:PrintString 123 | Dump string object (quoted and escaped) to standard output. 124 | 125 | # luac.c:PrintConstant 126 | Dump i-th constant in function prototype f. 127 | 128 | # luac.c:PrintCode 129 | Dump all opcodes in function prototype f. 130 | 131 | # luac.c:PrintHeader 132 | Dump metadata on function prototype f. 133 | 134 | # luac.c:PrintDebug 135 | Dump all constants/locals/upvalues in function prototype f. 136 | 137 | Used by undocumented "luac -l -l". 138 | 139 | # luac.c:PrintFunction 140 | Dump function prototype f. 141 | If full (0 or 1) is 1, invokes PrintDebug. 142 | 143 | # lparser.c:hasmultret 144 | Whether expkind k has multiple return values. 145 | 146 | # lparser.c:NILCONSTANT 147 | Use for structure initializer of TValue object representing nil. 148 | 149 | # lparser.c:ttype 150 | Returns a LUA_T* value. 151 | 152 | # lobject.h: 153 | This files provides the types an operations on for handling 154 | values (TValue objects) in Lua. 155 | 156 | # lobject.h:ttisnil 157 | Checks whether TValue o is nil. 158 | 159 | # lobject.h:ttisnumber 160 | Checks whether TValue o is of type number. 161 | 162 | # lobject.h:ttislcf 163 | Checks whether TValue o is a Lua function (or C function exposed 164 | to Lua, not including light C functions). Such functions have 165 | a prototype (see getproto) 166 | 167 | # lobject.h:ttislcf 168 | Checks whether TValue o is a light C function (lua_CFunction). 169 | 170 | # lobject.h:pvalue 171 | Gets void pointer in TValue o. 172 | 173 | # lobject.h:nvalue 174 | Gets number (lua_Number) in TValue o (or asserts if not number). 175 | 176 | # lobject.h:rawtsvalue 177 | Gets string (TString) in TValue o. 178 | 179 | # lobject.h:tsvalue 180 | Gets string header (TString.tsv) in TValue o. 181 | 182 | # lobject.h:uvalue 183 | Gets userdata header (Udata.uv) in TValue o. 184 | 185 | # lobject.h:clvalue 186 | Gets closure (Closure - GCObject.cl) in TValue o. 187 | 188 | # lobject.h:fvalue 189 | Gets light C function (lua_CFunction) in TValue o. 190 | 191 | # lobject.h:hvalue 192 | Gets table (Table - GCobject.h) in TValue o. 193 | 194 | # lobject.h:bvalue 195 | Gets boolean (int) value in TValue o. 196 | 197 | # lobject.h:thvalue 198 | Gets thread lua_State (GCObject.th) value in Tvalue o. 199 | 200 | # lobject.h:l_isfalse 201 | Gets whether TValue o evaluates to false (i.e. is nil or false). 202 | 203 | # lobject.h:setnvalue 204 | Sets value of TValue obj to number (lua_Number) x. 205 | 206 | # lobject.h:setfvalue 207 | Sets value of TValue obj to light C function (lua_CFunction) x. 208 | 209 | # lobject.h:setfvalue 210 | Sets value of TValue obj to light user data (void*) x. 211 | 212 | # lobject.h:setbvalue 213 | Sets value of TValue obj to boolean (int 0..1) x. 214 | 215 | # lobject.h:svalue 216 | Note: TValue o -> const char *. 217 | 218 | # lobject.h:Udata 219 | Note: each (heavyweight) userdata can be associated with a metatable 220 | and a user value (previously called a "userdata environment table") set 221 | via lua_setuservalue. 222 | A userdata is garbage collectable CommonHeader) and is allocated 223 | as a series of `len` bytes in Lua's own memory. 224 | 225 | # lobject.h:Upvaldesc 226 | Note: compare to Upval. 227 | 228 | # lobject.h:Proto 229 | Every definition of a Lua function (or C function exposed as a Lua function) 230 | is represented with a function prototype object. 231 | This contains things like a list of bytecode instructions (code), 232 | links to other constant data used by the functions 233 | (constants, nested functions, and upvalue descriptions), and other 234 | metadata (e.g. debugging info). 235 | 236 | For each function prototype, any number of values may be 237 | instantiated (allocated) based on that prototype. For example, this: 238 | 239 | local t = {} 240 | for i=1,10 do 241 | t[i] = function() return i end 242 | end 243 | 244 | creates 10 function objects that all link to the same prototype of 245 | "function() return i end". 246 | 247 | # lobject.h:Upvaluedesc. 248 | Compare to UpVal, which are stored in closures (instantiations of 249 | prototypes). 250 | 251 | # lobject.h:UpVal 252 | This represents upvalues. They are stored in a closure value (LClosure). 253 | Compare to Upvaldesc. 254 | 255 | # lobject.h:Closure 256 | Represents a closure (implemented via C Function or Lua function). 257 | These are linked to TValue's, among other places. 258 | 259 | # lobject.h:getproto 260 | Gets the prototype (Prototype) of TValue o (assumed to be a 261 | function, not a lightweight C function). 262 | 263 | # lobject.h:Table 264 | Represents a Lua table ({}). 265 | These are linked to TValues. 266 | 267 | Note: each table can have an optional metatable and can have 268 | an array part (stored in array `array` of length `sizearray` and 269 | a hash part (stored in array `node` of length encoded in `lsizenode`). 270 | 271 | You can quickly check for certain metamethods via the `flags` field 272 | rather than looking in the metatable. 273 | 274 | # lobject.h:twoto 275 | Efficiently raises 2 to the integer x power. 276 | 277 | # lopcodes.h:getarg 278 | Gets size bits starting at offset pos in Instruction i. 279 | Example: getarg(0x12345678,4,8) == 0x67 280 | 281 | # lopcodes.h:setarg 282 | Sets (in-place) size bits starting at offset pos in Instruction i to v. 283 | Example: Instruction i = 0x12345678; setarg(i,0x76,4,8); assert(i == 0x12345768); 284 | 285 | # lopcodes.h:GETARG_A 286 | Gets integer A fields bits of Instruction i. 287 | 288 | # lopcodes.h:SETARG_A 289 | Sets (in-place) A field bits of Instruction i to integer v. 290 | 291 | # lopcodes.h:CREATE_ABC 292 | Returns Instruction formed from opcode (OpCode) o and given integer A, B, C fields. 293 | 294 | # lcode:isnumeral 295 | Determines whether expression represents a number that is a known constant. 296 | Note: constant numbers can be used in expression folding (compile time evaluation). 297 | Careful on jumps (true (t) and false (f) patch lists). 298 | 299 | # lcode.c:luaK_ret 300 | Encode opcode for "return" (OP_RETURN). 301 | Note: (first,nret)=(0,0) means return no values. nret == LUA_MULTRET means return all 302 | values starting at first (useful for vararg expressions). 303 | 304 | # lcode.c:luaK_checkstack 305 | Updates function state's maximum needed stack size (maxstacksize) given that 306 | n additional registers will be needed. Raises syntax error if above limit (MAXSTACK). 307 | 308 | # lcode.c:luaK_reserveregs 309 | Like luaK_checkstack but also reserves those n additional registers. 310 | 311 | # lcode.c:freereg 312 | This complements luaK_reserveregs. It frees the top-most reserved register. 313 | But it only does this if reg is actually a register (not an index in the constant table) 314 | and it's not used for storage of a local variable (the lowest nactvar values on the stack). 315 | 316 | # lcode.c:addk 317 | Adds a constant with name `key` and value v to the function state's constant table 318 | (i.e. array k of size sizek where first nk values are used). 319 | Duplicates are detected and avoided via the helper table 'h', which maps each existing 320 | value in the constant table to an integer index in the constant table. The constant 321 | table allocated size may need to be grown (and new empty space filled 322 | with nil's) prior to inserting the constant. (TODO-comment on luaC_barrier?) 323 | Returns 0-based index of the new constant in the constant table. 324 | 325 | # lcode.c:luaK_stringK 326 | Adds a string to the constant table (addk). 327 | Note: stores in TValue first. 328 | 329 | # lcode.c:luaK_numberK 330 | Adds a number to the constant table (addk). 331 | (TODO: comment on "numeric problems") 332 | 333 | # lcode.c:boolK 334 | Adds a boolean (0 or 1) to the constant table (addk). 335 | 336 | # lcode.c:nilK 337 | Adds a nil to the constant table (addk). 338 | Note: the helper table 'h' (see addk) normally maps constant values to indicies in the 339 | constant table, but the constant value is nil here, which Lua tables don't allow. 340 | So, following a design pattern in , 341 | we use another unique value instead as its placeholder, which here is 342 | convenient to use the h table itself, which is never used outside of the compiler 343 | internal and therefore has no chance of misinterpretation. 344 | h is a Table, which we wrap in a TValue before doing addk. 345 | 346 | # lcode.c:constfolding 347 | Attempts to constant fold (i.e. evaluate at compile time as an optimization) the given 348 | operation on the two expressions. 349 | Folding is attempted only on operations on numbers that are known constants 350 | (e.g. `local x = 1+1` -> `local x = 2`). Moreover, constant folding is skipped on 351 | division (or modulo) by zero (resulting in not-a-number, NaN), which Lua 5.1 folded 352 | but it caused problems so this folding was eliminated in Lua 5.2. 353 | Returns 1 (not 0) if folding was possible. 354 | --see . 355 | 356 | # ltable.h:gnode 357 | Table*, int -> Node* 358 | Gets i-th node in table's hashpart array. 359 | (Question: why isn't there a corresponding function 360 | to get the i-th node in table's arraypart array? or why 361 | have this macro at all?) 362 | 363 | # ltable.h:gkey 364 | Node* -> TValue* 365 | Gets node key's TValue. 366 | 367 | # ltable.h:gval 368 | Node* -> TValue* 369 | Gets node value's TValue. 370 | 371 | # ltable.h:gnext 372 | Node* -> Node* 373 | Gets node following given node in chain of nodes. 374 | -------------------------------------------------------------------------------- /luaannotate.lua: -------------------------------------------------------------------------------- 1 | -- luaannotate.lua 2 | -- (C) 2010, David Manura 3 | 4 | 5 | -- Load annotations file. 6 | local function load_annotations(path) 7 | local filename = path:match'[^\\/]+$' 8 | if not filename then 9 | error('Invalid path ' .. path) 10 | end 11 | 12 | local annotations = {} 13 | local id 14 | local text = '' 15 | local function commit() 16 | if id then 17 | --print('DEBUG-luacomment-commit', id, text) 18 | text = text:gsub('[\r\n]$', '') 19 | annotations[id] = text 20 | end 21 | end 22 | 23 | -- Process line-by-line. 24 | local fh = assert(io.open(path)) 25 | local linenum = 1 26 | for line in fh:lines() do 27 | if line:match'^#' then 28 | commit() 29 | local sfile, sname = line:match'^#%s*([^:]+):([%w_]*)' 30 | if not sfile then 31 | error('Invalid directive in ' .. path .. ':' .. linenum) 32 | end 33 | text = '' 34 | id = sfile .. ':' .. sname 35 | else 36 | text = text .. (text ~= '' and '\n' or '') .. line 37 | end 38 | linenum = linenum + 1 39 | end 40 | commit() 41 | 42 | return annotations 43 | end 44 | 45 | -- Locates where annotations should go in source string `code` 46 | -- in file path `path`. 47 | local function place_annotations(code, path, annotations) 48 | local sfile = path:match'[^\\/]+$' 49 | 50 | local notes = {} 51 | 52 | -- Comments on functions/macros/structs 53 | -- TODO: could be improved (robustness) 54 | local iline = 1 55 | for line in (code .. '\n'):gmatch'(.-)\r?\n' do 56 | local sname = 57 | line:match'^[%w_ ]-[%w_*]+%s([%w_]+)%s*%b()%s*%{?$' or 58 | line:match'^#define%s+([%w_]+)' or 59 | line:match'^typedef%s+struct%s+([%w_]+)' or 60 | line:match'^typedef%s+union%s+([%w_]+)' or 61 | line:match'^typedef%s+.*%s+([%w_]+);' 62 | if sname then 63 | local id = sfile .. ':' .. sname 64 | local comment = annotations[id] 65 | --print('DEBUG-luacomment-comment', comment, id) 66 | if comment then 67 | table.insert(notes, {iline, comment}) 68 | end 69 | end 70 | iline = iline + 1 71 | end 72 | 73 | -- Comments on file. 74 | local filecomment = annotations[sfile .. ':'] 75 | if filecomment then 76 | if notes[1] and notes[1][1] == 1 then -- existing comment on line 1 77 | local comment = filecomment .. '\n\n' .. notes[1][2] 78 | notes[1][2] = comment 79 | else 80 | table.insert(notes, 1, {1, filecomment}) 81 | end 82 | end 83 | 84 | return notes 85 | end 86 | 87 | -- Utility function to check whether file exists (actually, is readable). 88 | local function exists_file(path) 89 | local fh = io.open(path) 90 | if fh then fh:close() return true end 91 | return false 92 | end 93 | 94 | -- Utility function to load file into string (text mode). 95 | local function read_file(path) 96 | local fh, err = io.open(path) 97 | if not fh then 98 | error('Could not open ' .. path .. ' : ' .. err) 99 | end 100 | local data = fh:read'*a' 101 | fh:close() 102 | return data 103 | end 104 | 105 | -- SciTE specific 106 | if scite_OnOpen then -- if ExtMan installed 107 | -- Add annotation notes to SciTE buffer. 108 | local function scite_annotate_buffer(notes) 109 | editor.AnnotationVisible = 2 110 | for _, note in ipairs(notes) do 111 | local iline, comment = unpack(note) 112 | editor:AnnotationSetText(iline-1, comment) 113 | --editor:AnnotationStyle[iline] = 1 114 | end 115 | end 116 | 117 | -- SciTE ExtMan callback function, on file opened. 118 | scite_OnOpen(function(path) 119 | local annotations_path = path:gsub('[^\\/]+$', 'annotations.txt') 120 | print('DEBUG-luacomment-open', path, annotations_path) 121 | if exists_file(annotations_path) then 122 | local code = editor:GetText() 123 | local annotations = load_annotations(annotations_path) 124 | local notes = place_annotations(code, path, annotations) 125 | scite_annotate_buffer(notes) 126 | end 127 | end) 128 | 129 | return 130 | end 131 | 132 | -- Escapes characters in text to allow embedding inside C comment (/* */). 133 | local function cpp_escape_comment(text) 134 | text = text:gsub('%*/', '* /') 135 | return text 136 | end 137 | 138 | -- Adds annotations to code. 139 | local function cpp_annotate(code, notes) 140 | local commentofline = {} -- index 141 | for _, linecomment in ipairs(notes) do 142 | local iline, comment = unpack(linecomment) 143 | commentofline[iline] = comment 144 | end 145 | 146 | -- TODO: could be improved: avoid nested comments 147 | local iline = 1 148 | code = (code .. '\n'):gsub('(.-\r?\n)', function(line) 149 | if commentofline[iline] then 150 | line = '/*# ' .. cpp_escape_comment(commentofline[iline]) .. '*/\n' .. line 151 | end 152 | iline = iline + 1 153 | return line 154 | end) 155 | return code 156 | end 157 | 158 | -- Command-line usage: lua luacomment.lua 159 | local path = ... 160 | if path then 161 | local annotations_path = path:gsub('[^\\/]+$', 'annotations.txt') 162 | local code = read_file(path) 163 | local annotations = load_annotations(annotations_path) 164 | local notes = place_annotations(code, path, annotations) 165 | code = cpp_annotate(code, notes) 166 | io.stdout:write(code) 167 | else 168 | io.stderr:write('usage: luaannotate.lua ') 169 | os.exit(1) 170 | end 171 | --------------------------------------------------------------------------------