aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
blob: 336fb1099b012a3411146369058d5ac847d5e5de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
## What is `cppawk`?

`cppawk` is a tiny shell script that is used like `awk`. It invokes
the C preprocessor (GNU `cpp`) on the Awk code and calls `gawk`.

`cppawk` understands the basic Awk options like `-F` and `-v`, and also
understand common `cpp` options like `-I` and `-Dmacro=value`.
The `cppawk` `man` page has the invocation and usage details.

For instance, if we define a file called `awkloop.h` which has these contents

    :::c
    #define awkloop(file)  for (; getline < file || (close(file) && 0); )
    #define nextrec        continue
    #define rule(cond)     if (cond)

Then this sort of code is possible:

    ::c
    #include "awkloop.h"

    function main()
    {
      awkloop ("/proc/mounts") {
        rule ($3 != "ext4") { nextrec }
        rule ($2 == "/") { print $1 }
      }
    }

    BEGIN {
      main()
    }

We have implemented a facsimile of an Awk input scanning loop inside a function
with a bit of syntactic sugar.

`cppawk` has low dependencies. It's written in shell, and makes use of the
`sed` and `printf` utilities.  Preprocessed programs can be captured and
transferred for execution to systems that have Awk but do not have a
preprocessor.

## Roadmap

`cppawk` is been carefully developed, and has a regression test suite.
Nearly every feature and fix was developed by first writing one or more
failing tests and getting them to pass. The script is stable and nearly
feature-complete, since it is out of the project scope to modify Awk
or the C preprocessor. The remaining work is likely solving portability
issues, like using with different implementations of the C preprocessor.

Among future directions for `cppawk` is the development of a small
library of useful standard headers. The foundation has been laid for
this because when `#include <...>` is used (angle bracket include), it looks in
a subdirectory called `cppawk-include` which is in the same directory as
itself. For instance if `cppawk` is `/usr/bin/cppawk`, it looks in
`/usr/bin/cppawk-include`. This library directory is currently empty.

## Why?

*   Why not?

*   You know Awk. You know C preprocessing inside out. Now use two things
    that you know, together, in obvious ways.

*   You can organize an Awk program into a tree of files that
    the preprocessor "compiles" into a single "executable".

*   You can use macros for C-style meta-programming, and for conditional
    selection of code.

*   Other minor benefits: Awk has no comments other than from a `#`
    character to the end of the line. You get `/* ... */` comments
    with `cppawk`, and also `#if 0` ... `#endif` for temporarily
    disabling code.

## But GNU Awk has `@include`?

*   GNU Awk's `@include` isn't a full preprocessor. There are no conditional
    expressions, and no macros.

*   It is only implemented in GNU Awk.

*   It provides no way to capture all the included output.

*   The way `@include` searches for files is inferior to `cpp`;
    it doesn't look in the same directory as the parent file which contains the
    `@include` syntax. It reacts to an `AWKPATH` environment variable which has
    no provision for referencing relative to the location of the parent file.

*   `@include` requires, syntactically, a string-literal-like specification
    of the path name to be included. An expression is not allowed. For
    instance, if a GNU Awk program cannot do this:

        ::awk
        self = calculate_own_path_somehow();
        @include self "lib/util"  # error

    By contrast `cppawk` program just does this:

        ::c
        #include "lib/util"  // no problem

    The C preprocessor allows macro-replacement to take place in `#include`:

        ::c
        #include FOO_LIB   // conditionally-defined macro to select lib