[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Imitation of AWK in Lua 5.1 using a PC.
- From: Sean Conner <sean@...>
- Date: Mon, 10 Jul 2017 19:21:38 -0400
It was thus said that the Great Gavin Holt once stated:
> Hi,
>
> This is my first post, please be gentle. I am trying to make a simple
> imitation of AWK in Lua 5.1 using a PC.
[ snip ]
> I would be grateful for some advice about how to manage the ORS. You
> will see that for the last source line I avoid appending the ORS. However,
> if the last line doesn't generate any output I can't get back the previously
> output ORS!
>
You could try the following (simplified to make it easier to follow):
awkENV.ORS = "" -- initially nothing
for _,pattern i pairs(instructions) do
if pattern[1](...) then
local output = pattern[2](...)
if output then
-- write output
-- write awkENV.ORS
awkENV.ORS = instructions.ORS or "\n" -- set ORS for next
interation
end
end
end
You always send the ORS, but the first time through, it's an empty string.
On each subsequent pass, it's set to the value you want. Yes, it's an extra
assignment on each pass, but it avoids quite a bit of tricky logic, so I
think it's a win overall.
> For a generalized approach I would also value some advice about creating
> an iterator to process a line at a time, while preserving the ability to
> send a string or table or file name.
An interator is a function that returns a function and some state data.
Something like:
function next_record(source,separator)
separator = separator or "\n"
-- -----------------------------------------------------------------------
-- our state is the source table; var is the record count. We can't just
-- use next() because the traveral of keys is unordered, even for
-- numerical indicies. So let's just do it ourselves.
-- -----------------------------------------------------------------------
local next_from_table(state,var)
var = var + 1
if state[var] then
return var,state[var]
end
end
-- -----------------------------------------------------------------------
-- Here, our state is a function that returns the next record, and again,
-- var is just the record count.
-- -----------------------------------------------------------------------
local next_from_file_or_string(state,var)
var = var + 1
local rec = state()
if rec then
return var,state()
end
end
-- -----------------------------------------------------------------------
-- This is used to handle error cases---there's nothing to iterate, so it
-- just exits.
-- -----------------------------------------------------------------------
local next_nothing()
return nil
end
-- ---------------------------------------------
-- See section 2.4.5 (Lua 5.1)
-- 3.3.5 (Lua 5.2)
-- 3.3.5 (Lua 5.3)
-- for more information about iterators
-- ---------------------------------------------
if type(source) == 'table' then
return next_from_table,source,0
-- ----------------------------------------------------------------------
-- For a string, if we can open it, treat it as a file. If the input
-- separator is "\n", use io.lines() for state (a function that will
-- return the next line); otherwise, read the entire input, and use
-- str:gmatch() (a function that will return the next match) as the state.
-- If we can't open it, assume a non-filename, and use str:gmatch() as the
-- state.
-- -----------------------------------------------------------------------
elseif type(source) == 'string' then
if file_exists(source) then
if separator == '\n' then
return next_from_file_or_string,io.lines(source),0
else
local f = io.open(source,"r")
if f then
local d = f:read("*a")
f:close()
return next_from_file_or_string,d:gmatch("[^" .. separator .. "]+"),0
else
return next_nothing
end
end
end
return next_from_file_or_string,source:gmatch("[^" .. separator .. "]+"),0
end
-- ---------------------------------
-- For any other source, just bail
-- ---------------------------------
else
return next_nothing
end
end
The code is untested, but it *should* work (or be close enough to get it
working). It's to be used like:
-- source can be a table, a filename or a string
for recnum,record in next_record(source,"\n") do
...
end
-spc (Hope this helps some)