From 479ff20704ecfb9e78dda1d52375368fbafbabbd Mon Sep 17 00:00:00 2001 From: pommicket Date: Fri, 7 Jan 2022 11:29:37 -0500 Subject: add 04 to bootstrap, #line --- 04/README.md | 3 +++ 04/in03 | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 76 insertions(+), 8 deletions(-) (limited to '04') diff --git a/04/README.md b/04/README.md index 6f638b6..a0a7f8d 100644 --- a/04/README.md +++ b/04/README.md @@ -212,6 +212,9 @@ conditionally jump to the specified label. `{operator}` should be one of - `return {rvalue}` - `string {str}` - places a literal string in the code - `byte {number}` - places a literal byte in the code +- `#line {line number} {filename}` / `#line {line number}` - set line number and optionally the filename for future errors (no code is outputted from this) + +The `#line` directive (which also exists in C) seems a bit strange, but its use will be revealed soon. Now let's get down into the weeds: diff --git a/04/in03 b/04/in03 index c2f45ef..6daf3c5 100644 --- a/04/in03 +++ b/04/in03 @@ -16,6 +16,13 @@ I=8S A=d2 ?I>A:argv_file_names ; use default input/output filenames + + ; set :filename appropriately + J=:filename + I=:input_filename + C=d0 + call :memccpy + ; open input file J=:input_filename I=d0 @@ -30,7 +37,18 @@ A=d2 J=A ?J<0:output_file_error !:second_pass_starting_point -:argv_file_names +:argv_file_names + ; get filenames from command-line arguments + + ; set :filename appropriately + I=S + ; argv[1] is at *(rsp+16) + I+=d16 + I=8I + J=:filename + C=d0 + call :memccpy + ; open input file J=S ; argv[1] is at *(rsp+16) @@ -173,6 +191,13 @@ call :string= D=A ?D!0:handle_string +I=:line +J=:"#line" +C=x20 +call :string= +D=A +?D!0:handle_#line + I=:line J=:"goto" C=x20 @@ -275,13 +300,18 @@ align ; 5 = length of "byte " I+=d5 call :read_number + ; store away number in rbp + R=A + ; make sure number is immediately followed by newline + C=1I + D=xa + ?C!D:bad_number ; make sure byte is 0-255 - C=A D=xff - ?CaD:bad_byte + ?RaD:bad_byte ; write byte I=:byte - 1I=C + 1I=R J=d4 D=d1 syscall x1 @@ -289,6 +319,35 @@ align :byte reserve d1 +:handle_#line + I=:line + ; 6 = length of "#line " + I+=d6 + call :read_number + ; store line number + D=A + C=:line_number + ; subtract one so that we specify the number of the *next* line + D-=d1 + 8C=D + ; check character after line number + C=1I + D=xa + ; if it's a newline, we're done + ?C=D:read_line + ; otherwise, it'd better be a space + D=x20 + ?C!D:bad_statement + ; set the filename + I+=d1 + J=:filename + C=xa + call :memccpy + ; we want a null-terminated, not newline-terminated filename + J-=d1 + 1J=0 + !:read_line + :handle_string I=:line ; 7 = length of "string " @@ -2139,7 +2198,9 @@ align :program_error R=B - B=:"Line" + B=:filename + call :eputs + B=:":" call :eputs D=:line_number @@ -2155,9 +2216,8 @@ align J=d1 syscall x3c -:"Line" - str Line - x20 +:":" + str : x0 :line_number_separator @@ -2346,6 +2406,9 @@ align :"string" str string x20 +:"#line" + str #line + x20 :"goto" str goto x20 @@ -2408,6 +2471,8 @@ align reserve d8 :line_number reserve d8 +:filename + reserve d80 :global_variables reserve d50000 :local_variables -- cgit v1.2.3