Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
-- peek.lua - a tool to inspect C data structures from Lua
-- This was developed as part of the DaVinci project.
-- Project page: <http://angg.twu.net/davinci.html>
--         also: <http://angg.twu.net/peek.html>
--               <http://angg.twu.net/middle-c.html>
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
-- Version: 2007aug05
-- (find-a2ps (buffer-file-name))

---  _                      _           _ _     _               
--- | |_ _   _ _ __   ___  | |__  _   _(_) | __| | ___ _ __ ___ 
--- | __| | | | '_ \ / _ \ | '_ \| | | | | |/ _` |/ _ \ '__/ __|
--- | |_| |_| | |_) |  __/ | |_) | |_| | | | (_| |  __/ |  \__ \
---  \__|\__, | .__/ \___| |_.__/ \__,_|_|_|\__,_|\___|_|  |___/
---      |___/|_|                                               

TD = {}
newctype = function (kind, typename, sizeof, td)
    td.kind = kind
    td.type = typename
    td.sizeof = sizeof
    TD[typename] = td
    PP(td)
  end

BaseType = function (new, sizeof)
    newctype("base", new, sizeof, {})
  end
ArrayOf = function (old, new, n)
    newctype("array", new, n and (n * TD[old].sizeof), {star=old})
  end
PointerTo = function (old, new)
    newctype("pointer", new, 4, {star=old})
  end

StructOrUnion = function (kind, fielddecls, shortname, typedefedname)
    local totalsize = 0
    local fields = {}
    local descriptions = {}
    for type,varname in string.gmatch(fielddecls, "(%S+)%s+([%w_]+);?") do
        local fieldsize = TD[type].sizeof
        local offset = (kind=="union") and 0 or totalsize
        if not fieldsize then
	  error(kind.." "..shortname..": type "..type.." has no sizeof")
        end
        table.insert(descriptions, type..":"..varname)
        table.insert(fields, {type=type, name=varname, offset=offset})
        fields[varname] = table.getn(fields)
	totalsize = (kind=="union")
                    and math.max(totalsize, fieldsize)
	             or totalsize + fieldsize
      end
    ---- I don't need the longnames now, and they make the dumps hard to read.
    -- local longname = kind.."{"..table.concat(descriptions, ",").."}"
    -- newctype(kind, longname, totalsize, {fields=fields})
    if shortname then
      newctype(kind, shortname, totalsize, {fields=fields})
    end
    if typedefedname then
      newctype(kind, typedefedname, totalsize, {fields=fields})
    end
  end

StructOf = function (fielddecls, shortname, typedefedname)
    StructOrUnion("struct", fielddecls, shortname, typedefedname)
  end
UnionOf = function (fielddecls, shortname, typedefedname)
    StructOrUnion("union", fielddecls, shortname, typedefedname)
  end

FunctionType = function (new, arglist)   -- practically a stub
    newctype("function", new, nil, {})
  end

smasharglist = function (arglist) 
    arglist = string.gsub(arglist, ",%s+", ",")
    arglist = string.gsub(arglist,  "%s+", ":")
    return arglist
  end

copy = function (tbl)
    newtbl = {}
    for k,v in pairs(tbl) do newtbl[k] = v end
    return newtbl
  end
TypedefTo = function (old, new)
    if old:match("^struct:[%w_]+") or old:match("^union:[%w_]+") then
      TD[new] = setmetatable({}, {
          __index = function (key) return TD[old][key] end
        })
    else
      TD[new] = copy(TD[old])
      TD[new].type = new
    end
  end



--[[
* (eepitch-kill)
* (eepitch-lua51)
--]]


---  _                                        
--- | |    _ __   ___  __ _    ___  _ __  ___ 
--- | |   | '_ \ / _ \/ _` |  / _ \| '_ \/ __|
--- | |___| |_) |  __/ (_| | | (_) | |_) \__ \
--- |_____| .__/ \___|\__, |  \___/| .__/|___/
---       |_|         |___/        |_|        

dotower = function (basetype, boxesandstars)
    PP("dotower",   basetype, boxesandstars)
    for _,s in ipairs(boxesandstars) do
      if s == "*" then
        PointerTo(basetype, basetype..s)
      else
	local n = tonumber(string.match(s, "%[([0-9]*)%]"))
        ArrayOf(basetype, basetype..s, n)
      end
      basetype = basetype..s
    end
  end
dostructdecl = function (structtype, fielddecls)
    PP("dostructdecl",   structtype, fielddecls)
    StructOf(fielddecls, structtype)
  end
dostructdecl = function (structtype, fielddecls)
    PP("dostructdecl",   structtype, fielddecls)
    StructOf(fielddecls, structtype)
  end
douniondecl = function (uniontype, fielddecls)
    PP("douniondecl",   uniontype, fielddecls)
    UnionOf(fielddecls, uniontype)
  end
