diff --git a/0-lang0py/lang0py.py b/0-lang0py/lang0py.py index adfed09..7de85d1 100644 --- a/0-lang0py/lang0py.py +++ b/0-lang0py/lang0py.py @@ -39,11 +39,6 @@ def skip(): PEEK = None -def skipchar(char): - global LINE - assert char == peek(), (LINE, char, peek()) - skip() - def emitln(data): emit(data) emit(eol) @@ -61,6 +56,11 @@ def lexident(): return word +def skipchar(char): + global LINE + assert char == peek(), (LINE, char, peek()) + skip() + def parseconststring(): skipchar(quote) emit(quote) @@ -364,33 +364,40 @@ def emitheader(): emitln("eof = chr(0)") emitln("eol = chr(10)") emitln("quote = chr(34)") - emitln("PEEK = None") - emitln("LINE = 1") + emitln("") + emitln("STDINCOLNO = 0") + emitln("STDINLINENO = 1") + emitln("STDINPEEK = None") + emitln("") + emitln("def _readchar():") + emitln(" char = sys.stdin.read(1)") + emitln(" trace('char', char)") + emitln(" if not char:") + emitln(" return eof") + emitln(" return char") emitln("") emitln("def peek():") - emitln(" global PEEK") - emitln(" if PEEK is None:") - emitln(" char = sys.stdin.read(1)") - emitln(" trace('char', char)") - emitln(" if not char:") - emitln(" PEEK = eof") - emitln(" else:") - emitln(" PEEK = char") - emitln(" return PEEK") - emitln("") - emitln("peek()") + emitln(" return STDINPEEK") emitln("") emitln("def skip():") - emitln(" global LINE") - emitln(" global PEEK") - emitln(" if eol == PEEK:") - emitln(" LINE += 1") - emitln(" PEEK = None") + emitln(" global STDINCOLNO") + emitln(" global STDINLINENO") + emitln(" global STDINPEEK") + emitln(" if eol == STDINPEEK:") + emitln(" STDINLINENO += 1") + emitln(" STDINCOLNO = 0") + emitln(" STDINCOLNO += 1") + emitln(" STDINPEEK = _readchar()") emitln("") - emitln("def skipchar(char):") - emitln(" global LINE") - emitln(" assert char == peek(), (LINE, char, peek())") - emitln(" skip()") + emitln("def stdinlineno():") + emitln(" global STDINLINENO") + emitln(" return str(STDINLINENO)") + emitln("") + emitln("def stdincolno():") + emitln(" global STDINCOLNO") + emitln(" return str(STDINCOLNO)") + emitln("") + emitln("skip()") emitln("") def emitfooter(): diff --git a/1-lang0py/lang0py.lang0 b/1-lang0py/lang0py.lang0 index aa9a897..d153d14 100644 --- a/1-lang0py/lang0py.lang0 +++ b/1-lang0py/lang0py.lang0 @@ -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: emit data emit eol @@ -430,33 +441,40 @@ emitheader: emitln "eof = chr(0)" emitln "eol = chr(10)" emitln "quote = chr(34)" - emitln "PEEK = None" - emitln "LINE = 1" + emitln "" + emitln "STDINCOLNO = 0" + emitln "STDINLINENO = 1" + emitln "STDINPEEK = None" + emitln "" + emitln "def _readchar():" + emitln " char = sys.stdin.read(1)" + emitln " trace('char', char)" + emitln " if not char:" + emitln " return eof" + emitln " return char" emitln "" emitln "def peek():" - emitln " global PEEK" - emitln " if PEEK is None:" - emitln " char = sys.stdin.read(1)" - emitln " trace('char', char)" - emitln " if not char:" - emitln " PEEK = eof" - emitln " else:" - emitln " PEEK = char" - emitln " return PEEK" - emitln "" - emitln "peek()" + emitln " return STDINPEEK" emitln "" emitln "def skip():" - emitln " global LINE" - emitln " global PEEK" - emitln " if eol == PEEK:" - emitln " LINE += 1" - emitln " PEEK = None" + emitln " global STDINCOLNO" + emitln " global STDINLINENO" + emitln " global STDINPEEK" + emitln " if eol == STDINPEEK:" + emitln " STDINLINENO += 1" + emitln " STDINCOLNO = 0" + emitln " STDINCOLNO += 1" + emitln " STDINPEEK = _readchar()" emitln "" - emitln "def skipchar(char):" - emitln " global LINE" - emitln " assert char == peek(), (LINE, char, peek())" - emitln " skip()" + emitln "def stdinlineno():" + emitln " global STDINLINENO" + emitln " return str(STDINLINENO)" + emitln "" + emitln "def stdincolno():" + emitln " global STDINCOLNO" + emitln " return str(STDINCOLNO)" + emitln "" + emitln "skip()" emitln "" / diff --git a/2-lang0c/lang0c.lang0 b/2-lang0c/lang0c.lang0 index 995ef4e..9c19c72 100644 --- a/2-lang0c/lang0c.lang0 +++ b/2-lang0c/lang0c.lang0 @@ -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: emit data emit eol @@ -273,13 +284,23 @@ parsestatcheck indent: emit indent emitln "{" + emit " fprintf(stderr, " + emit quote + emit "%s" + emit quote + emit ", " + emit quote + emit "ERROR:" + emit quote + emitln ");" + forever skipchar " " emit indent emit " fprintf(stderr, " emit quote - emit "%s " + emit " %s" emit quote emit ", " calc char peek @@ -568,35 +589,55 @@ emitheader: emitln " return 0;" emitln "}" emitln "" - emitln "int LINE = 1;" + emitln "int STDINCOLNO = 1;" + emitln "int STDINLINENO = 1;" + emitln "char * STDINPEEK = 0;" emitln "" - emitln "char * peek()" + emitln "char * _readchar()" emitln "{" emitln " char * res = malloc(2*sizeof(char));" emitln " res[0] = getc(stdin);" emitln " res[1] = 0;" - emitln " ungetc(res[0], stdin);" emitln " return res;" emitln "}" emitln "" + emitln "char * peek()" + emitln "{" + emitln " if( !STDINPEEK ) STDINPEEK = _readchar(); // First byte read" + emitln " return STDINPEEK;" + emitln "}" + emitln "" emitln "void skip()" emitln "{" - emitln " char c = getc(stdin);" - emitln " if( c == 10 ) LINE += 1;" + emitln " if( !STDINPEEK ) STDINPEEK = _readchar(); // First byte read, not even peek()'d" + emitln " if( STDINPEEK[0] == 10 ) {" + emitln " STDINLINENO += 1;" + emitln " STDINCOLNO = 0;" + emitln " }" + emitln " STDINCOLNO += 1;" + emitln " STDINPEEK = _readchar();" emitln "}" emitln "" - emitln "void skipchar(char * chr)" + emitln "char * stdinlineno()" emitln "{" - emitln " assert(strlen(chr) == 1);" - emitln " char * act = peek();" - emitln " assert(strlen(act) == 1);" - emitln " if( chr[0] == act[0] ) {skip(); return;};" - emit " fprintf(stderr, " + emitln " char * res = malloc(8*sizeof(char));" + emit " sprintf(res, " emit quote - emit "Expected '%c' on line %d but saw '%c' instead%c" + emit "%d" emit quote - emitln ", chr[0], LINE, act[0], 10);" - emitln " exit(1);" + emitln ", STDINLINENO);" + 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 "" return diff --git a/README.md b/README.md index 082ac23..1bee0d4 100644 --- a/README.md +++ b/README.md @@ -151,9 +151,13 @@ Checks stdin for the next character and returns it. 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 diff --git a/tests/Makefile b/tests/Makefile index 030c87c..8eb876e 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -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 -rm -f $@ - echo "Hello" | build/builtincheckfalse.it0 2> /dev/null 2>&1 | grep 'Success' - $(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; echo "Hello" | ./build/$(test).it0 >> $@ ; echo "" >> $@ ;) + cat test-input.txt | build/builtincheckfalse.it0 2> /dev/null 2>&1 | grep 'Success' + $(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 $@ - echo "Hello" | build/builtincheckfalse.it0 2> /dev/null 2>&1 | grep 'Success' - $(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; echo "Hello" | ./build/$(test).it1 >> $@ ; echo "" >> $@ ;) + cat test-input.txt | build/builtincheckfalse.it1 2> /dev/null 2>&1 | grep 'Success' + $(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 $@ - echo "Hello" | build/builtincheckfalse.it0 2> /dev/null 2>&1 | grep 'Success' - $(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; echo "Hello" | ./build/$(test).it2 >> $@ ; echo "" >> $@ ;) + cat test-input.txt | build/builtincheckfalse.it2 2> /dev/null 2>&1 | grep 'Success' + $(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; cat test-input.txt | ./build/$(test).it2 >> $@ ; echo "" >> $@ ;) clean: -rm -f *.results build/*.it0* build/*.it1* build/*.it2* diff --git a/tests/stdinlineno.lang0 b/tests/stdinlineno.lang0 new file mode 100644 index 0000000..1f15ae9 --- /dev/null +++ b/tests/stdinlineno.lang0 @@ -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" +/ diff --git a/tests/test-input.txt b/tests/test-input.txt new file mode 100644 index 0000000..37d8d0a --- /dev/null +++ b/tests/test-input.txt @@ -0,0 +1,3 @@ +Hello! + +This is an example of standard input.