Simple Code Parser

Simply used to parse a simple programming language I call BBPL.

I’m not done yet, not a lot to do.

EX:



Msg("Blahblahblah")
randomfunction(1+2+3+4+5)
Variable = 10+5/5


Create bbpl/TEST.txt then c&p this code.
Lua should be placed in autorun.
Type in runfile and watch it parse the code in the console.
No real instructions, this is not a real release of anything.

[lua]bbpl = {}
bbpl.Data = {}
function bbpl:DoString(str)
Msg(string.byte(“A”)…" “…string.byte(“a”)…” “…string.byte(“Z”)…” “…string.byte(“z”)…” “…string.byte(“1”)…” “…string.byte(“9”)…”
“)
local str = string.Replace(str,”
“,”
“)
local lines = string.Explode(”",str)
local chunk = “”
local Ret = false
local FunctionPar = 0
local CurFunc = “”
local CurVar = “”
local DeclareChunk = “”
local DeclareVar = “”
local InOperation = false
local InQuotes = false
local InDeclare = false
local Args = {}
for k,v in pairs(lines) do
if v == “”" then
if InQuotes then
InQuotes = false
else
InQuotes = true
end
end
if (v == "
“) and !InQuotes and !InDeclare then
Ret = true
end
if v == “(” and !InQuotes then
if InDeclare then
InDeclare = false
DeclareChunk = chunk
DeclareVar = CurVar
local newchunk = string.Explode(” “,string.Trim(string.Replace(chunk,”
“,” “)))
chunk = newchunk[#newchunk]
end
FunctionPar = FunctionPar + 1
if FunctionPar == 1 then
Ret = true
CurFunc = string.Trim(chunk)
chunk = “”
end
elseif v == “)” and !InQuotes then
if FunctionPar == 1 then
table.insert(Args,chunk)
//local args = string.Explode(”,",chunk)
for k,v in ipairs(Args) do
Args[k] = bbpl:Operations(v)
end
bbpl:DoFunction(CurFunc,Args)
Msg("Run Function: “…CurFunc…”
“)
Msg(“Arguments: “…string.Implode(”,”,Args)…”
“)
chunk = “”
Args = {}
Ret = true
else
//Msg(“ERROR!: Unnecessary ‘)’”)
end
FunctionPar = FunctionPar - 1
else
if FunctionPar then
if v == “,” and !InQuotes then
table.insert(Args,chunk)
Ret = true
chunk = “”
end
end
end
if v == “=” and !InQuotes then
if InDeclare then
DeclareChunk = chunk
DeclareVar = CurVar
local newchunk = string.Explode(” “,string.Trim(string.Replace(chunk,”
“,” “)))
CurVar = newchunk[#newchunk]
else
CurVar = string.Trim(chunk)
InDeclare = true
//bbpl.Data[chunk]
end
chunk = “”
Ret = true
end
if k == #lines then
if InDeclare then
DeclareChunk = chunk…v
DeclareVar = CurVar
end
end
if string.len(DeclareChunk) > 0 then
local newchunk = string.Explode(” “,string.Trim(string.Replace(DeclareChunk,”
“,” ")))
DeclareChunk = newchunk[1]
if self:GoodName(DeclareVar) then
Msg("Declare: “…DeclareVar…”
")
Msg("As: “…DeclareChunk…”
“)
else
Msg(“ERROR: Invalid variable name '”…DeclareVar…”’
")
end
DeclareChunk = “”
end
if !Ret then
chunk = chunk…v
end
Ret = false
end
end

function bbpl:GoodName(str)
local chars = string.Explode("",str)
for k,v in pairs(chars) do
local b = string.byte(v)
if !((b>=65 and b<=122) or (b>=49 and b<=57)) then
return false
end
end
return true
end

function bbpl:DoFunction(name,args)
if name == “Msg” then
Msg(args[1])
end
end

function bbpl:Operations(str)
local str = string.Trim(str)
local para = string.Explode("",str) – Paranthesis
local para_op = “”
local para_after = “”
local paras = 0
local Ret = false
for k,v in pairs(para) do
if v == “)” then
paras = paras - 1
Ret = true
end
if paras > 0 then
para_op = para_op…v
Ret = true
end
if v == “(” then
paras = paras + 1
Ret = true
end
if paras <= 0 then
if string.len(para_op) > 0 then
para_after = para_after…self:Operations(para_op)
para_op = “”
Ret = true
end
end
if !Ret then
para_after = para_after…v
end
Ret = false
end
local para = string.Explode("(",para_after) – Paranthesis
local minus = string.Explode("-",para_after)
if #minus > 1 then
local minus_after = 0
for k,v in pairs(minus) do
if k == 1 then
minus_after = tonumber(self:Operations(v))
else
minus_after = minus_after - tonumber(self:Operations(v))
end
end
return minus_after
end
local add = string.Explode("+",para_after)
if #add > 1 then
local add_after = 0
for k,v in pairs(add) do
if k == 1 then
add_after = tonumber(self:Operations(v))
else
add_after = add_after + tonumber(self:Operations(v))
end
end
return add_after
end
local divide = string.Explode("/",para_after)
if #divide > 1 then
local divide_after = 0
for k,v in pairs(divide) do
if k == 1 then
divide_after = tonumber(self:Operations(v))
else
divide_after = divide_after / tonumber(self:Operations(v))
end
end
return divide_after
end
local multiply = string.Explode("*",para_after)
if #multiply > 1 then
local multiply_after = 0
for k,v in pairs(multiply) do
if k == 1 then
multiply_after = tonumber(self:Operations(v))
else
multiply_after = multiply_after * tonumber(self:Operations(v))
end
end
return multiply_after
end
local exponent = string.Explode("^",para_after)
if #exponent > 1 then
local exponent_after = 0
for k,v in pairs(exponent) do
if k == 1 then
exponent_after = tonumber(self:Operations(v))
else
exponent_after = exponent_after ^ tonumber(self:Operations(v))
end
end
return exponent_after
end
return para_after
–[[if string.Left(str,1) == “”" then
if string.Right(str,1) == “”" then
else
end
end]]
end

function bbpl:Paranthesis(str)

end

function runfiles( player, command, arguments )
bbpl:DoString( file.Read(“bbpl/TEST.txt”) )
end

concommand.Add( “runfile”, runfiles )[/lua]

I’m a horrible coder, this thing looks like a giant mess. Hope it helps somebody.

Awesome job.

But… holy fuck

…learn to use Lua string patterns!

As demonstrated by this:

Meh, I just copied what I remembered from the Lua source code to parse strings.

Lua checks operations by going through individual characters in the file.

I know I could do something with string.find and string.gmatch in doing operations, but I just wanted to parse the code in order of top to bottom.

Using lua string patterns, imo, would be good for finding specific shit rather then going through things sequentially.

I almost got variable setting done. I coded this because I wanted to create a code parser like E2, just because I wanted to.

If you want to learn more about parsers (specifically, how to program them), I’d highly recommend you pick up a copy of the compiler “dragon” book. Worth every penny, in my opinion.

[lua]
v, count = string.gsub(v, “(%-?[%w_%d%.e]+)%s*([%%/%%])%s(%-?[%w%_%d%.e]+)”, function(a,b,c)
[/lua]

O.o How to understand that?

[lua]
v, count = string.gsub(v, “(%-?[%w_%d%.e]+)%s*([/%%])%s(%-?[%w_%d%.e]+)”, function(a,b,c)
[/lua]

means:

Match a minus sign and a word, or just a word and provide as argument a.
Skip any spacing.
Match a single *, / or % and provide it as argument b.
Skip any spacing.
Match a minus sign and a word, or just a word and provide as argument c.

The ‘v’ variable will be set to the original string with the matched part replaced with whatever is returned by the function.
The ‘count’ variable will be set to how many matches were made within the string.

Going through every char is a shitload faster than using string.find many times instead - which actually does the same (but in C++).