S-expressions: Difference between revisions
Content added Content deleted
(→{{header|TXR}}: Added explicit parser.) |
|||
Line 2,739: | Line 2,739: | ||
However, note that the <code>@</code> character has a special meaning: <code>@#</code> turns into <code>(sys:var #)</code>. TXR's printer right now does not convert this back to <code>@</code> notation upon printing. (The purpose of this notation is to support Lisp code that requires meta-variables: variables distinguished from variables. For instance, logic pattern matching or unification code. Instead of hacks like name-based conventions (for instance <code>x?</code> is a meta-variable, <code>x</code> is ordinary), why not build it into the language: <code>@x</code> is a meta-var, identifiable by special abstract syntax, and <code>x</code> is just an atom, a symbol. There is also <code>@(foo ...)</code> which expands into <code>(sys:expr foo ...)</code>, doing a similar thing for expressions. |
However, note that the <code>@</code> character has a special meaning: <code>@#</code> turns into <code>(sys:var #)</code>. TXR's printer right now does not convert this back to <code>@</code> notation upon printing. (The purpose of this notation is to support Lisp code that requires meta-variables: variables distinguished from variables. For instance, logic pattern matching or unification code. Instead of hacks like name-based conventions (for instance <code>x?</code> is a meta-variable, <code>x</code> is ordinary), why not build it into the language: <code>@x</code> is a meta-var, identifiable by special abstract syntax, and <code>x</code> is just an atom, a symbol. There is also <code>@(foo ...)</code> which expands into <code>(sys:expr foo ...)</code>, doing a similar thing for expressions. |
||
The following solution avoids "cheating" in this way with the built-in parser; it implements a from-scratch S-exp parser which treats <code>!@#</code> as just a symbol. |
|||
The grammar is as follows: |
|||
<pre> |
|||
expr := ws? atom |
|||
| ws? ( ws? expr* ws? ) |
|||
atom := float | int | sym | str |
|||
float := sign? digit+ . digit* exponent? |
|||
| sign? digit* . digit+ exponent? |
|||
| sign? digit+ exponent |
|||
int := sign? digit+ |
|||
str := " (\" | anychar )* " |
|||
sym := sym-char + |
|||
sym-char := /* non-whitespace, but not ( and not ) */</pre> |
|||
Code: |
|||
<lang txr>@(define float (f))@\ |
|||
@(local (tok))@\ |
|||
@(cases)@\ |
|||
@{tok /[+\-]?\d+\.\d*([Ee][+\-]?\d+)?/}@\ |
|||
@(or)@\ |
|||
@{tok /[+\-]?\d*\.\d+([Ee][+\-]?\d+)?/}@\ |
|||
@(or)@\ |
|||
@{tok /[+\-]?\d+[Ee][+\-]?\d+/}@\ |
|||
@(end)@\ |
|||
@(bind f @(flo-str tok))@\ |
|||
@(end) |
|||
@(define int (i))@\ |
|||
@(local (tok))@\ |
|||
@{tok /[+\-]?\d+/}@\ |
|||
@(bind i @(int-str tok))@\ |
|||
@(end) |
|||
@(define sym (s))@\ |
|||
@(local (tok))@\ |
|||
@{tok /[^\s()]+/}@\ |
|||
@(bind s @(intern tok))@\ |
|||
@(end) |
|||
@(define str (s))@\ |
|||
@(local (tok))@\ |
|||
@{tok /"(\\"|[^"])*"/}@\ |
|||
@(bind s @[tok 1..-1])@\ |
|||
@(end) |
|||
@(define atom (a))@\ |
|||
@(cases)@\ |
|||
@(float a)@(or)@(int a)@(or)@(str a)@(or)@(sym a)@\ |
|||
@(end)@\ |
|||
@(end) |
|||
@(define expr (e))@\ |
|||
@(cases)@\ |
|||
@/\s*/@(atom e)@\ |
|||
@(or)@\ |
|||
@/\s*\(\s*/@(coll :vars (e))@(expr e)@/\s*/@(until))@(end))@\ |
|||
@(end)@\ |
|||
@(end) |
|||
@(freeform) |
|||
@(expr e)@junk |
|||
@(output) |
|||
expr: @(format nil "~s" e) |
|||
junk: @junk |
|||
@(end)</lang> |
|||
Run: |
|||
<pre>$ txr s-expressions.txr - |
|||
() |
|||
expr: nil |
|||
junk: |
|||
$ txr s-expressions.txr - |
|||
3e3 |
|||
expr: 3000.0 |
|||
junk: |
|||
$ txr s-expressions.txr - |
|||
+3 |
|||
expr: 3 |
|||
junk: |
|||
$ txr s-expressions.txr - |
|||
abc* |
|||
expr: abc* |
|||
junk: |
|||
$ txr s-expressions.txr - |
|||
abc*) |
|||
expr: abc* |
|||
junk: ) |
|||
$ txr s-expressions.txr - |
|||
((data "quoted data" 123 4.5) |
|||
(data (!@# (4.5) "(more" "data)"))) |
|||
expr: ((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)"))) |
|||
junk: |
|||
</pre> |
|||
{{omit from|Brlcad}} |
{{omit from|Brlcad}} |