From Newsgroup: comp.lang.awk
On 2022-02-11, Kenny McCormack <
gazelle@shell.xmission.com> wrote:
In article <20220209235134.861@kylheku.com>,
Kaz Kylheku <480-992-1380@kylheku.com> wrote:
...
Sure, but you don't get to use pattern/action pairs on the result.
But that's largely just syntactic sugar for a glorified case statement.
Instead of
/abc/ { ... }
$2 > $3 { ... }
you have to write
if (/abc/) { ... }
if ($2 > $3) { ... }
kind of thing.
Of course, it can be (and often has been) argued that everything in any programming language is just "syntactic sugar"
Not by me.
for the underling machine
code.
When I say "syntactic sugar", I'm referring to a light transformation to improve the taste. This is justified for the above example because the
"machine code" differs from the "HLL" counterpart only in that
"if (...)" has been wrapped around the test expressions.
I have a lot of experience implementing complicated language features
as code transformations, which I wouldn't call syntactic sugar.
Personally, I tend to agree with Ben here, that not being able to use the "automatic input loop" (aka, the "pattern/action" facility for which AWK is
Ben didn't need a loop in the specific situation because he just wanted
to take a field and further split it as if it were a record.
You'd benefit from a loop if you wanted to take a string and treat it
as an entire file, separated into records and then fields.
I agree that having to implement that loop around your conditional
statements would start to get more than a little inconvenient.
I made a Lisp version of Awk as a macro. You can use it anywhere you can
use an expression, and cleanly nest it with itself.
E.g. we can use it to make a function which returns a list of objects:
This is the TXR Lisp interactive listener of TXR 273.
Quit with :quit or Ctrl-D on an empty line. Ctrl-X ? for cheatsheet.
This area is under 24 hour TTY surveillance.
1> (defun wrapped-awk (strings)
(build ;; establish sccope for procedural list construction
;; built-up list is returned when scope terminates
(awk (:inputs strings)
(:set fs ":") ;; field separator is colon (:)
(t (fconv - i i)) ;; convert second and third fields to integer
(#/plus/ (add (+ [f 1] [f 2])))
(#/minus/ (add (- [f 1] [f 2]))))))
wrapped-awk
Now we just pass a list of strings into this function: they become
records:
2> (wrapped-awk '("plus:1:2" "plus:3:4" "minus:5:5"))
(3 7 0)
The list of sums and differences is returned.
Now, let's use the wrapped-awk function inside another awk loop;
this time we will feed it input from the TTY interactively:
3> (awk (t (prn (wrapped-awk f))))
plus:1:2 plus:3:4 minus:5:5
3 7 0
minus:15:20
-5
"If the 't' condition is true, which is always, then print the list
obtained by passing the delimited fields f into wrapped-awk."
And I want to be able to use the pattern/action facility on piped-in input (and also output - see below), I have written an extension library for GAWK that enables that. That is, I can do:
@load "pipeline"
BEGIN { pipeline("in","Some Shell Command Here") }
/foo/ { bar...}
Let's pipe the above into a character string.
4> (with-out-string-stream (*stdout*)
(awk (t (prn (wrapped-awk f)))))
plus:10:20 minus:13:7
[Ctrl-D][Enter]
"30 6\n"
with-out-string-stream creates a scope in which it binds a variable
to a string stream. Everything sent to that stream is appended to
a string, and that string is returned when with-out-string-stream
terminates.
If we choose *stdout* for the variable name, then standard output
is temporary bound to this string stream. Everything that would go
to standard output goes into the string stream.
Already in the 1980s, people were able to use FFI to define bindings
to foreign libraries, and not have to write any glue code that had to be compiled.
Here is my "extension lib" for calling size_t wcslen(const wchar_t *str):
5> (with-dyn-lib nil
(deffi wcslen "wcslen" size-t (wstr)))
wcslen
(wcslen "abcd")
4
How about the structure-returning function
ldiv_t lldiv(long numerator, long long denominator);
Define the foreign structure:
6> (deffi-struct lldiv
(quot longlong)
(rem longlong))
#<ffi-type (struct lldiv (quot longlong) (rem longlong))>
Define the foreign function binding:
7> (with-dyn-lib nil
(deffi lldiv "lldiv" lldiv (longlong longlong)))
lldiv
Test:
8> (lldiv 127 15)
#S(lldiv quot 8 rem 7)
This shit is unsafe, since we are calling C:
9> (lldiv 127 0)
Floating point exception (core dumped)
We could catch that signal. Let's try it again:
1> (deffi-struct lldiv (quot longlong) (rem longlong))
#<ffi-type (struct lldiv (quot longlong) (rem longlong))>
2> (with-dyn-lib nil
(deffi lldiv "lldiv" lldiv (longlong longlong)))
lldiv
Now install signal handler for SIGFPE, binding it to a
lambda function which throws the yikes symbol as an exception:
3> (set-sig-handler sig-fpe (lambda (signal async-p) (throw 'yikes)))
t
Now:
4> (lldiv 127 15)
#S(lldiv quot 8 rem 7)
5> (lldiv 127 0)
** yikes exception, args: nil
6>
--
TXR Programming Language:
http://nongnu.org/txr
Cygnal: Cygwin Native Application Library:
http://kylheku.com/cygnal
--- Synchronet 3.19b-Linux NewsLink 1.113