Skip to content

Allows abbreviating ENDPROC as "EN.", in both compilers. - #124

Open
kimslawson wants to merge 2 commits into
dmsc:masterfrom
kimslawson:endproc-abbrev
Open

kimslawson wants to merge 2 commits into
dmsc:masterfrom
kimslawson:endproc-abbrev

Conversation

@kimslawson

Copy link
Copy Markdown
Contributor

Daniel,

This brings back @EricCarrGH's enhancement request from December 2023, #77 "Shorten EndProc abbrev from "ENDP." to "EN."". Eric pointed out that ENDP. is long for an abbreviation, and that EN. would save 2 characters per PROC, which adds up in size-coded programs and ten-liners.

You closed it because EN. is already an abbreviation of ENDIF. Inside a PROC, EN. first matches ENDIF, finds no IF to close, and the two compilers then differ. The cross compiler backtracks and tries ENDPROC. The native compiler stops with a loop error. You said "Changing this will require a big rewrite of the loop error handling", and you and Eric agreed both compilers must accept exactly the same language.

This PR keeps Eric's one-line grammar change and makes the native compiler behave like the cross compiler, without that rewrite. (I did this work with Claude Code, an AI assistant.)

How it works

  • basic.syn: Eric's change, "ENDProc" becomes "ENdproc". "Endif" still comes first in STATEMENT.
  • Native E_POP_IF (actions.asm): before popping, it checks for an IF or ELSE on top of the loop stack. If there isn't one, it doesn't jump to loop_error. Instead it stores ERR_LOOP in a new zero-page byte parse_err and returns with C=1, so the parser goes on to the next statement, ENDPROC. All the other loop actions are unchanged.
  • Native parse.asm: parse_err is set to ERR_PARSE at the start of each statement, and set_parse_error reports parse_err. So when nothing else matches, the error is still "bad loop".
  • Cross compiler: no change. It already works this way, because loop_error() saves the message and only fails the current alternative.
  • Size: 23 bytes more in each native compiler (fb.xex, fbc.xex, fbi.xex, fbci.xex).

What changes for programs

  • Every program that compiles today means the same thing. With an IF open, EN. (and END.) still close the IF. They close the PROC only where they used to be a loop error.
  • ENDPROC, ENDP., ENDIF, E. and ENDI. work as before.
  • -ls now writes EN. for ENDPROC, 2 characters shorter each time.
  • The -ls:120 output of all the samples, cmdline.bas and editor.bas (45 EN.) compiles to the same code as the sources. That needs the block order fix from my other PR (branch parser-fixes), because several PROCs now share a line.
  • Natively, the -ls output of pi.bas, joyas.bas and the new test compiles. nc/mastodon (FujiNet) and cmdline.bas (@ asm symbols) don't compile natively from the sources either.

Native compiler and cross compiler now agree, errors included

I compiled 22 small programs with both compilers, before and after the change: valid and stray ENDIF/E./EN./END., inside and outside PROC, with IF/ELSE/ELIF, DO/EXIT and FOR, alone and after :.

  • Before: EN. closing a PROC failed in both compilers. Also, native and cross reported loop errors at different columns. For example, a stray ENDIF gave native "bad loop at line 2 column 1" but cross 2:5.
  • After: both compilers accept and reject the same programs. Native "bad loop" matches cross "missing IF/PROC", native "parse error" matches cross "parse error", and the line and column agree in every case. Native errors are now reported after all the alternatives are tried, as in the cross compiler.

Tests

  • make test: 86/86, which is the 83 existing tests plus 3 new ones. The existing loop error tests (err-loop-*, err-endif, ...) pass unchanged.
  • proc-abbrev: runs every form of ENDPROC/ENDIF, including EN. closing an IF inside a PROC, after ELIF/ELSE, after DO/EXIT, and in one-line PROCs.
  • err-endif-proc and err-endproc: stray E. and EN.. They check the native message and the cross position, so both compilers must agree.
  • All three fail on master and pass with this change.
  • The manual entry is now ENDPROC / EN., with a note on the IF case.

Thanks to Eric for the original idea, and to you for giving context (and for writing Fastbasic)!

🤖 Generated with Claude Code

https://claude.ai/code/session_01NASRhH2Xg6HmeBUZTSPhwM

"EN." is also an abbreviation of ENDIF, which is tried first: if there
is an IF open it closes the IF, as before, and if not, the parser now
tries ENDPROC.

The cross compiler already did this, as a loop error from ENDIF only
fails the current alternative. The native E_POP_IF now does the same:
when there is no IF or ELSE to close it fails, so the parser continues
with the next statements, and sets the error to report if none matches
to "bad loop". As errors are now reported after trying all the
alternatives, the column of these errors is the same in both compilers.

Costs 23 bytes in the native compilers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NASRhH2Xg6HmeBUZTSPhwM
The Windows fallback was a static "strndup", which conflicts with the
declaration in newer MinGW <string.h>, failing the Windows CI. Use
another name for it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NASRhH2Xg6HmeBUZTSPhwM
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants