S-expressions: Difference between revisions
Content deleted Content added
m →{{header|F#}}: Corrected header as suggested on the Count examples/Full list/Tier 4 talk page |
Thundergnat (talk | contribs) m syntax highlighting fixup automation |
||
Line 21: | Line 21: | ||
The reader should be able to read the following input |
The reader should be able to read the following input |
||
< |
<syntaxhighlight lang="lisp">((data "quoted data" 123 4.5) |
||
(data (!@# (4.5) "(more" "data)")))</ |
(data (!@# (4.5) "(more" "data)")))</syntaxhighlight> |
||
and turn it into a native datastructure. (see the [[#Pike|Pike]], [[#Python|Python]] and [[#Ruby|Ruby]] implementations for examples of native data structures.) |
and turn it into a native datastructure. (see the [[#Pike|Pike]], [[#Python|Python]] and [[#Ruby|Ruby]] implementations for examples of native data structures.) |
||
Line 36: | Line 36: | ||
{{trans|Nim}} |
{{trans|Nim}} |
||
< |
<syntaxhighlight lang="11l">T Token |
||
T.enum Kind |
T.enum Kind |
||
INT |
INT |
||
Line 170: | Line 170: | ||
assert(0B) |
assert(0B) |
||
print(parse().to_str())</ |
print(parse().to_str())</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 186: | Line 186: | ||
Specification of package S_Expr: |
Specification of package S_Expr: |
||
< |
<syntaxhighlight lang="ada">with Ada.Strings.Unbounded; |
||
private with Ada.Containers.Indefinite_Vectors; |
private with Ada.Containers.Indefinite_Vectors; |
||
Line 240: | Line 240: | ||
end record; |
end record; |
||
end S_Expr;</ |
end S_Expr;</syntaxhighlight> |
||
The implementation of S_Expr: |
The implementation of S_Expr: |
||
< |
<syntaxhighlight lang="ada">with Ada.Integer_Text_IO, Ada.Float_Text_IO; |
||
package body S_Expr is |
package body S_Expr is |
||
Line 298: | Line 298: | ||
end Print; |
end Print; |
||
end S_Expr;</ |
end S_Expr;</syntaxhighlight> |
||
Specification and Implementation of S_Expr.Parser (a child package of S_Expr): |
Specification and Implementation of S_Expr.Parser (a child package of S_Expr): |
||
< |
<syntaxhighlight lang="ada">generic -- child of a generic package must be a generic unit |
||
package S_Expr.Parser is |
package S_Expr.Parser is |
||
Line 308: | Line 308: | ||
-- the result of a parse process is always a list of expressions |
-- the result of a parse process is always a list of expressions |
||
end S_Expr.Parser;</ |
end S_Expr.Parser;</syntaxhighlight> |
||
< |
<syntaxhighlight lang="ada">with Ada.Integer_Text_IO, Ada.Float_Text_IO; |
||
package body S_Expr.Parser is |
package body S_Expr.Parser is |
||
Line 419: | Line 419: | ||
end Parse; |
end Parse; |
||
end S_Expr.Parser;</ |
end S_Expr.Parser;</syntaxhighlight> |
||
The main program Test_S_Expr: |
The main program Test_S_Expr: |
||
< |
<syntaxhighlight lang="ada">with S_Expr.Parser, Ada.Text_IO; |
||
procedure Test_S_Expr is |
procedure Test_S_Expr is |
||
Line 445: | Line 445: | ||
Expression_List.First.Print(Indention => 0); |
Expression_List.First.Print(Indention => 0); |
||
-- Parse will output a list of S-Expressions. We need the first Expression. |
-- Parse will output a list of S-Expressions. We need the first Expression. |
||
end Test_S_Expr;</ |
end Test_S_Expr;</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 473: | Line 473: | ||
=={{header|ALGOL 68}}== |
=={{header|ALGOL 68}}== |
||
< |
<syntaxhighlight lang="algol68"># S-Expressions # |
||
CHAR nl = REPR 10; |
CHAR nl = REPR 10; |
||
# mode representing an S-expression # |
# mode representing an S-expression # |
||
Line 599: | Line 599: | ||
+ nl |
+ nl |
||
) |
) |
||
)</ |
)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 706: | Line 706: | ||
< |
<syntaxhighlight lang="apl">sexp←{ |
||
wspace←' ',⎕TC ⍝ whitespace is space, tab, cr, lf |
wspace←' ',⎕TC ⍝ whitespace is space, tab, cr, lf |
||
Line 769: | Line 769: | ||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Arturo}}== |
=={{header|Arturo}}== |
||
< |
<syntaxhighlight lang="rebol">code: { |
||
((data "quoted data" 123 4.5) |
((data "quoted data" 123 4.5) |
||
(data (!@# (4.5) "(more" "data)"))) |
(data (!@# (4.5) "(more" "data)"))) |
||
Line 779: | Line 779: | ||
s: first to :block code |
s: first to :block code |
||
inspect.muted s |
inspect.muted s |
||
print as.code s</ |
print as.code s</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 807: | Line 807: | ||
=={{header|AutoHotkey}}== |
=={{header|AutoHotkey}}== |
||
< |
<syntaxhighlight lang="autohotkey">S_Expressions(Str){ |
||
Str := RegExReplace(Str, "s)(?<![\\])"".*?[^\\]""(*SKIP)(*F)|((?<![\\])[)(]|\s)", "`n$0`n") |
Str := RegExReplace(Str, "s)(?<![\\])"".*?[^\\]""(*SKIP)(*F)|((?<![\\])[)(]|\s)", "`n$0`n") |
||
Str := RegExReplace(Str, "`am)^\s*\v+") , Cnt := 0 |
Str := RegExReplace(Str, "`am)^\s*\v+") , Cnt := 0 |
||
Line 822: | Line 822: | ||
Res .= "`t" |
Res .= "`t" |
||
return Res |
return Res |
||
}</ |
}</syntaxhighlight> |
||
Examples:< |
Examples:<syntaxhighlight lang="autohotkey">Str = |
||
( |
( |
||
((data da\(\)ta "quot\\ed data" 123 4.5) |
((data da\(\)ta "quot\\ed data" 123 4.5) |
||
("data" (!@# (4.5) "(mo\"re" "data)"))) |
("data" (!@# (4.5) "(mo\"re" "data)"))) |
||
) |
) |
||
MsgBox, 262144, , % S_Expressions(Str)</ |
MsgBox, 262144, , % S_Expressions(Str)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>( |
<pre>( |
||
Line 854: | Line 854: | ||
=={{header|C}}== |
=={{header|C}}== |
||
< |
<syntaxhighlight lang="c">#include <stdio.h> |
||
#include <stdlib.h> |
#include <stdlib.h> |
||
#include <ctype.h> |
#include <ctype.h> |
||
Line 1,079: | Line 1,079: | ||
print_expr(x, 0); |
print_expr(x, 0); |
||
return 0; |
return 0; |
||
}</ |
}</syntaxhighlight> |
||
{{out}}<lang>input is: |
{{out}}<syntaxhighlight lang="text">input is: |
||
((data da\(\)ta "quot\\ed data" 123 4.5) |
((data da\(\)ta "quot\\ed data" 123 4.5) |
||
("data" (!@# (4.5) "(mo\"re" "data)"))) |
("data" (!@# (4.5) "(mo\"re" "data)"))) |
||
Line 1,103: | Line 1,103: | ||
) |
) |
||
) |
) |
||
)</ |
)</syntaxhighlight> |
||
=={{header|C sharp|C#}}== |
=={{header|C sharp|C#}}== |
||
Line 1,110: | Line 1,110: | ||
Git repository with code and tests can be found here: https://github.com/ichensky/SExpression/tree/rosettacode |
Git repository with code and tests can be found here: https://github.com/ichensky/SExpression/tree/rosettacode |
||
< |
<syntaxhighlight lang="csharp"> |
||
using System; |
using System; |
||
using System.Collections.Generic; |
using System.Collections.Generic; |
||
Line 1,157: | Line 1,157: | ||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
< |
<syntaxhighlight lang="csharp"> |
||
using System; |
using System; |
||
using System.Collections.Generic; |
using System.Collections.Generic; |
||
Line 1,343: | Line 1,343: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
< |
<syntaxhighlight lang="csharp"> |
||
using System; |
using System; |
||
using System.Collections.Generic; |
using System.Collections.Generic; |
||
Line 1,365: | Line 1,365: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,378: | Line 1,378: | ||
apart from writing it out, which fulfils this task's requirements. With some more work |
apart from writing it out, which fulfils this task's requirements. With some more work |
||
this code might actually be useful. |
this code might actually be useful. |
||
< |
<syntaxhighlight lang="cpp">#include <cctype> |
||
#include <iomanip> |
#include <iomanip> |
||
#include <iostream> |
#include <iostream> |
||
Line 1,648: | Line 1,648: | ||
} |
} |
||
return 0; |
return 0; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,674: | Line 1,674: | ||
=={{header|Ceylon}}== |
=={{header|Ceylon}}== |
||
< |
<syntaxhighlight lang="ceylon">class Symbol(symbol) { |
||
shared String symbol; |
shared String symbol; |
||
string => symbol; |
string => symbol; |
||
Line 1,842: | Line 1,842: | ||
prettyPrint(tree); |
prettyPrint(tree); |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,868: | Line 1,868: | ||
=={{header|CoffeeScript}}== |
=={{header|CoffeeScript}}== |
||
{{improve|CoffeeScript|This solution does not reproduce unquoted strings as per task description}} |
{{improve|CoffeeScript|This solution does not reproduce unquoted strings as per task description}} |
||
< |
<syntaxhighlight lang="coffeescript"> |
||
# This code works with Lisp-like s-expressions. |
# This code works with Lisp-like s-expressions. |
||
# |
# |
||
Line 1,999: | Line 1,999: | ||
console.log "output:\n#{pp output}\n" |
console.log "output:\n#{pp output}\n" |
||
console.log "round trip:\n#{sexp output}\n" |
console.log "round trip:\n#{sexp output}\n" |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<lang> |
<syntaxhighlight lang="text"> |
||
> coffee sexp.coffee |
> coffee sexp.coffee |
||
input: |
input: |
||
Line 2,031: | Line 2,031: | ||
round trip: |
round trip: |
||
(("data" "quoted data with escaped \"" 123 4.5 "14") ("data" ("!@#" (4.5) "(more" "data)"))) |
(("data" "quoted data with escaped \"" 123 4.5 "14") ("data" ("!@#" (4.5) "(more" "data)"))) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Common Lisp}}== |
=={{header|Common Lisp}}== |
||
Line 2,049: | Line 2,049: | ||
Unfortunately, our pointy-haired boss has asked you to write a parser for an unusual s-expression syntax that uses square brackets instead of parenthesis. In most programming languages, this would necessitate writing an entire parser. Fortunately, the Common Lisp reader can be modified through the use of macro-characters to accomplish this task. When the reader parses a macro-character token, a function associated with the macro-character is called. As evidenced below, modifying the behavior of the Lisp reader by setting macro-character functions to handle additional sytax requires far less work than writing a complete parser from scratch. |
Unfortunately, our pointy-haired boss has asked you to write a parser for an unusual s-expression syntax that uses square brackets instead of parenthesis. In most programming languages, this would necessitate writing an entire parser. Fortunately, the Common Lisp reader can be modified through the use of macro-characters to accomplish this task. When the reader parses a macro-character token, a function associated with the macro-character is called. As evidenced below, modifying the behavior of the Lisp reader by setting macro-character functions to handle additional sytax requires far less work than writing a complete parser from scratch. |
||
< |
<syntaxhighlight lang="lisp">(defun lsquare-reader (stream char) |
||
(declare (ignore char)) |
(declare (ignore char)) |
||
(read-delimited-list #\] stream t)) |
(read-delimited-list #\] stream t)) |
||
(set-macro-character #\[ #'lsquare-reader) ;;Call the lsquare-reader function when a '[' token is parsed |
(set-macro-character #\[ #'lsquare-reader) ;;Call the lsquare-reader function when a '[' token is parsed |
||
(set-macro-character #\] (get-macro-character #\) nil)) ;;Do the same thing as ')' when a ']' token is parsed</ |
(set-macro-character #\] (get-macro-character #\) nil)) ;;Do the same thing as ')' when a ']' token is parsed</syntaxhighlight> |
||
Unit test code: |
Unit test code: |
||
< |
<syntaxhighlight lang="lisp">;;A list of unit tests. Each test is a cons in which the car (left side) contains the |
||
;;test string and the cdr (right side) the expected result of reading the S-Exp. |
;;test string and the cdr (right side) the expected result of reading the S-Exp. |
||
(setf unit-tests |
(setf unit-tests |
||
Line 2,070: | Line 2,070: | ||
(dolist (test unit-tests) |
(dolist (test unit-tests) |
||
(format t "String: ~23s Expected: ~23s Actual: ~s~%" |
(format t "String: ~23s Expected: ~23s Actual: ~s~%" |
||
(car test) (cdr test) (read-from-string (car test)))))</ |
(car test) (cdr test) (read-from-string (car test)))))</syntaxhighlight> |
||
{{out| Unit test output}} |
{{out| Unit test output}} |
||
<pre>CL-USER> (run-tests) |
<pre>CL-USER> (run-tests) |
||
Line 2,104: | Line 2,104: | ||
===Writing S-Expressions=== |
===Writing S-Expressions=== |
||
The next step in this task is to write a standard Lisp s-expression in the square bracket notation. |
The next step in this task is to write a standard Lisp s-expression in the square bracket notation. |
||
< |
<syntaxhighlight lang="lisp">(defun write-sexp (sexp) |
||
"Writes a Lisp s-expression in square bracket notation." |
"Writes a Lisp s-expression in square bracket notation." |
||
(labels ((parse (sexp) |
(labels ((parse (sexp) |
||
Line 2,127: | Line 2,127: | ||
(subseq str 0 last-char) |
(subseq str 0 last-char) |
||
str))))))) |
str))))))) |
||
(concatenate 'string "[" (fix-spacing (parse sexp)) "]")))</ |
(concatenate 'string "[" (fix-spacing (parse sexp)) "]")))</syntaxhighlight> |
||
Unit test code: |
Unit test code: |
||
< |
<syntaxhighlight lang="lisp">(setf unit-tests '(((1 2) (3 4)) (1 2 3 4) ("ab(cd" "mn)op") |
||
(1 (2 (3 (4)))) ((1) (2) (3)) ())) |
(1 (2 (3 (4)))) ((1) (2) (3)) ())) |
||
Line 2,135: | Line 2,135: | ||
(dolist (test unit-tests) |
(dolist (test unit-tests) |
||
(format t "Before: ~18s After: ~s~%" |
(format t "Before: ~18s After: ~s~%" |
||
test (write-sexp test))))</ |
test (write-sexp test))))</syntaxhighlight> |
||
{{out|Unit test output}} |
{{out|Unit test output}} |
||
<pre>CL-USER> (run-tests) |
<pre>CL-USER> (run-tests) |
||
Line 2,161: | Line 2,161: | ||
a native floating point type, floating point numbers are not. |
a native floating point type, floating point numbers are not. |
||
< |
<syntaxhighlight lang="cowgol">include "cowgol.coh"; |
||
include "strings.coh"; |
include "strings.coh"; |
||
include "malloc.coh"; |
include "malloc.coh"; |
||
Line 2,426: | Line 2,426: | ||
print("Parsed:\n"); |
print("Parsed:\n"); |
||
prettyprint(ParseSExp(str)); |
prettyprint(ParseSExp(str)); |
||
print_nl();</ |
print_nl();</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 2,455: | Line 2,455: | ||
=={{header|D}}== |
=={{header|D}}== |
||
< |
<syntaxhighlight lang="d">import std.stdio, std.conv, std.algorithm, std.variant, std.uni, |
||
std.functional, std.string; |
std.functional, std.string; |
||
Line 2,541: | Line 2,541: | ||
"Printed: ".write; |
"Printed: ".write; |
||
pTest.writeSexp; |
pTest.writeSexp; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Parsed: [[data, quoted data, 123, 4.5], [data, [!@#, [4.5], (more, data)]]] |
<pre>Parsed: [[data, quoted data, 123, 4.5], [data, [!@#, [4.5], (more, data)]]] |
||
Line 2,548: | Line 2,548: | ||
=={{header|EchoLisp}}== |
=={{header|EchoLisp}}== |
||
The '''(read-from-string input-string)''' function parses a string into an s-expression, which is the native representation of program/data in EchoLisp and the majority of Lisps . |
The '''(read-from-string input-string)''' function parses a string into an s-expression, which is the native representation of program/data in EchoLisp and the majority of Lisps . |
||
< |
<syntaxhighlight lang="lisp"> |
||
(define input-string #'((data "quoted data" 123 4.5)\n(data (!@# (4.5) "(more" "data)")))'#) |
(define input-string #'((data "quoted data" 123 4.5)\n(data (!@# (4.5) "(more" "data)")))'#) |
||
Line 2,565: | Line 2,565: | ||
(first(rest s-expr)) |
(first(rest s-expr)) |
||
→ (data (!@# (4.5) "(more" "data)")) |
→ (data (!@# (4.5) "(more" "data)")) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|F_Sharp|F#}}== |
=={{header|F_Sharp|F#}}== |
||
Line 2,578: | Line 2,578: | ||
The file <code>SExpr.fs</code> containing the implementation: |
The file <code>SExpr.fs</code> containing the implementation: |
||
< |
<syntaxhighlight lang="fsharp"> |
||
module SExpr |
module SExpr |
||
(* This module is a very simple port of the OCaml version to F# (F-Sharp) *) |
(* This module is a very simple port of the OCaml version to F# (F-Sharp) *) |
||
Line 2,810: | Line 2,810: | ||
(* print_endline (string_of_sexpr_indent s) *) |
(* print_endline (string_of_sexpr_indent s) *) |
||
printfn "%s" (string_of_sexpr_indent s) |
printfn "%s" (string_of_sexpr_indent s) |
||
</syntaxhighlight> |
|||
</lang> |
|||
Line 2,817: | Line 2,817: | ||
Read the experession from a file of preset it in the code. |
Read the experession from a file of preset it in the code. |
||
< |
<syntaxhighlight lang="fsharp"> |
||
module Program |
module Program |
||
(* Learn more about F# at https://fsharp.org *) |
(* Learn more about F# at https://fsharp.org *) |
||
Line 2,855: | Line 2,855: | ||
(* return an integer exit code *) |
(* return an integer exit code *) |
||
0 |
0 |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
Line 2,881: | Line 2,881: | ||
Factor has a comprehensive prettyprinter which can print any Factor object in a readable way. Not only can we leverage it to easily print our native data structure, but we can also call <code>unparse</code> to convert it to a string. This leaves us with a string reminiscent of the original input, and we are able to take it the rest of the way with two simple regular expressions. |
Factor has a comprehensive prettyprinter which can print any Factor object in a readable way. Not only can we leverage it to easily print our native data structure, but we can also call <code>unparse</code> to convert it to a string. This leaves us with a string reminiscent of the original input, and we are able to take it the rest of the way with two simple regular expressions. |
||
< |
<syntaxhighlight lang="factor">USING: formatting kernel math.parser multiline peg peg.ebnf |
||
regexp sequences prettyprint words ; |
regexp sequences prettyprint words ; |
||
IN: rosetta-code.s-expressions |
IN: rosetta-code.s-expressions |
||
Line 2,907: | Line 2,907: | ||
sexp>seq dup seq>sexp |
sexp>seq dup seq>sexp |
||
"Native:\n%u\n\nRound trip:\n%s\n" printf |
"Native:\n%u\n\nRound trip:\n%s\n" printf |
||
] bi</ |
] bi</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 2,926: | Line 2,926: | ||
=={{header|Go}}== |
=={{header|Go}}== |
||
< |
<syntaxhighlight lang="go">package main |
||
import ( |
import ( |
||
Line 3,099: | Line 3,099: | ||
fmt.Println(s.i) |
fmt.Println(s.i) |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 3,127: | Line 3,127: | ||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
< |
<syntaxhighlight lang="haskell">import qualified Data.Functor.Identity as F |
||
import qualified Text.Parsec.Prim as Prim |
import qualified Text.Parsec.Prim as Prim |
||
import Text.Parsec |
import Text.Parsec |
||
Line 3,166: | Line 3,166: | ||
"((data \"quoted data\" 123 4.5)\n (data (!@# (4.5) \"(more\" \"data)\")))" |
"((data \"quoted data\" 123 4.5)\n (data (!@# (4.5) \"(more\" \"data)\")))" |
||
putStrLn ("The input:\n" ++ expr ++ "\n\nParsed as:") |
putStrLn ("The input:\n" ++ expr ++ "\n\nParsed as:") |
||
p expr</ |
p expr</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
<pre>The input: |
<pre>The input: |
||
Line 3,177: | Line 3,177: | ||
Or, parsing by hand (rather than with a parser combinator library) and printing a parse tree diagram: |
Or, parsing by hand (rather than with a parser combinator library) and printing a parse tree diagram: |
||
< |
<syntaxhighlight lang="haskell">{-# LANGUAGE TupleSections #-} |
||
import Data.Bifunctor (bimap) |
import Data.Bifunctor (bimap) |
||
Line 3,294: | Line 3,294: | ||
headDef :: a -> [a] -> a |
headDef :: a -> [a] -> a |
||
headDef d [] = d |
headDef d [] = d |
||
headDef _ (x : _) = x</ |
headDef _ (x : _) = x</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
<pre>Symbol "List" |
<pre>Symbol "List" |
||
Line 3,335: | Line 3,335: | ||
The example takes single and double quotes. <br> |
The example takes single and double quotes. <br> |
||
Single quotes were used instead of doubles in the input. |
Single quotes were used instead of doubles in the input. |
||
< |
<syntaxhighlight lang="icon">link ximage |
||
procedure main() |
procedure main() |
||
Line 3,394: | Line 3,394: | ||
} |
} |
||
return T |
return T |
||
end</ |
end</syntaxhighlight> |
||
{{libheader|Icon Programming Library}} |
{{libheader|Icon Programming Library}} |
||
Line 3,425: | Line 3,425: | ||
This implementation does not support escape characters. If escape characters were added, we would need additional support in the tokenizer (an extra character class, and in the state table an extra column and two extra rows, or almost double the number of state transitions: 35 instead of 20), and additional support in the data language (unfmt would need to strip out escape characters and fmt would need to insert escape characters -- so each of these routines would also perhaps double in size.) And that's a lot of bulk for serialize/deserialize mechanism which, by design, cannot represent frequently used data elements (such as matrices and gerunds). |
This implementation does not support escape characters. If escape characters were added, we would need additional support in the tokenizer (an extra character class, and in the state table an extra column and two extra rows, or almost double the number of state transitions: 35 instead of 20), and additional support in the data language (unfmt would need to strip out escape characters and fmt would need to insert escape characters -- so each of these routines would also perhaps double in size.) And that's a lot of bulk for serialize/deserialize mechanism which, by design, cannot represent frequently used data elements (such as matrices and gerunds). |
||
< |
<syntaxhighlight lang="j">NB. character classes: 0: paren, 1: quote, 2: whitespace, 3: wordforming (default) |
||
chrMap=: '()';'"';' ',LF,TAB,CR |
chrMap=: '()';'"';' ',LF,TAB,CR |
||
Line 3,476: | Line 3,476: | ||
readSexpr=: fmt L:0 @rdSexpr :.writeSexpr |
readSexpr=: fmt L:0 @rdSexpr :.writeSexpr |
||
writeSexpr=: wrSexpr @(unfmt L:0) :.readSexpr</ |
writeSexpr=: wrSexpr @(unfmt L:0) :.readSexpr</syntaxhighlight> |
||
Example use: |
Example use: |
||
< |
<syntaxhighlight lang="j"> readSexpr '((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))' |
||
┌───────────────────────────┬────────────────────────────────┐ |
┌───────────────────────────┬────────────────────────────────┐ |
||
│┌─────┬───────────┬───┬───┐│┌─────┬────────────────────────┐│ |
│┌─────┬───────────┬───┬───┐│┌─────┬────────────────────────┐│ |
||
Line 3,492: | Line 3,492: | ||
└───────────────────────────┴────────────────────────────────┘ |
└───────────────────────────┴────────────────────────────────┘ |
||
writeSexpr readSexpr '((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))' |
writeSexpr readSexpr '((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))' |
||
((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))</ |
((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))</syntaxhighlight> |
||
=={{header|Java}}== |
=={{header|Java}}== |
||
Line 3,502: | Line 3,502: | ||
====LispTokenizer.java==== |
====LispTokenizer.java==== |
||
< |
<syntaxhighlight lang="java">package jfkbits; |
||
import java.io.BufferedReader; |
import java.io.BufferedReader; |
||
Line 3,612: | Line 3,612: | ||
{ |
{ |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
====Token.java==== |
====Token.java==== |
||
< |
<syntaxhighlight lang="java">package jfkbits; |
||
import java.io.StreamTokenizer; |
import java.io.StreamTokenizer; |
||
Line 3,643: | Line 3,643: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
====Atom.java==== |
====Atom.java==== |
||
< |
<syntaxhighlight lang="java">package jfkbits; |
||
import jfkbits.LispParser.Expr; |
import jfkbits.LispParser.Expr; |
||
Line 3,662: | Line 3,662: | ||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
====StringAtom.java==== |
====StringAtom.java==== |
||
< |
<syntaxhighlight lang="java">package jfkbits; |
||
public class StringAtom extends Atom |
public class StringAtom extends Atom |
||
Line 3,685: | Line 3,685: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
====ExprList.java==== |
====ExprList.java==== |
||
< |
<syntaxhighlight lang="java">package jfkbits; |
||
import java.util.AbstractCollection; |
import java.util.AbstractCollection; |
||
Line 3,758: | Line 3,758: | ||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
====LispParser.java==== |
====LispParser.java==== |
||
< |
<syntaxhighlight lang="java">package jfkbits; |
||
Line 3,808: | Line 3,808: | ||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
====LispParserDemo.java==== |
====LispParserDemo.java==== |
||
< |
<syntaxhighlight lang="java">import jfkbits.ExprList; |
||
import jfkbits.LispParser; |
import jfkbits.LispParser; |
||
import jfkbits.LispParser.ParseException; |
import jfkbits.LispParser.ParseException; |
||
Line 3,836: | Line 3,836: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
=={{header|JavaScript}}== |
=={{header|JavaScript}}== |
||
===Procedural=== |
===Procedural=== |
||
< |
<syntaxhighlight lang="javascript">String.prototype.parseSexpr = function() { |
||
var t = this.match(/\s*("[^"]*"|\(|\)|"|[^\s()"]+)/g) |
var t = this.match(/\s*("[^"]*"|\(|\)|"|[^\s()"]+)/g) |
||
for (var o, c=0, i=t.length-1; i>=0; i--) { |
for (var o, c=0, i=t.length-1; i>=0; i--) { |
||
Line 3,877: | Line 3,877: | ||
document.write('Invalid s-expr!', '<br>') |
document.write('Invalid s-expr!', '<br>') |
||
else |
else |
||
document.write('s-expr:<br>', sexpr, '<br><br>', sexpr.constructor != Array ? '' : 'pretty print:<br>' + sexpr.toPretty())</ |
document.write('s-expr:<br>', sexpr, '<br><br>', sexpr.constructor != Array ? '' : 'pretty print:<br>' + sexpr.toPretty())</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>text: |
<pre>text: |
||
Line 3,910: | Line 3,910: | ||
===Functional=== |
===Functional=== |
||
Showing the parse tree in an indented JSON format, and writing out a reserialization: |
Showing the parse tree in an indented JSON format, and writing out a reserialization: |
||
< |
<syntaxhighlight lang="javascript">(() => { |
||
"use strict"; |
"use strict"; |
||
Line 4,047: | Line 4,047: | ||
return main(); |
return main(); |
||
})();</ |
})();</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
<pre>[ |
<pre>[ |
||
Line 4,082: | Line 4,082: | ||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
< |
<syntaxhighlight lang="julia"> |
||
function rewritequotedparen(s) |
function rewritequotedparen(s) |
||
segments = split(s, "\"") |
segments = split(s, "\"") |
||
Line 4,157: | Line 4,157: | ||
println("The processed native structure is:\n", nat) |
println("The processed native structure is:\n", nat) |
||
println("The reconstructed string is:\n"), printAny(nat) |
println("The reconstructed string is:\n"), printAny(nat) |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{output}}<pre> |
{{output}}<pre> |
||
The input string is: |
The input string is: |
||
Line 4,173: | Line 4,173: | ||
=={{header|Kotlin}}== |
=={{header|Kotlin}}== |
||
{{trans|JavaScript}} |
{{trans|JavaScript}} |
||
< |
<syntaxhighlight lang="groovy">// version 1.2.31 |
||
const val INDENT = 2 |
const val INDENT = 2 |
||
Line 4,270: | Line 4,270: | ||
tokens2.prettyPrint() |
tokens2.prettyPrint() |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 4,328: | Line 4,328: | ||
Tested with Lua 5.3.5 and LPeg 1.0.2-1. |
Tested with Lua 5.3.5 and LPeg 1.0.2-1. |
||
< |
<syntaxhighlight lang="lua">lpeg = require 'lpeg' -- see http://www.inf.puc-rio.br/~roberto/lpeg/ |
||
imports = 'P R S C V match' |
imports = 'P R S C V match' |
||
Line 4,354: | Line 4,354: | ||
'S'; |
'S'; |
||
S = ws * lpar * C((atom + V'S')^0) * rpar / tolist |
S = ws * lpar * C((atom + V'S')^0) * rpar / tolist |
||
}</ |
}</syntaxhighlight> |
||
Now to use the <i>sexpr</i> pattern: |
Now to use the <i>sexpr</i> pattern: |
||
< |
<syntaxhighlight lang="lua">eg_input = [[ |
||
((data "quoted data" 123 4.5) |
((data "quoted data" 123 4.5) |
||
(data (!@# (4.5) "(more" "data)"))) |
(data (!@# (4.5) "(more" "data)"))) |
||
Line 4,382: | Line 4,382: | ||
check(eg_produced, eg_expected) |
check(eg_produced, eg_expected) |
||
print("checks out!") -- won't get here if any <i>check()</i> assertion fails |
print("checks out!") -- won't get here if any <i>check()</i> assertion fails |
||
</syntaxhighlight> |
|||
</lang> |
|||
And here's the pretty printer, whose output looks like all the others: |
And here's the pretty printer, whose output looks like all the others: |
||
< |
<syntaxhighlight lang="lua">function pprint(expr, indent) |
||
local function prindent(fmt, expr) |
local function prindent(fmt, expr) |
||
io.write(indent) -- no line break |
io.write(indent) -- no line break |
||
Line 4,411: | Line 4,411: | ||
end |
end |
||
pprint(eg_expected, '')</ |
pprint(eg_expected, '')</syntaxhighlight> |
||
=={{header|Nim}}== |
=={{header|Nim}}== |
||
< |
<syntaxhighlight lang="nim">import strutils |
||
const Input = """ |
const Input = """ |
||
Line 4,559: | Line 4,559: | ||
else: nil |
else: nil |
||
echo parse()</ |
echo parse()</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 4,576: | Line 4,576: | ||
The file <code>SExpr.mli</code> containing the interface: |
The file <code>SExpr.mli</code> containing the interface: |
||
< |
<syntaxhighlight lang="ocaml">(** This module is a very simple parsing library for S-expressions. *) |
||
(* Copyright (C) 2009 Florent Monnier, released under MIT license. *) |
(* Copyright (C) 2009 Florent Monnier, released under MIT license. *) |
||
Line 4,604: | Line 4,604: | ||
val string_of_sexpr_indent : sexpr list -> string |
val string_of_sexpr_indent : sexpr list -> string |
||
(** same than [string_of_sexpr] but with indentation *)</ |
(** same than [string_of_sexpr] but with indentation *)</syntaxhighlight> |
||
The file <code>SExpr.ml</code> containing the implementation: |
The file <code>SExpr.ml</code> containing the implementation: |
||
< |
<syntaxhighlight lang="ocaml">(** This module is a very simple parsing library for S-expressions. *) |
||
(* Copyright (C) 2009 Florent Monnier, released under MIT license. *) |
(* Copyright (C) 2009 Florent Monnier, released under MIT license. *) |
||
(* modified to match the task description *) |
(* modified to match the task description *) |
||
Line 4,785: | Line 4,785: | ||
let print_sexpr_indent s = |
let print_sexpr_indent s = |
||
print_endline (string_of_sexpr_indent s)</ |
print_endline (string_of_sexpr_indent s)</syntaxhighlight> |
||
Then we compile this small module and test it in the interactive loop: |
Then we compile this small module and test it in the interactive loop: |
||
Line 4,823: | Line 4,823: | ||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
< |
<syntaxhighlight lang="perl">#!/usr/bin/perl -w |
||
use strict; |
use strict; |
||
use warnings; |
use warnings; |
||
Line 4,877: | Line 4,877: | ||
ref($_) eq 'ARRAY' ? sexpr2txt($_) : $$_ |
ref($_) eq 'ARRAY' ? sexpr2txt($_) : $$_ |
||
} @{$_[0]} ]})} |
} @{$_[0]} ]})} |
||
}</ |
}</syntaxhighlight> |
||
Check: |
Check: |
||
< |
<syntaxhighlight lang="perl">my $s = sexpr(q{ |
||
((data "quoted data" 123 4.5) |
((data "quoted data" 123 4.5) |
||
Line 4,891: | Line 4,891: | ||
# Convert back |
# Convert back |
||
print sexpr2txt($s)."\n";</ |
print sexpr2txt($s)."\n";</syntaxhighlight> |
||
Output: |
Output: |
||
<pre>$VAR1 = [ |
<pre>$VAR1 = [ |
||
Line 4,920: | Line 4,920: | ||
that may not be clear on the display: 4e-5 and 4-e5 may appear similar but the latter is probably a parse failure. It may |
that may not be clear on the display: 4e-5 and 4-e5 may appear similar but the latter is probably a parse failure. It may |
||
be more sensible for get_term() to raise an error if the scanf fails, than assume it is a symbol like it does now. |
be more sensible for get_term() to raise an error if the scanf fails, than assume it is a symbol like it does now. |
||
<!--< |
<!--<syntaxhighlight lang="phix">(phixonline)--> |
||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
||
<span style="color: #008080;">constant</span> <span style="color: #000000;">s_expr_str</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""" |
<span style="color: #008080;">constant</span> <span style="color: #000000;">s_expr_str</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""" |
||
Line 5,006: | Line 5,006: | ||
<span style="color: #000080;font-style:italic;">--ppEx(s_expr,{pp_Nest,1,pp_StrFmt,-1,pp_IntCh,false,pp_Brkt,"()"})</span> |
<span style="color: #000080;font-style:italic;">--ppEx(s_expr,{pp_Nest,1,pp_StrFmt,-1,pp_IntCh,false,pp_Brkt,"()"})</span> |
||
<span style="color: #7060A8;">ppEx</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s_expr</span><span style="color: #0000FF;">,{</span><span style="color: #004600;">pp_Nest</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #004600;">pp_StrFmt</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #004600;">pp_IntCh</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">,</span><span style="color: #004600;">pp_Brkt</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"()"</span><span style="color: #0000FF;">})</span> |
<span style="color: #7060A8;">ppEx</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s_expr</span><span style="color: #0000FF;">,{</span><span style="color: #004600;">pp_Nest</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #004600;">pp_StrFmt</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #004600;">pp_IntCh</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">,</span><span style="color: #004600;">pp_Brkt</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"()"</span><span style="color: #0000FF;">})</span> |
||
<!--</ |
<!--</syntaxhighlight>--> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 5,030: | Line 5,030: | ||
=={{header|PicoLisp}}== |
=={{header|PicoLisp}}== |
||
The '[http://software-lab.de/doc/refA.html#any any]' function parses an s-expression from a string (indentical to the way '[http://software-lab.de/doc/refR.html#read read]' does this from an input stream). |
The '[http://software-lab.de/doc/refA.html#any any]' function parses an s-expression from a string (indentical to the way '[http://software-lab.de/doc/refR.html#read read]' does this from an input stream). |
||
< |
<syntaxhighlight lang="picolisp">: (any "((data \"quoted data\" 123 4.5) (data (!@# (4.5) \"(more\" \"data)\")))") |
||
-> ((data "quoted data" 123 5) (data (!@# (5) "(more" "data)"))) |
-> ((data "quoted data" 123 5) (data (!@# (5) "(more" "data)"))) |
||
Line 5,050: | Line 5,050: | ||
+-- "(more" |
+-- "(more" |
||
| |
| |
||
+-- "data)"</ |
+-- "data)"</syntaxhighlight> |
||
Implementing a subset of 'any' explicitly: |
Implementing a subset of 'any' explicitly: |
||
< |
<syntaxhighlight lang="picolisp">(de readSexpr () |
||
(case (skip) |
(case (skip) |
||
("(" (char) (readList)) |
("(" (char) (readList)) |
||
Line 5,077: | Line 5,077: | ||
(until (or (sp? (peek)) (member (peek) '("(" ")"))) |
(until (or (sp? (peek)) (member (peek) '("(" ")"))) |
||
(link (char)) ) ) |
(link (char)) ) ) |
||
(or (format X) (intern (pack X))) ) )</ |
(or (format X) (intern (pack X))) ) )</syntaxhighlight> |
||
It can be used in a pipe to read from a string: |
It can be used in a pipe to read from a string: |
||
< |
<syntaxhighlight lang="picolisp">: (pipe (prin "((data \"quoted data\" 123 4.5) (data (!@# (4.5) \"(more\" \"data)\")))") (readSexpr)) |
||
-> ((data "quoted data" 123 5) (data (!@# (5) "(more" "data)")))</ |
-> ((data "quoted data" 123 5) (data (!@# (5) "(more" "data)")))</syntaxhighlight> |
||
'[http://software-lab.de/doc/refS.html#sym sym]' does the reverse (i.e. builds a symbol (string) from an expression). |
'[http://software-lab.de/doc/refS.html#sym sym]' does the reverse (i.e. builds a symbol (string) from an expression). |
||
< |
<syntaxhighlight lang="picolisp">: (sym @@) |
||
-> "((data \"quoted data\" 123 5) (data (!@# (5) \"(more\" \"data)\")))"</ |
-> "((data \"quoted data\" 123 5) (data (!@# (5) \"(more\" \"data)\")))"</syntaxhighlight> |
||
Implementing a subset of the built-in printer: |
Implementing a subset of the built-in printer: |
||
< |
<syntaxhighlight lang="picolisp">(de printSexpr (Expr Fun) |
||
(cond |
(cond |
||
((pair Expr) |
((pair Expr) |
||
Line 5,098: | Line 5,098: | ||
(mapc Fun (chop Expr)) |
(mapc Fun (chop Expr)) |
||
(Fun "\"") ) |
(Fun "\"") ) |
||
(T (mapc Fun (chop Expr))) ) )</ |
(T (mapc Fun (chop Expr))) ) )</syntaxhighlight> |
||
This can be used for plain printing |
This can be used for plain printing |
||
< |
<syntaxhighlight lang="picolisp">: (printSexpr |
||
'((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)"))) |
'((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)"))) |
||
prin ) |
prin ) |
||
((data "quoted data" 123 5) (data (!@# (5) "(more" "data)")))</ |
((data "quoted data" 123 5) (data (!@# (5) "(more" "data)")))</syntaxhighlight> |
||
or to collect the characters into a string: |
or to collect the characters into a string: |
||
< |
<syntaxhighlight lang="picolisp">: (pack |
||
(make |
(make |
||
(printSexpr |
(printSexpr |
||
'((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)"))) |
'((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)"))) |
||
link ) ) ) |
link ) ) ) |
||
-> "((data \"quoted data\" 123 5) (data (!@# (5) \"(more\" \"data)\")))"</ |
-> "((data \"quoted data\" 123 5) (data (!@# (5) \"(more\" \"data)\")))"</syntaxhighlight> |
||
=={{header|Pike}}== |
=={{header|Pike}}== |
||
< |
<syntaxhighlight lang="pike">class Symbol(string name) |
||
{ |
{ |
||
string _sprintf(int type) |
string _sprintf(int type) |
||
Line 5,218: | Line 5,218: | ||
string input = "((data \"quoted data\" 123 4.5)\n (data (!@# (4.5) \"(more\" \"data)\")))"; |
string input = "((data \"quoted data\" 123 4.5)\n (data (!@# (4.5) \"(more\" \"data)\")))"; |
||
array data = group(tokenizer(input))[0]; |
array data = group(tokenizer(input))[0]; |
||
string output = sexp(data);</ |
string output = sexp(data);</syntaxhighlight> |
||
Output: |
Output: |
||
Line 5,230: | Line 5,230: | ||
=={{header|Potion}}== |
=={{header|Potion}}== |
||
How values are stored: Tuples for list, integers for integers, floats for floats, strings for symbols, quoted strings for strings. This implementation is not the most elegant/succinct or practical (it's trusty and has no real error handling). |
How values are stored: Tuples for list, integers for integers, floats for floats, strings for symbols, quoted strings for strings. This implementation is not the most elegant/succinct or practical (it's trusty and has no real error handling). |
||
< |
<syntaxhighlight lang="potion">isdigit = (c): 47 < c ord and c ord < 58. |
||
iswhitespace = (c): c ord == 10 or c ord == 13 or c == " ". |
iswhitespace = (c): c ord == 10 or c ord == 13 or c == " ". |
||
Line 5,301: | Line 5,301: | ||
parsesexpr("((data \"quoted data\" 123 4.5) |
parsesexpr("((data \"quoted data\" 123 4.5) |
||
(data (!@# (4.5) \"(more\" \"data)\")))") string print |
(data (!@# (4.5) \"(more\" \"data)\")))") string print |
||
"\n" print</ |
"\n" print</syntaxhighlight> |
||
=={{header|Python}}== |
=={{header|Python}}== |
||
===Procedural=== |
===Procedural=== |
||
< |
<syntaxhighlight lang="python">import re |
||
dbg = False |
dbg = False |
||
Line 5,364: | Line 5,364: | ||
print("\nParsed to Python:", parsed) |
print("\nParsed to Python:", parsed) |
||
print("\nThen back to: '%s'" % print_sexp(parsed))</ |
print("\nThen back to: '%s'" % print_sexp(parsed))</syntaxhighlight> |
||
;Output: |
;Output: |
||
Line 5,375: | Line 5,375: | ||
;Simpler parser: |
;Simpler parser: |
||
Note that in the example above the parser also recognises and changes the type of some tokens as well as generating a nested list. If that functionality is not needed, or better done elsewhere, then the parse function can be achieved more simply by just applying the regexp: |
Note that in the example above the parser also recognises and changes the type of some tokens as well as generating a nested list. If that functionality is not needed, or better done elsewhere, then the parse function can be achieved more simply by just applying the regexp: |
||
< |
<syntaxhighlight lang="python">>>> from pprint import pprint as pp |
||
>>> x = [[(t,v) for t,v in termtypes.groupdict().items() if v][0] for termtypes in re.finditer(term_regex, sexp)] |
>>> x = [[(t,v) for t,v in termtypes.groupdict().items() if v][0] for termtypes in re.finditer(term_regex, sexp)] |
||
>>> pp(x) |
>>> pp(x) |
||
Line 5,397: | Line 5,397: | ||
('brackr', ')'), |
('brackr', ')'), |
||
('brackr', ')')] |
('brackr', ')')] |
||
>>> </ |
>>> </syntaxhighlight> |
||
===Functional=== |
===Functional=== |
||
Composing functionally, and writing out a tree diagram, and a serialization, of the parse. |
Composing functionally, and writing out a tree diagram, and a serialization, of the parse. |
||
< |
<syntaxhighlight lang="python">'''S-expressions''' |
||
from itertools import chain, repeat |
from itertools import chain, repeat |
||
Line 5,648: | Line 5,648: | ||
# MAIN --- |
# MAIN --- |
||
if __name__ == '__main__': |
if __name__ == '__main__': |
||
main()</ |
main()</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
<pre>{'name': 'List'} |
<pre>{'name': 'List'} |
||
Line 5,685: | Line 5,685: | ||
Racket has builtin support for S-expressions in the form of the read function. |
Racket has builtin support for S-expressions in the form of the read function. |
||
< |
<syntaxhighlight lang="racket"> |
||
#lang racket |
#lang racket |
||
(define input |
(define input |
||
Line 5,695: | Line 5,695: | ||
(read (open-input-string input)) |
(read (open-input-string input)) |
||
</syntaxhighlight> |
|||
</lang> |
|||
Output: |
Output: |
||
<pre> |
<pre> |
||
Line 5,707: | Line 5,707: | ||
This parses the task, but it isn't really a good lisp parser, because it always wants whitespace between lists, so <code>(()())</code> will fail ( <code>(() ())</code> wont) |
This parses the task, but it isn't really a good lisp parser, because it always wants whitespace between lists, so <code>(()())</code> will fail ( <code>(() ())</code> wont) |
||
<lang |
<syntaxhighlight lang="raku" line>grammar S-Exp { |
||
rule TOP {^ <s-list> $}; |
rule TOP {^ <s-list> $}; |
||
Line 5,749: | Line 5,749: | ||
say "the expression:\n$s-exp\n"; |
say "the expression:\n$s-exp\n"; |
||
say "the Raku expression:\n{$raku_array.raku}\n"; |
say "the Raku expression:\n{$raku_array.raku}\n"; |
||
say "and back:\n{s-exp_writer($raku_array)}";</ |
say "and back:\n{s-exp_writer($raku_array)}";</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 5,769: | Line 5,769: | ||
It would normally be considered improper, but the literal string delimiters were left intact; making it much easier to understand what is/was being parsed. |
It would normally be considered improper, but the literal string delimiters were left intact; making it much easier to understand what is/was being parsed. |
||
< |
<syntaxhighlight lang="rexx">/*REXX program parses an S-expression and displays the results to the terminal. */ |
||
input= '((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))' |
input= '((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))' |
||
say center('input', length(input), "═") /*display the header title to terminal.*/ |
say center('input', length(input), "═") /*display the header title to terminal.*/ |
||
Line 5,824: | Line 5,824: | ||
exit 0 /*stick a fork in it, we're all done. */ |
exit 0 /*stick a fork in it, we're all done. */ |
||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
||
add!: if !='' then return; #=#+1; @.#=left("", max(0, tabs*(level-1)))!; !=; return</ |
add!: if !='' then return; #=#+1; @.#=left("", max(0, tabs*(level-1)))!; !=; return</syntaxhighlight> |
||
{{out|output|text= when using the default input:}} |
{{out|output|text= when using the default input:}} |
||
<pre> |
<pre> |
||
Line 5,853: | Line 5,853: | ||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
{{works with|Ruby|1.9}} |
{{works with|Ruby|1.9}} |
||
< |
<syntaxhighlight lang="ruby">class SExpr |
||
def initialize(str) |
def initialize(str) |
||
@original = str |
@original = str |
||
Line 5,974: | Line 5,974: | ||
puts "original sexpr:\n#{sexpr.original}" |
puts "original sexpr:\n#{sexpr.original}" |
||
puts "\nruby data structure:\n#{sexpr.data}" |
puts "\nruby data structure:\n#{sexpr.data}" |
||
puts "\nand back to S-Expr:\n#{sexpr.to_sexpr}"</ |
puts "\nand back to S-Expr:\n#{sexpr.to_sexpr}"</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 5,991: | Line 5,991: | ||
=={{header|Rust}}== |
=={{header|Rust}}== |
||
lib.rs: |
lib.rs: |
||
< |
<syntaxhighlight lang="rust"> |
||
//! This implementation isn't based on anything in particular, although it's probably informed by a |
//! This implementation isn't based on anything in particular, although it's probably informed by a |
||
//! lot of Rust's JSON encoding code. It should be very fast (both encoding and decoding the toy |
//! lot of Rust's JSON encoding code. It should be very fast (both encoding and decoding the toy |
||
Line 6,382: | Line 6,382: | ||
println!("{:?}", SExp::parse(ctx)); |
println!("{:?}", SExp::parse(ctx)); |
||
} |
} |
||
</ |
</syntaxhighlight>{{out}} |
||
<pre> |
<pre> |
||
Ok("((\"data\" \"quoted data\" 123 4.5) (\"data\" (\"!@#\" (4.5) \"(more\" \"data)\")))") |
Ok("((\"data\" \"quoted data\" 123 4.5) (\"data\" (\"!@#\" (4.5) \"(more\" \"data)\")))") |
||
Line 6,399: | Line 6,399: | ||
Using guile scheme 2.0.11 |
Using guile scheme 2.0.11 |
||
< |
<syntaxhighlight lang="scheme">(define (sexpr-read port) |
||
(define (help port) |
(define (help port) |
||
(let ((char (read-char port))) |
(let ((char (read-char port))) |
||
Line 6,442: | Line 6,442: | ||
(format-sexpr (sexpr-read |
(format-sexpr (sexpr-read |
||
(open-input-string "((data \"quoted data\" 123 4.5) (data (!@# (4.5) \"(more\" \"data)\")))")))</ |
(open-input-string "((data \"quoted data\" 123 4.5) (data (!@# (4.5) \"(more\" \"data)\")))")))</syntaxhighlight> |
||
Output: |
Output: |
||
Line 6,467: | Line 6,467: | ||
=={{header|Sidef}}== |
=={{header|Sidef}}== |
||
{{trans|Perl}} |
{{trans|Perl}} |
||
< |
<syntaxhighlight lang="ruby">func sexpr(txt) { |
||
txt.trim! |
txt.trim! |
||
Line 6,516: | Line 6,516: | ||
say s # dump structure |
say s # dump structure |
||
say sexpr2txt(s) # convert back</ |
say sexpr2txt(s) # convert back</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 6,525: | Line 6,525: | ||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
||
Note that because Tcl doesn't expose a type system (well, not in a conventional sense) the parts of the parsed out data structure are tagged lists; the first element is one of “<tt>string</tt>”, “<tt>int</tt>”, “<tt>real</tt>” and “<tt>atom</tt>” to indicate a leaf token, or “<tt>list</tt>” to indicate a sublist. A “native” data structure could also be generated, but then that would turn things into lists that are not in the original. |
Note that because Tcl doesn't expose a type system (well, not in a conventional sense) the parts of the parsed out data structure are tagged lists; the first element is one of “<tt>string</tt>”, “<tt>int</tt>”, “<tt>real</tt>” and “<tt>atom</tt>” to indicate a leaf token, or “<tt>list</tt>” to indicate a sublist. A “native” data structure could also be generated, but then that would turn things into lists that are not in the original. |
||
< |
<syntaxhighlight lang="tcl">package require Tcl 8.5 |
||
proc fromSexp {str} { |
proc fromSexp {str} { |
||
Line 6,573: | Line 6,573: | ||
return [lindex $content 0] |
return [lindex $content 0] |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
Demonstrating with the sample data: |
Demonstrating with the sample data: |
||
< |
<syntaxhighlight lang="tcl">set sample {((data "quoted data" 123 4.5) |
||
(data (!@# (4.5) "(more" "data)")))} |
(data (!@# (4.5) "(more" "data)")))} |
||
set parsed [fromSexp $sample] |
set parsed [fromSexp $sample] |
||
puts "sample: $sample" |
puts "sample: $sample" |
||
puts "parsed: $parsed" |
puts "parsed: $parsed" |
||
puts "regen: [toSexp $parsed]"</ |
puts "regen: [toSexp $parsed]"</syntaxhighlight> |
||
Output: |
Output: |
||
<pre> |
<pre> |
||
Line 6,626: | Line 6,626: | ||
Code: |
Code: |
||
< |
<syntaxhighlight lang="txr">@(define float (f))@\ |
||
@(local (tok))@\ |
@(local (tok))@\ |
||
@(cases)@\ |
@(cases)@\ |
||
Line 6,669: | Line 6,669: | ||
expr: @(format nil "~s" e) |
expr: @(format nil "~s" e) |
||
junk: @junk |
junk: @junk |
||
@(end)</ |
@(end)</syntaxhighlight> |
||
Run: |
Run: |
||
Line 6,704: | Line 6,704: | ||
Explanation of most confusing line: |
Explanation of most confusing line: |
||
< |
<syntaxhighlight lang="txr"> @/\s*\(\s*/@(coll :vars (e))@(expr e)@/\s*/@(last))@(end)</syntaxhighlight> |
||
First, we match an open parenthesis that can be embedded in whitespace. Then we have a <code>@(coll)</code> construct which terminates with <code>@(end)</code>. This is a repetition construct for collecting zero or more items. The <code>:vars (e)</code> argument makes the collect strict: each repetition must bind the variable <code>e</code>. More importantly, in this case, if nothing is |
First, we match an open parenthesis that can be embedded in whitespace. Then we have a <code>@(coll)</code> construct which terminates with <code>@(end)</code>. This is a repetition construct for collecting zero or more items. The <code>:vars (e)</code> argument makes the collect strict: each repetition must bind the variable <code>e</code>. More importantly, in this case, if nothing is |
||
Line 6,713: | Line 6,713: | ||
{{libheader|Wren-pattern}} |
{{libheader|Wren-pattern}} |
||
{{libheader|Wren-fmt}} |
{{libheader|Wren-fmt}} |
||
< |
<syntaxhighlight lang="ecmascript">import "/pattern" for Pattern |
||
import "/fmt" for Fmt |
import "/fmt" for Fmt |
||
Line 6,800: | Line 6,800: | ||
System.print("\nRecovered S-Expression (pretty print):") |
System.print("\nRecovered S-Expression (pretty print):") |
||
prettyPrint.call(tokens) |
prettyPrint.call(tokens) |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |