#!/home/arne/wisp/wisp-multiline.sh
; !#
; we need to be able to replace end-of-line characters in brackets and strings
;; nostringandbracketbreaks INPORT
;;
;; Replace linebreaks within brackets and strings in the INPORT by the
;; placeholders \STRING_BREAK_N and \STRING_BREAK_R. Also identify
;; real comments as ;\REALCOMMENTHERE
;;
;; -Author: Arne Babenhauserheide
define : nostringandbracketbreaks inport
; Replace end of line characters in brackets and strings
; FIXME: Breaks if the string is shorter than 2 chars
let*
: lastchar : read-char inport
nextchar : read-char inport
text ""
incomment #f
incommentfirstchar #f ; first char of a comment
instring #f
inbrackets 0
incharform 0 ; #\<something>
while : not : eof-object? nextchar
; incommentfirstchar is only valid for exactly one char
when incommentfirstchar : set! incommentfirstchar #f
; already started char forms win over everything, so process them first.
; already started means: after the #\
when : >= incharform 2
if : char=? nextchar #\space
set! incharform 0
; else
set! incharform : + incharform 1
; check if we switch to a string: last char is space, linebreak or in a string, not in a charform, not in a comment
when
and
char=? nextchar #\"
or
. instring ; when I’m in a string, I can get out
char=? lastchar #\space ; when the last char was a space, I can get into a string
char=? lastchar #\linefeed ; same for newline chars
char=? lastchar #\newline
not incomment
< incharform 1
set! instring : not instring
; check if we switch to a comment
when
and
char=? nextchar #\;
not incomment
not instring
< incharform 2
set! incomment #t
set! incommentfirstchar #t
; this also closes any potential charform
set! incharform 0
when
and incomment
or
char=? nextchar #\newline
char=? nextchar #\linefeed
set! incomment #f
; check for the beginning of a charform
when
and
not instring
not incomment
char=? lastchar #\space
char=? nextchar #\#
set! incharform 1
; check whether a charform is continued
when
and
= incharform 1
char=? lastchar #\#
char=? nextchar #\\
set! incharform 2
; check for brackets
when : and ( char=? nextchar #\( ) ( not instring ) ( not incomment ) ( = incharform 0 )
set! inbrackets : + inbrackets 1
when : and ( char=? nextchar #\) ) ( not instring ) ( not incomment ) ( = incharform 0 )
set! inbrackets : - inbrackets 1
if : or instring ( > inbrackets 0 )
if : char=? nextchar #\linefeed
set! text : string-append text "\\LINE_BREAK_N"
if : char=? nextchar #\newline
set! text : string-append text "\\LINE_BREAK_R"
set! text : string-append text : string nextchar
; mark the start of a comment, so we do not have to repeat the string matching in later code
if incommentfirstchar
set! text : string-append text ( string nextchar ) "\\REALCOMMENTHERE"
; when not in brackets or string or starting a
; comment: just append the char
set! text : string-append text : string nextchar
set! lastchar nextchar
set! nextchar : read-char inport
; return the text
. text
; As next part we have split a text into a list of lines which we can process one by one.
; FIXME: Cuts off the beginning of the content.
define : splitlines inport
let
: lines '()
nextchar : read-char inport
nextline ""
while : not : eof-object? nextchar
if : not : or (char=? nextchar #\newline ) (char=? nextchar #\linefeed )
set! nextline : string-append nextline : string nextchar
begin
set! lines : append lines (list nextline)
set! nextline ""
set! nextchar : read-char inport
. lines
; Now we have to split a single line into indentation, content and comment.
define : splitindent inport
let
: nextchar : read-char inport
inindentunderbar #t
inindent #t ; it always begins in indent
incomment #f ; but not in a comment
commentstart #f
commentstartidentifier "\\REALCOMMENTHERE"
commentstartidentifierlength 16
commentidentifierindex 0
indent 0
content ""
comment ""
while : not : eof-object? nextchar
; check wether we leave the initial underbars
when : and inindentunderbar : not : char=? nextchar #\_
set! inindentunderbar #f
set! indent : + indent 1
set! nextchar : read-char inport
continue
; check whether we leave the indentation
when : and inindent : not : char=? nextchar #\space
set! inindent #f
set! indent : + indent 1
set! nextchar : read-char inport
continue
; check whether we leave the content
when : and ( not incomment ) : char=? nextchar #\;
set! commentstart #t
set! comment : string-append comment : string nextchar
set! nextchar : read-char inport
continue
; check whether we stay in the commentcheck
when : and commentstart : char=? nextchar : string-ref commentstartidentifier commentidentifierindex
set! commentidentifierindex : + commentidentifierindex 1
set! comment : string-append comment : string nextchar
when : = commentidentifierindex : - commentstartidentifierlength 1
set! commentstart #f
set! incomment #t
; reset used variables
set! commentidentifierindex 0
set! comment ""
set! nextchar : read-char inport
continue
; if we cannot complete the commentcheck, we did not start a real comment. Append it to the content
when : and commentstart : not : char=? nextchar : string-ref commentstartidentifier commentidentifierindex
set! commentstart #f
set! content : string-append content comment
set! comment ""
set! commentidentifierindex 0
set! nextchar : read-char inport
continue
; if we are in the comment, just append to the comment
when incomment
set! comment : string-append comment : string nextchar
set! nextchar : read-char inport
continue
; if nothing else is true, we are in the content
set! content : string-append content : string nextchar
set! nextchar : read-char inport
; return the indentation, the content and the comment
list indent content comment
; Now use the function to split a list of lines
define : linestoindented lines
let
: split '()
lineindex 0
nextline : list-ref lines 0
while : < ( + lineindex 1 ) : length lines
set! split : append split : list : call-with-input-string nextline splitindent
set! lineindex : + lineindex 1
set! nextline : list-ref lines lineindex
. split
; first step: Be able to mirror a file to stdout
let*
: filename : list-ref ( command-line ) 1
origfile : open-file filename "r" ; mode
nextchar : read-char origfile
text ""
lines '()
while : not : eof-object? nextchar
set! text : string-append text : string nextchar
set! nextchar : read-char origfile
set! text : call-with-input-string text nostringandbracketbreaks
; display text
set! lines : call-with-input-string text splitlines
set! lines : linestoindented lines
display : list-ref lines 100
newline