Remove skipchar, add stdinlineno / stdincolno

With the new check function, this helper method doesn't make
much sense to put in the standard library.

To replicate the same result, we do need to expose the current
line number; adding column number is a nice bonus.

Also; made it a bit clearer when a check failes in it2.

Also; the builtincheckfalse was not working.

Also; separated out the test input file to have more data.
This commit is contained in:
Johan B.W. de Vries 2025-02-09 15:38:02 +01:00
parent ed09d37213
commit 2eaa763a2c
7 changed files with 233 additions and 74 deletions

View File

@ -39,11 +39,6 @@ def skip():
PEEK = None PEEK = None
def skipchar(char):
global LINE
assert char == peek(), (LINE, char, peek())
skip()
def emitln(data): def emitln(data):
emit(data) emit(data)
emit(eol) emit(eol)
@ -61,6 +56,11 @@ def lexident():
return word return word
def skipchar(char):
global LINE
assert char == peek(), (LINE, char, peek())
skip()
def parseconststring(): def parseconststring():
skipchar(quote) skipchar(quote)
emit(quote) emit(quote)
@ -364,33 +364,40 @@ def emitheader():
emitln("eof = chr(0)") emitln("eof = chr(0)")
emitln("eol = chr(10)") emitln("eol = chr(10)")
emitln("quote = chr(34)") emitln("quote = chr(34)")
emitln("PEEK = None")
emitln("LINE = 1")
emitln("") emitln("")
emitln("def peek():") emitln("STDINCOLNO = 0")
emitln(" global PEEK") emitln("STDINLINENO = 1")
emitln(" if PEEK is None:") emitln("STDINPEEK = None")
emitln("")
emitln("def _readchar():")
emitln(" char = sys.stdin.read(1)") emitln(" char = sys.stdin.read(1)")
emitln(" trace('char', char)") emitln(" trace('char', char)")
emitln(" if not char:") emitln(" if not char:")
emitln(" PEEK = eof") emitln(" return eof")
emitln(" else:") emitln(" return char")
emitln(" PEEK = char")
emitln(" return PEEK")
emitln("") emitln("")
emitln("peek()") emitln("def peek():")
emitln(" return STDINPEEK")
emitln("") emitln("")
emitln("def skip():") emitln("def skip():")
emitln(" global LINE") emitln(" global STDINCOLNO")
emitln(" global PEEK") emitln(" global STDINLINENO")
emitln(" if eol == PEEK:") emitln(" global STDINPEEK")
emitln(" LINE += 1") emitln(" if eol == STDINPEEK:")
emitln(" PEEK = None") emitln(" STDINLINENO += 1")
emitln(" STDINCOLNO = 0")
emitln(" STDINCOLNO += 1")
emitln(" STDINPEEK = _readchar()")
emitln("") emitln("")
emitln("def skipchar(char):") emitln("def stdinlineno():")
emitln(" global LINE") emitln(" global STDINLINENO")
emitln(" assert char == peek(), (LINE, char, peek())") emitln(" return str(STDINLINENO)")
emitln(" skip()") emitln("")
emitln("def stdincolno():")
emitln(" global STDINCOLNO")
emitln(" return str(STDINCOLNO)")
emitln("")
emitln("skip()")
emitln("") emitln("")
def emitfooter(): def emitfooter():

View File

@ -1,3 +1,14 @@
skipchar exp:
declare act
declare lineno
declare colno
calc act peek
calc lineno stdinlineno
calc colno stdincolno
check eq exp act : "Unexpected character" act "expected" exp "at" lineno colno
skip
/
emitln data: emitln data:
emit data emit data
emit eol emit eol
@ -430,33 +441,40 @@ emitheader:
emitln "eof = chr(0)" emitln "eof = chr(0)"
emitln "eol = chr(10)" emitln "eol = chr(10)"
emitln "quote = chr(34)" emitln "quote = chr(34)"
emitln "PEEK = None"
emitln "LINE = 1"
emitln "" emitln ""
emitln "def peek():" emitln "STDINCOLNO = 0"
emitln " global PEEK" emitln "STDINLINENO = 1"
emitln " if PEEK is None:" emitln "STDINPEEK = None"
emitln ""
emitln "def _readchar():"
emitln " char = sys.stdin.read(1)" emitln " char = sys.stdin.read(1)"
emitln " trace('char', char)" emitln " trace('char', char)"
emitln " if not char:" emitln " if not char:"
emitln " PEEK = eof" emitln " return eof"
emitln " else:" emitln " return char"
emitln " PEEK = char"
emitln " return PEEK"
emitln "" emitln ""
emitln "peek()" emitln "def peek():"
emitln " return STDINPEEK"
emitln "" emitln ""
emitln "def skip():" emitln "def skip():"
emitln " global LINE" emitln " global STDINCOLNO"
emitln " global PEEK" emitln " global STDINLINENO"
emitln " if eol == PEEK:" emitln " global STDINPEEK"
emitln " LINE += 1" emitln " if eol == STDINPEEK:"
emitln " PEEK = None" emitln " STDINLINENO += 1"
emitln " STDINCOLNO = 0"
emitln " STDINCOLNO += 1"
emitln " STDINPEEK = _readchar()"
emitln "" emitln ""
emitln "def skipchar(char):" emitln "def stdinlineno():"
emitln " global LINE" emitln " global STDINLINENO"
emitln " assert char == peek(), (LINE, char, peek())" emitln " return str(STDINLINENO)"
emitln " skip()" emitln ""
emitln "def stdincolno():"
emitln " global STDINCOLNO"
emitln " return str(STDINCOLNO)"
emitln ""
emitln "skip()"
emitln "" emitln ""
/ /

View File

@ -1,3 +1,14 @@
skipchar exp:
declare act
declare lineno
declare colno
calc act peek
calc lineno stdinlineno
calc colno stdincolno
check eq exp act : "Unexpected character" act "expected" exp "at" lineno colno
skip
/
emitln data: emitln data:
emit data emit data
emit eol emit eol
@ -273,13 +284,23 @@ parsestatcheck indent:
emit indent emit indent
emitln "{" emitln "{"
emit " fprintf(stderr, "
emit quote
emit "%s"
emit quote
emit ", "
emit quote
emit "ERROR:"
emit quote
emitln ");"
forever forever
skipchar " " skipchar " "
emit indent emit indent
emit " fprintf(stderr, " emit " fprintf(stderr, "
emit quote emit quote
emit "%s " emit " %s"
emit quote emit quote
emit ", " emit ", "
calc char peek calc char peek
@ -568,35 +589,55 @@ emitheader:
emitln " return 0;" emitln " return 0;"
emitln "}" emitln "}"
emitln "" emitln ""
emitln "int LINE = 1;" emitln "int STDINCOLNO = 1;"
emitln "int STDINLINENO = 1;"
emitln "char * STDINPEEK = 0;"
emitln "" emitln ""
emitln "char * peek()" emitln "char * _readchar()"
emitln "{" emitln "{"
emitln " char * res = malloc(2*sizeof(char));" emitln " char * res = malloc(2*sizeof(char));"
emitln " res[0] = getc(stdin);" emitln " res[0] = getc(stdin);"
emitln " res[1] = 0;" emitln " res[1] = 0;"
emitln " ungetc(res[0], stdin);"
emitln " return res;" emitln " return res;"
emitln "}" emitln "}"
emitln "" emitln ""
emitln "char * peek()"
emitln "{"
emitln " if( !STDINPEEK ) STDINPEEK = _readchar(); // First byte read"
emitln " return STDINPEEK;"
emitln "}"
emitln ""
emitln "void skip()" emitln "void skip()"
emitln "{" emitln "{"
emitln " char c = getc(stdin);" emitln " if( !STDINPEEK ) STDINPEEK = _readchar(); // First byte read, not even peek()'d"
emitln " if( c == 10 ) LINE += 1;" emitln " if( STDINPEEK[0] == 10 ) {"
emitln " STDINLINENO += 1;"
emitln " STDINCOLNO = 0;"
emitln " }"
emitln " STDINCOLNO += 1;"
emitln " STDINPEEK = _readchar();"
emitln "}" emitln "}"
emitln "" emitln ""
emitln "void skipchar(char * chr)" emitln "char * stdinlineno()"
emitln "{" emitln "{"
emitln " assert(strlen(chr) == 1);" emitln " char * res = malloc(8*sizeof(char));"
emitln " char * act = peek();" emit " sprintf(res, "
emitln " assert(strlen(act) == 1);"
emitln " if( chr[0] == act[0] ) {skip(); return;};"
emit " fprintf(stderr, "
emit quote emit quote
emit "Expected '%c' on line %d but saw '%c' instead%c" emit "%d"
emit quote emit quote
emitln ", chr[0], LINE, act[0], 10);" emitln ", STDINLINENO);"
emitln " exit(1);" emitln " return res;"
emitln "}"
emitln ""
emitln "char * stdincolno()"
emitln "{"
emitln " char * res = malloc(8*sizeof(char));"
emit " sprintf(res, "
emit quote
emit "%d"
emit quote
emitln ", STDINCOLNO);"
emitln " return res;"
emitln "}" emitln "}"
emitln "" emitln ""
return return

View File

@ -151,9 +151,13 @@ Checks stdin for the next character and returns it.
Advances stdin a single character. Advances stdin a single character.
#### skipchar a #### stdincolno
Advances stdin a single character, if it matches the first character of `a`. Otherwise, exits the program. Returns the column number for stdin (starting at 1)
#### stdinlineno
Returns the line number for stdin (starting at 1)
### Typing ### Typing

View File

