Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -1383,12 +1383,17 @@ Control Statements

**Define A Subroutine.**
**PROC _name_ _var1_ .../ PR.**
**ENDPROC / ENDP.**
**ENDPROC / EN.**

`PROC` statement starts the
definition of a subroutine that can
be called via `EXEC` or `@`.

`EN.` is also an abbreviation of
`ENDIF`: if there is an `IF` open,
`EN.` closes the `IF`, if not, it
closes the `PROC`.

You can pass a list of integer
variables separated by spaces after
the `PROC` name to specify a number
Expand Down
20 changes: 19 additions & 1 deletion src/actions.asm
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
; From parser.asm
.import parser_error, parser_skipws, parser_emit_byte, parser_inc_opos
; From error.asm
.importzp ERR_LOOP
.importzp ERR_LOOP, parse_err

.ifdef FASTBASIC_FP
; Exported only in Floating Point version
Expand Down Expand Up @@ -801,6 +801,24 @@ move:
.endproc

.proc E_POP_IF
; Check that there is an IF or ELSE to close. If not, don't give the
; error now: fail, so the parser tries the next statements (ENDIF and
; ENDPROC share the "EN." abbreviation), and report a loop error only
; if none matches. The cross compiler does the same.
ldy loop_sp
beq no_if
lda loop_stk-3, y
.assert LT_ELSE = LT_IF + 1, error, "LT_ELSE must be LT_IF + 1"
; C=0 on entry, so this is A - LT_IF: 0 for IF, 1 for ELSE
sbc #LT_IF-1
cmp #2
bcc is_if
no_if:
lda #ERR_LOOP
sta parse_err
sec
rts
is_if:
; Patch IF/ELSE with current position
lda #LT_ELSE
check_elif:
Expand Down
7 changes: 5 additions & 2 deletions src/parse.asm
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
.export parser_start, parser_error, parser_skipws, parser_emit_byte, parser_inc_opos
; Parser state
.exportzp bptr, bpos, bmax, linenum, buf_ptr
.exportzp loop_sp, var_sp
.exportzp loop_sp, var_sp, parse_err
; Output state
.exportzp opos
; From actions.asm
Expand Down Expand Up @@ -51,6 +51,7 @@
buf_ptr:.res 2
bmax: .res 1
pptr: .res 2
parse_err: .res 1 ; Error to report if the statement does not parse

; This variables are cleared in one loop:
zp_clear_start:
Expand Down Expand Up @@ -260,6 +261,8 @@ ucase_end:
lda #0
parse_start:
; Parse statement, A=0 on input
ldx #ERR_PARSE
stx parse_err
ldx #<(PARSE_START-1)
ldy #>(PARSE_START-1)

Expand Down Expand Up @@ -449,7 +452,7 @@ go_ploop:
: jmp ploop_line

set_parse_error:
ldy #ERR_PARSE
ldy parse_err
jmp parser_error

; vi:syntax=asm_ca65
2 changes: 1 addition & 1 deletion src/syntax/basic.syn
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ STATEMENT: statement
"INC" VAR_WORD_LVALUE_SADDR emit TOK_INC
"DEc" VAR_WORD_LVALUE_SADDR emit TOK_DEC
"PRoc" E_LABEL_CREATE emit { TOK_JUMP } E_LABEL_DEF emit LT_PROC_2 E_PUSH_LT OPT_PROC_VAR
"ENDProc" E_POP_PROC_2 emit TOK_RET E_POP_PROC_DATA
"ENdproc" E_POP_PROC_2 emit TOK_RET E_POP_PROC_DATA
EXEC_CALL E_LABEL_CREATE OPT_EXEC_PARAM emit { TOK_CALL } E_DO_EXEC
"DAta" DATA_VAR DATA_END
"END" emit TOK_END
Expand Down
8 changes: 5 additions & 3 deletions testsuite/src/fbtest.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,16 @@

#ifdef _WIN32
# define PATH_SEP "\\"
// Implement missing "strndup"
static char *strndup(const char *s, size_t n)
// Implement "strndup", missing in older MinGW versions. Use another name, as
// newer MinGW versions declare it in <string.h>.
static char *fbtest_strndup(const char *s, size_t n)
{
char *ret = malloc(n + 1);
strncpy(ret, s, n);
ret[n] = 0;
return ret;
};
}
# define strndup fbtest_strndup
#else
# define PATH_SEP "/"
#endif
Expand Down
4 changes: 4 additions & 0 deletions testsuite/tests/err-endif-proc.bas
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
' ENDIF without IF inside a PROC
PROC P
E.
ENDPROC
4 changes: 4 additions & 0 deletions testsuite/tests/err-endif-proc.chk
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Name: Check detection of ENDIF without IF inside PROC
Test: compile-error
Error: bad loop at line 3 column 4
Error-pos: 3:4
3 changes: 3 additions & 0 deletions testsuite/tests/err-endproc.bas
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
' ENDPROC without PROC, abbreviated
? 1
EN.
4 changes: 4 additions & 0 deletions testsuite/tests/err-endproc.chk
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Name: Check detection of ENDPROC without PROC
Test: compile-error
Error: bad loop at line 3 column 3
Error-pos: 3:3
34 changes: 34 additions & 0 deletions testsuite/tests/proc-abbrev.bas
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
' Test abbreviations of ENDPROC and ENDIF
PROC P1 X
IF X > 1
? "BIG ";
EN.
? X
EN.
PROC P2 X
IF X = 1
? "ONE"
ELIF X = 2
? "TWO"
ELSE
? "MANY"
E.
END.
PROC P3 X
DO
IF X > 2 THEN EXIT
INC X
LOOP
IF X = 3
? "THREE"
ENDI.
ENDP.
PROC P4:? "P4":EN.
? "Start"
@P1 1:@P1 5
@P2 1:@P2 2:@P2 3
@P3 0
@P4
IF 1
? "IF"
EN.
12 changes: 12 additions & 0 deletions testsuite/tests/proc-abbrev.chk
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Name: Test abbreviations of ENDPROC and ENDIF
Test: run
Output:
Start
1
BIG 5
ONE
TWO
MANY
THREE
P4
IF
Loading