"--[[ Copyright (C) 2021 Momi-g\n"
"\n"
" This program is free software; you can redistribute it and/or modify\n"
" it under the terms of the GNU General Public License as published by\n"
" the Free Software Foundation; either version 3 of the License, or\n"
" (at your option) any later version.\n"
"\n"
" This program is distributed in the hope that it will be useful,\n"
" but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
" GNU General Public License for more details.\n"
"\n"
" You should have received a copy of the GNU General Public License\n"
" along with this program. If not, see <http://www.gnu.org/licenses/>.\n"
"--]]\n"
"local u = require('util');	--s = pretty.write(t) pretty.dump(t)\n"
"local ffi = require('ffi')\n"
"--require(\"strict\")\n"
"local ctx= {}\n"
"--global\n"
"\n"
"\n"
"--ソースは事前に全て\\nに変換しとく。\n"
"function ctx.srcemsg(str, pos, msg) \n"
"	--posはエラーstrの最後尾+1\n"
"	local pre = string.sub(str, 1, pos-1)\n"
"	local dmy, lcnt = string.gsub(pre, \"\\n\", \"\");	--line count for info\n"
"	lcnt = lcnt  or  1\n"
"	lcnt=lcnt+1\n"
"	--表示用にラスト一行を取得\n"
"	local eline=\"\"\n"
"	local cnt=1\n"
"	local scnt=0\n"
"	for s in string.gmatch(str, \"[^\\n]*[\\n]\")  do do eline=s;if cnt==lcnt then  do break end  end ;cnt=cnt+1;scnt=scnt+#s end::_luka_LOOPNEXT::end \n"
"	local cpos = pos-scnt\n"
"	eline = string.sub(eline, 1, cpos-1)..\"@\"..string.sub(eline, cpos, -1)\n"
"	local sbuf = u.fprintf(nil, \"errpos %d,%d:%s: %s\",lcnt, cpos, eline, msg )\n"
"	local emsg = u.fperr(nil, sbuf, 1)\n"
"	return emsg\n"
" end\n"
"\n"
"local SENTINEL_RNAME=\"%R_OPT\"\n"
"--tear-off string\n"
"function ctx.f_tof(str, reg, pos, ctg) \n"
"	local rstr = string.match(str, reg, pos)\n"
"	if rstr~=nil then  pos=pos + #rstr  end \n"
"	return rstr,pos,ctg\n"
" end\n"
"\n"
"-- '' [] \"\" r// lit系tokenを切り取る 後ろの]系は外す。posはnextから\n"
"function ctx.f_blkstr(str, pos, resc, rend, ctg) \n"
"	--resc:[\\\\], rend:['] etc\n"
"	local rs=\"\"\n"
"	local s, e = ctx.f_blkend(str, pos, resc, rend)\n"
"	if s==nil then 	--no blkend\n"
"		ctg=\"err\"\n"
"		rs=e\n"
"		e=pos\n"
"	 \n"
"	else \n"
"		rs=string.sub(str, pos, s-1)	--尻尾の==]は含めない\n"
"		e=e+1\n"
"	 end \n"
"	return rs,e,ctg	--posはnext位置になる\n"
" end\n"
"\n"
"-- fc(\"(-....\\(...-)\", 1, '\\\\', \"-)\" ) で-)の\")\"位置を返す\n"
"-- escとendはluaパターン eposは]の一番最後を示す\n"
"-- rescが\"\"ならesc無しで純粋にrendを探す\n"
"function ctx.f_blkend(str, pos, resc, rend) \n"
"	resc=resc or \"\"\n"
"	local spos=pos\n"
"	local srtn, ertn=0, 0\n"
"	pos=pos-1\n"
"	while 1 do do \n"
"	::lb_NEXT::\n"
"		pos=pos+1\n"
"		local s, e = string.find(str, resc, pos)	-- \\\"esc\n"
"		if s==nil or resc==\"\" then  s = string.len(str)+1  end 	--捏造\n"
"		local ss, ee = string.find(str, rend, pos)	-- \"end\n"
"		--no blkend\n"
"		if ss==nil then  return nil, \"closing symbol is not found: \"..rend  end \n"
"		if  s  and  s<ss then pos=s+1;goto lb_NEXT end \n"
"		srtn=ss\n"
"		ertn=ee\n"
"		 do break end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	return srtn, ertn\n"
" end\n"
"\n"
"--uni[]は[^-^]がありえるので小細工が必要 単体は[^]でいいけど >> 違法 \\^のみ\n"
"--[\\u005e] == [^] は\\^に変換しないとダメ[^]]も対応していない。\n"
"--...だめだ。^はoctはarrで検査してるけどuniはそのままなので分離できない。\n"
"-- [^\\u0001\\u0002] != ([^\\u0001]|[^\\u0002])\n"
"--は数学的に成立しない 内部の移動のみに止めるべき。\n"
"--先頭に\\u005e-は不可能にしておいて\\u005e単体は最後に持っていく\n"
"--notがついているならそのままでいい 肩鎖のみ\n"
"function ctx.uniclass(str) \n"
"	local cpy = str\n"
"	local inv = string.match(str, \"^%^\") or \"\"\n"
"	if inv~=\"\" then  cpy=string.sub(str, 2, -1)  end \n"
"\n"
"	local cur=1\n"
"	local hex = \"[0-9a-fA-F]\"\n"
"	local u4 = \"\\\\u\"..hex..hex..hex..hex\n"
"	local u8 = \"\\\\U\"..hex..hex..hex..hex..hex..hex..hex..hex\n"
"	\n"
"	local buf = string.gsub(cpy, u8, \"\")\n"
"	buf = string.gsub(buf, u4, \"\")\n"
"	buf = string.gsub(buf, \"%-\", \"\")\n"
"	if buf~=\"\" then  return nil, \"reg-uniclass holds badstr: \"..buf  end \n"
"	\n"
"	local sym={}	--uni系は[].:=^の特殊文字が邪魔なので別枠でメモ\n"
"	local res=\"\"\n"
"	local ptn = \"(\\\\[uU]([0-9a-fA-F]+)%-\\\\[uU]([0-9a-fA-F]+))\"\n"
"	for a,s,e in string.gmatch(cpy, ptn)  do do \n"
"		local snum = tonumber(s, 16)\n"
"		local enum = tonumber(e, 16)\n"
"		if snum==0x5e and enum==0x5e then  sym[\"^\"]=\"\\\\u005e\"; goto lb_NEXT  end \n"
"		if snum==0x5e then \n"
"			snum=0x5f\n"
"			sym[\"^\"]=\"\\\\u005e\"\n"
"			a=\"\\\\u005f-\\\\U\"..string.format(\"%08x\", enum)\n"
"			--書き換えとメモ\n"
"		 end \n"
"		if snum>0x10ffff or enum>0x10ffff then  return nil, \"unicode num >0x10FFFF: \"  end \n"
"		if snum>enum then  return nil, \"unicode bad range s>e: \"  end \n"
"		res=res..a\n"
"		::lb_NEXT::\n"
"	 end::_luka_LOOPNEXT::end \n"
"	cpy = string.gsub(cpy, ptn, \"\")\n"
"	ptn = \"(\\\\[uU]([0-9a-fA-F]+))\"\n"
"--\n"
"	for a,s in string.gmatch(cpy, ptn)  do do \n"
"		local snum = tonumber(s, 16)\n"
"		if snum>0x10ffff then  return nil, \"unicode num >0x10FFFF: \"  end \n"
"		-- -[^ 2d,5b,5e は設置順序が決まってる\n"
"		-- -は常に先頭、^は常に尻尾 [ は尻尾か[^のどっちか\n"
"		if snum==0x2d then  sym[\"-\"]=\"\\\\u002d\" \n"
"		elseif snum==0x5b then  sym[\"[\"]=\"\\\\u005b\" \n"
"		elseif snum==0x5e then  sym[\"^\"]=\"\\\\u005e\" \n"
"		else  res=res..a  end \n"
"		-- :とか]は尻尾に追加される [が無い以上特殊にはなりえない\n"
"	 end::_luka_LOOPNEXT::end \n"
"	res= (sym[\"-\"] or \"\")..res\n"
"	res= res..(sym[\"[\"] or \"\")\n"
"	res= res..(sym[\"^\"] or \"\")\n"
"	res= inv..res\n"
"	if res==\"\\\\u005e\" then  return \"\\\\^\" end 	--[]系で[^]だけは表現不可能\n"
"	return 	\"[\"..res..\"]\"\n"
" end\n"
"\n"
"--octclassは()にばらされるので^問題は不要\n"
"function ctx.octclass(str) \n"
"	local cpy=str\n"
"	local inv = string.match(str, \"^%^\")\n"
"	if inv then  cpy=string.sub(str, 2, -1)  end \n"
"\n"
"	local cur=1\n"
"	local nml=\"\"\n"
"	cpy = string.gsub(cpy, \"([0-9]+)\", \"0%1\")\n"
"	cpy = string.gsub(cpy, \"\\\\0([0-9][0-9][0-9])\", \"\\\\%1\")\n"
"	local ptn1 = \"\\\\([0-3][0-7]?[0-7]?)%-\\\\([0-3][0-7]?[0-7]?)\"\n"
"	local ptn2 = \"\\\\([0-3][0-7]?[0-7]?)\"	--ptn1の後の生き残り 単体系\n"
"	--range\n"
"	local binarr = {}\n"
"	for s,e in string.gmatch(cpy, ptn1) do do \n"
"		local snum = tonumber(s,8)\n"
"		local enum = tonumber(e,8)\n"
"		if enum<snum then  return nil, \"bad reg-octclass range, s>e:\"..s..\">\"..e  end \n"
"		for i=snum, enum do do  binarr[i]=1  end::_luka_LOOPNEXT::end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	cpy = string.gsub(cpy, ptn1, \"\")\n"
"	for s in string.gmatch(cpy, ptn2)  do do  binarr[tonumber(s,8)]=1  end::_luka_LOOPNEXT::end \n"
"	cpy = string.gsub(cpy, ptn2, \"\")\n"
"	--残骸\n"
"	if cpy~=\"\" then  return nil, \"reg-octclass holds bad oct: \"..str..\": \"..cpy  end \n"
"	-- 0-255を\\123系でor結合 esc変換に備える	^は反転させる\n"
"	local res=\"\"\n"
"	for i=0,255 do do \n"
"		if next(binarr)==nil then  do break end  end \n"
"		local buf=nil\n"
"		if  not inv and binarr[i] then  buf=string.format(\"\\\\%03o\", i)	 \n"
"		elseif inv and binarr[i]==nil then  buf=string.format(\"\\\\%03o\", i)  end \n"
"		local c = string.char(i)\n"
"		-- c=\\とか)のescは後ろで纏めて追加する。[]の前にも\\123がいたりする\n"
"		if buf then  res=res..\"|\"..buf  end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	if res~=\"\" then  res=\"(\"..string.sub(res, 2,-1)..\")\"  end \n"
"	return res\n"
" end\n"
"\n"
"\n"
"--[:alpha:]系を直した 前後[]は除かれてるので追加して返す\n"
"-- \\n 文字escは全範囲で有効にしとく\n"
"function ctx.f_kickoct(str, ctg) \n"
"	local cpy=string.sub(str,2,-2)\n"
"	--oct-class\n"
"	if ctg==\"bre\"  and  string.match(cpy, \"\\\\[0-9]\")  then \n"
"		return nil, \"BRE doesnt allow binary class data, [\\\\nnn]\"\n"
"	 \n"
"	elseif string.match(cpy, \"\\\\[0-9]\") then  return ctx.octclass(cpy)  \n"
"	elseif string.match(cpy, \"\\\\[uU]\") then  return ctx.uniclass(cpy)  end \n"
"	return \"[\"..cpy..\"]\"\n"
" end\n"
"\n"
"function ctx.getclass(str, spos) \n"
"	local cur=spos+1	--[が含まれるので\n"
"	if string.sub(str, cur, cur+1)==\"^]\" then  cur=cur+2  end 	--[^]] を逃がす\n"
"	local res=\"\"\n"
"	local farr={}\n"
"	while 1 do do \n"
"		local spos = string.find(str, \"%[([%.%:%=])\", cur)\n"
"		local eblk = string.find(str, \"]\", cur, true)\n"
"		--[ [::] ] 系か[ [:dmy ] かの判別が必要 先に]が閉じてればよし\n"
"		if spos==nil then  do break end  end \n"
"		if eblk<spos then  do break end  end \n"
"		cur=spos+2\n"
"		local estr = string.sub(str, spos+1, spos+1)..\"]\"\n"
"		local epos = string.find(str, estr, cur, true)\n"
"		if epos==nil then  do break end  end \n"
"		epos=epos+1\n"
"		for i=spos, epos do do farr[i]=1 end::_luka_LOOPNEXT::end \n"
"		cur=epos+1\n"
"	 end::_luka_LOOPNEXT::end \n"
"	if cur==spos+1 then  cur=cur+1  end 	--[]はエラー []]ならok\n"
"	while 1 do do \n"
"		cur = string.find(str, \"]\", cur, true)\n"
"		if cur==nil then \n"
"			res=nil\n"
"			emsg=\"closing reg-class symbol not found\"\n"
"			return res, emsg\n"
"		 end \n"
"		if farr[cur]==nil then  do break end  end \n"
"		cur=cur+1\n"
"	 end::_luka_LOOPNEXT::end \n"
"	res = string.sub(str, spos, cur)\n"
"	return res\n"
" end\n"
"\n"
"\n"
"-- ereとbreに対応させるのと修正\n"
"-- eb// eb\"\" eb'' どれか。 内部全てでendskipはescが必要にする\n"
"-- class修正 .と[]は文字クラスなのでバイナリは外だしする . は対応不可能なので\n"
"-- ([\\0-\\377]|.)で対応する uniを全部削除して、残りを()で加工すればいいか\n"
"--uregで.はmulti>>なければ1byteに対応した。そのまま放置でいい\n"
"\n"
"-- regの[]はバイナリを扱えない。[]外で(123|123)を使って羅列するしか手段がない\n"
"-- ここでは\\\", [\\123]のclass内部のbinを外だしにするだけ。他のesc, \\a \\1 \\oooは\n"
"-- \\u系と合わせて始末する\n"
"function ctx.f_regstr(str, pos, resc, rend, ctg) \n"
"	--resc:[\\\\], rend:['] etc\n"
"	-- +1は速度が遅いのでスキップ利用\n"
"	resc=resc or \"\"\n"
"	local ipos=pos	--先頭\"を飛ばす\n"
"	pos=ipos-1\n"
"	local rs=\"\"\n"
"	local elen = #str+1\n"
"	local deltb={}\n"
"	while 1 do do \n"
"		::lb_NEXT::\n"
"		pos=pos+1\n"
"		local s, e = string.find(str, rend, pos)	-- \"end\n"
"		local ss, ee = string.find(str, resc, pos)	-- \\ esc\n"
"		if ss==nil or resc==\"\" then  ss = string.len(str)+1  end 	--捏造\n"
"		local s_, e_ = string.find(str, resc..rend, pos)	-- \\\"	omitに使う\n"
"		local sss, eee = string.find(str, \"[%[]\", pos)	--charclass \\[こんなのもある\n"
"--regexのescは固定なのでblockのescとかぶってもうまく始末する必要がある\n"
"--sedを参考に. ハードコードになるけど\\\\でもいいかもしれない\n"
"\n"
"		-- これが正しい。close charは[]内部でescしてはいけない sedと同じ方式\n"
"		if s==nil then 	--no blkend\n"
"			ctg=\"err\"\n"
"			rs=\"closing symbol is not found: \"..rend..\" \"..string.sub(str, ipos-1, ipos+10)\n"
"			 do break end \n"
"		 end \n"
"--print(pos, ee, s,ss,sss,ssss, elen)\n"
"		ss=ss or elen\n"
"		sss=sss or elen\n"
"\n"
"		if sss<s  and  sss<ss then \n"
"			--hit [  加工して\\123系は外にだす\n"
"			rs = rs..string.sub(str, pos, sss-1)\n"
"			--normalは普通に追加しとく\n"
"			local res, emsg = ctx.getclass(str, sss)\n"
"--print(res, emsg, \"e_\")\n"
"			if emsg then \n"
"				ctg=\"err\"\n"
"				rs=emsg\n"
"				 do break end \n"
"			 end \n"
"--print(22222, res, emsg)\n"
"			pos = sss + #res -1	--上で+1するのでendを入れる\n"
"			--[]付きclass内部文字の羅列たち これがベースになる\n"
"			local sgrp, emsg = ctx.f_kickoct(res, ctg)\n"
"--print(res, sgrp)\n"
"			if emsg then \n"
"				ctg=\"err\"\n"
"				rs=emsg\n"
"				 do break end \n"
"			 end \n"
"			--\\123系は()に変換 [\\1]は[\\001]に直して外だし \\u系とorgは放置\n"
"			rs = rs..sgrp\n"
"			goto lb_NEXT\n"
"		 end \n"
"		if ss<s  and  ss<sss then \n"
"			--hit esc \\\"なら\"に変換してそれ以外は\\xxxのまま放置\n"
"			-- >> \\[ \\{系があるので+1で始末する\n"
"			-- blkのescとregのescがかぶっているが実装を優先する\n"
"			--後処理の\\uとかでそのまま処理させる\n"
"			rs = rs..string.sub(str, pos, ss-1)	--escの直前までとって\\b or \"を追加\n"
"			--検査 end系なら escは切らないといけない\n"
"			local buf = string.sub(str, ss, ee+1 ) --長すぎは最長になる\n"
"			local npos = ee+1\n"
"			if  ss == s_  then \n"
"				buf=string.sub(str, ee+1, e_ )\n"
"				npos=e_\n"
"			 end \n"
"			rs = rs..buf\n"
"			pos= npos\n"
"			goto lb_NEXT\n"
"		 end \n"
"		--hit\n"
"		rs = rs..string.sub(str, pos, s-1)\n"
"		pos=e\n"
"		 do break end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	pos=pos+1	--next位置\n"
"	return rs,pos,ctg\n"
" end\n"
"\n"
"--file読みだったけど外だししたので%R_optだけになった\n"
"function ctx.src2str(str, exp) \n"
"	--pegルールに最終ルール追加。オプションによって出力方式を変える。\n"
"	if   string.match(exp, \"n\")  then  str = str..\"\\n\"..SENTINEL_RNAME..\" <- . { _0 = '' }\\n\"  \n"
"	elseif  string.match(exp, \"N\")  then  str = str..\"\\n\"..SENTINEL_RNAME..\" <- . { _E }\\n\"  \n"
"	elseif 1 then  str = str..\"\\n\"..SENTINEL_RNAME..\" <- . \\n\"  end \n"
"	return str\n"
" end\n"
"\n"
"-- rtnは tb, srcstr かnil, emsg\n"
"function ctx.f_scanpeg(data, exp) \n"
"	exp=exp or \"\"\n"
"	local str, emsg = ctx.src2str(data, exp)\n"
"	if str==nil then return str, emsg end \n"
"	local cur=1;	--seekcur.\n"
"	local ctg=\"\";	--category\n"
"	local mcur=string.len(str)\n"
"	local rs=\"\";	--rtnstr\n"
"	local rc=0\n"
"	local terms = {}\n"
"	local aflg=0	--act系の存在で仕分けが必要になった\n"
"	local grule=1	--一般ルール origモードで%R_OPTの{}をrRから逃がすのに必要になった\n"
"\n"
"	--lex. f_tofは結果を出してcurを先頭に進める。常に未知の先頭。continueがない。\n"
"::lbl_NEXT::\n"
"	while cur<=mcur do do \n"
"		--while...alt goto\n"
"		while true do do \n"
"			--reg\n"
"			rs=string.sub(str,cur,cur+1)\n"
"			if rs==\"e/\" then 	rs,cur,ctg = ctx.f_regstr(str, cur+2, \"[\\\\]\", \"[/]\", \"ere\");  do break end   end \n"
"			if rs=='e\"' then 	rs,cur,ctg = ctx.f_regstr(str, cur+2, \"[\\\\]\", '[\"]', \"ere\");  do break end   end \n"
"			if rs==\"e'\" then 	rs,cur,ctg = ctx.f_regstr(str, cur+2, \"[\\\\]\", \"[']\", \"ere\");  do break end   end \n"
"\n"
"			if rs==\"b/\" then 	rs,cur,ctg = ctx.f_regstr(str, cur+2, \"[\\\\]\", \"[/]\", \"bre\");  do break end   end \n"
"			if rs=='b\"' then 	rs,cur,ctg = ctx.f_regstr(str, cur+2, \"[\\\\]\", '[\"]', \"bre\");  do break end   end \n"
"			if rs==\"b'\" then 	rs,cur,ctg = ctx.f_regstr(str, cur+2, \"[\\\\]\", \"[']\", \"bre\");  do break end   end \n"
"			\n"
"			--heredoc\n"
"			if rs=='h\"' then 	rs,cur,ctg = ctx.f_blkstr(str, cur+2, \"\", '[\"]', \"hlit\");  do break end   end \n"
"			if rs==\"h'\" then 	rs,cur,ctg = ctx.f_blkstr(str, cur+2, \"\", \"[']\", \"hlit\");  do break end   end 		\n"
"			--lit,class, multi word. cur/escreg/endreg\n"
"			rs=string.sub(str,cur,cur)\n"
"			if rs==\"'\" then 	rs,cur,ctg = ctx.f_blkstr(str, cur+1, \"[\\\\]\", \"[']\", \"lit\");  do break end   end \n"
"			if rs=='\"' then 	rs,cur,ctg = ctx.f_blkstr(str, cur+1, \"[\\\\]\", '[\"]', \"lit\");  do break end   end \n"
"			if rs==\"[\" then 	rs,cur,ctg = ctx.f_blkstr(str, cur+1, \"[\\\\]\", '[%]]', \"class\");  do break end   end \n"
"		\n"
"			--blank\n"
"			rs,cur,ctg=ctx.f_tof(str,\"^[#][^\\n]*[\\n]\", cur, \"skip\"); if rs then  do break end  end  --lcmt\n"
"			rs,cur,ctg=ctx.f_tof(str,\"^[ \\t\\r\\v\\f\\n]+\", cur, \"skip\"); if rs then  do break end  end  --blank\n"
"			--nlはblankに統合。actもLA(2)で探索。;は無視。\n"
"			\n"
"			--rule term\n"
"			if aflg<=0 then \n"
"				rs,cur,ctg=ctx.f_tof(str,\"^[_a-zA-Z][_a-zA-Z0-9]*\", cur, \"ident\"); if rs then  do break end  end \n"
"				rs,cur,ctg=ctx.f_tof(str,\"^%\"..SENTINEL_RNAME, cur, \"ident\"); if rs then grule=nil;  do break end  end \n"
"				--%R_OPTが必要なのでorigからここで逃がす gruleのフラグを潰す\n"
"			 end \n"
"			rs,cur,ctg=ctx.f_tof(str,\"^[<][-]\", cur, \"def\"); if rs then  do break end  end \n"
"			rs,cur,ctg=ctx.f_tof(str,\"^[/]\", cur, \"subdef\"); if rs then  do break end  end \n"
"			rs,cur,ctg=ctx.f_tof(str,\"^[.]\", cur, \"class\"); if rs then  do break end  end \n"
"			--add BOF\n"
"			rs,cur,ctg=ctx.f_tof(str,\"^!![.]\", cur, \"bof\"); if rs then  do break end  end \n"
"			--\"lit\" 'lit' [cls] is upper\n"
"			--symbol\n"
"			rs,cur,ctg=ctx.f_tof(str,\"^[(]\", cur, \"(\"); if rs then  do break end  end \n"
"			rs,cur,ctg=ctx.f_tof(str,\"^[)]\", cur, \")\"); if rs then  do break end  end \n"
"			rs,cur,ctg=ctx.f_tof(str,\"^[!]\", cur, \"pre\"); if rs then  do break end  end \n"
"			rs,cur,ctg=ctx.f_tof(str,\"^[&]\", cur, \"pre\"); if rs then  do break end  end \n"
"			rs,cur,ctg=ctx.f_tof(str,\"^[*]\", cur, \"suf\"); if rs then  do break end  end \n"
"			rs,cur,ctg=ctx.f_tof(str,\"^[?]\", cur, \"suf\"); if rs then  do break end  end \n"
"			rs,cur,ctg=ctx.f_tof(str,\"^[+]\", cur, \"suf\"); if rs then  do break end  end \n"
"			\n"
"			--act\n"
"			rs,cur,ctg=ctx.f_tof(str,\"^[{]\", cur, \"{\"); if rs then aflg=aflg+1;  do break end  end \n"
"			rs,cur,ctg=ctx.f_tof(str,\"^[}]\", cur, \"}\"); if rs then aflg=aflg-1;  do break end  end \n"
"			rs,cur,ctg=ctx.f_tof(str,\"^[_]E\", cur, \"aE\"); if rs then  do break end  end 	--errsym@act\n"
"			rs,cur,ctg=ctx.f_tof(str,\"^[_][0]\", cur, \"aC\"); if rs then  do break end  end 	--lcnt微妙\n"
"			rs,cur,ctg=ctx.f_tof(str,\"^[_][1-9][0-9]*\", cur, \"aC\"); if rs then  do break end  end \n"
"			rs,cur,ctg=ctx.f_tof(str,\"^[:]?[=]\", cur, \"=\"); if rs then  do break end  end 	--assign\n"
"			rs,cur,ctg=ctx.f_tof(str,\"^[;]\", cur, \"sep\"); if rs then  do break end  end 	-- ; == nl @act\n"
"			\n"
"			--other == invalid char\n"
"			ctg=\"err\"\n"
"			rs=\"badrule/bad char: \"..string.sub(str, cur, cur)\n"
"			 do break end \n"
"		 end::_luka_LOOPNEXT::end \n"
"		--err\n"
"		if aflg<0 then ctg=\"err\"; rs=\"uneven curly braces\" end \n"
"		if ctg == \"err\"  then 	return nil, ctx.srcemsg(str, cur, rs)  end \n"
"		--charesc\n"
"		if   not string.match(exp, \"[rR]\",1)  then \n"
"			--拡張モード以外はオリジナルだけ\n"
"			-- %R_OPTはNで{_E}が必須になるので逃がす\n"
"			if  string.find(\"{} aE aC = hlit bre ere sep bof\", ctg, 1, true) and grule  then \n"
"				if ctg~=\"lit\" then \n"
"					---1はendの']がズレるため\n"
"					return nil, ctx.srcemsg(str, cur-string.len(rs)-1, \"bad word in orig peg mode: ctg/char \".. ctg..\"/\"..rs)\n"
"				 end \n"
"			 end \n"
"			--esc表現が標準外\n"
"			if ctg==\"class\" or ctg==\"lit\" then \n"
"				local sbuf=rs\n"
"				sbuf = string.gsub(sbuf, \"\\\\[\\\\%[%]nrt'\\\"]\", \"\")\n"
"				sbuf = string.gsub(sbuf, \"\\\\[0-2][0-7][0-7]\", \"\")\n"
"				sbuf = string.gsub(sbuf, \"\\\\[0-7][0-7]?\", \"\")\n"
"				if  string.find(sbuf, \"\\\\\", 1, true)  then \n"
"					return nil, ctx.srcemsg(str, cur-string.len(rs)-1, \"bad escchar in orig peg mode: \"..sbuf)\n"
"				 end \n"
"			 end \n"
"		 end \n"
"		\n"
"		if ctg == \"skip\" then  goto lbl_NEXT  end \n"
"		local s = rs\n"
"		--sは\"\" r//を除いた純粋な餡子なのでerrは尻尾から数えた方が安定する\n"
"		if ctg==\"class\" or ctg == \"lit\" or ctg==\"bre\" or ctg==\"ere\" then \n"
"			--parse with LL(1)\n"
"			local cpos=1\n"
"			s=\"\"\n"
"			local bstr = rs\n"
"			local sbuf=\"\"\n"
"			local rcls=0\n"
"			local rg = 0\n"
"			if ctg==\"bre\" or ctg==\"ere\" then rcls= -1; rg=1 end \n"
"			while 1 do do \n"
"			::lb_NEXT::\n"
"				if string.len(bstr)<cpos then  do break end  end \n"
"				--基本共通\n"
"				--chars\n"
"				if  string.match(bstr,'^\\\\n',cpos)  then  s=s..\"\\n\";cpos=cpos+2; goto lb_NEXT end \n"
"				if  string.match(bstr,'^\\\\r',cpos)  then  s=s..\"\\r\";cpos=cpos+2; goto lb_NEXT end \n"
"				if  string.match(bstr,'^\\\\t',cpos)  then  s=s..\"\\t\";cpos=cpos+2; goto lb_NEXT end \n"
"				--lit, peg-class	regは[]が複雑かつbackrefなので下で纏めて始末\n"
"				if  ctg==\"class\" or ctg==\"lit\" then \n"
"					if  string.match(bstr,'^\\\\\"',cpos)  then  s=s..\"\\\"\";cpos=cpos+2; goto lb_NEXT end \n"
"					if  string.match(bstr,\"^\\\\'\",cpos)  then  s=s..\"\\'\";cpos=cpos+2; goto lb_NEXT end \n"
"					if  string.match(bstr,'^\\\\%[',cpos) then  s=s..\"[\"; cpos=cpos+2; goto lb_NEXT end \n"
"					if  string.match(bstr,'^\\\\%]',cpos) then  s=s..\"]\"; cpos=cpos+2; goto lb_NEXT end \n"
"					if  string.match(bstr,'^\\\\\\\\',cpos) then  s=s..\"\\\\\";cpos=cpos+2; goto lb_NEXT end \n"
"				 end \n"
"				--reg\n"
"				if  rcls<0  and  rg==1  then \n"
"					-- not reg-class + esc\n"
"					sbuf = string.sub(bstr, cpos, cpos)\n"
"					--bad char\n"
"					if sbuf=='$' then \n"
"						return nil, ctx.srcemsg(str, cur-(string.len(rs)-cpos)-2,\n"
"					 \"use peg-eof '!.' instead of anchor '$' eg) e/abc$/ >> e/abc/ !.\")\n"
"					 end \n"
"					if sbuf==\"\\\\\" then \n"
"						-- https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_03\n"
"						sbuf = string.sub(bstr,cpos+1,cpos+1)\n"
"						if ctg==\"bre\"  and  string.find('^.[$*\\\\(){}', sbuf, 1, true)  then \n"
"							s = s..\"\\\\\"..sbuf\n"
"							cpos = cpos+2\n"
"							goto lb_NEXT\n"
"						 end \n"
"						if ctg==\"ere\"  and  string.find('^.[$()|*+?{\\\\', sbuf, 1, true)  then \n"
"							s = s..\"\\\\\"..sbuf\n"
"							cpos = cpos+2\n"
"							goto lb_NEXT\n"
"						 end \n"
"					 end \n"
"				 end \n"
"				--oct	-\\277 \\34, bkref\\9 系も\n"
"				sbuf =  string.match(bstr, '^\\\\[0-9][0-7]?[0-7]?', cpos)\n"
"				while  sbuf  do do \n"
"					--bkref \\1-9 ==breのみ\n"
"					if ctg==\"bre\" and rcls<0 and #sbuf==2 and sbuf~=\"\\\\0\" then \n"
"						--regは\\1系はスルー\n"
"						s = s..sbuf\n"
"						cpos = cpos+string.len(sbuf)\n"
"						goto lb_NEXT\n"
"					 \n"
"					elseif ctg==\"ere\" and rcls<0 and #sbuf==2 and sbuf~=\"\\\\0\" then \n"
"						--ereはbkrefはない。エラーにする\n"
"						return nil, ctx.srcemsg(str, cur-(string.len(rs)-cpos)-2,\n"
"					 \"regex ERE doesnt support back reference: \\\\1-9\")\n"
"					 end \n"
"					if string.match(sbuf, \"[89]\") then  do break end  end 	--\\83etc >>err\\8[3]\n"
"					--\\0-\\277 filter\n"
"					local num = tonumber(string.sub(sbuf, 2,2) )\n"
"					if #sbuf==4  and  num>2 then  do break end  end 	--\\366 etc	\\300> ...-r/R\n"
"					\n"
"					num = tonumber(string.sub(sbuf, 2), 8)\n"
"					cstr = string.char(num)\n"
"					--\\ooo >> 1char >> add \\\\ if needed\n"
"					if ctg==\"ere\" and rcls<0 and string.find(\"^.[$()|*+?{\\\\\",cstr,1,true)  then cstr=\"\\\\\"..cstr \n"
"					elseif ctg==\"bre\" and rcls<0 and string.find('^.[$*\\\\(){}', cstr, 1,true)  then cstr=\"\\\\\"..cstr \n"
"					elseif ctg==\"class\" and cstr==\"-\" then \n"
"						--peg-class hyphen問題は-のみ\\[は1byteでいい。oct-は小細工が必要\n"
"						--octの\\055 - を始末 三連を頭にセット trick\n"
"						cstr=\"\"\n"
"						if  not string.find(\"---\", s, 1, true)  then s=\"---\"..s end \n"
"					 end \n"
"					s = s..cstr\n"
"					cpos = cpos+string.len(sbuf)\n"
"					goto lb_NEXT\n"
"				 end::_luka_LOOPNEXT::end \n"
"				--拡張, c99 unicode, classは基本のみ>>やっぱ拡張\\377が使えない\n"
"				if  string.match(exp, \"[rR]\",1)  then \n"
"					--chars\n"
"					if  string.match(bstr,'^\\\\a',cpos)  then  s=s..\"\\a\";cpos=cpos+2; goto lb_NEXT end \n"
"					if  string.match(bstr,'^\\\\b',cpos)  then  s=s..\"\\b\";cpos=cpos+2; goto lb_NEXT end \n"
"					if  string.match(bstr,'^\\\\v',cpos)  then  s=s..\"\\v\";cpos=cpos+2; goto lb_NEXT end \n"
"					if  string.match(bstr,'^\\\\f',cpos)  then  s=s..\"\\f\";cpos=cpos+2; goto lb_NEXT end \n"
"					--oct 2桁は上で始末済み\n"
"					sbuf = string.match(bstr, '^\\\\[0-3][0-7]?[0-7]?', cpos)\n"
"					if  sbuf  then \n"
"						--reg後方参照形は頭で処理済み\n"
"						--reg,class,lit共通 reg[]の\\123はblkで始末済み\n"
"						local num = tonumber( string.sub(sbuf, 2), 8)\n"
"						s = s..string.char(num)\n"
"						cpos = cpos+string.len(sbuf)\n"
"						goto lb_NEXT\n"
"					 end \n"
"					--uni\n"
"					sbuf = string.match(bstr, '^\\\\[uU]', cpos)\n"
"					if  sbuf  then \n"
"						local c = \"[0-9a-fA-F]\"\n"
"						local u4 = string.match(bstr, '^\\\\u'..c..c..c..c, cpos)\n"
"						local u8 = string.match(bstr, '^\\\\U'..c..c..c..c..c..c..c..c, cpos)\n"
"						sbuf=u4 or u8 or nil\n"
"						if sbuf==nil then  return nil, ctx.srcemsg(str, cur-(string.len(rs)-cpos)-2, \"bad unicode len, needs u4/U8\")  end \n"
"						if ctg==\"class\" then  return nil, ctx.srcemsg(str, cur-(string.len(rs)-cpos)-2, \"peg-class unsupports unicode: \"..sbuf)  end \n"
"						c = u.strconv(sbuf, \"uc:b\")\n"
"						-- reg系機能付きはesc pclsは弾いてる 全て変換してよし\n"
"						if ctg==\"bre\" and rcls<0 and string.find('^.[$*\\\\(){}', c, 1, true)  then c=\"\\\\\"..c \n"
"						elseif ctg==\"ere\" and rcls<0 and string.find(\"^.[$()|*+?{\\\\\", c, 1, true)  then c=\"\\\\\"..c end \n"
"						s = s..c\n"
"						cpos = cpos+string.len(sbuf)\n"
"						goto lb_NEXT\n"
"					 end \n"
"				 end \n"
"				--生き残り==通常char系\n"
"				sbuf = string.sub(bstr, cpos, cpos)\n"
"				--invalid esc\n"
"				if rcls~=1  and  sbuf=='\\\\' then \n"
"					return nil, ctx.srcemsg(str, cur-(string.len(rs)-cpos)-2,\n"
"						\"bad charesc: \"..string.sub(bstr,cpos,cpos+1) )\n"
"				 end \n"
"				-- normal\n"
"				s = s..sbuf\n"
"				cpos = cpos+1\n"
"				--reg-class flg\n"
"				if rcls<0  and  sbuf=='[' then rcls= 1  \n"
"				elseif rcls>0  and  sbuf==']' then rcls= -1 end 	--reg[]脱出				\n"
"			 end::_luka_LOOPNEXT::end \n"
"		 end \n"
"		--classは追加変換したいけどtermsが出来て!. EOFが必要なので後回し\n"
"		local term = { [\"ctg\"]=ctg, [\"data\"]=s, [\"info\"]=ctg..\":\"..s, [\"pos\"]=cur }\n"
"		if ctg==\"class\" and s==\".\" then  term.ctg = \"any\"  \n"
"		elseif ctg==\"hlit\" then  term.ctg = \"lit\"  \n"
"		elseif ctg==\"class\" then \n"
"			--class dataは255のbinになる\n"
"			local res, str = ctx.convclass(term.data)\n"
"			if res==nil then  return nil, ctx.srcemsg(str, cur, str..s)  end \n"
"			term.data = string.char(u.tb2va(res) )\n"
"--print(term.data, string.byte(term.data, 34) );os.exit(1);\n"
"			term.info = term.info .. \" \"..str\n"
"		 end \n"
"		terms[#terms+1]=term\n"
"		--defの入れ替え。LALR2から1になる\n"
"		if ctg==\"def\" then 	terms[#terms], terms[#terms-1] = terms[#terms-1], terms[#terms]  end \n"
"	 end::_luka_LOOPNEXT::end 	--until EOS\n"
"	return terms, str\n"
" end\n"
"\n"
"--peg-classは256のcharに変換\n"
"function ctx.convclass(base) \n"
"	local str = string.gsub(base, \"^%-%-%-%-?\", \"-\")	-----aaa ----aaa>>> -aに変換\n"
"	--先頭-なら単体range両対応出来るので纏めてしまえる\n"
"	-- ---a-b >> -a-b\n"
"	-- -----b >> --b	頭の-は消えるがrangeに入ってるので結果オーライ \n"
"	\n"
"	--info用\n"
"	local tb = { string.byte(str, 1, #str) }\n"
"	local hnum = string.byte(\"-\")\n"
"	local ninfo = \"\"\n"
"	for i=1,#tb do do \n"
"		if i==1 or i==#tb or tb[i]~=hnum then ninfo=ninfo .. string.format(\"\\\\%03o\",tb[i])  \n"
"		else  ninfo=ninfo ..\"-\"  end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	\n"
"	local ONE = 64	-- bin 1 だとputs(でみえない \\0と\\100=64= @にしとく\n"
"	local rtb={}\n"
"	for i=1,256 do do rtb[i]=0 end::_luka_LOOPNEXT::end \n"
"	---を始末 \\055, 45 2d\n"
"	if  str==\"--\"  then \n"
"		-- -- だけ\n"
"		rtb[hnum+1]=ONE;	---は45だけどluaidxが1スタートなので\\0はrtb[1]になる\n"
"		str=\"\"\n"
"	 end \n"
"	if string.find(str, \"^%-\")  and   not string.find(str, \"^%-%-\")  then \n"
"		rtb[hnum+1]=ONE\n"
"		str=string.sub(str, 2)\n"
"	 end \n"
"	if string.find(str, \"%-$\")  and   not string.find(str, \"%-%-$\")  then \n"
"		rtb[hnum+1]=ONE\n"
"		str=string.sub(str, 1, -2)\n"
"	 end \n"
"	local ptn = \"(.)-(.)\"\n"
"	for s,e in string.gmatch(str, ptn)  do do \n"
"		local sc = string.byte(s) \n"
"		local ec = string.byte(e)\n"
"		if ec<sc then \n"
"			local buf = u.sprintf(\"%s(%d)>%s(%d): \", s,sc,e,ec)\n"
"			return nil, \"bad peg-class range, s>e: \"..buf\n"
"		 end \n"
"		for i=sc, ec do do  rtb[i+1]=ONE  end::_luka_LOOPNEXT::end \n"
"		\n"
"	 end::_luka_LOOPNEXT::end \n"
"	str = string.gsub(str, ptn, \"\")\n"
"	--- kick\n"
"	if string.find(str, \"%-\")  then  return nil, \"detect bad range in peg-class: \"..str  end \n"
"\n"
"	--single\n"
"	tb = { string.byte(str, 1, #str) }\n"
"	for i=1, #tb do do  rtb[tb[i]+1] = ONE  end::_luka_LOOPNEXT::end \n"
"	return rtb, ninfo\n"
" end\n"
"\n"
"\n"
"--()とか+とかを%1系に変更\n"
"function ctx.subterm(subcnt, term) \n"
"	local buf={}\n"
"	buf.ctg=\"ident\"\n"
"	buf.data=\"%\"..subcnt\n"
"	buf.pos=term.pos\n"
"	buf.info=\"ident:\"..buf.data\n"
"	buf.pre=term.pre\n"
"	return buf\n"
" end\n"
"\n"
"-- 文法チェックと構成編集組み立て termsから調整済みのrulesを吐く\n"
"--bstrはエラー用の生src \n"
"--term:	ctg, data, pos, info	(ctg==act, data=actlist)\n"
"--ctg:	ident,lit,class,act,any(.),eof(!.) 	...clsが消えて最終的に5つにまとまる\n"
"-- >>clsからregに変換。c側で高速化させる>> regで変換したら逆に遅い うんこ。戻す。\n"
"-- onigは遅かったけど、そもそもregを呼び出す事自体が遅くなる\n"
"-- gnurgでも同じ。litはO(1)だけどregはコストがかかるのでなるべく避けたい\n"
"-- regの利点はpegの多数のruleを一つの表現にまとめて判定出来ること 1文字ならlitが有利\n"
"-- 戦略としてはregでまとめて判定出来るのはregに突っ込んで太らせる\n"
"-- blkとかどうしてもやりにくいのだけpegで追加する\n"
"--actctg:	aC, aE, lit\n"
"\n"
"--再帰を使ってるのでrtnはobj,pos,strの変則系になる\n"
"function ctx.bldrules(bstr, terms, pos, subcnt) \n"
"	if terms==nil  or  #terms == 0 then  return {}  end 	--no rule. blank file etc\n"
"	\n"
"	pos=pos or 0\n"
"	local subflg=1;	if pos==0 then subflg=0 end 	--rootかそれ以外か\n"
"	local term=nil\n"
"	local rtop=nil	--subdefでrule名保管用\n"
"	local pre=nil\n"
"	subcnt=subcnt or 1\n"
"	local anyhash=\"\" ;for i=1,256 do do anyhash=anyhash..\"1\" end::_luka_LOOPNEXT::end \n"
"	local zerohash=\"\" ;for i=1,256 do do zerohash=zerohash..\"\\0\" end::_luka_LOOPNEXT::end \n"
"\n"
"	-- 非存在は問答無用で間違い 可能性は残す\n"
"	-- reg classは同じ性質なのでclassで二役判定\n"
"	-- defの後ろにはidentだけが炬火される...みたいな方式 lexで書き直せそうな気はする\n"
"	-- \\系の中間処理もあるから簡単には行かないだろうしlua /C の複合になる気もする\n"
"	-- 熟成して仕様が固まったらCに直せばいいだろう B言語の例もあるし\n"
"	local nlist = {}	--allow nextctg...+ \"act\"\n"
"	nlist.def	= { ident=1 }	--scan時にひっくり返してある\n"
"	nlist.subdef= { pre=1, [\"(\"]=1, ident=1, lit=1, class=1, bof=1 }\n"
"	nlist.ident	= {def=1,subdef=1,pre=1,suf=1,[\"(\"]=1,[\")\"]=1,ident=1,lit=1,class=1,bof=1,[\"{\"]=1 }\n"
"	nlist.lit	= nlist.ident\n"
"	nlist.class = nlist.ident\n"
"	nlist.bof	= nlist.ident\n"
"	nlist.any   = nlist.ident\n"
"	nlist.ere	= nlist.ident\n"
"	nlist.bre	= nlist.ident\n"
"	nlist.pre	= { [\"(\"]=1, ident=1, lit=1, class=1, bof=1 }\n"
"	nlist.suf	= {def=1,subdef=1,pre=1,[\"(\"]=1,[\")\"]=1,ident=1,lit=1,class=1, bof=1,[\"{\"]=1}\n"
"	nlist[\"(\"]	= nlist.subdef\n"
"	nlist[\")\"]	= nlist.ident\n"
"	\n"
"	nlist[\"{\"]	= { aC=1, aE=1, sep=1, [\"}\"]=1 }\n"
"	nlist.aC	= { [\"=\"]=1, aC=1, lit=1, sep=1, [\"}\"]=1 }\n"
"	nlist.aE	= { sep=1, [\"}\"]=1 }\n"
"	nlist[\"=\"]	= { aC=1, lit=1 }\n"
"	nlist.alit	= { aC=1, lit=1, sep=1, [\"}\"]=1 }	-- lit...act/rule common atm\n"
"	nlist.sep	= { sep=1, aC=1, [\"}\"]=1 }\n"
"	nlist[\"}\"]	= { def=1, subdef=1 }\n"
"	\n"
"	local rules= {}\n"
"	local rule= {}\n"
"	local subrules= {}\n"
"	\n"
"	local abuf= {}	--act listbuf\n"
"	local aflg=0	--in act\n"
"	--init\n"
"	local xctg = {def=1}	--guess neXt ctg\n"
"\n"
"::lbl_NEXT::\n"
"	--init: pos=0\n"
"	while pos<#terms do do 	\n"
"		pos=pos+1\n"
"		term=terms[pos]\n"
"	--rule_err, pegrule ck. class/any/reg do same work.\n"
"		local tmp = term.ctg\n"
"		; if tmp==\"ere\" or tmp==\"bre\" or tmp==\"any\" then tmp=\"class\" end \n"
"		if xctg[tmp]==nil then  return nil,ctx.srcemsg(bstr,term.pos,\"bad pegrule seq:\"..term.ctg..\": \"..term.data) end \n"
"		xctg=nlist[term.ctg]\n"
"		if aflg==1 and term.ctg==\"lit\" then  xctg=nlist.alit end 	--actのlitは別枠\n"
"\n"
"		if  term.ctg==\"def\" then \n"
"			--初回はダミーが入る\n"
"			rules[#rules+1]=rule\n"
"			rule={}\n"
"			goto lbl_NEXT\n"
"		 end \n"
"		if  term.ctg==\"subdef\"  then \n"
"			rules[#rules+1]=rule\n"
"			rule={}\n"
"			rule[1]=rtop\n"
"			goto lbl_NEXT\n"
"		 end \n"
"		if term.ctg==\"{\" then  aflg=1; goto lbl_NEXT  end \n"
"		if aflg==1 then \n"
"			--actは羅列してsubfuncで処理する.ctgがactになるので後で処理\n"
"			if term.ctg==\"}\" then \n"
"				aflg=0\n"
"				if #abuf==0 then goto lbl_NEXT end \n"
"				local res, emsg = ctx.f_actrules(rtop, #rules, abuf, nlist, bstr)\n"
"				--#rules == rnum追加 初回はダミーが入るが+1で結果的に一致する\n"
"				if res==nil then return res, emsg end \n"
"				rule[#rule+1] = res\n"
"				abuf={}\n"
"				goto lbl_NEXT\n"
"			 end \n"
"			--_0系。prefixは変わりそう。スキップしてnumをとる。ovh上も先処理が有利\n"
"			abuf[#abuf+1]=term\n"
"			goto lbl_NEXT\n"
"		 end \n"
"		\n"
"		--通常のrule系, sufの展開は止めた。ruleデータが爆発しそうなので分岐で対処.jmp数も減らせるし。\n"
"		if term.ctg==\"pre\" then pre=term.data; goto lbl_NEXT end 	-- !&\n"
"		if term.ctg==\"suf\" then \n"
"			rule[#rule].suf=term.data\n"
"			goto lbl_NEXT\n"
"		 end 	--*+?\n"
"		--blk系。捏造%1系ins\n"
"		if term.ctg==\"(\" then \n"
"			term=ctx.subterm(subcnt, term)	--header作成\n"
"			subcnt=subcnt+1\n"
"			\n"
"			local tbuf0={ctg=\"def\"}\n"
"			local tbuf1=u.tdup(term)\n"
"			table.insert(terms, pos+1, tbuf1)\n"
"			table.insert(terms, pos+1, tbuf0)	-- <- %3 みたいな。\n"
"			local buf\n"
"			buf, pos, subcnt = ctx.bldrules(bstr, terms, pos, subcnt)	--カウンタを避けて再帰\n"
"			if buf==nil then return buf, pos end 		--err\n"
"			for i=1, #buf do do  subrules[#subrules+1]=buf[i]  end::_luka_LOOPNEXT::end \n"
"			xctg=nlist[\")\"]		--next用に調整\n"
"			term.pre=pre\n"
"			pre=nil\n"
"			rule[#rule+1]=term\n"
"			goto lbl_NEXT\n"
"		 end \n"
"		if term.ctg==\")\"  and  subflg==1  then  do break end  end \n"
"		if term.ctg==\")\" then  return nil, ctx.srcemsg(bstr, term.pos, \"invalid EOF, uneven block()\")  end \n"
"		--(), uneven...多分中間から入ってきた奴ら\n"
"	\n"
"		--reg,lit,ident\n"
"		--preが共通で付く。あと()もだけど、個別処理済み\n"
"		term.pre=pre\n"
"		pre=nil\n"
"		--reg... 重い. 速度の7割ぐらいがこれ@onig\n"
"		if term.ctg==\"any\" and term.pre==\"!\" then term.ctg=\"eof\";term.pre=nil;term.data=zerohash end \n"
"		if term.ctg==\"any\" then term.data=anyhash end \n"
"		--elif(term.ctg==\"class\"&&term.data==\".\"){term.ctg=\"any\"}\n"
"		rule[#rule+1]=term\n"
"		if #rule==1 then rtop=term; xctg=nlist.subdef  end 	--初回defはidentの制限ver\n"
"		goto lbl_NEXT\n"
"	 end::_luka_LOOPNEXT::end \n"
"	--loop_end\n"
"	--頭は+1されてるので取り除く\n"
"	table.remove(rules, 1)\n"
"	--尻尾がちぎれるのでくっつける\n"
"	rules[#rules+1]=rule\n"
"	--root_rule\n"
"	for i=1, #subrules do do  rules[#rules+1]=subrules[i]  end::_luka_LOOPNEXT::end \n"
"	\n"
"	--term検査を追加 badfixをkickする !&*+?は択一にする\n"
"	for r=1, #rules do do \n"
"		local rule=rules[r]\n"
"		for t=1, #rule do do \n"
"			local term=rule[t]\n"
"			if  term.pre  and  term.suf then \n"
"			local s = \"\\nterms using both '!&' and '?*' is valid PEG but must be illegal rule\\n\" ..\n"
"			\"   !__*, !__? is always fail same as !''	eg) R <- !'a'*	#>>'a', 'x'>>fail\\n\"..\n"
"			\"   &__*, &__? is always suc  same as  ''	eg) R <- &'a'?	#>>'a', 'x'>>suc\\n\"..\n"
"			\"\\n'!&' and '+' is valid but used only in rare cases, so split the rules if necessary plz\\n\"..\n"
"			\"	eg) R<- !'a'+ 	>>>		R1 <- !R2	R2<- 'a'+\"\n"
"			return nil, ctx.srcemsg( bstr, term.pos, term.data..s)\n"
"			 end \n"
"		 end::_luka_LOOPNEXT::end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	return rules, pos, subcnt\n"
"	--ctgは ident,lit,class,act,+any,eof(., !.)あたり \n"
" end\n"
"\n"
"-- チェックは済んでる。listに切り分けるだけ >>ckをこっちに持ってきた\n"
"-- regとclassはないから判定不要\n"
"-- dataはsep/esep付きのリニアterm. dataからalist[]の作成がしやすいよう細工\n"
"function ctx.f_actrules(rtop, rnum, tb, nlist, bstr) \n"
"	local acts={}\n"
"	local xctg = nlist[\"{\"]\n"
"	local flg = -1\n"
"	for i,v in pairs(tb)  do do \n"
"		--continue dmy\n"
"		while 1 do do \n"
"			if xctg[v.ctg] ==nil then  return nil, ctx.srcemsg(bstr, v.pos, \"bad actblk tokens\")  end \n"
"			xctg=nlist[v.ctg]\n"
"			if v.ctg==\"lit\" then  xctg=nlist[\"alit\"]  end \n"
"			if v.ctg==\"=\" then  do break end  end 	--assingは無視スキップ\n"
"			if v.ctg==\"sep\" then  if flg == -1 then   do break end   end ; flg= -1  end 	--空連続はスキップ\n"
"			--追加。最終出力で速度を上げるため先に加工しておく\n"
"			if v.ctg==\"aC\" then \n"
"				local buf=string.sub(v.data,2)\n"
"				v.data=tonumber(buf)\n"
"			 end \n"
"			acts[#acts+1]=v\n"
"			if v.ctg~=\"sep\" then  flg=0  end \n"
"			 do break end \n"
"		 end::_luka_LOOPNEXT::end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	if #acts~=0 then \n"
"		local pterm = acts[#acts]\n"
"		if pterm.ctg~=\"sep\" then \n"
"			local term = u.tdup(acts[#acts])\n"
"			term.ctg=\"sep\"\n"
"			term.info=\"sep:;\"\n"
"			acts[#acts+1] = term\n"
"		 end \n"
"		local term = u.tdup(acts[#acts])\n"
"		term.ctg=\"esep\"\n"
"		term.info=\"esep\"\n"
"		acts[#acts+1] = term\n"
"	 end \n"
"	local term={}\n"
"	term.ctg=\"act\"\n"
"	term.data=acts		\n"
"	term.pos=acts[1].pos		\n"
"	term.info=\"act: RULE \"..tostring(rnum)..\": \"..rtop.data		\n"
"	return term\n"
" end\n"
"--デバッグ向け。ジャンプマップ表示 実用上は非常に重要\n"
"function ctx.rulesinfo(rules)  return ctx.frulesinfo(io.stderr, rules)  end\n"
"function ctx.frulesinfo(fh, rules) \n"
"	if rules==nil then  return nil, \"rules is nil\" end \n"
"	local res = \"\"\n"
"	for i=1, #rules do do \n"
"		local rule=rules[i]\n"
"		res =  res..i..\": \"\n"
"		for ii=1, #rule do do \n"
"			local term = rule[ii]\n"
"			local presub = (term.pre  or  \"\")..(term.suf or \"\")\n"
"			local sbuf = string.match(term.info, \":.*\")\n"
"			res = res.. term.ctg..sbuf..\" \"..presub..\", \"\n"
"		 end::_luka_LOOPNEXT::end \n"
"		res=res..\":\\n\"\n"
"		if rule[#rule].ctg==\"act\" then \n"
"			local acts=rule[#rule].data\n"
"			res = res..\"act, \"\n"
"			for j=1, #acts do do \n"
"				local term = acts[j]\n"
"				res = res.. term.info..\", \"\n"
"				if term.ctg==\"sep\" then  res=res..\":\\nact, \" end \n"
"			 end::_luka_LOOPNEXT::end \n"
"			res=res..\":\\n\"\n"
"			-- esepで終わるから体裁はそれなりに整う\n"
"		 end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	res = string.gsub(res, \"%z\", \"\\\\0\")\n"
"	u.fprintf(fh, \"%s\", res)\n"
"	return res\n"
" end\n"
"\n"
"\n"
"-- rulesはtbなのでC向けリニアに変更。actも分離 合わせてrhead, aheadも作成\n"
"-- dataはlit/regでnumはszかident jmpのrule番号でctgで動作を変える\n"
"-- classは255 strで0/1作成する。-だけ注意して作る...事前にやった方が\n"
"-- スマートか。 classはdataが空いている。本来はlitとかreqの文字列が\n"
"-- 入るけど, 256につかえるからここに突っ込もう。上で突っ込んであったから\n"
"-- cデータへの変換部分かな\n"
"function ctx.taperules(rules) \n"
"	if rules==nil then  return nil, \"rules is nil\" end \n"
"	local rtokens, atokens, rhead, ahead={}, {}, {}, {} --hashはrule番号からposを取り出す\n"
"	--init\n"
"	rhead[1]=1\n"
"	ahead[1]=1\n"
"\n"
"-- 一時的に必要。すぐ下で使う\n"
"	local rnhash={}\n"
"	for i=1, #rules do do \n"
"		local rname=rules[i][1].data\n"
"		assert(rname, \"hasherr\")\n"
"		rnhash[rname]=rnhash[rname] or i		--無ければ設定、あくまでlua側のindにしとく\n"
"	 end::_luka_LOOPNEXT::end \n"
"	for i=1, #rules do do \n"
"		rhead[i]  = #rtokens +1	--nextruleのlua番号なので+1\n"
"		ahead[i]  = -1\n"
"		local rule=rules[i]\n"
"		for ii=1, #rule do do \n"
"			local term=rule[ii]\n"
"			local cterm={}\n"
"			cterm.ctg=term.ctg\n"
"			cterm.data=term.data\n"
"			cterm.num=0	--strlen if lit/reg. ruleind if ident rendマイナスも使う\n"
"			if term.ctg==\"lit\" or term.ctg==\"ere\" or term.ctg==\"bre\" then  cterm.num= #term.data  end \n"
"			--前はlitで文字数reqのため#dataだったけど、regは結局全文字\n"
"			--必要なので全読込になった。んでnumが不要になったのでidentのみ利用\n"
"			-- 本体ではなく筆頭のrnumを突っこむ fail時に再挑戦で使う\n"
"			if term.ctg==\"ident\" then \n"
"				local buf = rnhash[term.data]\n"
"				if buf==nil then \n"
"					buf = u.fprintf(nil, \": bad peg. using nodef rule: rule %d %s: %d,%d >> %s\", i, rule[1].data, i, ii-1, term.data)\n"
"					return nil, buf\n"
"				 end \n"
"				cterm.num=buf\n"
"			 end \n"
"			cterm.pre=term.pre or \"\"\n"
"			cterm.suf=term.suf or \"\"\n"
"			--jmpは数値の方が何かと使い勝手がいい。\n"
"			if term.ctg~=\"act\" then  rtokens[#rtokens+1]=cterm  \n"
"			elseif term.ctg==\"act\" then \n"
"				--a側は事前にリニアにしてるからtypeを揃えて入れるだけ\n"
"				ahead[i] = #atokens +1\n"
"				for _,v in ipairs(term.data)  do do \n"
"					local tbuf = {}\n"
"					tbuf.ctg = v.ctg\n"
"					tbuf.data= \"\"\n"
"					tbuf.num = 0\n"
"					if v.ctg == \"lit\" then \n"
"						tbuf.data=v.data\n"
"						tbuf.num =#v.data\n"
"					 end \n"
"					if v.ctg == \"aC\" then  tbuf.num = v.data  end \n"
"					if v.ctg == \"sep\" then  tbuf.num = -1  end \n"
"					if v.ctg == \"esep\" then  tbuf.num = -2 end \n"
"					tbuf.rnum = i\n"
"					tbuf.rname= \"rule \"..tostring(i)..\": \"..rule[1].data\n"
"					atokens[#atokens+1] = tbuf\n"
"				 end::_luka_LOOPNEXT::end \n"
"			 end \n"
"		 end::_luka_LOOPNEXT::end \n"
"		local tbuf={ctg=\"sep\", data=\"\", num=-1, pre=\"\", suf=\"\"}\n"
"		rtokens[#rtokens+1]=tbuf\n"
"	 end::_luka_LOOPNEXT::end \n"
"	local tbuf={ctg=\"esep\", data=\"\", num= -9, pre=\"\", suf=\"\"}\n"
"	rtokens[#rtokens+1]=tbuf\n"
"	tbuf={ctg=\"esep\", data=\"\", num= -9, rnum=0, rname=\"\"}\n"
"	atokens[#atokens+1]=tbuf\n"
"	rhead[#rhead+1]  = -9	--sentinel\n"
"	ahead[#ahead+1]  = -9\n"
"	tbuf={rtokens=rtokens, atokens=atokens, rhead=rhead, ahead=ahead}\n"
"	return tbuf \n"
" end\n"
"\n"
"-- jmpチェック. identと''*の無限を調べる。それ以外は進む可能性が残る\n"
"-- *系は限りなく黒だけどスルー 実行時検査に任せる\n"
"-- rootrulesを使ってたおかげでそのまま使える。助かった\n"
"-- 追加検査: !& *?の競合''と!''に縮退するので文法エラーとするのが正しい\n"
"-- !+と&+は無意味だからこいつもついでにkickする\n"
"function ctx.loopck(rules) \n"
"	--枝分かれとerr記録用。err以外は巻き戻したりする\n"
"	local st={rpos=1, tpos=1, eres=\"\", looptb={}, jmpstk={}, rc=0 }\n"
"	local buf=nil\n"
"	st.eres=st.eres..\"> -- rule 1 \"..rules[st.rpos][1].data\n"
"	while 1 do do \n"
"		local term=rules[st.rpos][st.tpos]\n"
"		if st.tpos==1 then  st.looptb[term.data]=1; goto lb_WALK  end \n"
"		if st.tpos>=2 and term.ctg~=\"ident\" and term.pre==nil then \n"
"			--進行要素があればリセット\n"
"			st.looptb[rules[st.rpos][1].data]=nil\n"
"		 end \n"
"		--空文字loopは即死 regはcに渡すまで分からないのでそっちでやる\n"
"		if  (term.suf==\"*\" or term.suf==\"+\") and (term.ctg==\"lit\" and term.data==\"\")  then \n"
"			st.eres=st.eres..\n"
"			u.fprintf(nil, \"\\nERR rule %d %s: %d,%d: bad peg. empty lit loop\"\n"
"			, st.rpos, rules[st.rpos][1].data, st.rpos, st.tpos-1)\n"
"			return nil, st.eres\n"
"		 end \n"
"		--本来の検査\n"
"		if term.ctg==\"ident\" then \n"
"			--事前に消費要素があってidentならスキップで*?扱い\n"
"			--結果の再利用はしないから少し無駄があるけど面倒なので放置\n"
"			if  st.looptb[rules[st.rpos][1].data]==nil  then goto lb_WALK end \n"
"			--アウト\n"
"			if st.looptb[term.data] then \n"
"				local dst\n"
"				for i,v in ipairs(rules)  do do 	if v[1].data==term.data then dst=i; do break end  end   end::_luka_LOOPNEXT::end \n"
"				st.eres=st.eres..\n"
"				u.fprintf(nil, \": bad peg. infinite ruleloop: rule %d %s: %d,%d >> rule %d %s\"\n"
"				, st.rpos, rules[st.rpos][1].data, st.rpos, st.tpos-1, dst, rules[dst][1].data)\n"
"				return nil, st.eres\n"
"			 end \n"
"			--loop候補 初jmp\n"
"			st.jmpstk[#st.jmpstk+1] = st.rpos\n"
"			st.jmpstk[#st.jmpstk+1] = st.tpos\n"
"			local rname = rules[st.rpos][st.tpos].data\n"
"			--未定義検査 逆引き\n"
"			for i,v in ipairs(rules)  do do  if v[1].data==rname then rname=i;  do break end  end   end::_luka_LOOPNEXT::end \n"
"			if type(rname)~=\"number\" then \n"
"				st.eres=st.eres..\n"
"				u.fprintf(nil, \": bad peg. using nodef rule: rule %d %s: %d,%d >> %s\"\n"
"				, st.rpos, rules[st.rpos][1].data, st.rpos, st.tpos-1, rname)\n"
"				return nil, st.eres\n"
"			 end \n"
"			st.rpos=rname\n"
"			st.tpos = 1\n"
"			st.eres=st.eres..\"\\n> jmp rule \"..tostring(st.rpos)..\": \"..rules[st.rpos][1].data\n"
"			goto lb_NEXT\n"
"		 end \n"
"		-- identはpreがあっても必須それ以外は preと''は未消費なのでスキップ\n"
"		if term.pre~=nil or (term.ctg==\"lit\" and term.data==\"\") then  goto lb_WALK  end \n"
"	::lb_NOLP::\n"
"		--おそらく消費があった jmp/skip系はWALKかNEXTしてる\n"
"		st.eres=st.eres..\"\\n> jmp stop \"..tostring(st.rpos)\n"
"		if #st.jmpstk~=0 then  st.rpos=st.jmpstk[1] end \n"
"		goto lb_RNEXT\n"
"	::lb_WALK::\n"
"		st.tpos=st.tpos+1\n"
"		if  st.tpos <= #rules[st.rpos]  then  goto lb_NEXT  end \n"
"		--終端なら判定が必要 jmpで次に行くかもしれない\n"
"		goto lb_WALL\n"
"	::lb_WALL::\n"
"		-- >>jmp中ならnextを調べないといけない\n"
"		if #st.jmpstk~=0 then \n"
"			--nextが居た\n"
"			if rules[st.rpos+1][1].data == rules[st.rpos+1][1].data then \n"
"				st.rpos=st.rpos+1\n"
"				st.tpos=1\n"
"				st.eres=st.eres..\"\\n> subrule \"..tostring(st.rpos)\n"
"				goto lb_NEXT\n"
"			 end \n"
"			--いなかったらloop無し確定\n"
"			goto lb_NOLP\n"
"		 end \n"
"		--jmp中じゃなかった フツーにok\n"
"		goto lb_RNEXT\n"
"	::lb_RNEXT::\n"
"		st.rpos=st.rpos+1\n"
"		if  #rules<st.rpos  then   do break end   end \n"
"		buf = rules[st.rpos][1].data\n"
"		buf = string.sub(buf, 1, 1)\n"
"		if buf==\"%\" then  do break end  end \n"
"		--init\n"
"		st.tpos=1\n"
"		st.looptb={}\n"
"		st.jmpstk={}\n"
"		st.eres=st.eres..\"\\n> -- rule \"..tostring(st.rpos)..\" \"..rules[st.rpos][1].data\n"
"	::lb_NEXT::\n"
"	 end::_luka_LOOPNEXT::end \n"
"	st.eres=st.eres..\"\\nloop check ok\\n\"\n"
"	return st.eres\n"
" end\n"
"-- 1stはinfostr, 2ndは未消費の危険がある奴等のflg, r[10]=1 , rule10が*のみとか\n"
"\n"
"\n"
"--[[\n"
"ID <- \"123\"	...1\n"
"ID <- \"123\"* \"xyz\"	...1,x\n"
"ID <- \"123\"+ \"xyz\"	...1\n"
"ID <- \"123\"? \"xyz\"	...1,x\n"
"ID <- !\"123\" \"xyz\"	...x xは必須条件 !は全て無視\n"
"ID <- jmp	\"xyz\"	...jmpのリストをコピー\n"
"ID <- jmp*	\"xyz\"	...jmp, x \n"
"]]\n"
"\n"
"-- tb2c conv\n"
"function ctx.cdatamaker(obj) \n"
"	local ffi = require(\"ffi\")\n"
"ffi.cdef[[\n"
"typedef struct rtoken_tag {\n"
"	const char* ctg;\n"
"	const char* data;\n"
"	int num;\n"
"	const char* pre;\n"
"	const char* suf;\n"
"} rtoken_t;\n"
"\n"
"typedef struct atoken_tag {\n"
"	const char* ctg;\n"
"	const char* data;\n"
"	int num;\n"
"	int rnum;\n"
"	const char* rname;\n"
"} atoken_t;\n"
"]]\n"
"	--rtokens, atokens, rhead, aheadの四つ	+	rsaveでgrub\n"
"	local rsave={}\n"
"	rsave[#rsave+1]=obj\n"
"	--rtokens	各tokenを基本形にしてるのでluajitが自動的にconv作成してくれる\n"
"	local rtokens_c = {}\n"
"	for i, v in ipairs(obj.rtokens)  do do rtokens_c[#rtokens_c+1] = ffi.new(\"rtoken_t\", v)  end::_luka_LOOPNEXT::end \n"
"	local rtokens = ffi.new(\"rtoken_t[?]\", #rtokens_c, rtokens_c)\n"
"	rsave[#rsave+1] = rtokens_c\n"
"	rsave[#rsave+1] = rtokens\n"
"	--rhead\n"
"	local rhead = ffi.new(\"int[?]\", #obj.rhead, obj.rhead)\n"
"	rsave[#rsave+1] = rhead\n"
"	\n"
"	--atokens\n"
"	local atokens_c = {}\n"
"	for i, v in ipairs(obj.atokens)  do do atokens_c[#atokens_c+1] = ffi.new(\"atoken_t\", v)  end::_luka_LOOPNEXT::end \n"
"	local atokens = ffi.new(\"atoken_t[?]\", #atokens_c, atokens_c)\n"
"	rsave[#rsave+1] = atokens_c\n"
"	rsave[#rsave+1] = atokens\n"
"	--ahead\n"
"	local ahead = ffi.new(\"int[?]\", #obj.ahead, obj.ahead)\n"
"	rsave[#rsave+1] = ahead\n"
"	\n"
"	local res = {\n"
"		rtokens=rtokens\n"
"		, rhead=rhead\n"
"		, atokens=atokens\n"
"		, ahead=ahead\n"
"		, rsave=rsave }\n"
"	return res\n"
" end\n"
"\n"
"function ctx.ped_makeinfo(mode, s) \n"
"	local tb, rstr = ctx.f_scanpeg(s, mode);		assert(tb, rstr)\n"
"	local rules, emsg = ctx.bldrules(rstr, tb);		assert(rules, emsg)\n"
"	local loopinfo, emsg = ctx.loopck(rules); assert(loopinfo, emsg)\n"
"	local ruleinfo =  ctx.frulesinfo(nil, rules) .. \"\\n\".. loopinfo\n"
"	return ruleinfo\n"
" end\n"
"\n"
"--cdata to ptr address num\n"
"function ctx.c2p(cdata) \n"
"	return tonumber(ffi.cast('uintptr_t',ffi.cast('void *', cdata) ) )\n"
" end\n"
"\n"
"-- (str, str)\n"
"function ctx.ped_makebase(mode, rstr) \n"
"	--	mode = \"nNrR\"	の4種類が必要\n"
"	local tb, rstr = ctx.f_scanpeg(rstr, mode);		assert(tb, rstr)\n"
"	local rules, emsg = ctx.bldrules(rstr, tb);		assert(rules, emsg)\n"
"	--bldは再帰をつかうのでemsgにposデータが入ってることがある\n"
"	local loopinfo, emsg = ctx.loopck(rules);	 assert(loopinfo, emsg)\n"
"	local ruleinfo = nil\n"
"	if  string.find(mode, \"d\")  then \n"
"		 ruleinfo = ctx.frulesinfo(nil, rules) .. \"\\n\".. loopinfo\n"
"	  end \n"
"	--infoにloop危険情報入り。2ndはrule[3]==1ならloop危険だけど使わんかも\n"
"	tb, emsg = ctx.taperules(rules); assert(tb, emsg)	\n"
"	--こいつらが基本の成果物 pvmに通すとfuncが入ってくるので寸止め\n"
"	--tb = {rtokens=rtokens,atokens=atokens,rhead=rhead,ahead=ahead}\n"
"	tb = ctx.cdatamaker(tb)\n"
"	local f = ctx.c2p\n"
"	local res = { rtokens=f(tb.rtokens), rhead=f(tb.rhead)\n"
"		, atokens=f(tb.atokens), ahead=f(tb.ahead), ruleinfo=ruleinfo, rsave=tb.rsave }\n"
"	return res\n"
" end\n"
"\n"
"\n"
"function ctx.ped_version() \n"
"	local buf=[=[\n"
"ped 2.1.0\n"
"Copyright (C) 2021 momi-g\n"
"License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.\n"
"This is free software: you are free to change and redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by law.]=]\n"
"	return buf\n"
" end\n"
"\n"
"function ctx.ped_help() \n"
"	local buf=[=[\n"
"HowTo (ped, sed-style editer using peg)	\n"
"opt: -[e|f][n|N][r|R] ( -hHgVtTodEL: others. see ~$ ped -H|less ) \n"
" e/f(pegexpr/file), n/N(noout/NotALLOW if hit norule), r/R(expand syntax)\n"
"--\n"
" eg) ~$ echo \"12a\"|ped -re 'ID<-[a-z]+ {_1=\"Z\"}'  #-enf works like sed opt\n"
" eg) ~$ ped -rf buf.peg < src.txt	# load rulefile (noBOM ascii/utf8 only)\n"
" eg) ~$ ped -nrf buf.peg src.txt	# disp only hit rule\n"
"\n"
"-- peg sample. support all orig peg syntax: '' \"\" <- / () [] .!&+*?#\n"
"	NAME <- 'alice'+  / . \"ob\" / ID		#bob rob 3ob etc... \n"
"	ID <- ![0-9] [_a-zA-Z0-9]+		#varname etc\n"
" ...see https://pdos.csail.mit.edu/papers/parsing:popl04.pdf\n"
"\n"
"-- expansion(-r/R opt): editblk, ERE/BRE-reg, esc(\\ooo), accept binary etc\n"
" editblk: {} = ; \"\" '' _0 _1 _2..(blk/assign/sep/lit/field. nl works as sep)\n"
" charesc: \\[abntvrf\\[]'\"], \\0-377, \\u0000-\\U0010FFFF(4/8 digits)\n"
" reg: e/(a|b)+/, e\"(a|b)+\", b'[0-9][\\u3042-\\u3044]' etc. see -H\n"
"\n"
" eg) ~$ ped -re 'MYRULE <- \"a\" (\"b\"/\"c\") \"d\" {_1=_3 \"\\043\" _2; _3=\"Z\"}' \n"
"	(in)acd >>> 'd#c' 'c' 'Z' >>> (out)d#ccZ (_0:concat all field str)\n"
"]=]\n"
"	return buf\n"
" end\n"
"\n"
"function ctx.ped_Help() \n"
"	local buf=[=[\n"
"-- ped detail help\n"
" ped [-e rule|-f rulefile] [OPT] file/stdin\n"
" opt: [n|N] [r|R] [t|T] [others: hHgVodEL] \n"
"\n"
" -e/f: set pegrule with -e:optargs / -f:file (ascii/noBOM utf8)\n"
"    eg) ~$ echo abc|ped -re 'R1<-\"b\" {_1=\"Z\"}'  #>>  aZc  \n"
"    eg) ~$ echo abc|ped -rf myrule.peg\n"
"\n"
" -E: set parse target instead of file/stdin\n"
"    eg) ~$ ped -re 'R1<-\"b\" {_1=\"Z\"}' -E 'abc'  #>>  aZc  \n"
"    eg) ~$ printf \"abc\"| ped -re 'R1<-\"b\" {_1=\"Z\"}'	#>> (same)\n"
"    ...-E/stdin/ag1(file) is selective. \n"
"\n"
" -n/N: noout/stop if hit norule\n"
"    eg) echo abc|ped -nre 'R1<-\"a\" {_1=\"Z\"}'  #>>  Z\n"
"    eg) echo abc|ped -Ne 'R1<-\"a\"'  #>> stop. $?=1\n"
"    \n"
"    below commands work the same\n"
"    eg) echo abc |ped -nre 'R1<-\"a\"'  #>> a\n"
"    eg) echo abc |ped  -re 'R1 <- \"a\"	OTHER <- . {_0 = \"\"}'	#>> a\n"
"\n"
" -r: expand peg syntax. allow only orig-peg syntax if noset.\n"
"   editblk: {} = ; \"\" '' _0 _1 _2..(blk/assign/sep/lit/field. nl works as sep)\n"
"   regex  : ERE: r'', r\"\", r//, BRE: b'', b\"\", b//,\n"
"   herelit: h'', h\"\"   h\"\\123\\n\" == \"\\\\123\\\\n\",  stop back slash working\n"
"   charesc: \\0-377, \\a, \\u, \\U etc\n"
"   BOF    : add anchor syntax !!. as BOF. sed anchor ^$ >> ped !!. !.\n"
"\n"
"  --edit block\n"
"    peg is just a grammar/syntax rule like BNF and doesnt have\n"
"    action block as sed/awk/yacc. -r/R add edit block.\n"
"    \n"
"    eg)\n"
"    NAME <- [aA] 'lice'	{_1='z'; _2=\"xx\" _1}   #alice >> z + xxz >> zxxz\n"
"    NAME <- [aA] 'lice'	{_0 = 'bob\\012' _2 }   #Alice >> bob(\\n)lice\n"
"    ~$ echo \"abd\" |ped -re 'R1 <- \"a\" (\"b\"/\"c\") \"d\" {_1=_3 \"AB\" _2;_3=\"Z\"}' \n"
"    ... _1=\"a\", _2=(\"b\"/\"c\"), _3=\"d\", _0 = all	>>>d AB b b Z\n"
"    \n"
"    edit block syntax:\n"
"      {}: edit block\n"
"      = : assign\n"
"      _1: field. same as sh $1,$2. select grp allstr if use to grouping()\n"
"      _0: allstr of the rule as awk $0. other flds become undef if edit _0\n"
"      '': lit. allow charesc \\u0010, \\n etc. accept h'...'\n"
"      \"\": lit. accept h\"...\"\n"
"      ; : separator(ignore). editblk is free format so just improve readability\n"
"      (space/tab/newline): same as separator\n"
"\n"
"  --regex\n"
"    add ERE: e'', e\"\", e// or BRE: b'', b\"\", b//. regex supports posix\n"
"    ERE/BRE with the following.  \n"
"\n"
"			(guideline)\n"
"     - resemble 'posix sed -E/sed' syntax as much as possible\n"
"     - unclear syntax causes error (\\191 != \\1[9][1], raise err)\n"
"     - plz use ERE and use BRE only when you need backref \\1-9\n"
"\n"
"			(expantion)\n"
"     - .(any)/[] includes '\\0' and doesnt hold binary. locale charactor only.\n"
"     - accept charesc \\ooo, \\n, \\u, \\U etc. see the below charesc.\n"
"     - \\ooo is used as bin in ERE []: [\\316\\243]=(\\316|\\243) != [Σ]==[\\u03a3]\n"
"     - \\ooo cant use in BRE []: [\\316] != [136\\], raise err.(BRE misses '|' op)\n"
"     - use system locale setting (see ~$ locale, maybe utf8 etc )\n"
"	\n"
"			(restriction)\n"
"     - regex tests only the head of the input, work as tokenizer like lex.\n"
"     - eos anchor '^' works but get the same result: e/^abc/ == e/abc/\n"
"     - needs esc blockchar outside of []: e\"/\" == e/\\// == e/[/]/\n"
"     - eol anchor '$' raises error. use peg-eof '!.': e/abc$/ >>> e/abc/ !.\n"
"	\n"
"       eg) R1 <- ![0-9] [_a-zA-Z0-9]+\n"
"           R1 <- e'[_a-zA-Z][a-zA-Z0-9]*'	#works the same except binary\n"
"       \n"
"       eg) R1<- e'\\u0061' e'[\\u0061-\\u0062]' \"\\u0061\"\n"
"           R1<- e'a' e/[a-b]/ 'a'\n"
"           R1<- e'a' e/[ab]/ 'a'\n"
"       \n"
"       eg) R1<- \"\\1\" b'\\(ab\\)\\10\\1'   #>> \"\\001\" \"ab\" \"\\010\" \"ab\"  bkref:\\1-\\9\n"
"       eg) R1<- b'\\(ab\\)\\1[\\1]'	#>> \"ab\" \"ab\" \"\\\" or \"1\" :posix rule\n"
"       eg) R1<- e'[\\a]'	#>> \"\\a\" == \"\\7\" == \"\\007\"\n"
"       eg) R1<- e'[a\\]'	#>> r/(a|[\\])/, posix rule\n"
"\n"
"    posix-regex cant use unicode/binary charesc, but -r/R mode regex accept\n"
"    them using escape syntax as follows.\n"
"     \n"
"     - charesc \\abntvrf works\n"
"     - \\ooo,\\uU work as bin/unicode char itself(doesnt work as special)\n"
"     - out of reg-class[] allows all charesc except BRE backref \\1-9\n"
"     - reg-class cant mix charesc. [\\oct], [\\uni], [posix+\\abntvrf]\n"
"    \n"
"    	eg) e'/\\n[\\t\\n]/'	== e'/\\012(\\011|\\012)'	...newline etc\n"
"    	eg) e'/ab\\101\\u0041/'	== e'/abAA/'\n"
"    	eg) e'/\\a\\134/' == e'/\\007\\\\/' == e'/\\a[\\]/'	..bin itself\n"
"    	eg) e'/a\\u0028/' == e'/a\\(/' == e'/a[(]/'\n"
"    	eg) b'/\\(a\\)b\\1\\01/' == b'/\\(a\\)b\\1\\001/'   ..\\1 is backref\n"
"    	eg) e'/[\\1-\\02\\10]/' == e'/(\\001|\\002|\\010)/'	...ok\n"
"    	    e'/[abc\\n\\t[:alnum:]]/' ...ok, posix+\\a...\n"
"    	    e'/[\\u0041-\\U00000042\\u0043]/' == ([A-B]|[C])	...ok\n"
"    	    e'/[\\012\\u0010]/'	...NG	mix \\ooo, \\u\n"
"    	    e'/[a\\012]/'	...NG	mix \\ooo, posix+\\a..\n"
"    	    e'/[\\n\\012]/'	...NG\n"
"    	    e'/[a\\u0012]/'	...NG\n"
"    	    e'/[^\\u0012]/'	...ok, hat(op 'not') works \n"
"    	\n"
"  --charesc\n"
"    orig-peg allows only ascii-env(\\0-\\277) and limited charesc(\\a is invalid).\n"
"    -r/R expand ascii to byte-oriented(\\0-377) and add c99 charesc.\n"
"        peg-class: [] 1char   >>> 1byte\n"
"        peg-any: .(dot) 1char >>> 1byte\n"
"\n"
"    charesc rule will be 'orig-peg(base)+c99' or 'regex(base)+c99'\n"
"\n"
"                      (no -r/R mode and c99)    \n"
"        peg       ERE(out[])      ERE(in[])         c99\n"
"    \\[nrt[]\\'\"]   \\[.[$()|*+?\\{]     -          \\[abntvrf?\\\"']	\n"
"     \\0-\\277             -           -             \\0-377 \n"
"         -               -           -            \\x0-\\xff\n"
"         -               -           -      \\u0000-\\U0010ffff..u4/U8\n"
"   \n"
"                        (-r/R mode)\n"
"        peg                  ERE(out[])             ERE(in[])      \n"
"   \\[nrt[]\\'\"abntvrf]  \\[.[$()|*+?\\{abntvrf]       \\[abntvrf]\n"
"        \\0-\\377               \\0-\\377                \\0-\\377         \n"
"        -nohex-               -nohex-                -nohex-        \n"
"  u4/U8(pegcls cant use)       u4/U8                  u4/U8          \n"
"\n"
"   ...basic charesc working in -r/R mode are the belows\n"
"    - \\xHH doesnt work\n"
"    - regex-class e/[]/ restricts some charesc, see above regex section\n"
"    - \\abntvrf work everywhare\n"
"    - \\0-\\377 work everywhare\n"
"    - unicode \\u4, \\U8 work evrywhere except peg-class (byte oriented)\n"
"    - \\ooo and \\uU never works as special chars, \\101==A, \\134 == \\\\ \n"
"    - others depend on where they belong: peg-class [\\[] == reg-class [[]\n"
"  \n"
"  eg)\n"
"      id <- 'abc\\[\\\"\\'\\u0041'  >>>  abc[\"'A ...peg-lit\n"
"      id <- [\\n\\101\\a]   >>> [\\012A\\007] 	...peg-class(1byte)\n"
"      id <- [\\u0041]     >>> invalid 		...peg-class\n"
"      id <- [\\101-\\103]    >>> [ABC]		...peg-class(range)\n"
"      id <- [\\136\\055\\101] >>> [^-A] == [-A^] 	...peg-class(3chars)\n"
"      (..peg-class is very similar to regex-class, but differ in detailis)\n"
"      \n"
"      id <- e'\\u0041[\\136\\101-\\103]'  >>> e'A(^|A|B|C)'	...ERE(in[])\n"
"      id <- e'[\\u0041-\\u0043]' >>> e'[A-C]'	...ERE(in[])\n"
"      id <- e'[\\u005e\\0041]' >>> e'([^]|[A])'	...ERE(in[])\n"
"      id <- e/[\\n\\u0041]/ >>> invalid, mixed charesc\n"
"      id <- e/\\n[\\[a]/  >>> e/\\134([\\]|[[]|a)/	...ERE(in[])\n"
"      (..add c99 to ERE-regex. see regex section)\n"
"\n"
"  --BOF\n"
"	add syntax '!!.' as begining of file. dont make space, '! ! .' etc.\n"
"	ped BOF '!!.' and EOF '!.' corresponds to sed anchor '^' and '$'\n"
"	  eg) printf \"abc \\n 123\" | sed -e 's/^/@/g'	#>> @abc @123\n"
"	  eg) printf \"abc \\n 123\" | ped -re 'R <- (!!./'\\n') {_0=_0 '@' }\n"
"\n"
" -R: same as -r but regex doesnt use system locale.\n"
"  opt \"-r\" checks system locale amd use it automatically.\n"
"  opt \"-R\" skips system locale check (maybe use \"C\" locale)\n"
"  if you dont use regex, -r and -R will behave the same.\n"
"    \n"
"    ~$ locale	#>> LC_CTYPE == lang.UTF-8\n"
"    ~$ echo \"Σ\" | ped -re 'RULE <- e/./ {_0 = \"Z\"}'	#>> Z\n"
"    ~$ echo \"Σ\" | ped -Re 'RULE <- e/./ {_0 = \"Z\"}'	#>> ZZ\n"
"    \n"
"    ~$ locale	#>> LC_CTYPE==lang (system unsupports multibyte locale)\n"
"    ~$ echo \"Σ\" | ped -re 'RULE <- e/./ {_0 = \"Z\"}'	#>> ZZ\n"
"    ~$ echo \"Σ\" | ped -Re 'RULE <- e/./ {_0 = \"Z\"}'	#>> ZZ\n"
"    	\n"
"    posix .(any)/[] doesnt use 'one byte' but 'one charactor' so system\n"
"    locale setting affects to multibyte chars handling.  \n"
"    https://www.gnu.org/software/sed/manual/html_node/Locale-Considerations.html\n"
"    \n"
"    I recommend you to use -r opt basically. use -R when you need:\n"
"      - parse binary data\n"
"      - needs regex absolutely\n"
"      - the env isnt fixed but want to make the pedrule portable\n"
"\n"
" -t: output concrete syntax tree(CST) with ascii text\n"
"\n"
"    ~$ echo abc | ped -tre 'R1 <- \"a\"'\n"
"    >>>\n"
"     # 1 OP RULE 1 0 R1\n"
"     # 1 OP FIELD 1 1\n"
"     \\142\n"
"     # 1 C FIELD 1 1\n"
"     # 1 C RULE 1 0 R1\n"
"       ...\n"
"    info fmt: # (depth) (open/close) (rule/fld) (rulenum) (fldnum) [rulename]\n"
"    data fmt: \\ooo (octet 3 digit, \\042 etc)\n"
"      - if you set an edit block, the nested inside ruleinfo will be lost\n"
"      - internal ruledata may be displayed (%1, %R_OPT etc. see -d opt)\n"
"    \n"
" -T: same as -t but parser doesnt edit. it may be useful when creating your\n"
"    own syntax tree.\n"
"	 \n"
" -o: output to a file instead of stdout\n"
"	eg) ~$ ped -rf buf.peg src.txt		#>> write to stdout \n"
"	eg) ~$ ped -rf buf.peg src.txt -o dst.txt 	#>> write to dst.txt \n"
"\n"
" -d: disp pegrule debuginfo. return 1 ($?==1) if pegrule is invalid.\n"
" 	eg) ~$ ped -df buf.peg	#>> $? == 0 if pegrule is valid\n"
"\n"
" -L: newline str, \\r\\n, \\r, \\0 etc. this opt only uses for parse emsg.\n"
"    this opt never affects to parse result. accept c99 charesc syntax.\n"
"    use dfl:'\\n' if noset\n"
"    eg) ~$ ped -rL 'ab' -f buf.peg src.txt  #>> use 'ab' as line separator \n"
"    eg) ~$ ped -rL '\\141\\142' -f buf.peg src.txt  #>> the same result\n"
"    eg) ~$ ped -rL '\\r\\u000a' -f buf.peg src.txt  #>> '\\r\\n'\n"
" \n"
" -h: disp help\n"
" -H: disp detail Help\n"
" -g: ignore. this option do nothing\n"
" -V: version info\n"
"\n"
"-- appendix\n"
" - pegrule(orig) ..https://pdos.csail.mit.edu/papers/parsing:popl04.pdf\n"
"   ped supports all orig pegrule. orig/ped is freeformat.\n"
" \n"
" '' : lit	eg) 'abc', 'a\\143c'\n"
" \"\" : lit\n"
" <- : rule define	eg) RULE_HW <- 'hello' \n"
"  / : rule def 'OR'	eg) RULE_HW <- 'hello' / 'hi'\n"
" () : grouping  	eg) NAME <- ('bo' / 'bom') 'b'	# bob,bomb\n"
" [] : char class	eg) NAME <- [a-cA] 'lice'   # alice,blice,clice,Alice\n"
"  . : any 1 char	eg) NAME <- . 'lice'	# xlice, ylice, zlice...	\n"
"  + : one or more	eg) NAME <- 'ab'+	# ab, abab, ababab...\n"
"  * : zero or more	eg) NAME <- 'a' 'b'* 'c'   # ac, abc, abbc.. (danger)\n"
"  ? : zero or one	eg) NAME <- 'a' 'b'? 'c'   # ac, abc (danger)\n"
"  ! : not/except	eg) NAME <- !'A' . 'lice'  # similar to regex [^A]lice	\n"
"  & : and/include	eg) NAME <- &'ab' [a-z]+   # abzz, ababc, abx ...\n"
"  # : linecomment	eg) NAME <- 'abc'  # cmt skip until newline, \\r\\n,\\n,\\r\n"
" !. : not+any==EOF	eg) END  <- '\\n' !.	# similar to sed EOL '$'	 	\n"
" \n"
" class[] is similar to regex, but 'NOTsymbol' [^] doesnt work, needs esc [\\]]. \n"
" '*?' is danger symbol. peg is recursive descent parsing so the below rule\n"
" is valid grammar but causes infinite loop.\n"
"	RULE1 <- '' / 'abc'\n"
"	RULE2 <- 'abc'*\n"
"	RULE3 <- 'abc'?\n"
" be careful when '*?' is at the top of the rule. ped raises error if infinite\n"
" ruleloop exists. you can also ckeck ruleloop if set -d opt.\n"
"\n"
" - run orig peg\n"
"   ped works fine under the orig syntax. it will run as a grammar checker. \n"
"	~$ echo xyz | ped -e  'R1 <- \"abc\"'	#>> xyz,      $?=0\n"
"	~$ echo xyz | ped -ne 'R1 <- \"abc\"'	#>> (nodisp), $?=0\n"
"	~$ echo xyz | ped -Ne 'R1 <- \"abc\"'	#>> (errstop) $?=1\n"
"\n"
" - bench mark: 1cpu 2.8GHz\n"
"	~$ time cat 1Mb.txt| sed -e 's@[_a-zA-Z][_0-9a-zA-Z]*@X@g'\n"
"	~$ time cat 1Mb.txt| ped -re 'ID<-![0-9] [_0-9a-zA-Z]+ {_0=\"X\"}'\n"
"	>>>\n"
"	 sed: real 0m0.517s\n"
"	 ped: real 0m0.618s\n"
"	...130-150ms to convert 1000 lines (in ped self-hosting) \n"
"\n"
" - literal rule,  \"123\\\"abc\" etc\n"
"    ERE: [\"](\\\\\"|[^\"])*[\"]\n"
"\n"
"	ped:\n"
"	LIT <- DQ (!DQ .|ESC_DQ)* DQ \n"
"	DQ <- '\"'\n"
"	ESC_DQ <- h'\\\"'		# or '\\134\\042'\n"
"\n"
"	LIT2 <- DQ e'(\\\\\"|[^\"])*' DQ		# text input only \n"
"	LIT3 <- DQ e'(\\\\\"|[^\\u0022])*' DQ	# same \n"
"	LIT4 <- DQ e'(\\\\\"|[^\\042])*' DQ	  # allow binary input \"a(\\377)b\" etc\n"
" \n"
" - search cmt\n"
"   (delcmt.ped)\n"
"     LINECMT <- '//' (!'\\n' .)* '\\n'	{_0 = \"KILL_L \" }\n"
"     MULTICMT <- '/@' !'@/' .* '@/'  {_0 = \"KILL_M \" } #.(dot) == 1byte\n"
"     \n"
"     # easy+fast using ped-regex\n"
"     # L <- e'//[^\\n]\\n' {_0=\"KILL_L\"}\n"
"     # M <- e'/@(@[^/]|[^@])*@/' {_0=\"KILL_M\"}\n"
"     \n"
"   (src.txt)\n"
"     abc //cmt\n"
"     xyz /@ cmt //abc\n"
"       hello, world @/\n"
"   ~$ ped -f delcmt.peg<src.txt		#>> abc KILL_L xyz KILL_M\n"
"\n"
" - ped concept\n"
"    - sed with more powerful grammer expression\n"
"    - respect the orig and standard. avoid vendor lock-in syntax as PCRE\n"
"    - portable\n"
"    - easy to use. low learning cost\n"
"\n"
" - other sample (ped self-hosting C >> luajit, ~$ ped -rf luka.ped src.txt)\n"
"]=]..[=====[\n"
"\n"
"# luka.ped, transpiler C-syn to lj \n"
"#--main-rules\n"
"stmt <- \n"
"		#skip multibyte-terms\n"
"	BLANK	\n"
"	/ LITS\n"
"	/ CMT\n"
"		#edit statement\n"
"	/ blk_stmt	# loop etc: for(i=1,10){..} >> for i=1,10 do .. end\n"
"	/ RB_DFL	#if( a=(1+2) ), nest logic, !\")\" stmt\n"
"	/ CB_DFL\n"
"		#edit terms\n"
"	/ M_TERM\n"
"		#pass oters\n"
"	/ IDENT		#get longbyte using regex to same jmpcost\n"
"	/ .		#all 1 byte\n"
"EOF <- !.\n"
"#--main-rules-end\n"
"\n"
"#--scanner\n"
"\n"
"		#add myrule-syntax\n"
"M_TERM <- \":=\" {_0 = \"=\"}\n"
"	/ \"**\" {_0 = \"^\"}\n"
"	/ \"!=\" {_0 = \"~=\"}\n"
"	/ \"!\"  {_0 = \" not \"}\n"
"	/ \"&&\" {_0 = \" and \"}\n"
"	/ \"||\" {_0 = \" or \"}\n"
"	/ \"break\" ! [.a-zA-Z_]		{_1 = \" do break end \"}\n"
"	/ \"continue\" ! [.a-zA-Z_]  {_1 = \" goto _luka_LOOPNEXT \"} #for/while\n"
"	/ \"lo\"	! [.a-zA-Z_]		{_1=\"local\"}\n"
"	/ \";\\n\" {_0=\"\\n\"}		# for astyle etc. del last semi-colon\n"
"\n"
"		#blank\n"
"BLANK <- (SPACE/TAB/NL)+\n"
"SPACE <- \" \"\n"
"TAB <- \"\\t\"\n"
"NL <- \"\\r\\n\" / \"\\n\" / EOF\n"
"\n"
"		#ident	nohit a[\"b\"].val etc. uses only for jmpcost + func_stmt\n"
"IDENT <- e\"([a-zA-Z_][a-zA-Z0-9_]*)([.][a-zA-Z_][a-zA-Z0-9_]*)*\"  #aa.bb.cc\n"
"\n"
"		#cmt \n"
"CMT <- MCMT / LCMT\n"
"LCMT <- e\"--[^\\n]*\" \"--\" (! NL .)* NL\n"
"	 / \"//\"  (! NL .)* NL {_1=\"--\"}\n"
"\n"
"		#add for C-cmtstyle...longstr comes 1st. \n"
"MCMT <- \"--\" MLIT		#MLIT [[...]], MCMT --[[...]]\n"
"	/ \"/*---\" (!\"---*/\" .)*  \"---*/\" {_1=\"--[===[\"; _3=\"]===]\"}\n"
"	/ \"/*--\" (!\"--*/\" .)*  \"--*/\" {_1=\"--[==[\"; _3=\"]==]\"}\n"
"	/ \"/*-\"  (!\"-*/\" .)* \"-*/\" {_1=\"--[=[\"; _3=\"]=]\"}\n"
"	/ \"/*\" (!\"*/\" .)* \"*/\"	{_0=\"--[[\" _2 \"]]\"}\n"
"\n"
"		#lit\n"
"LITS <-	e/\"([\\].|[^\\\"])*\"/\n"
"	/	e/'([\\].|[^\\'])*'/\n"
"	/ MLIT		#here-lit == multiline-lit\n"
"\n"
"MLIT <- \"[[\" (!\"]]\" .)* \"]]\"\n"
"	/ \"[=[\" (!\"]=]\" .)* \"]=]\"\n"
"	/ \"[==[\" (!\"]==]\" .)* \"]==]\"\n"
"	/ \"[===[\" (!\"]===]\" .)* \"]===]\"\n"
"	/ \"[====[\" (!\"]====]\" .)* \"]====]\"\n"
"	/ \"[=====[\" (!\"]====\\075]\" .)* \"]====\\075]\"\n"
"	/ \"[\" \"=\"+	{_E}		# stop if more than =6\n"
"		#add C-style mlit\n"
"	/ \"/*===\" (!\"===*/\" .)*  \"===*/\"	{_0 =\"[===[\" _2 \"]===]\"}\n"
"	/ \"/*==\" (!\"==*/\" .)*  \"==*/\"		{_0 = \"[==[\" _2 \"]==]\"}\n"
"	/ \"/*=\"  (!\"=*/\" .)* \"=*/\"			{_0 =  \"[=[\" _2 \"]=]\"}\n"
"\n"
"		#block_stmt...very complex:  for(){}, if(){}, elif(){}\n"
"blk_stmt <- (\"for\"/\"while\") RB_LP CB_LP\n"
"			{_3 = \"do do\" _3 \"end::_luka_LOOPNEXT::end \"}\n"
"	/ if_stmt\n"
"	/ func_stmt\n"
"	/ \";{\" CB_LP { _0 = \"do\" _0 \"end \"}		# ;{...} >> do ... end\n"
"\n"
"		# if_stmt	if(){..} >> (else)if .. then .. end\n"
"if_stmt <- BLANK? \"if\" RB_LP CB_LP ELIF_BLK* EL_BLK?\n"
"		{_3 = _3 \"then\"; _0 = _0 \"end \"}\n"
"ELIF_BLK <- BLANK? ELIF_WORD RB_LP CB_LP { _3= _3 \"then\" }\n"
"EL_BLK <- BLANK? \"else\" CB_LP\n"
"ELIF_WORD <- \"elseif\"\n"
"		/ \"elif\" {_0=\"elseif\"}\n"
"\n"
"		#uses only while,for,if etc		for(a) >> for a \n"
"RB_LP <- BLANK? \"(\" ( !\")\" stmt)* \")\" {_0 = \" \" _3 \" \"}\n"
"CB_LP <- BLANK? \"{\" ( !\"}\" stmt)* \"}\" {_0= \" \" _3 \" \"}\n"
"\n"
"		#normal blk, if( (1+2) ) >> if (1+2) : needs ERB_DFL in stmt\n"
"RB_DFL <- BLANK? \"(\" ( !\")\" stmt)* \")\"\n"
"CB_DFL <- BLANK? \"{\" ( !\"}\" stmt)* \"}\"\n"
"\n"
"		#fn_def:  fn a.b(){}, a=fn(){}, 	edit {} >> ...end\n"
"func_stmt <- FN_WORD BLANK? IDENT? RB_DFL CB_LP	{_0 = _0 \"end\"}\n"
"FN_WORD <- \"function\"\n"
"		/ \"fn\"	{_0=\"function\"}\n"
"]=====]\n"
"	return buf\n"
" end\n"
"\n"
"--[[SH_SMP\n"
"local u = require(\"ped_ljmod\")\n"
"print( u.ped_help() )\n"
"//SH_SMPE]]\n"
"\n"
"if u.ismain()  then \n"
"	local tb={u.tb2va(_G.arg)}\n"
"	print(ctx.ped_Help() )\n"
" end \n"
"return ctx\n"
"\n"
"\n"
"\n"
"--[[\n"
" change log\n"
" --\n"
"2021-08-15  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* ped_ljmod.sh.lua (usage_H):  fix doc\n"
"\n"
"2021-08-11  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* ped_ljmod.sh.lua (f_scanpeg): change reg r\"\" >> e\"\", b\"\"\n"
"	* (other): fix scan \\[ and other charesc, reg syntax, reg esc\n"
"\n"
"2021-07-26  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* ped_ljmod.sh.lua (frulesinfo): replace infostr \\0 >> '\\\\0' for disp msg\n"
"	\n"
"	* ped_ljmod.sh.lua (scanpeg): fix reg-octesc 'hat' \".[$(...\" >> \"^.[$(...\"\n"
"\n"
"2021-07-21  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* ped_ljmod.sh.lua (loopck): change loopck routine, add -2, fillrpos etc\n"
"\n"
"2021-07-15  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* ped_ljmod.sh.lua (scanpeg): add heredoc h\"\"/h''\n"
"\n"
"2021-07-10  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* ped_ljmod.sh.lua (loopck): add undef rule using emsg\n"
"\n"
"2021-07-05  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* ped_ljmod.sh.lua (ped_version): apply license info. v2.0.0\n"
"\n"
"2021-07-01  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* ped_ljmod.sh.lua (uniclass): fix [\\u005e-\\u005f] >> [^-_] logic, [_-_^]\n"
"	* (usage): fix doc\n"
"	\n"
"]]\n"
/*63860*/