@ -18,18 +18,18 @@ check: all-it0.results all-it1.results all-it2.results
all-it0.results: $(addprefix build/,$(addsuffix .it0, $(TESTLIST))) build/builtincheckfalse.it0 all-it0.results: $(addprefix build/,$(addsuffix .it0, $(TESTLIST))) build/builtincheckfalse.it0
-rm -f $@ -rm -f $@
echo "Hello" | build/builtincheckfalse.it0 2> /dev/null 2>&1 | grep 'Success' cat test-input.txt | build/builtincheckfalse.it0 2> /dev/null 2>&1 | grep 'Success'
$(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; echo "Hello" | ./build/$(test).it0 >> $@ ; echo "" >> $@ ;) $(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; cat test-input.txt | ./build/$(test).it0 >> $@ ; echo "" >> $@ ;)
all-it1.results: $(addprefix build/,$(addsuffix .it1, $(TESTLIST))) build/builtincheckfalse.it0 all-it1.results: $(addprefix build/,$(addsuffix .it1, $(TESTLIST))) build/builtincheckfalse.it1
-rm -f $@ -rm -f $@
echo "Hello" | build/builtincheckfalse.it0 2> /dev/null 2>&1 | grep 'Success' cat test-input.txt | build/builtincheckfalse.it1 2> /dev/null 2>&1 | grep 'Success'
$(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; echo "Hello" | ./build/$(test).it1 >> $@ ; echo "" >> $@ ;) $(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; cat test-input.txt | ./build/$(test).it1 >> $@ ; echo "" >> $@ ;)
all-it2.results: $(addprefix build/,$(addsuffix .it2, $(TESTLIST))) build/builtincheckfalse.it0 all-it2.results: $(addprefix build/,$(addsuffix .it2, $(TESTLIST))) build/builtincheckfalse.it2
-rm -f $@ -rm -f $@
echo "Hello" | build/builtincheckfalse.it0 2> /dev/null 2>&1 | grep 'Success' cat test-input.txt | build/builtincheckfalse.it2 2> /dev/null 2>&1 | grep 'Success'
$(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; echo "Hello" | ./build/$(test).it2 >> $@ ; echo "" >> $@ ;) $(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; cat test-input.txt | ./build/$(test).it2 >> $@ ; echo "" >> $@ ;)
clean: clean:
-rm -f *.results build/*.it0* build/*.it1* build/*.it2* -rm -f *.results build/*.it0* build/*.it1* build/*.it2*

86
tests/stdinlineno.lang0 Normal file
View File

@ -0,0 +1,86 @@
main:
declare char
declare colno
declare lineno
calc char peek
calc colno stdincolno
calc lineno stdinlineno
check eq char "H" : "Read: H" char
check eq colno "1" : "The column number should not have advanced yet" colno
check eq lineno "1" : "The line number should not have advanced yet" lineno
skip
calc char peek
calc colno stdincolno
calc lineno stdinlineno
check eq char "e" : "Read: e" char
check eq colno "2" : "The column number should have been advanced by 1" colno
check eq lineno "1" : "The line number should not have advanced yet" lineno
skip
calc char peek
calc colno stdincolno
calc lineno stdinlineno
check eq char "l" : "Read: l" char
check eq colno "3" : "The column number should have been advanced by 2" colno
check eq lineno "1" : "The line number should not have advanced yet" lineno
skip
calc char peek
calc colno stdincolno
calc lineno stdinlineno
check eq char "l" : "Read: l" char
check eq colno "4" : "The column number should have been advanced by 3" colno
check eq lineno "1" : "The line number should not have advanced yet" lineno
skip
calc char peek
calc colno stdincolno
calc lineno stdinlineno
check eq char "o" : "Read: o" char
check eq colno "5" : "The column number should have been advanced by 4" colno
check eq lineno "1" : "The line number should not have advanced yet" lineno
skip
calc char peek
calc colno stdincolno
calc lineno stdinlineno
check eq char "!" : "Read: !" char
check eq colno "6" : "The column number should have been advanced by 5" colno
check eq lineno "1" : "The line number should not have advanced yet" lineno
skip
calc char peek
calc colno stdincolno
calc lineno stdinlineno
check eq char eol : "Read: eol" char
check eq colno "7" : "The column number should have been advanced by 6" colno
check eq lineno "1" : "The line number should not have advanced yet" lineno
skip
calc char peek
calc colno stdincolno
calc lineno stdinlineno
check eq char eol : "Read: eol" char
check eq colno "1" : "The column number should have been reset" colno
check eq lineno "2" : "The line number should have advanced by 1" lineno
skip
calc char peek
calc colno stdincolno
calc lineno stdinlineno
check eq char "T" : "Read: T" char
check eq colno "1" : "The column number should have been reset again" colno
check eq lineno "3" : "The line number should have advanced by 2" lineno
skip
calc char peek
calc colno stdincolno
calc lineno stdinlineno
check eq char "h" : "Read: h" char
check eq colno "2" : "The line number should not have been advanced by 1" colno
check eq lineno "3" : "The line number should not have advanced further" lineno
emit "Success"
/

3
tests/test-input.txt Normal file
View File

@ -0,0 +1,3 @@
Hello!
This is an example of standard input.