Skip to content
Snippets Groups Projects
Commit 0517fba2 authored by dg's avatar dg
Browse files

Upgraded to lpeg 0.10

git-svn-id: http://svn.net-core.org/repos/t-engine4@4155 51575b47-30f0-44d4-a5cc-537603b46e54
parent b27fa754
No related branches found
No related tags found
No related merge requests found
...@@ -40,6 +40,7 @@ collectgarbage("restart") ...@@ -40,6 +40,7 @@ collectgarbage("restart")
-- Setup correct lua path -- Setup correct lua path
package.path = "/?.lua" package.path = "/?.lua"
package.moonpath = "/?.moon"
math.randomseed(os.time()) math.randomseed(os.time())
......
-- $Id: re.lua,v 1.32 2008/10/09 20:25:06 roberto Exp $ -- $Id: re.lua,v 1.39 2010/11/04 19:44:18 roberto Exp $
local m = require"lpeg" -- imported functions and modules
local _G = _G
local tonumber, type, print, error = tonumber, type, print, error local tonumber, type, print, error = tonumber, type, print, error
local mt = getmetatable(m.P(0)) local setmetatable = setmetatable
local m = require"lpeg"
-- 'm' will be used to parse expressions, and 'mm' will be used to
-- create expressions; that is, 're' runs on 'm', creating patterns
-- on 'mm'
local mm = m
-- pattern's metatable
local mt = getmetatable(mm.P(0))
-- No more global accesses after this point
local version = _VERSION
if version == "Lua 5.2" then _ENV = nil end
module "re"
local any = m.P(1) local any = m.P(1)
-- Pre-defined names -- Pre-defined names
Predef = { nl = m.P"\n" } local Predef = { nl = m.P"\n" }
local mem
local fmem
local gmem
local function updatelocale ()
mm.locale(Predef)
Predef.a = Predef.alpha
Predef.c = Predef.cntrl
Predef.d = Predef.digit
Predef.g = Predef.graph
Predef.l = Predef.lower
Predef.p = Predef.punct
Predef.s = Predef.space
Predef.u = Predef.upper
Predef.w = Predef.alnum
Predef.x = Predef.xdigit
Predef.A = any - Predef.a
Predef.C = any - Predef.c
Predef.D = any - Predef.d
Predef.G = any - Predef.g
Predef.L = any - Predef.l
Predef.P = any - Predef.p
Predef.S = any - Predef.s
Predef.U = any - Predef.u
Predef.W = any - Predef.w
Predef.X = any - Predef.x
mem = {} -- restart memoization
fmem = {}
gmem = {}
local mt = {__mode = "v"}
setmetatable(mem, mt)
setmetatable(fmem, mt)
setmetatable(gmem, mt)
end
updatelocale()
local I = m.P(function (s,i) print(i, s:sub(1, i-1)); return i end) local I = m.P(function (s,i) print(i, s:sub(1, i-1)); return i end)
...@@ -31,7 +86,7 @@ local function patt_error (s, i) ...@@ -31,7 +86,7 @@ local function patt_error (s, i)
end end
local function mult (p, n) local function mult (p, n)
local np = m.P(true) local np = mm.P(true)
while n >= 1 do while n >= 1 do
if n%2 >= 1 then np = np * p end if n%2 >= 1 then np = np * p end
p = p * p p = p * p
...@@ -47,11 +102,13 @@ local function equalcap (s, i, c) ...@@ -47,11 +102,13 @@ local function equalcap (s, i, c)
end end
local S = (m.S(" \t\n") + "--" * (any - m.S"\n")^0)^0 local S = (m.S(" \f\n\r\t\v") + "--" * (any - Predef.nl)^0)^0
local name = m.R("AZ", "az") * m.R("AZ", "az", "09")^0 local name = m.R("AZ", "az") * m.R("AZ", "az", "__", "09")^0
local exp_follow = m.P"/" + ")" + "}" + ":}" + "~}" + name + -1 local arrow = S * "<-"
local exp_follow = m.P"/" + ")" + "}" + ":}" + "~}" + (name * arrow) + -1
name = m.C(name) name = m.C(name)
...@@ -65,15 +122,15 @@ local String = "'" * m.C((any - "'")^0) * "'" + ...@@ -65,15 +122,15 @@ local String = "'" * m.C((any - "'")^0) * "'" +
'"' * m.C((any - '"')^0) * '"' '"' * m.C((any - '"')^0) * '"'
local Cat = "%" * Identifier / function (c,Defs) local defined = "%" * Identifier / function (c,Defs)
local cat = Defs and Defs[c] or Predef[c] local cat = Defs and Defs[c] or Predef[c]
if not cat then error ("name '" .. c .. "' undefined") end if not cat then error ("name '" .. c .. "' undefined") end
return cat return cat
end end
local Range = m.Cs(any * (m.P"-"/"") * (any - "]")) / m.R local Range = m.Cs(any * (m.P"-"/"") * (any - "]")) / mm.R
local item = Cat + Range + m.C(any) local item = defined + Range + m.C(any)
local Class = local Class =
"[" "["
...@@ -118,39 +175,34 @@ local exp = m.P{ "Exp", ...@@ -118,39 +175,34 @@ local exp = m.P{ "Exp",
) * S ) * S
)^0, function (a,b,f) return f(a,b) end ); )^0, function (a,b,f) return f(a,b) end );
Primary = "(" * m.V"Exp" * ")" Primary = "(" * m.V"Exp" * ")"
+ String / m.P + String / mm.P
+ Class + Class
+ Cat + defined
+ "{:" * (name * ":" + m.Cc(nil)) * m.V"Exp" * ":}" / + "{:" * (name * ":" + m.Cc(nil)) * m.V"Exp" * ":}" /
function (n, p) return m.Cg(p, n) end function (n, p) return mm.Cg(p, n) end
+ "=" * name / function (n) return m.Cmt(m.Cb(n), equalcap) end + "=" * name / function (n) return mm.Cmt(mm.Cb(n), equalcap) end
+ m.P"{}" / m.Cp + m.P"{}" / mm.Cp
+ "{~" * m.V"Exp" * "~}" / m.Cs + "{~" * m.V"Exp" * "~}" / mm.Cs
+ "{" * m.V"Exp" * "}" / m.C + "{" * m.V"Exp" * "}" / mm.C
+ m.P"." * m.Cc(any) + m.P"." * m.Cc(any)
+ "<" * name * ">" / m.V; + name * -arrow / mm.V
Definition = Identifier * S * '<-' * m.V"Exp"; + "<" * name * ">" / mm.V;
Definition = Identifier * arrow * m.V"Exp";
Grammar = m.Cf(m.V"Definition" / firstdef * m.Cg(m.V"Definition")^0, adddef) / Grammar = m.Cf(m.V"Definition" / firstdef * m.Cg(m.V"Definition")^0, adddef) /
m.P mm.P
} }
local pattern = S * exp / m.P * (-any + patt_error) local pattern = S * exp / mm.P * (-any + patt_error)
function compile (p, defs) local function compile (p, defs)
if m.type(p) == "pattern" then return p end -- already compiled if mm.type(p) == "pattern" then return p end -- already compiled
local cp = pattern:match(p, 1, defs) local cp = pattern:match(p, 1, defs)
if not cp then error("incorrect pattern", 3) end if not cp then error("incorrect pattern", 3) end
return cp return cp
end end
local function match (s, p, i)
local mem
local fmem
local gmem
local mt = {__mode = "v"}
function match (s, p, i)
local cp = mem[p] local cp = mem[p]
if not cp then if not cp then
cp = compile(p) cp = compile(p)
...@@ -159,58 +211,38 @@ function match (s, p, i) ...@@ -159,58 +211,38 @@ function match (s, p, i)
return cp:match(s, i or 1) return cp:match(s, i or 1)
end end
function find (s, p, i) local function find (s, p, i)
local cp = fmem[p] local cp = fmem[p]
if not cp then if not cp then
cp = compile(p) cp = compile(p)
cp = m.P{ m.Cp() * cp + 1 * m.V(1) } cp = mm.P{ mm.Cp() * cp + 1 * mm.V(1) }
fmem[p] = cp fmem[p] = cp
end end
return cp:match(s, i or 1) return cp:match(s, i or 1)
end end
function gsub (s, p, rep) local function gsub (s, p, rep)
gmem[p] = gmem[p] or {} local g = gmem[p] or {} -- ensure gmem[p] is not collected while here
local cp = gmem[p][rep] gmem[p] = g
local cp = g[rep]
if not cp then if not cp then
cp = compile(p) cp = compile(p)
cp = m.Cs((cp / rep + 1)^0) cp = mm.Cs((cp / rep + 1)^0)
gmem[p][rep] = cp g[rep] = cp
end end
return cp:match(s) return cp:match(s)
end end
function updatelocale () -- exported names
m.locale(Predef) local re = {
Predef.a = Predef.alpha compile = compile,
Predef.c = Predef.cntrl match = match,
Predef.d = Predef.digit find = find,
Predef.g = Predef.graph gsub = gsub,
Predef.l = Predef.lower updatelocale = updatelocale,
Predef.p = Predef.punct }
Predef.s = Predef.space
Predef.u = Predef.upper
Predef.w = Predef.alnum
Predef.x = Predef.xdigit
Predef.A = any - Predef.a
Predef.C = any - Predef.c
Predef.D = any - Predef.d
Predef.G = any - Predef.g
Predef.L = any - Predef.l
Predef.P = any - Predef.p
Predef.S = any - Predef.s
Predef.U = any - Predef.u
Predef.W = any - Predef.w
Predef.X = any - Predef.x
mem = {} -- restart memoization
fmem = {}
gmem = {}
_G.setmetatable(mem, mt)
_G.setmetatable(fmem, mt)
_G.setmetatable(gmem, mt)
end
updatelocale() if version == "Lua 5.1" then _G.re = re end
return re
/* /*
** $Id: lpeg.c,v 1.98 2008/10/11 20:20:43 roberto Exp $ ** $Id: lpeg.c,v 1.114 2011/02/16 15:02:20 roberto Exp $
** LPeg - PEG pattern matching for Lua ** LPeg - PEG pattern matching for Lua
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) ** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
** written by Roberto Ierusalimschy ** written by Roberto Ierusalimschy
...@@ -15,15 +15,49 @@ ...@@ -15,15 +15,49 @@
#include "lua.h" #include "lua.h"
#include "lauxlib.h" #include "lauxlib.h"
#include "lpeg.h"
#define VERSION "0.9"
#define PATTERN_T "pattern"
/* maximum call/backtrack levels */ #define VERSION "0.10"
#define MAXBACK 400 #define PATTERN_T "lpeg-pattern"
#define MAXSTACKIDX "lpeg-maxstack"
/*
** compatibility with Lua 5.2
*/
#if (LUA_VERSION_NUM == 502)
#undef lua_equal
#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
#undef lua_getfenv
#define lua_getfenv lua_getuservalue
#undef lua_setfenv
#define lua_setfenv lua_setuservalue
#undef lua_objlen
#define lua_objlen lua_rawlen
#undef luaL_register
#define luaL_register(L,n,f) \
{ if ((n) == NULL) luaL_setfuncs(L,f,0); else luaL_newlib(L,f); }
#endif
/* initial size for call/backtrack stack */
#define INITBACK 100
/* default maximum size for call/backtrack stack */
#define MAXBACK INITBACK
/* size for call/backtrack stack for verifier */
#define MAXBACKVER 200
/* initial size for capture's list */ /* initial size for capture's list */
#define IMAXCAPTURES 600 #define INITCAPSIZE 32
/* index, on Lua stack, for subject */ /* index, on Lua stack, for subject */
...@@ -41,6 +75,9 @@ ...@@ -41,6 +75,9 @@
/* index, on Lua stack, for pattern's fenv */ /* index, on Lua stack, for pattern's fenv */
#define penvidx(ptop) ((ptop) + 3) #define penvidx(ptop) ((ptop) + 3)
/* index, on Lua stack, for backtracking stack */
#define stackidx(ptop) ((ptop) + 4)
typedef unsigned char byte; typedef unsigned char byte;
...@@ -52,15 +89,10 @@ typedef unsigned char byte; ...@@ -52,15 +89,10 @@ typedef unsigned char byte;
typedef byte Charset[CHARSETSIZE]; typedef byte Charset[CHARSETSIZE];
typedef const char *(*PattFunc) (const void *ud,
const char *o, /* string start */
const char *s, /* current position */
const char *e); /* string end */
/* Virtual Machine's instructions */ /* Virtual Machine's instructions */
typedef enum Opcode { typedef enum Opcode {
IAny, IChar, ISet, ISpan, IAny, IChar, ISet, ISpan,
IBack,
IRet, IEnd, IRet, IEnd,
IChoice, IJmp, ICall, IOpenCall, IChoice, IJmp, ICall, IOpenCall,
ICommit, IPartialCommit, IBackCommit, IFailTwice, IFail, IGiveup, ICommit, IPartialCommit, IBackCommit, IFailTwice, IFail, IGiveup,
...@@ -70,19 +102,20 @@ typedef enum Opcode { ...@@ -70,19 +102,20 @@ typedef enum Opcode {
} Opcode; } Opcode;
#define ISJMP 1 #define ISJMP 0x1
#define ISCHECK (ISJMP << 1) #define ISCHECK 0x2
#define ISNOFAIL (ISCHECK << 1) #define ISFIXCHECK 0x4
#define ISCAPTURE (ISNOFAIL << 1) #define ISNOFAIL 0x8
#define ISMOVABLE (ISCAPTURE << 1) #define ISCAPTURE 0x10
#define ISFENVOFF (ISMOVABLE << 1) #define ISMOVABLE 0x20
#define HASCHARSET (ISFENVOFF << 1) #define ISFENVOFF 0x40
static const byte opproperties[] = { static const int opproperties[] = {
/* IAny */ ISCHECK, /* IAny */ ISCHECK | ISFIXCHECK | ISJMP,
/* IChar */ ISCHECK, /* IChar */ ISCHECK | ISFIXCHECK | ISJMP,
/* ISet */ ISCHECK | HASCHARSET, /* ISet */ ISCHECK | ISFIXCHECK | ISJMP,
/* ISpan */ ISNOFAIL | HASCHARSET, /* ISpan */ ISNOFAIL,
/* IBack */ 0,
/* IRet */ 0, /* IRet */ 0,
/* IEnd */ 0, /* IEnd */ 0,
/* IChoice */ ISJMP, /* IChoice */ ISJMP,
...@@ -95,7 +128,7 @@ static const byte opproperties[] = { ...@@ -95,7 +128,7 @@ static const byte opproperties[] = {
/* IFailTwice */ 0, /* IFailTwice */ 0,
/* IFail */ 0, /* IFail */ 0,
/* IGiveup */ 0, /* IGiveup */ 0,
/* IFunc */ 0, /* IFunc */ ISCHECK | ISJMP,
/* IFullCapture */ ISCAPTURE | ISNOFAIL | ISFENVOFF, /* IFullCapture */ ISCAPTURE | ISNOFAIL | ISFENVOFF,
/* IEmptyCapture */ ISCAPTURE | ISNOFAIL | ISMOVABLE, /* IEmptyCapture */ ISCAPTURE | ISNOFAIL | ISMOVABLE,
/* IEmptyCaptureIdx */ISCAPTURE | ISNOFAIL | ISMOVABLE | ISFENVOFF, /* IEmptyCaptureIdx */ISCAPTURE | ISNOFAIL | ISMOVABLE | ISFENVOFF,
...@@ -112,6 +145,7 @@ typedef union Instruction { ...@@ -112,6 +145,7 @@ typedef union Instruction {
short offset; short offset;
} i; } i;
PattFunc f; PattFunc f;
int iv;
byte buff[1]; byte buff[1];
} Instruction; } Instruction;
...@@ -123,16 +157,21 @@ static const Instruction giveup = {{IGiveup, 0, 0}}; ...@@ -123,16 +157,21 @@ static const Instruction giveup = {{IGiveup, 0, 0}};
#define dest(p,x) ((x) + ((p)+(x))->i.offset) #define dest(p,x) ((x) + ((p)+(x))->i.offset)
#define MAXOFF 0xF #define MAXOFF 0xF
#define MAXAUX 0xFF
/* maximum size (in elements) for a pattern */
#define MAXPATTSIZE (SHRT_MAX - 10)
#define isprop(op,p) (opproperties[(op)->i.code] & (p)) #define isprop(op,p) (opproperties[(op)->i.code] & (p))
#define isjmp(op) isprop(op, ISJMP) #define isjmp(op) (isprop(op, ISJMP) && (op)->i.offset != 0)
#define iscapture(op) isprop(op, ISCAPTURE) #define iscapture(op) isprop(op, ISCAPTURE)
#define ischeck(op) (isprop(op, ISCHECK) && (op)->i.offset == 0) #define ischeck(op) (isprop(op, ISCHECK) && (op)->i.offset == 0)
#define isfixcheck(op) (isprop(op, ISFIXCHECK) && (op)->i.offset == 0)
#define istest(op) (isprop(op, ISCHECK) && (op)->i.offset != 0) #define istest(op) (isprop(op, ISCHECK) && (op)->i.offset != 0)
#define isnofail(op) isprop(op, ISNOFAIL) #define isnofail(op) isprop(op, ISNOFAIL)
#define ismovable(op) isprop(op, ISMOVABLE) #define ismovable(op) isprop(op, ISMOVABLE)
#define isfenvoff(op) isprop(op, ISFENVOFF) #define isfenvoff(op) isprop(op, ISFENVOFF)
#define hascharset(op) isprop(op, HASCHARSET)
/* kinds of captures */ /* kinds of captures */
...@@ -152,17 +191,15 @@ typedef struct Capture { ...@@ -152,17 +191,15 @@ typedef struct Capture {
} Capture; } Capture;
/* maximum size (in elements) for a pattern */
#define MAXPATTSIZE (SHRT_MAX - 10)
/* size (in elements) for an instruction plus extra l bytes */ /* size (in elements) for an instruction plus extra l bytes */
#define instsize(l) (((l) - 1)/sizeof(Instruction) + 2) #define instsize(l) (((l) + sizeof(Instruction) - 1)/sizeof(Instruction) + 1)
/* size (in elements) for a ISet instruction */ /* size (in elements) for a ISet instruction */
#define CHARSETINSTSIZE instsize(CHARSETSIZE) #define CHARSETINSTSIZE instsize(CHARSETSIZE)
/* size (in elements) for a IFunc instruction */
#define funcinstsize(p) ((p)->i.aux + 2)
#define loopset(v,b) { int v; for (v = 0; v < CHARSETSIZE; v++) b; } #define loopset(v,b) { int v; for (v = 0; v < CHARSETSIZE; v++) b; }
...@@ -172,11 +209,15 @@ typedef struct Capture { ...@@ -172,11 +209,15 @@ typedef struct Capture {
#define setchar(st,c) ((st)[(c) >> 3] |= (1 << ((c) & 7))) #define setchar(st,c) ((st)[(c) >> 3] |= (1 << ((c) & 7)))
static int target (Instruction *p, int i);
static int sizei (const Instruction *i) { static int sizei (const Instruction *i) {
if (hascharset(i)) return CHARSETINSTSIZE; switch((Opcode)i->i.code) {
else if (i->i.code == IFunc) return i->i.offset; case ISet: case ISpan: return CHARSETINSTSIZE;
else return 1; case IFunc: return funcinstsize(i);
default: return 1;
}
} }
...@@ -185,7 +226,7 @@ static const char *val2str (lua_State *L, int idx) { ...@@ -185,7 +226,7 @@ static const char *val2str (lua_State *L, int idx) {
if (k != NULL) if (k != NULL)
return lua_pushfstring(L, "rule '%s'", k); return lua_pushfstring(L, "rule '%s'", k);
else else
return lua_pushfstring(L, "rule <a %s>", luaL_typename(L, -1)); return lua_pushfstring(L, "rule <a %s>", luaL_typename(L, idx));
} }
...@@ -204,10 +245,9 @@ static int getposition (lua_State *L, int t, int i) { ...@@ -204,10 +245,9 @@ static int getposition (lua_State *L, int t, int i) {
} }
/* /*
** {====================================================== ** {======================================================
** Printing patterns ** Printing patterns (for debugging)
** ======================================================= ** =======================================================
*/ */
...@@ -246,7 +286,7 @@ static void printjmp (const Instruction *op, const Instruction *p) { ...@@ -246,7 +286,7 @@ static void printjmp (const Instruction *op, const Instruction *p) {
static void printinst (const Instruction *op, const Instruction *p) { static void printinst (const Instruction *op, const Instruction *p) {
const char *const names[] = { const char *const names[] = {
"any", "char", "set", "span", "any", "char", "set", "span", "back",
"ret", "end", "ret", "end",
"choice", "jmp", "call", "open_call", "choice", "jmp", "call", "open_call",
"commit", "partial_commit", "back_commit", "failtwice", "fail", "giveup", "commit", "partial_commit", "back_commit", "failtwice", "fail", "giveup",
...@@ -306,12 +346,13 @@ static void printpatt (Instruction *p) { ...@@ -306,12 +346,13 @@ static void printpatt (Instruction *p) {
Instruction *op = p; Instruction *op = p;
for (;;) { for (;;) {
printinst(op, p); printinst(op, p);
if (p->i.code == IEnd) break; if ((Opcode)p->i.code == IEnd) break;
p += sizei(p); p += sizei(p);
} }
} }
#if 0
static void printcap (Capture *cap) { static void printcap (Capture *cap) {
printcapkind(cap->kind); printcapkind(cap->kind);
printf(" (idx: %d - size: %d) -> %p\n", cap->idx, cap->siz, cap->s); printf(" (idx: %d - size: %d) -> %p\n", cap->idx, cap->siz, cap->s);
...@@ -321,12 +362,11 @@ static void printcap (Capture *cap) { ...@@ -321,12 +362,11 @@ static void printcap (Capture *cap) {
static void printcaplist (Capture *cap) { static void printcaplist (Capture *cap) {
for (; cap->s; cap++) printcap(cap); for (; cap->s; cap++) printcap(cap);
} }
#endif
/* }====================================================== */ /* }====================================================== */
/* /*
** {====================================================== ** {======================================================
** Virtual Machine ** Virtual Machine
...@@ -341,6 +381,9 @@ typedef struct Stack { ...@@ -341,6 +381,9 @@ typedef struct Stack {
} Stack; } Stack;
#define getstackbase(L, ptop) ((Stack *)lua_touserdata(L, stackidx(ptop)))
static int runtimecap (lua_State *L, Capture *close, Capture *ocap, static int runtimecap (lua_State *L, Capture *close, Capture *ocap,
const char *o, const char *s, int ptop); const char *o, const char *s, int ptop);
...@@ -356,6 +399,26 @@ static Capture *doublecap (lua_State *L, Capture *cap, int captop, int ptop) { ...@@ -356,6 +399,26 @@ static Capture *doublecap (lua_State *L, Capture *cap, int captop, int ptop) {
} }
static Stack *doublestack (lua_State *L, Stack **stacklimit, int ptop) {
Stack *stack = getstackbase(L, ptop);
Stack *newstack;
int n = *stacklimit - stack;
int max, newn;
lua_getfield(L, LUA_REGISTRYINDEX, MAXSTACKIDX);
max = lua_tointeger(L, -1);
lua_pop(L, 1);
if (n >= max)
luaL_error(L, "too many pending calls/choices");
newn = 2*n; if (newn > max) newn = max;
newstack = (Stack *)lua_newuserdata(L, newn * sizeof(Stack));
memcpy(newstack, stack, n * sizeof(Stack));
lua_replace(L, stackidx(ptop));
*stacklimit = newstack + newn;
return newstack + n;
}
static void adddyncaptures (const char *s, Capture *base, int n, int fd) { static void adddyncaptures (const char *s, Capture *base, int n, int fd) {
int i; int i;
assert(base[0].kind == Cruntime && base[0].siz == 0); assert(base[0].kind == Cruntime && base[0].siz == 0);
...@@ -374,35 +437,36 @@ static void adddyncaptures (const char *s, Capture *base, int n, int fd) { ...@@ -374,35 +437,36 @@ static void adddyncaptures (const char *s, Capture *base, int n, int fd) {
#define condfailed(p) { int f = p->i.offset; if (f) p+=f; else goto fail; } #define condfailed(p) { int f = p->i.offset; if (f) p+=f; else goto fail; }
static const char *match (lua_State *L, static const char *match (lua_State *L,
const char *o, const char *s, const char *e, const char *o, const char *s, const char *e,
Instruction *op, Capture *capture, int ptop) { Instruction *op, Capture *capture, int ptop) {
Stack stackbase[MAXBACK]; Stack stackbase[INITBACK];
Stack *stacklimit = stackbase + MAXBACK; Stack *stacklimit = stackbase + INITBACK;
Stack *stack = stackbase; /* point to first empty slot in stack */ Stack *stack = stackbase; /* point to first empty slot in stack */
int capsize = IMAXCAPTURES; int capsize = INITCAPSIZE;
int captop = 0; /* point to first empty slot in captures */ int captop = 0; /* point to first empty slot in captures */
const Instruction *p = op; const Instruction *p = op;
stack->p = &giveup; stack->s = s; stack->caplevel = 0; stack++; stack->p = &giveup; stack->s = s; stack->caplevel = 0; stack++;
lua_pushlightuserdata(L, stackbase);
for (;;) { for (;;) {
#if defined(DEBUG) #if defined(DEBUG)
printf("s: |%s| stck: %d c: %d ", s, stack - stackbase, captop); printf("s: |%s| stck: %d c: %d ",
s, stack - getstackbase(L, ptop), captop);
printinst(op, p); printinst(op, p);
#endif #endif
switch ((Opcode)p->i.code) { switch ((Opcode)p->i.code) {
case IEnd: { case IEnd: {
assert(stack == stackbase + 1); assert(stack == getstackbase(L, ptop) + 1);
capture[captop].kind = Cclose; capture[captop].kind = Cclose;
capture[captop].s = NULL; capture[captop].s = NULL;
return s; return s;
} }
case IGiveup: { case IGiveup: {
assert(stack == stackbase); assert(stack == getstackbase(L, ptop));
return NULL; return NULL;
} }
case IRet: { case IRet: {
assert(stack > stackbase && (stack - 1)->s == NULL); assert(stack > getstackbase(L, ptop) && (stack - 1)->s == NULL);
p = (--stack)->p; p = (--stack)->p;
continue; continue;
} }
...@@ -424,6 +488,12 @@ static const char *match (lua_State *L, ...@@ -424,6 +488,12 @@ static const char *match (lua_State *L,
else condfailed(p); else condfailed(p);
continue; continue;
} }
case IBack: {
int n = p->i.aux;
if (n > s - o) goto fail;
s -= n; p++;
continue;
}
case ISpan: { case ISpan: {
for (; s < e; s++) { for (; s < e; s++) {
int c = (byte)*s; int c = (byte)*s;
...@@ -433,10 +503,9 @@ static const char *match (lua_State *L, ...@@ -433,10 +503,9 @@ static const char *match (lua_State *L,
continue; continue;
} }
case IFunc: { case IFunc: {
const char *r = (p+1)->f((p+2)->buff, o, s, e); const char *r = (p+1)->f(s, e, o, (p+2)->buff);
if (r == NULL) goto fail; if (r != NULL) { s = r; p += funcinstsize(p); }
s = r; else condfailed(p);
p += p->i.offset;
continue; continue;
} }
case IJmp: { case IJmp: {
...@@ -444,8 +513,8 @@ static const char *match (lua_State *L, ...@@ -444,8 +513,8 @@ static const char *match (lua_State *L,
continue; continue;
} }
case IChoice: { case IChoice: {
if (stack >= stacklimit) if (stack == stacklimit)
return (luaL_error(L, "too many pending calls/choices"), (char *)0); stack = doublestack(L, &stacklimit, ptop);
stack->p = dest(0, p); stack->p = dest(0, p);
stack->s = s - p->i.aux; stack->s = s - p->i.aux;
stack->caplevel = captop; stack->caplevel = captop;
...@@ -454,8 +523,8 @@ static const char *match (lua_State *L, ...@@ -454,8 +523,8 @@ static const char *match (lua_State *L,
continue; continue;
} }
case ICall: { case ICall: {
if (stack >= stacklimit) if (stack == stacklimit)
return (luaL_error(L, "too many pending calls/choices"), (char *)0); stack = doublestack(L, &stacklimit, ptop);
stack->s = NULL; stack->s = NULL;
stack->p = p + 1; /* save return address */ stack->p = p + 1; /* save return address */
stack++; stack++;
...@@ -463,32 +532,33 @@ static const char *match (lua_State *L, ...@@ -463,32 +532,33 @@ static const char *match (lua_State *L,
continue; continue;
} }
case ICommit: { case ICommit: {
assert(stack > stackbase && (stack - 1)->s != NULL); assert(stack > getstackbase(L, ptop) && (stack - 1)->s != NULL);
stack--; stack--;
p += p->i.offset; p += p->i.offset;
continue; continue;
} }
case IPartialCommit: { case IPartialCommit: {
assert(stack > stackbase && (stack - 1)->s != NULL); assert(stack > getstackbase(L, ptop) && (stack - 1)->s != NULL);
(stack - 1)->s = s; (stack - 1)->s = s;
(stack - 1)->caplevel = captop; (stack - 1)->caplevel = captop;
p += p->i.offset; p += p->i.offset;
continue; continue;
} }
case IBackCommit: { case IBackCommit: {
assert(stack > stackbase && (stack - 1)->s != NULL); assert(stack > getstackbase(L, ptop) && (stack - 1)->s != NULL);
s = (--stack)->s; s = (--stack)->s;
captop = stack->caplevel;
p += p->i.offset; p += p->i.offset;
continue; continue;
} }
case IFailTwice: case IFailTwice:
assert(stack > stackbase); assert(stack > getstackbase(L, ptop));
stack--; stack--;
/* go through */ /* go through */
case IFail: case IFail:
fail: { /* pattern failed: try to backtrack */ fail: { /* pattern failed: try to backtrack */
do { /* remove pending calls */ do { /* remove pending calls */
assert(stack > stackbase); assert(stack > getstackbase(L, ptop));
s = (--stack)->s; s = (--stack)->s;
} while (s == NULL); } while (s == NULL);
captop = stack->caplevel; captop = stack->caplevel;
...@@ -575,10 +645,18 @@ static const char *match (lua_State *L, ...@@ -575,10 +645,18 @@ static const char *match (lua_State *L,
*/ */
/*
** check whether pattern may go from 'p' to 'e' without consuming any
** input. Raises an error if it detects a left recursion. 'op' points
** the beginning of the pattern. If pattern belongs to a grammar,
** 'rule' is the stack index where is its corresponding key (only for
** error messages) and 'posttable' is the stack index with a table
** mapping rule keys to the position of their code in the pattern.
*/
static int verify (lua_State *L, Instruction *op, const Instruction *p, static int verify (lua_State *L, Instruction *op, const Instruction *p,
Instruction *e, int postable, int rule) { Instruction *e, int postable, int rule) {
static const char dummy[] = ""; static const char dummy[] = "";
Stack back[MAXBACK]; Stack back[MAXBACKVER];
int backtop = 0; /* point to first empty slot in back */ int backtop = 0; /* point to first empty slot in back */
while (p != e) { while (p != e) {
switch ((Opcode)p->i.code) { switch ((Opcode)p->i.code) {
...@@ -587,7 +665,7 @@ static int verify (lua_State *L, Instruction *op, const Instruction *p, ...@@ -587,7 +665,7 @@ static int verify (lua_State *L, Instruction *op, const Instruction *p,
continue; continue;
} }
case IChoice: { case IChoice: {
if (backtop >= MAXBACK) if (backtop >= MAXBACKVER)
return luaL_error(L, "too many pending calls/choices"); return luaL_error(L, "too many pending calls/choices");
back[backtop].p = dest(0, p); back[backtop].p = dest(0, p);
back[backtop++].s = dummy; back[backtop++].s = dummy;
...@@ -596,7 +674,7 @@ static int verify (lua_State *L, Instruction *op, const Instruction *p, ...@@ -596,7 +674,7 @@ static int verify (lua_State *L, Instruction *op, const Instruction *p,
} }
case ICall: { case ICall: {
assert((p + 1)->i.code != IRet); /* no tail call */ assert((p + 1)->i.code != IRet); /* no tail call */
if (backtop >= MAXBACK) if (backtop >= MAXBACKVER)
return luaL_error(L, "too many pending calls/choices"); return luaL_error(L, "too many pending calls/choices");
back[backtop].s = NULL; back[backtop].s = NULL;
back[backtop++].p = p + 1; back[backtop++].p = p + 1;
...@@ -610,7 +688,7 @@ static int verify (lua_State *L, Instruction *op, const Instruction *p, ...@@ -610,7 +688,7 @@ static int verify (lua_State *L, Instruction *op, const Instruction *p,
if (back[i].s == NULL && back[i].p == p + 1) if (back[i].s == NULL && back[i].p == p + 1)
return luaL_error(L, "%s is left recursive", val2str(L, rule)); return luaL_error(L, "%s is left recursive", val2str(L, rule));
} }
if (backtop >= MAXBACK) if (backtop >= MAXBACKVER)
return luaL_error(L, "too many pending calls/choices"); return luaL_error(L, "too many pending calls/choices");
back[backtop].s = NULL; back[backtop].s = NULL;
back[backtop++].p = p + 1; back[backtop++].p = p + 1;
...@@ -633,11 +711,29 @@ static int verify (lua_State *L, Instruction *op, const Instruction *p, ...@@ -633,11 +711,29 @@ static int verify (lua_State *L, Instruction *op, const Instruction *p,
continue; continue;
} }
} }
case IBack: {
if (p->i.aux == 1 && isfixcheck(p + 1)) { /* char test? */
p++; /* skip back instruction */
p += sizei(p); /* skip char test */
}
else { /* standard lookbehind code */
assert((Opcode)(p - 1)->i.code == IChoice); /* look behind */
backtop--;
p += (p - 1)->i.offset;
assert((Opcode)(p - 1)->i.code == IFail); /* look behind */
}
continue;
}
case IAny: case IAny:
case IChar: case IChar:
case ISet: { case ISet: {
if (p->i.offset == 0) goto fail; const Instruction *next = p + sizei(p);
/* else goto dojmp; go through */ if ((Opcode)next->i.code == IBack)
p = next + 1; /* continue after the back instruction */
else if (p->i.offset == 0) goto fail;
else /* jump */
p += p->i.offset;
continue;
} }
case IJmp: case IJmp:
dojmp: { dojmp: {
...@@ -672,9 +768,9 @@ static int verify (lua_State *L, Instruction *op, const Instruction *p, ...@@ -672,9 +768,9 @@ static int verify (lua_State *L, Instruction *op, const Instruction *p,
goto fail; /* be liberal in this case */ goto fail; /* be liberal in this case */
} }
case IFunc: { case IFunc: {
const char *r = (p+1)->f((p+2)->buff, dummy, dummy, dummy); const char *r = (p+1)->f(dummy, dummy, dummy, (p+2)->buff);
if (r == NULL) goto fail; if (r != NULL) { p += funcinstsize(p); }
p += p->i.offset; else condfailed(p);
continue; continue;
} }
case IEnd: /* cannot happen (should stop before it) */ case IEnd: /* cannot happen (should stop before it) */
...@@ -693,7 +789,8 @@ static void checkrule (lua_State *L, Instruction *op, int from, int to, ...@@ -693,7 +789,8 @@ static void checkrule (lua_State *L, Instruction *op, int from, int to,
for (i = from; i < to; i += sizei(op + i)) { for (i = from; i < to; i += sizei(op + i)) {
if (op[i].i.code == IPartialCommit && op[i].i.offset < 0) { /* loop? */ if (op[i].i.code == IPartialCommit && op[i].i.offset < 0) { /* loop? */
int start = dest(op, i); int start = dest(op, i);
assert(op[start - 1].i.code == IChoice && dest(op, start - 1) == i + 1); assert(op[start - 1].i.code == IChoice &&
dest(op, start - 1) == target(op, i + 1));
if (start <= lastopen) { /* loop does contain an open call? */ if (start <= lastopen) { /* loop does contain an open call? */
if (!verify(L, op, op + start, op + i, postable, rule)) /* check body */ if (!verify(L, op, op + start, op + i, postable, rule)) /* check body */
luaL_error(L, "possible infinite loop in %s", val2str(L, rule)); luaL_error(L, "possible infinite loop in %s", val2str(L, rule));
...@@ -712,8 +809,6 @@ static void checkrule (lua_State *L, Instruction *op, int from, int to, ...@@ -712,8 +809,6 @@ static void checkrule (lua_State *L, Instruction *op, int from, int to,
/* }====================================================== */ /* }====================================================== */
/* /*
** {====================================================== ** {======================================================
** Building Patterns ** Building Patterns
...@@ -766,7 +861,7 @@ static void rotate (Instruction *p, int e, int n) { ...@@ -766,7 +861,7 @@ static void rotate (Instruction *p, int e, int n) {
static int skipchecks (Instruction *p, int up, int *pn) { static int skipchecks (Instruction *p, int up, int *pn) {
int i, n = 0; int i, n = 0;
for (i = 0; ischeck(p + i); i += sizei(p + i)) { for (i = 0; isfixcheck(p + i); i += sizei(p + i)) {
int st = op_step(p + i); int st = op_step(p + i);
if (n + st > MAXOFF - up) break; if (n + st > MAXOFF - up) break;
n += st; n += st;
...@@ -784,7 +879,7 @@ static void optimizecaptures (Instruction *p) { ...@@ -784,7 +879,7 @@ static void optimizecaptures (Instruction *p) {
for (i = 0; p[i].i.code != IEnd; i += sizei(p + i)) { for (i = 0; p[i].i.code != IEnd; i += sizei(p + i)) {
if (isjmp(p + i) && dest(p, i) >= limit) if (isjmp(p + i) && dest(p, i) >= limit)
limit = dest(p, i) + 1; /* do not optimize jump targets */ limit = dest(p, i) + 1; /* do not optimize jump targets */
else if (i >= limit && ismovablecap(p + i) && ischeck(p + i + 1)) { else if (i >= limit && ismovablecap(p + i) && isfixcheck(p + i + 1)) {
int end, n, j; /* found a border capture|check */ int end, n, j; /* found a border capture|check */
int maxoff = getoff(p + i); int maxoff = getoff(p + i);
int start = i; int start = i;
...@@ -800,7 +895,7 @@ static void optimizecaptures (Instruction *p) { ...@@ -800,7 +895,7 @@ static void optimizecaptures (Instruction *p) {
p[j].i.aux += (n << 4); /* correct offset of captures to be moved */ p[j].i.aux += (n << 4); /* correct offset of captures to be moved */
rotate(p + start, end - start, i - start + 1); /* move them up */ rotate(p + start, end - start, i - start + 1); /* move them up */
i = end; i = end;
assert(ischeck(p + start) && iscapture(p + i)); assert(isfixcheck(p + start) && iscapture(p + i));
} }
} }
} }
...@@ -823,10 +918,10 @@ static void optimizejumps (Instruction *p) { ...@@ -823,10 +918,10 @@ static void optimizejumps (Instruction *p) {
static void optimizechoice (Instruction *p) { static void optimizechoice (Instruction *p) {
assert(p->i.code == IChoice); assert(p->i.code == IChoice);
if (ischeck(p + 1)) { if (isfixcheck(p + 1)) {
int lc = sizei(p + 1); int lc = sizei(p + 1);
rotate(p, lc, 1); rotate(p, lc, 1);
assert(ischeck(p) && (p + lc)->i.code == IChoice); assert(isfixcheck(p) && (p + lc)->i.code == IChoice);
(p + lc)->i.aux = op_step(p); (p + lc)->i.aux = op_step(p);
check2test(p, (p + lc)->i.offset); check2test(p, (p + lc)->i.offset);
(p + lc)->i.offset -= lc; (p + lc)->i.offset -= lc;
...@@ -850,16 +945,34 @@ static int isheadfail (Instruction *p) { ...@@ -850,16 +945,34 @@ static int isheadfail (Instruction *p) {
#define checkpattern(L, idx) ((Instruction *)luaL_checkudata(L, idx, PATTERN_T)) #define checkpattern(L, idx) ((Instruction *)luaL_checkudata(L, idx, PATTERN_T))
/*
** Return the number of elements in the ktable of a pattern.
** in Lua 5.2, default "environment" for patterns is nil, not
** a table. Treat it as an empty table.
*/
static int ktablelen (lua_State *L, int idx) {
if (!lua_istable(L, idx)) return 0;
else return lua_objlen(L, idx);
}
/*
** join the elements of the ktable from pattern 'p1' into the ktable of
** the pattern at the top of the stack ('p'). If 'p1' has no elements,
** 'p' keeps its original ktable. If 'p' has no elements, it shares
** 'p1' ktable. Otherwise, this function creates a new ktable for 'p'.
** Return the offset of original 'p' elements in the new ktable.
*/
static int jointable (lua_State *L, int p1) { static int jointable (lua_State *L, int p1) {
int n, n1, i; int n, n1, i;
lua_getfenv(L, p1); lua_getfenv(L, p1);
n1 = lua_objlen(L, -1); /* number of elements in p1's env */ n1 = ktablelen(L, -1); /* number of elements in p1's env */
lua_getfenv(L, -2); lua_getfenv(L, -2);
if (n1 == 0 || lua_equal(L, -2, -1)) { if (n1 == 0 || lua_equal(L, -2, -1)) {
lua_pop(L, 2); lua_pop(L, 2);
return 0; /* no need to change anything */ return 0; /* no need to change anything */
} }
n = lua_objlen(L, -1); /* number of elements in p's env */ n = ktablelen(L, -1); /* number of elements in p's env */
if (n == 0) { if (n == 0) {
lua_pop(L, 1); /* removes p env */ lua_pop(L, 1); /* removes p env */
lua_setfenv(L, -2); /* p now shares p1's env */ lua_setfenv(L, -2); /* p now shares p1's env */
...@@ -903,6 +1016,7 @@ static int addpatt (lua_State *L, Instruction *p, int p1idx) { ...@@ -903,6 +1016,7 @@ static int addpatt (lua_State *L, Instruction *p, int p1idx) {
static void setinstaux (Instruction *i, Opcode op, int offset, int aux) { static void setinstaux (Instruction *i, Opcode op, int offset, int aux) {
assert(aux <= MAXAUX);
i->i.code = op; i->i.code = op;
i->i.offset = offset; i->i.offset = offset;
i->i.aux = aux; i->i.aux = aux;
...@@ -913,6 +1027,10 @@ static void setinstaux (Instruction *i, Opcode op, int offset, int aux) { ...@@ -913,6 +1027,10 @@ static void setinstaux (Instruction *i, Opcode op, int offset, int aux) {
#define setinstcap(i,op,idx,k,n) setinstaux(i,op,idx,((k) | ((n) << 4))) #define setinstcap(i,op,idx,k,n) setinstaux(i,op,idx,((k) | ((n) << 4)))
/*
** create a new ktable for pattern at the stack top, mapping
** '1' to the value at stack position 'vidx'.
*/
static int value2fenv (lua_State *L, int vidx) { static int value2fenv (lua_State *L, int vidx) {
lua_createtable(L, 1, 0); lua_createtable(L, 1, 0);
lua_pushvalue(L, vidx); lua_pushvalue(L, vidx);
...@@ -959,7 +1077,7 @@ static void fillcharset (Instruction *p, Charset cs) { ...@@ -959,7 +1077,7 @@ static void fillcharset (Instruction *p, Charset cs) {
*/ */
static enum charsetanswer tocharset (Instruction *p, CharsetTag *c) { static enum charsetanswer tocharset (Instruction *p, CharsetTag *c) {
if (ischeck(p)) { if (isfixcheck(p)) {
fillcharset(p, c->cs); fillcharset(p, c->cs);
if ((p + sizei(p))->i.code == IEnd && op_step(p) == 1) if ((p + sizei(p))->i.code == IEnd && op_step(p) == 1)
c->tag = ISCHARSET; c->tag = ISCHARSET;
...@@ -1068,7 +1186,7 @@ static Instruction *fix_l (lua_State *L, int t) { ...@@ -1068,7 +1186,7 @@ static Instruction *fix_l (lua_State *L, int t) {
continue; continue;
} }
if (!testpattern(L, -1)) if (!testpattern(L, -1))
luaL_error(L, "invalid field in grammar"); luaL_error(L, "%s is not a pattern", val2str(L, -2));
l = pattsize(L, -1) + 1; /* space for pattern + ret */ l = pattsize(L, -1) + 1; /* space for pattern + ret */
if (totalsize >= MAXPATTSIZE - l) if (totalsize >= MAXPATTSIZE - l)
luaL_error(L, "grammar too large"); luaL_error(L, "grammar too large");
...@@ -1284,17 +1402,16 @@ static int unm_l (lua_State *L) { ...@@ -1284,17 +1402,16 @@ static int unm_l (lua_State *L) {
static int pattand_l (lua_State *L) { static int pattand_l (lua_State *L) {
int l1; int l1;
Instruction *p1 = getpatt(L, 1, &l1);
CharsetTag st1; CharsetTag st1;
Instruction *p1 = getpatt(L, 1, &l1);
if (isfail(p1) || issucc(p1)) if (isfail(p1) || issucc(p1))
lua_pushvalue(L, 1); /* &fail == fail; &true == true */ lua_pushvalue(L, 1); /* &fail == fail; &true == true */
else if (tocharset(p1, &st1) == ISCHARSET) { else if (tocharset(p1, &st1) == ISCHARSET) {
Instruction *p = newpatt(L, CHARSETINSTSIZE + 1); Instruction *p = newpatt(L, l1 + 1);
setinst(p, ISet, CHARSETINSTSIZE + 1); copypatt(p, p1, l1); p += l1;
loopset(i, p[1].buff[i] = ~st1.cs[i]); setinstaux(p, IBack, 0, 1);
setinst(p + CHARSETINSTSIZE, IFail, 0);
} }
else { else { /* Choice L1; p1; BackCommit L2; L1: Fail; L2: */
Instruction *p = newpatt(L, 1 + l1 + 2); Instruction *p = newpatt(L, 1 + l1 + 2);
setinst(p++, IChoice, 1 + l1 + 1); setinst(p++, IChoice, 1 + l1 + 1);
p += addpatt(L, p, 1); p += addpatt(L, p, 1);
...@@ -1305,6 +1422,41 @@ static int pattand_l (lua_State *L) { ...@@ -1305,6 +1422,41 @@ static int pattand_l (lua_State *L) {
} }
static int nocalls (const Instruction *p) {
for (; (Opcode)p->i.code != IEnd; p += sizei(p))
if ((Opcode)p->i.code == IOpenCall) return 0;
return 1;
}
static int pattbehind (lua_State *L) {
int l1;
CharsetTag st1;
Instruction *p1 = getpatt(L, 1, &l1);
int n = luaL_optint(L, 2, 1);
luaL_argcheck(L, n <= MAXAUX, 2, "lookbehind delta too large");
if (!nocalls(p1))
luaL_error(L, "lookbehind pattern cannot contain non terminals");
if (isfail(p1) || issucc(p1))
lua_pushvalue(L, 1); /* <fail == fail; <true == true */
else if (n == 1 && tocharset(p1, &st1) == ISCHARSET) {
Instruction *p = newpatt(L, 1 + l1);
setinstaux(p, IBack, 0, 1); p++;
copypatt(p, p1, l1);
}
else { /* Choice L1; Back; p1; BackCommit L2; L1: fail; L2: */
Instruction *p = newpatt(L, 2 + l1 + 2);
setinst(p++, IChoice, 2 + l1 + 1);
setinstaux(p++, IBack, 0, n);
p += addpatt(L, p, 1);
setinst(p++, IBackCommit, 2);
setinst(p, IFail, 0);
}
return 1;
}
static int firstpart (Instruction *p, int l) { static int firstpart (Instruction *p, int l) {
if (istest(p)) { if (istest(p)) {
int e = p[0].i.offset - 1; int e = p[0].i.offset - 1;
...@@ -1652,44 +1804,26 @@ static int capconst_l (lua_State *L) { ...@@ -1652,44 +1804,26 @@ static int capconst_l (lua_State *L) {
/* }====================================================== */ /* }====================================================== */
/* /*
** {====================================================== ** {======================================================
** User-Defined Patterns ** User-Defined Patterns
** ======================================================= ** =======================================================
*/ */
static void newpattfunc (lua_State *L, PattFunc f, const void *ud, size_t l) { static void l_newpf (lua_State *L, PattFunc f, const void *ud, size_t l) {
int n = instsize(l) + 1; int n = instsize(l) + 1;
Instruction *p = newpatt(L, n); Instruction *p = newpatt(L, n);
if (n > MAXAUX) luaL_error(L, "pattern data too long");
p[0].i.code = IFunc; p[0].i.code = IFunc;
p[0].i.offset = n; p[0].i.aux = n - 2;
p[0].i.offset = 0;
p[1].f = f; p[1].f = f;
memcpy(p[2].buff, ud, l); memcpy(p[2].buff, ud, l);
} }
#include <ctype.h>
static const char *span (const void *ud, const char *o,
const char *s,
const char *e) {
const char *u = (const char *)ud;
(void)o; (void)e;
return s + strspn(s, u);
}
static int span_l (lua_State *L) {
const char *s = luaL_checkstring(L, 1);
newpattfunc(L, span, s, strlen(s) + 1);
return 1;
}
/* }====================================================== */ /* }====================================================== */
/* /*
** {====================================================== ** {======================================================
** Captures ** Captures
...@@ -2145,8 +2279,10 @@ static int locale_l (lua_State *L) { ...@@ -2145,8 +2279,10 @@ static int locale_l (lua_State *L) {
lua_settop(L, 0); lua_settop(L, 0);
lua_createtable(L, 0, 12); lua_createtable(L, 0, 12);
} }
else else {
luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 1, LUA_TTABLE);
lua_settop(L, 1);
}
createcat(L, "alnum", isalnum); createcat(L, "alnum", isalnum);
createcat(L, "alpha", isalpha); createcat(L, "alpha", isalpha);
createcat(L, "cntrl", iscntrl); createcat(L, "cntrl", iscntrl);
...@@ -2162,11 +2298,19 @@ static int locale_l (lua_State *L) { ...@@ -2162,11 +2298,19 @@ static int locale_l (lua_State *L) {
} }
static int setmax (lua_State *L) {
luaL_optinteger(L, 1, -1);
lua_settop(L, 1);
lua_setfield(L, LUA_REGISTRYINDEX, MAXSTACKIDX);
return 0;
}
static int printpat_l (lua_State *L) { static int printpat_l (lua_State *L) {
Instruction *p = getpatt(L, 1, NULL); Instruction *p = getpatt(L, 1, NULL);
int n, i; int n, i;
lua_getfenv(L, 1); lua_getfenv(L, 1);
n = lua_objlen(L, -1); n = ktablelen(L, -1);
printf("["); printf("[");
for (i = 1; i <= n; i++) { for (i = 1; i <= n; i++) {
printf("%d = ", i); printf("%d = ", i);
...@@ -2184,7 +2328,7 @@ static int printpat_l (lua_State *L) { ...@@ -2184,7 +2328,7 @@ static int printpat_l (lua_State *L) {
static int matchl (lua_State *L) { static int matchl (lua_State *L) {
Capture capture[IMAXCAPTURES]; Capture capture[INITCAPSIZE];
const char *r; const char *r;
size_t l; size_t l;
Instruction *p = getpatt(L, 1, NULL); Instruction *p = getpatt(L, 1, NULL);
...@@ -2206,10 +2350,12 @@ static int matchl (lua_State *L) { ...@@ -2206,10 +2350,12 @@ static int matchl (lua_State *L) {
} }
static struct luaL_reg pattreg[] = { static struct luaL_Reg pattreg[] = {
{"match", matchl}, {"match", matchl},
{"print", printpat_l}, {"print", printpat_l},
{"locale", locale_l}, {"locale", locale_l},
{"setmaxstack", setmax},
{"B", pattbehind},
{"C", capture_l}, {"C", capture_l},
{"Cf", fold_l}, {"Cf", fold_l},
{"Cc", capconst_l}, {"Cc", capconst_l},
...@@ -2224,14 +2370,13 @@ static struct luaL_reg pattreg[] = { ...@@ -2224,14 +2370,13 @@ static struct luaL_reg pattreg[] = {
{"R", range_l}, {"R", range_l},
{"S", set_l}, {"S", set_l},
{"V", nter_l}, {"V", nter_l},
{"span", span_l},
{"type", type_l}, {"type", type_l},
{"version", version_l}, {"version", version_l},
{NULL, NULL} {NULL, NULL}
}; };
static struct luaL_reg metapattreg[] = { static struct luaL_Reg metapattreg[] = {
{"__add", union_l}, {"__add", union_l},
{"__pow", star_l}, {"__pow", star_l},
{"__sub", diff_l}, {"__sub", diff_l},
...@@ -2245,9 +2390,11 @@ static struct luaL_reg metapattreg[] = { ...@@ -2245,9 +2390,11 @@ static struct luaL_reg metapattreg[] = {
int luaopen_lpeg (lua_State *L); int luaopen_lpeg (lua_State *L);
int luaopen_lpeg (lua_State *L) { int luaopen_lpeg (lua_State *L) {
// lua_newtable(L); lua_pushcfunction(L, (lua_CFunction)&l_newpf); /* new-pattern function */
// lua_replace(L, LUA_ENVIRONINDEX); /* empty env for new patterns */ lua_setfield(L, LUA_REGISTRYINDEX, KEYNEWPATT); /* register it */
luaL_newmetatable(L, PATTERN_T); luaL_newmetatable(L, PATTERN_T);
lua_pushnumber(L, MAXBACK);
lua_setfield(L, LUA_REGISTRYINDEX, MAXSTACKIDX);
luaL_register(L, NULL, metapattreg); luaL_register(L, NULL, metapattreg);
luaL_register(L, "lpeg", pattreg); luaL_register(L, "lpeg", pattreg);
lua_pushliteral(L, "__index"); lua_pushliteral(L, "__index");
......
/*
** $Id: lpeg.h,v 1.1 2009/12/23 16:15:36 roberto Exp $
** LPeg - PEG pattern matching for Lua
** Copyright 2009, Lua.org & PUC-Rio (see 'lpeg.html' for license)
** written by Roberto Ierusalimschy
*/
#ifndef lpeg_h
#define lpeg_h
#include "lua.h"
#define KEYNEWPATT "lpeg.newpf"
/*
** type of extension functions that define new "patterns" for LPEG
** It should return the new current position or NULL if match fails
*/
typedef const char *(*PattFunc) (const char *s, /* current position */
const char *e, /* string end */
const char *o, /* string start */
const void *ud); /* user data */
/*
** function to create new patterns based on 'PattFunc' functions.
** This function is available at *registry[KEYNEWPATT]. (Notice
** the extra indirection; the userdata at the registry points to
** a variable that points to the function. In ANSI C a void* cannot
** point to a function.)
*/
typedef void (*Newpf) (lua_State *L,
PattFunc f, /* pattern */
const void *ud, /* (user) data to be passed to 'f' */
size_t l); /* size of data to be passed to 'f' */
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment