RosettaCodeData/Task/S-Expressions/ALGOL-68/s-expressions.alg
2016-12-05 22:15:40 +01:00

127 lines
5.3 KiB
Text

# S-Expressions #
CHAR nl = REPR 10;
# mode representing an S-expression #
MODE SEXPR = STRUCT( UNION( VOID, STRING, REF SEXPR ) element, REF SEXPR next );
# creates an initialises an SEXPR #
PROC new s expr = REF SEXPR: HEAP SEXPR := ( EMPTY, NIL );
# reports an error #
PROC error = ( STRING msg )VOID: print( ( "**** ", msg, newline ) );
# S-expression reader - reads and returns an S-expression from the string s #
PROC s reader = ( STRING s )REF SEXPR:
BEGIN
PROC at end = BOOL: s pos > UPB s;
PROC curr = CHAR: IF at end THEN REPR 0 ELSE s[ s pos ] FI;
PROC skip spaces = VOID: WHILE NOT at end AND ( curr = " " OR curr = nl ) DO s pos +:= 1 OD;
PROC end of list = BOOL: at end OR curr = ")";
INT s pos := LWB s;
INT t pos;
[ ( UPB s - LWB s ) + 1 ]CHAR token; # token text - large enough to hold the whole string if necessary #
# adds the current character to the token #
PROC add curr = VOID: token[ t pos +:= 1 ] := curr;
# get an s expression element from s #
PROC get element = REF SEXPR:
BEGIN
REF SEXPR result = new s expr;
skip spaces;
# get token text #
IF at end THEN
# no element #
element OF result := EMPTY
ELIF curr = "(" THEN
s pos +:= 1;
skip spaces;
IF NOT end of list
THEN
REF SEXPR nested expression = get element;
REF SEXPR element pos := nested expression;
element OF result := nested expression;
skip spaces;
WHILE NOT end of list
DO
element pos := next OF element pos := get element;
skip spaces
OD
FI;
IF curr = ")" THEN
s pos +:= 1
ELSE
error( "Missing "")""" )
FI
ELIF curr = ")" THEN
s pos +:= 1;
error( "Unexpected "")""" );
element OF result := EMPTY
ELSE
# quoted or unquoted string #
t pos := LWB token - 1;
IF curr /= """" THEN
# unquoted string #
WHILE add curr;
s pos +:= 1;
NOT at end AND curr /= " " AND curr /= "("
AND curr /= ")" AND curr /= """"
AND curr /= nl
DO SKIP OD
ELSE
# quoted string #
WHILE add curr;
s pos +:= 1;
NOT at end AND curr /= """"
DO SKIP OD;
IF curr /= """" THEN
# missing string quote #
error( "Unterminated string: <<" + token[ : t pos ] + ">>" )
ELSE
# have the closing quote #
add curr;
s pos +:= 1
FI
FI;
element OF result := token[ : t pos ]
FI;
result
END # get element # ;
REF SEXPR s expr = get element;
skip spaces;
IF NOT at end THEN
# extraneuos text after the expression #
error( "Unexpected text at end of expression: " + s[ s pos : ] )
FI;
s expr
END # s reader # ;
# prints an S expression #
PROC s writer = ( REF SEXPR s expr )VOID:
BEGIN
# prints an S expression with a suitable indent #
PROC print indented s expression = ( REF SEXPR s expr, INT indent )VOID:
BEGIN
REF SEXPR s pos := s expr;
WHILE REF SEXPR( s pos ) ISNT REF SEXPR( NIL ) DO
FOR i TO indent DO print( ( " " ) ) OD;
CASE element OF s pos
IN (VOID ): print( ( "()", newline ) )
, (STRING s): print( ( s, newline ) )
, (REF SEXPR e): BEGIN
print( ( "(", newline ) );
print indented s expression( e, indent + 4 );
FOR i TO indent DO print( ( " " ) ) OD;
print( ( ")", newline ) )
END
OUT
error( "Unexpected S expression element" )
ESAC;
s pos := next OF s pos
OD
END # print indented s expression # ;
print indented s expression( s expr, 0 )
END # s writer # ;
# test the eader and writer with the example from the task #
s writer( s reader( "((data ""quoted data"" 123 4.5)"
+ nl
+ " (data (!@# (4.5) ""(more"" ""data)"")))"
+ nl
)
)