dotypedefstruct = function (structtype, fielddecls, simpletype)
    PP("dotypedefstruct",   structtype, fielddecls, simpletype)
    StructOf(fielddecls,    structtype,             simpletype)
  end
dotypedefunion = function (uniontype, fielddecls, simpletype)
    PP("dotypedefunion",   uniontype, fielddecls, simpletype)
    UnionOf(fielddecls,    uniontype,             simpletype)
  end
dotypedefbase = function (towertype, simpletype)
    PP("dotypedefbase",   towertype, simpletype)
    TypedefTo(            towertype, simpletype)
  end
dotypedeffun = function (rettype, arglist, simpletype)
    PP("dotypedeffun",   rettype, arglist, simpletype)
    funtype = rettype .. "(" .. smasharglist(arglist) .. ")"
    funptrtype = funtype .. "*"
    PointerTo(funtype, funptrtype)
    TypedefTo(funptrtype, simpletype)
  end


---  _                                    _       
--- | |    _ __   ___  __ _   _ __   __ _| |_ ___ 
--- | |   | '_ \ / _ \/ _` | | '_ \ / _` | __/ __|
--- | |___| |_) |  __/ (_| | | |_) | (_| | |_\__ \
--- |_____| .__/ \___|\__, | | .__/ \__,_|\__|___/
---       |_|         |___/  |_|                  
--
-- (find-es "lua5" "lpeg-quickref")

loadlpeg()

-- Parsing-only versions of the patterns.
-- Not all of these are used in the final program,
-- but they are the skeletons for the versions in the
-- block below, that involve "capture"s and "do"s.

S          = lpeg.S(" \t\n\r") ^ 0
Alpha      = lpeg.R("AZ", "az", "__")
AlphaNum   = lpeg.R("AZ", "az", "__", "09")
SimpleType = Alpha * AlphaNum ^ 0
StructType = "struct:" * SimpleType
UnionType  = "union:"  * SimpleType
SemiSimpleType = StructType + UnionType + SimpleType
Box        = "[" * lpeg.R("09") ^ 0 * "]"
Star       = lpeg.P("*")
TowerType  = SemiSimpleType * (Box + Star) ^ 0
Field      = S * TowerType * S * SimpleType * lpeg.P(";") ^ -1 * S
Arg        = S * TowerType * S * SimpleType * lpeg.P(",") ^ -1 * S
FieldList  = "{" * Field ^ 0 * "}"
ArgList    = "(" * Arg   ^ 0 * ")"
StructDecl = StructType * S * FieldList * ";" * S
UnionDecl  = UnionType  * S * FieldList * ";" * S
TypedefStruct = "typedef" * S * StructType *  S  * FieldList * S *
                                SimpleType * ";" * S
TypedefUnion  = "typedef" * S * UnionType  *  S  * FieldList * S *
                                SimpleType * ";" * S
TypedefBase   = "typedef" * S * TowerType  *  S  *
                                SimpleType * ";" * S
TypedefFun    = "typedef" * S * TowerType  *  S  * ArgList * "*" * S *
                                SimpleType * ";" * S

---  _                                    _            ____ ____  
--- | |    _ __   ___  __ _   _ __   __ _| |_ ___ _   / ___|  _ \ 
--- | |   | '_ \ / _ \/ _` | | '_ \ / _` | __/ __(_) | |   | | | |
--- | |___| |_) |  __/ (_| | | |_) | (_| | |_\__ \_  | |___| |_| |
--- |_____| .__/ \___|\__, | | .__/ \__,_|\__|___(_)  \____|____/ 
---       |_|         |___/  |_|                                  

-- Suffixes: "C" stands for "Capture",
--           "D" stands for "Do".
-- We could have built the "D" patterns right away,
-- but if we keep also the "C" subpatterns around
-- then things become easier to understand and to debug.

SimpleTypeC = lpeg.C(SimpleType)
StructTypeC = lpeg.C(StructType)
UnionTypeC  = lpeg.C(UnionType)
TowerTypeC  = (lpeg.C(SemiSimpleType) * lpeg.Ct((lpeg.C(Box + Star)) ^ 0))
TowerTypeD  = lpeg.C(TowerTypeC / dotower)
FieldD      = S * TowerTypeD * S * SimpleType * lpeg.P(";") ^ -1 * S
ArgD        = S * TowerTypeD * S * SimpleType * lpeg.P(",") ^ -1 * S
FieldListC  = "{" * lpeg.C(FieldD ^ 0) * "}"
ArgListC    = "(" * lpeg.C(ArgD   ^ 0) * ")"
StructDeclC = StructTypeC * S * FieldListC * ";" * S
UnionDeclC  = UnionTypeC  * S * FieldListC * ";" * S
TypedefStructC = "typedef" * S * StructTypeC *  S  * FieldListC * S *
                                 SimpleTypeC * ";" * S
TypedefUnionC  = "typedef" * S * UnionTypeC  *  S  * FieldListC * S *
                                 SimpleTypeC * ";" * S
TypedefBaseC   = "typedef" * S * TowerTypeD  *  S  *
                                 SimpleTypeC * ";" * S
TypedefFunC    = "typedef" * S * TowerTypeD  *  S  * ArgListC * "*" * S *
                                 SimpleTypeC * ";" * S

StructDeclD    = StructDeclC    / dostructdecl
UnionDeclD     = UnionDeclC     / douniondecl
TypedefStructD = TypedefStructC	/ dotypedefstruct
TypedefUnionD  = TypedefUnionC 	/ dotypedefunion
TypedefBaseD   = TypedefBaseC 	/ dotypedefbase
TypedefFunD    = TypedefFunC    / dotypedeffun
                 
DeclarationD = StructDeclD    +
	       UnionDeclD     +
	       TypedefStructD +
	       TypedefUnionD  +
	       TypedefBaseD   +
	       TypedefFunD


-- (find-es "lua5" "lpeg-quickref")
-- (TowerTypeC / PP):match("foo*[2][3][]")
-- TowerTypeT:match("str:foo*[2][3][]")

---  _____         _          __     _   __  
--- |_   _|__  ___| |_ ___   / /___ | | _\ \ 
---   | |/ _ \/ __| __/ __| | |/ _ \| |/ /| |
---   | |  __/\__ \ |_\__ \ | | (_) |   < | |
---   |_|\___||___/\__|___/ | |\___/|_|\_\| |
---                          \_\         /_/ 

BaseType("char",         1)
BaseType("unsignedchar", 1)
BaseType("int",          4)
BaseType("unsignedint",  4)
BaseType("long",         4)
BaseType("unsignedlong", 4)
BaseType("double",       8)
BaseType("void",       nil)

dd = function (str) (DeclarationD ^ 1):match(str) end

dd [==[
typedef int ptrdiff_t;
typedef unsignedint size_t;
typedef int wchar_t;
union:luai_Cast { double l_d; long l_l; };
typedef struct:lua_State lua_State;
]==]

PP(TypedefBaseC:match [==[
typedef struct:lua_State lua_State;
]==])

dd [==[
typedef int (lua_State* L)* lua_CFunction;
typedef char* (lua_State* L, void* ud, size_t* sz)* lua_Reader;
typedef int (lua_State* L, void* p, size_t sz, void* ud)* lua_Writer;
typedef void* (void* ud, void* ptr, size_t osize, size_t nsize)* lua_Alloc;
typedef double lua_Number;
typedef ptrdiff_t lua_Integer;
typedef struct:lua_Debug lua_Debug;
typedef void (lua_State* L, lua_Debug* ar)* lua_Hook;
]==]

dd [==[
struct:lua_Debug {
  int event;
  char* name;
  char* namewhat;
  char* what;
  char* source;
  int currentline;
  int nups;
  int linedefined;
  int lastlinedefined;
  char[60] short_src;
  int i_ci;
};
]==]

dd [==[
typedef unsignedint lu_int32;
typedef size_t lu_mem;
typedef ptrdiff_t l_mem;
typedef unsignedchar lu_byte;
typedef union:L_Umaxalign { double u; void* s; long l; } L_Umaxalign;
typedef double l_uacNumber;
typedef lu_int32 Instruction;
typedef union:GCObject GCObject;
typedef struct:GCheader {
  GCObject* next; lu_byte tt; lu_byte marked;
} GCheader;
]==]






--[[
# (find-angg "LUA/lua50init.lua" "loadpeek")

* (eepitch-kill)
* (eepitch-lua51)

dofile(ee_expand("~/DAVINCI/peek.lua"))


-- **** error below
dd [==[
typedef union:Value {
  GCObject* gc;
  void* p;
  lua_Number n;
  int b;
} Value;
]==]

dd [==[
typedef union:uu {
  int ii;
} uu;
]==]




dd [==[
typedef struct:lua_TValue {
  Value value; int tt;
} TValue;
]==]

dd [==[
typedef TValue* StkId;
struct:TString__tsv {
  GCObject* next; lu_byte tt; lu_byte marked;
  lu_byte reserved;
  unsigned int hash;
  size_t len;
};
]==]

dd [==[
]==]




-- Tests for peek:
hexton = function (str) return tonumber(str, 16) end
gethexaddr = function (str) return string.match(str, " 0x([0-9A-Za-z]+)") end
getaddr = function (obj)
    return tonumber(string.match(tostring(obj), " 0x([0-9A-Za-z]+)"), 16)
  end
= getaddr(peek)
= getaddr({})
= tostring(peek)
a = getaddr(tostring(peek))
= a
= peek(a, 4)
= format("%q", peek(a, 4))
= tostring("foo")
= tostring("foo\n")

* (eepitch-gdb-lua-kill)
* (eepitch-gdb-lua)
p sizeof(double)
p sizeof(long)
* (eepitch-gdb-lua-kill)
--]]