CP-1610 machine code (Intellivision), 23 22 DECLEs1 ≈ 28 bytes
As per the exception described in this meta answer, the exact score is 27.5 bytes (220 bits)
A routine taking a null-terminated string as an inline argument through R4 and returning the result in R1.
2B9 001 | MVII #1, R1
2A0 | @@read MVI@ R4, R0
080 | TSTR R0
204 00F | BEQ @@rtn
378 05B | CMPI #'[', R0
22C 007 | BNEQ @@read
2A0 | MVI@ R4, R0
00C | INCR R4
320 | SUB@ R4, R0
020 | NEGR R0
008 | INCR R0
004 11C 1DC | CALL MULT
091 | MOVR R2, R1
220 012 | B @@read
0A7 | @@rtn JR R4
A note about subroutine calls
The CP-1610 instruction for calling subroutines is JSR Rx, $address
. This instruction saves the return address in Rx
instead of pushing it on the stack as many other CPUs do.
This allows to pass a block of arguments that immediately follows the function call. This is a common practice in CP-1610 programming and that's what we use here.
JSR R4, count ; call to subroutine through R4
STRING "[*-0]", 0 ; argument
... ; we will return here
Obviously, the subroutine is responsible for reading the correct number of arguments and eventually jumping to the expected return address.
Full commented test code
ROMW 10 ; use 10-bit ROM width
ORG $4800 ; map this program at $4800
PNUM QEQU $18C5 ; EXEC routine: print a number
MULT QEQU $1DDC ; EXEC routine: signed multiplication
;; ------------------------------------------------------------- ;;
;; main code ;;
;; ------------------------------------------------------------- ;;
main PROC
SDBD ; set up an interrupt service routine
MVII #isr, R0 ; to do some minimal STIC initialization
MVO R0, $100
SWAP R0
MVO R0, $101
EIS ; enable interrupts
MVII #$200, R3 ; R3 = backtab pointer
JSR R4, count ; test cases
STRING "", 0
CALL print
JSR R4, count
STRING "a", 0
CALL print
JSR R4, count
STRING "[*-0]", 0
CALL print
JSR R4, count
STRING "[0-9][0-9]", 0
CALL print
JSR R4, count
STRING "[a-z]d[A-z]", 0
CALL print
JSR R4, count
STRING "[<->]", 0
CALL print
JSR R4, count
STRING "[!-&]", 0
CALL print
JSR R4, count
STRING "[d-z]abf[d-z]fg", 0
CALL print
JSR R4, count
STRING "[[-]]", 0
CALL print
JSR R4, count
STRING "[a-a][b-b]cde[---]", 0
CALL print
JSR R4, count
STRING "[0-1][0-1][0-1][0-1][0-1][0-1][0-1][0-1][0-1][0-1][0-1][0-1]", 0
CALL print
JSR R4, count
STRING "[--[][--]]", 0
CALL print
JSR R4, count
STRING "[[-[].[]-]]", 0
CALL print
DECR R7 ; done: loop forever
ENDP
;; ------------------------------------------------------------- ;;
;; prints the result of a test case ;;
;; ------------------------------------------------------------- ;;
print PROC
PSHR R5 ; save the return address on the stack
MOVR R1, R0 ; R0 = number to print
MVII #4, R1 ; R1 = number of digits
MOVR R3, R4 ; R4 = backtab pointer
ADDI #5, R3 ; advance by 5 characters for the next one
PSHR R3 ; save R3
CLRR R3 ; R3 = attributes (black)
CALL PNUM ; invoke the EXEC routine
PULR R3 ; restore R3
PULR R7 ; return
ENDP
;; ------------------------------------------------------------- ;;
;; ISR ;;
;; ------------------------------------------------------------- ;;
isr PROC
MVO R0, $0020 ; enable display
CLRR R0
MVO R0, $0030 ; no horizontal delay
MVO R0, $0031 ; no vertical delay
MVO R0, $0032 ; no border extension
MVII #$D, R0
MVO R0, $0028 ; light-blue background
MVO R0, $002C ; light-blue border
JR R5 ; return from ISR
ENDP
;; ------------------------------------------------------------- ;;
;; our routine ;;
;; ------------------------------------------------------------- ;;
count PROC
MVII #1, R1 ; initialize R1 to 1
@@read MVI@ R4, R0 ; R0 = current character
TSTR R0 ; end of string?
BEQ @@rtn ; if yes, return
CMPI #'[', R0 ; is this a '['?
BNEQ @@read ; if not, just go on with the next character
MVI@ R4, R0 ; R0 = ASCII code of the starting character
INCR R4 ; skip the '-'
SUB@ R4, R0 ; subtract the ASCII code of the ending character
NEGR R0 ; negate
INCR R0 ; increment
CALL MULT ; compute R2 = R0 * R1
MOVR R2, R1 ; and save the result in R1
B @@read ; go on with the next character
@@rtn JR R4 ; return
ENDP
Output

screenshot from jzIntv
1. A CP-1610 opcode is encoded with a 10-bit value (0x000 to 0x3FF), known as a 'DECLE'.