• cppawk: portable case statement.

    From Kaz Kylheku@21:1/5 to All on Mon Mar 28 07:09:41 2022
    GNU Awk has a switch statement.

    In cppawk I made a case statement which translates to GNU Awk switch,
    but supports non-GNU Awk.

    Check this out:

    #include <case.h>

    {
    case ($0) {
    of ("foo") {
    print "** foo case: fallthrough!"
    }
    of ("bar", "xyzzy") {
    print "** bar/xyzzy case"
    cbreak;
    }
    matching (/x/) {
    print "** /x/ case"
    cbreak;
    }
    otherwise {
    print "** default"
    }
    }
    }

    Translate for GNU Awk:

    $ ./cppawk --prepro-only -f case.cwk
    # 1 "<stdin>"
    [ snip ]
    # 33 "./cppawk-include/case.h" 2
    # 2 "case.cwk" 2

    {
    switch ($0) {
    case "foo": {
    print "** foo case: fallthrough!"
    }
    case "bar": case "xyzzy": {
    print "** bar/xyzzy case"
    break;
    }
    case /x/: {
    print "** /x/ case"
    break;
    }
    default: {
    print "** default"
    }
    }
    }

    Translate for Mawk:

    $ ./cppawk --prepro-only --awk=mawk -f case.cwk
    # 1 "<stdin>"
    [snip]
    # 33 "./cppawk-include/case.h" 2
    # 2 "case.cwk" 2

    {
    for ((__once = 1) && (__pass = 0) || (__val = $0); __once; __once = 0) {
    if (__pass || ((__val == ("foo"))) && (__pass = 1)) {
    print "** foo case: fallthrough!"
    }
    if (__pass || ((__val == ("bar")) || (__val == ("xyzzy"))) && (__pass = 1)) {
    print "** bar/xyzzy case"
    break;
    }
    if (__pass || ((__val ~ (/x/))) && (__pass = 1)) {
    print "** /x/ case"
    break;
    }
    if (__pass = 1) {
    print "** default"
    }
    }
    }

    The temporary variables are a bit ugly. In a function you can declare them like this:

    function fun(arg1, arg2,
    local_var, case_temps)

    case_temps expands to __val, __once, __pass for that implementation.

    Some test cases and tweaking is needed to get the construct to work if nested with itself.

    I may switch it (pun intended) to have no fallthough by default between cases. Perhaps a fallthrough statement can request it explicitly. A good way to
    do that when targetting the Gawk switch is not obvious.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ed Morton@21:1/5 to Kaz Kylheku on Mon Mar 28 07:45:04 2022
    On 3/28/2022 2:09 AM, Kaz Kylheku wrote:
    GNU Awk has a switch statement.

    In cppawk I made a case statement which translates to GNU Awk switch,
    but supports non-GNU Awk.

    Check this out:

    #include <case.h>

    {
    case ($0) {
    of ("foo") {
    print "** foo case: fallthrough!"
    }
    of ("bar", "xyzzy") {
    print "** bar/xyzzy case"
    cbreak;
    }
    matching (/x/) {
    print "** /x/ case"
    cbreak;
    }
    otherwise {
    print "** default"
    }
    }
    }

    Translate for GNU Awk:

    $ ./cppawk --prepro-only -f case.cwk
    # 1 "<stdin>"
    [ snip ]
    # 33 "./cppawk-include/case.h" 2
    # 2 "case.cwk" 2

    {
    switch ($0) {
    case "foo": {
    print "** foo case: fallthrough!"
    }
    case "bar": case "xyzzy": {
    print "** bar/xyzzy case"
    break;
    }
    case /x/: {
    print "** /x/ case"
    break;
    }
    default: {
    print "** default"
    }
    }
    }

    Translate for Mawk:

    $ ./cppawk --prepro-only --awk=mawk -f case.cwk
    # 1 "<stdin>"
    [snip]
    # 33 "./cppawk-include/case.h" 2
    # 2 "case.cwk" 2

    {
    for ((__once = 1) && (__pass = 0) || (__val = $0); __once; __once = 0) {
    if (__pass || ((__val == ("foo"))) && (__pass = 1)) {
    print "** foo case: fallthrough!"
    }
    if (__pass || ((__val == ("bar")) || (__val == ("xyzzy"))) && (__pass = 1)) {
    print "** bar/xyzzy case"
    break;
    }
    if (__pass || ((__val ~ (/x/))) && (__pass = 1)) {
    print "** /x/ case"
    break;
    }
    if (__pass = 1) {
    print "** default"
    }
    }
    }

    The temporary variables are a bit ugly. In a function you can declare them like
    this:

    function fun(arg1, arg2,
    local_var, case_temps)

    case_temps expands to __val, __once, __pass for that implementation.

    Some test cases and tweaking is needed to get the construct to work if nested with itself.

    I may switch it (pun intended) to have no fallthough by default between cases.
    Perhaps a fallthrough statement can request it explicitly. A good way to
    do that when targetting the Gawk switch is not obvious.


    If I want portable code why wouldn't I simply write portable code?

    {
    s = $0
    if (s == "foo") {
    print "** foo case: fallthrough!"
    }
    if ( (s == "bar") || (s == "xyzzy") ) {
    print "** bar/xyzzy case"
    }
    else if (s ~ /x/) {
    print "** /x/ case"
    }
    else {
    print "** default"
    }
    }

    With "cppawk" you seem to be solving a problem that doesn't exist by
    creating a real problem - introducing a private tool that'd be required
    to parse the code and the necessity for people to have to look up ".h"
    files to figure out what the language constructs in the code mean and
    the potential for the tokens in the .h files to clash with variables or
    other language constructs used in the script.

    Ed.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Ed Morton on Mon Mar 28 22:52:57 2022
    On 2022-03-28, Ed Morton <mortonspam@gmail.com> wrote:
    On 3/28/2022 2:09 AM, Kaz Kylheku wrote:
    GNU Awk has a switch statement.

    In cppawk I made a case statement which translates to GNU Awk switch,
    but supports non-GNU Awk.

    If I want portable code why wouldn't I simply write portable code?

    My use case is that what I *have* is nonportable code, and I want
    GNU Awk to keep seeing more or less that same nonportable code while
    I make it run on another implementation also.

    Furthermore, I have reached a more or less final version of the macro
    which is safer to use than switch: each clause must explicitly break, fall-through or return from the surrounding function. This is now a
    syntax error:

    case (state) {
    of (1, 2, 3)
    state++
    of (4)
    return 0
    }

    it has to be:

    case (state) {
    of (1, 2, 3)
    state++
    cbreak # explicit cbreak, cfall or cret() required
    of (4)
    cret (0)
    }

    The syntax error isn't something nice (just unbalanced braces), but it's
    better than silence.

    s = $0
    if (s == "foo") {
    print "** foo case: fallthrough!"
    }
    if ( (s == "bar") || (s == "xyzzy") ) {
    print "** bar/xyzzy case"
    }

    This translation doesn't preserve the fallthrough; so while we have
    portable code now, it has succumbed to human error.

    I will make fewer conversion mistakes with a macro whose features
    closely mimic switch, and which can be separately validated by its own
    test cases.

    With "cppawk" you seem to be solving a problem that doesn't exist by
    creating a real problem - introducing a private tool that'd be required

    I released this to the public, under a BSD license. It relies on other
    commonly available and installed public tools.

    to parse the code and the necessity for people to have to look up ".h"
    files to figure out what the language constructs in the code mean and

    That could be a problem in a project without documentation.
    Oh, look; good thing I have that!

    $ man -l cppawk-case.1
    CPPAWK-CASE(1) Case Macro CPPAWK-CASE(1)

    NAME
    case - macro for portable switch statement

    SYNOPSIS
    #include <case.h>
    [...]

    the potential for the tokens in the .h files to clash with variables or
    other language constructs used in the script.

    While it's certainly possible to make a dog's breakfast of this, I'm consciously following best practices for header file hygiene, because
    that is super important in a tool like this. I'm hardly a beginner.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ed Morton@21:1/5 to Kaz Kylheku on Tue Mar 29 07:19:31 2022
    On 3/28/2022 5:52 PM, Kaz Kylheku wrote:
    On 2022-03-28, Ed Morton <mortonspam@gmail.com> wrote:
    On 3/28/2022 2:09 AM, Kaz Kylheku wrote:
    GNU Awk has a switch statement.

    In cppawk I made a case statement which translates to GNU Awk switch,
    but supports non-GNU Awk.

    If I want portable code why wouldn't I simply write portable code?

    My use case is that what I *have* is nonportable code, and I want
    GNU Awk to keep seeing more or less that same nonportable code while
    I make it run on another implementation also.

    Furthermore, I have reached a more or less final version of the macro
    which is safer to use than switch: each clause must explicitly break, fall-through or return from the surrounding function. This is now a
    syntax error:

    case (state) {
    of (1, 2, 3)
    state++
    of (4)
    return 0
    }

    it has to be:

    case (state) {
    of (1, 2, 3)
    state++
    cbreak # explicit cbreak, cfall or cret() required
    of (4)
    cret (0)
    }

    The syntax error isn't something nice (just unbalanced braces), but it's better than silence.

    s = $0
    if (s == "foo") {
    print "** foo case: fallthrough!"
    }
    if ( (s == "bar") || (s == "xyzzy") ) {
    print "** bar/xyzzy case"
    }

    This translation doesn't preserve the fallthrough;

    Yeah, looks like I forgot how a "fallthrough" worked and thought the
    next condition would be tested before the associated action was
    executed. It's been a long time since I wrote such code.

    so while we have
    portable code now, it has succumbed to human error.

    The error was just in my understanding of what your code does, not in my writing code to do what I intended it to do.

    Ed.


    I will make fewer conversion mistakes with a macro whose features
    closely mimic switch, and which can be separately validated by its own
    test cases.

    With "cppawk" you seem to be solving a problem that doesn't exist by
    creating a real problem - introducing a private tool that'd be required

    I released this to the public, under a BSD license. It relies on other commonly available and installed public tools.

    to parse the code and the necessity for people to have to look up ".h"
    files to figure out what the language constructs in the code mean and

    That could be a problem in a project without documentation.
    Oh, look; good thing I have that!

    $ man -l cppawk-case.1
    CPPAWK-CASE(1) Case Macro CPPAWK-CASE(1)

    NAME
    case - macro for portable switch statement

    SYNOPSIS
    #include <case.h>
    [...]

    the potential for the tokens in the .h files to clash with variables or
    other language constructs used in the script.

    While it's certainly possible to make a dog's breakfast of this, I'm consciously following best practices for header file hygiene, because
    that is super important in a tool like this. I'm hardly a beginner.


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kenny McCormack@21:1/5 to mortonspam@gmail.com on Tue Mar 29 12:27:04 2022
    In article <t1utgk$s11$1@dont-email.me>,
    A raving lunatic <mortonspam@gmail.com> wrote:
    ...
    The error was just in my understanding of what your code does, not in my >writing code to do what I intended it to do.

    Said every buggy programmer ever.

    --
    People who want to share their religious views with you
    almost never want you to share yours with them. -- Dave Barry

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)