Índice de entradas del conversor
Modificado el 12/03/2026, ampliaciones en color rojo
📘 Tabla de Contenidos
Gramática del ZX BASIC del Spectrum 48K
Esta entrada ofrece un resumen estructurado de la gramática del ZX BASIC del Sinclair ZX Spectrum 48K, basado en las referencias originales del manual oficial del Spectrum y las versiones digitalizadas del manual en español. nir lenguajes de programación: primero se presenta una versión ligera y, después, la definición formal completa.
- BNF/EBNF práctica, apta para implementar (recursive descent o LL(1) con pequeñas adaptaciones).
- Las restricciones del hardware (p. ej. rango de números de línea) se indican en comentarios
- Se prioriza claridad en la introducción; los detalles formales aparecen en el BNF completo final.
NOTA IMPORTANTE: Heredado de los ZX80/81 con solo 1Kb disponible, para ahorrar memoria todas las palabras clave se almacenan internamente como tokens de 1 byte (internamente ocupaban un solo caracter, aunque se presentaban en pantalla con los necesarios). Por tanto, toda sentencia debe comenzar obligatoriamente por un token de palabra clave. No puede comenzar por un identificador. LET es obligatorio siempre. REM solo se reconoce si es exactamente REM.
Hasta que no empecé el desarrollo y vi las pruebas no me di cuenta de esto, los cambios son mínimos pero importantes para definir correcta y compeltamente la gramática del programa y la generación de tokens.
1. Estructura de un programa
Un programa en ZX BASIC está compuesto por líneas numeradas:
<linea> ::= <numero> <espacio> <instruccion>
- Los números de línea van de 1 a 9999.
- Una línea puede contener una o varias instrucciones separadas por
:
2. Tipos de datos
2.1 Tipos básicos
- Números: coma flotante de 40 bits.
- Cadenas: delimitadas por comillas (
"texto"). - No existen enteros ni booleanos como tipos nativos; la lógica usa 0 para falso y <>0 para cierto
2.2 Nombres de variables
<var_num> ::= <letra> [ <letra_o_digito> ]
<var_str> ::= <letra> [ <letra_o_digito> ] "$"
<var_array> ::= <var> "(" <lista_expresiones> ")"
- Las variables numéricas y de cadena con el mismo nombre son distintas.
- Las matrices pueden ser numéricas o de cadena.
3. Expresiones
3.1 Expresiones numéricas
Precedencia de operadores (de mayor a menor):
- Unario:
- - Potencia:
^ - Multiplicación / División:
*/ - Suma / Resta:
+- - Relacionales:
=,<,>,<=,>=,<> - Lógicos:
AND,OR,NOT
Fuentes: capítulos 3, 7 y 13 del manual
3.2 Expresiones de cadena
- Concatenación:
"A" + "B". - Slicing:
A$(n TO m). - Longitud:
LEN A$.
Fuente: Capítulo 8 del manual
4. Sentencias
4.1 Asignación
<asignacion> ::= LET <var> = <expresion>
LET es obligatorio en el Spectrum 48K (no puede omitirse).
4.2 Entrada y salida
PRINTINPUTCLSTAB(n),AT y,x
Fuente: Capítulos 2 y 15.del manual
5. Control de flujo
5.1 IF
IF <expresión> THEN <instrucciones>
Ejecuta todas las instrucciones (separadas por :) hasta fin de línea.
No existe ELSE en el ZX Spectrum 48K.
5.2 Bucles FOR
FOR <var> = <expr> TO <expr> [STEP <expr>] ... NEXT <var>
Fuente: Capítulo 4 del manual
5.3 Subrutinas
GOSUB número RETURN
Fuente: Capítulo 5 del manual
5.4 Saltos
GO TOSTOPCONTINUE
6. Datos
READ <lista_variables> DATA <lista_constantes> RESTORE [número]
Fuente: Capítulo 6 del manual
7. Funciones incorporadas
Matemáticas
ABS, INT, SGN, SIN, COS, TAN, ASN, ACS, ATN, SQR, EXP, LN, PI …
Cadenas
LEN, STR$, VAL, CHR$, CODE
Sistema
PEEK, POKE, USR, IN, OUT, RND, RANDOMIZE
Fuente: Capítulos 9, 10, 11, 14 y 23 del manual
8. Arrays
DIM A(10) DIM N$(5)
- Índices desde 1 hasta el tamaño declarado (arrays base 1).
- Acceso:
A(1), A(5), N$(1)…
9. Gráficos
PLOT x,yDRAW dx,dyCIRCLE x,y,rPOINT x,y
Fuente: Capítulo 17 del manual
10. Colores
INK nPAPER nFLASH nBRIGHT nINVERSE nOVER nBORDER n
Fuente: Capítulo 16 del manual
11. Sonido
BEEP duracion, tono
Fuente: Capítulo 19 del manual
12. Cinta y ficheros
SAVELOADMERGEVERIFY
Fuente: Capítulo 20 del manual
13. Gramática mínima para transpiladores
<program> ::= { <line> }
<line> ::= <number> <Statement>
<Statement> ::= <SimpleStatement> { ":" <SimpleStatement> }
<SimpleStatement> ::= <assign>
| PRINT <print_list>
| INPUT <var_list>
| IF <expr> THEN <Statement>
| FOR <assign> TO <expr> ["STEP" <expr>]
| NEXT <var>
| GOSUB <number>
| RETURN
| GO TO <number>
| READ <var_list>
| DATA <const_list>
| DIM <dim_list>
| PLOT | DRAW | CIRCLE | POINT | ...
BNF del ZX BASIC del Spectrum 48K (versión corregida)
Esta gramática formal refleja el comportamiento real del tokenizador del ZX Spectrum 48K BASIC. Todas las sentencias deben comenzar por un token de palabra reservada (tal como ocurre en la ROM del 48K).
1) Léxico
letter = "A".."Z" | "a".."z"
digit = "0".."9"
alnum = letter | digit
numVar = letter , [ alnum ]
strVar = letter , [ alnum ] , "$"
var = numVar | strVar
intLiteral = digit , { digit }
fractPart = "." , { digit }
expPart = ("E" | "e") , [ "+" | "-" ] , digit , { digit }
numLiteral = intLiteral , [ fractPart ] , [ expPart ]
| fractPart , [ expPart ]
strLiteral = '"' , { charExceptQuote | '""' } , '"'
; REM solo se reconoce como palabra clave si el token es exactamente "REM".
; Identificadores como "REMA", "REM2", "REMXYZ" NO son REM, son variables.
; Un identificador NO puede iniciar una sentencia.
2) Estructura del programa
program = { line }
line = lineNumber , Statement
lineNumber = intLiteral (* 1..9999 *)
3) Statement y SimpleStatement
Statement = SimpleStatement , { ":" , SimpleStatement }
; CAMBIO: SimpleStatement debe comenzar por un token de palabra reservada siempre.
SimpleStatement =
letStmt
| printStmt
| inputStmt
| ifStmt
| forStmt
| nextStmt
| gotoStmt
| gosubStmt
| returnStmt
| stopStmt
| continueStmt
| readStmt
| dataStmt
| restoreStmt
| dimStmt
| clsStmt
| graphicStmt
| colorStmt
| soundStmt
| tapeStmt
| remStmt
; Una sentencia NO puede comenzar por un identificador.
; Ejemplos NO válidos: "REMA=4", "PRINTA", "IFX=3".
4) Expresiones
expr = logicOr
logicOr = logicAnd , { "OR" , logicAnd }
logicAnd = relation , { "AND" , relation }
relation = arithExpr , [ relOp , arithExpr ]
relOp = "=" | "<>" | "<" | ">" | "<=" | ">="
arithExpr = term , { ("+" | "-") , term }
term = power , { ("*" | "/") , power }
power = unary , { "^" , unary }
unary = [ "-" | "NOT" ] , primary
primary = numLiteral
| strLiteral
| varRef
| funcCall
| "(" , expr , ")"
5) Variables y arrays
varRef = arrayRef | var
arrayRef = ( numVar | strVar ) ,
"(" , indexExpr , { "," , indexExpr } , ")"
indexExpr = expr (* entero ≥ 1: arrays base 1 *)
6) Funciones
funcCall = funcNum | funcStr | sysFunc
funcNum = ("ABS" | "INT" | "SGN" | "SIN" | "COS" | "TAN"
| "ASN" | "ACS" | "ATN" | "SQR" | "EXP" | "LN"
| "VAL" | "PI")
"(" , [ expr ] , ")"
funcStr = "LEN" "(" , ( strVar | strLiteral ) , ")"
| "STR$" "(" , expr , ")"
| "CHR$" "(" , expr , ")"
sysFunc = "PEEK" "(" , expr , ")"
| "USR" "(" , expr , ")"
| "CODE" "(" , (strVar | strLiteral) , ")"
7) Sentencias (SimpleStatement)
letStmt = "LET" , ( varRef | var ) , "=" , expr
; LET es obligatorio. No existe la forma <var> "=" expr
remStmt = "REM" , { ? cualquier carácter hasta fin de línea ? }
printStmt = "PRINT" , [ printList ]
printList = printItem , { ("," | ";") , printItem }
printItem = expr
| "TAB" "(" , expr , ")"
| "AT" expr "," expr
inputStmt = "INPUT" , varList
varList = varRef , { "," , varRef }
ifStmt = "IF" , expr , "THEN" , Statement (* sin ELSE en 48K *)
forStmt = "FOR" , numVar , "=" , expr ,
"TO" , expr ,
[ "STEP" , expr ]
nextStmt = "NEXT" , [ numVar ]
gotoStmt = ("GOTO" | "GO TO") , lineNumber
gosubStmt = ("GOSUB" | "GO SUB") , lineNumber
returnStmt = "RETURN"
stopStmt = "STOP"
continueStmt = "CONTINUE"
readStmt = "READ" , varList
dataStmt = "DATA" , constList
constList = constItem , { "," , constItem }
constItem = numLiteral | strLiteral
restoreStmt = "RESTORE" , [ lineNumber ]
dimStmt = "DIM" , dimList
dimList = dimItem , { "," , dimItem }
dimItem = ( numVar | strVar ) ,
"(" , sizeExpr , { "," , sizeExpr } , ")"
sizeExpr = expr
clsStmt = "CLS"
graphicStmt = plotStmt | drawStmt | circleStmt | pointStmt
plotStmt = "PLOT" , expr , "," , expr
drawStmt = "DRAW" , expr , "," , expr
circleStmt = "CIRCLE" , expr , "," , expr , "," , expr
pointStmt = "POINT" , expr , "," , expr
colorStmt = ("INK" | "PAPER" | "FLASH" | "BRIGHT"
| "INVERSE" | "OVER" | "BORDER") , expr
soundStmt = "BEEP" , expr , "," , expr
tapeStmt = ("SAVE" | "LOAD" | "VERIFY" | "MERGE") , strLiteral
Referencias
- Manual canónico (World of Spectrum) — Índice completo del ZX Spectrum BASIC Programming Manual (Sinclair/Amstrad). https://worldofspectrum.org/ZXBasicManual/
- World of Spectrum — Capítulo 13: Conditions — Operadores lógicos y prioridad (AND/OR/NOT, relacionales). https://worldofspectrum.org/ZXBasicManual/zxmanchap13.html
-
Introducción Sinclair (Statement LET) — Documento donde se especifica que en 48K
LETno puede omitirse en las asignaciones. https://worldofspectrum.org/ZXSpectrumIntroduction/chapter_five.html - Manual de Investrónica (español) — Edición en HTML con capítulos de cadenas, matrices, gráficos y colores (útil para consultas rápidas en español). https://manuales.speccy.org/basic_gomas/
No hay comentarios:
Publicar un comentario