TODO SOBRE CHR$ Y LA VERSION ASCII DEL ZX SPECTRUM. - ó de teclas y colores va la cosa. Estaba recientemente revisando el foro de WOS, cuando me topé con un viejo post en el que se preguntaban qué hacían los códigos del 0 al 31 y yo decidí poner mi pequeño grano de arena al respecto, según las anotaciones que yo había hecho. Pero admito que era demasiado conciso, así que releerlo me decidió a volver a publicarlo pero con mayores notas aclaratorias sobre lo que esos códigos hacen y como utilizarlos. De paso, repaso un poco la historia de los códigos ASCII, para pasar luego a hacer su comparación con los códigos elegidos para el Spectrum, así como las funciones asociadas a ellos. EL CODIGO ASCII El código ASCII (siglas en ingles para "American Standard Code for Information Interchange", es decir "Código Norte Americano Estándar para el intercambio de Información" y se pronuncia Aski, basado en el alfabeto latino, tal como se usa en inglés moderno. Creado en 1963, nació a partir de reordenar y expandir el conjunto de símbolos y caracteres ya utilizados en aquel momento en telegrafía por la compañía Bell. Al principio constaba de mayúsculas y números, pero en 1967 se agregaron las minúsculas y algunos caracteres de control, formando así lo que se conoce como US-ASCII, es decir los caracteres del 0 al 127. En 1981, IBM desarrolló una versión en la que reemplazaron algunos caracteres de control obsoletos, por caracteres gráficos. Además incorporaron 128 caracteres nuevos, con símbolos, signos, gráficos adicionales del 128 al 255. Curiosamente algunos de los fabricantes de micro ordenadores eligieron usar su propio juego de caracteres no estandar como es el caso de Commodore o Atari, quienes crearon cada uno por su cuenta, el PETSCII para su líea CBM PET el primero y ATASCII el último para sus 8 bits. Otro caso fue el del ZX80 y 81 de Sinclair que usan un juego de caracteres muy particular. CC Communication Control (control de comunicación) FE Format Effector (manipulador de formato) IS Information Separator (separador de información) ASCII Símbolo Tipo Descripción 0 NUL Null (nulo) 1 SOH CC Start of Heading (inicio de cabecera) 2 STX CC Start of Text (inicio de texto) 3 ETX CC End of Text (fin de texto) 4 EOT CC End of Transmission (fin de transmisión) 5 ENQ CC Enquiry (solicitud de información) 6 ACK CC Acknowledge (confirmación) 7 BEL Bell (señal audible / tono de atención) 8 BS FE Backspace (retroceso) 9 TAB FE Horizontal Tabulation (tabulado horizontal) 10 LF FE Line Feed (avance de línea) 11 VT FE Vertical Tabulation (tabulado vertical) 12 FF FE Form Feed (avance de página) 13 CR FE Carriage Return (Retorno de carro, iniciar nueva línea) 14 SO Shift Out (terminar modo mayúsculas) 15 SI Shift In (iniciar modo mayúsculas) 16 DLE CC Data Link Escape (escape del enlace de datos) 17 DC1 Device Control 1 (control de dispositivo 1) 18 DC2 Device Control 2 (control de dispositivo 2) 19 DC3 Device Control 3 (control de dispositivo 3) 20 DC4 Device Control 4 (control de dispositivo 4) 21 NAK CC Negative Acknowledge (confirmación negativa) 22 SYN CC Synchronous Idle (sincronización de la comunicación) 23 ETB CC End of Transmission Block (fin de bloque de transmisión) 24 CAN Cancel (cancelar) 25 EM End of Medium (fin del medio. Cinta/disco/papel) 26 SUB Substitute (reemplazar) 27 ESC Escape 28 FS IS File Separator (separador de archivos) 29 GS IS Group Separator (separador de grupo) 30 RS IS Record Separator (separador de registro) 31 US IS Unit Separator (separador de unidad) 32 SPC espacio 33 - 126 caracteres, dígitos y símbolos 127 DEL Delete (Borrar) 128 - 255 varía según el sistema o micro Como se puede ver por las funciones de cada código de control, estas fueron pensadas no para la pantalla, sino para el manejo de teletipos y luego con impresoras, todas manejadas mediante terminales. Funciones relacionadas con el ASCII No habían funciones de cadena en las primeras versiones de Basic, estas aparecerían a partir de la 5 edición del Basic Darmouth en 1969. Para manejar los códigos ASCII tenemos los sigtes.: CHR$ sintaxis: CHR$(n) donde n = un valor entero de 0 a 255 permite generar caracteres alfanuméricos correspondientes al código dado en su único parámetro. ASC sintaxis: ASC(a$) convierte la primera letra o caracter de una cadena en su valor numérico correspondiente con el código ASCII. En el Spectrum CHR$ sintaxis: CHR$ n ninguna diferencia con su contraparte en el BASIC estandar. CODE sintaxis: CODE a$ operando con cadenas hace lo mismo que la función ASC de otros BASICs. EL SET DE CARACTERES DEL SPECTRUM Lo que nos muestra el manual del Spectrum en su apendice A: el juego de caracteres, en la pag. 183: Chr$ caracter ----- ---------- 0 \ 1 | 2 |__ no utilizados 3 | 4 | 5 / 6 PRINT coma 7 EDIT 8 Cursor izquierda 9 cur. derecha 10 cur. abajo 11 cur. arriba 12 DELETE 13 ENTER 14 Número 15 --- No utilizado 16 INK control 17 PAPER " 18 FLASH " 19 BRIGHT " 20 INVERSE " 21 OVER " 22 AT " 23 TAB " 24 \ 25 | 26 | 27 |__ no utilizados 28 | 29 | 30 | 31 / 32 SPACE 33 - 126 caracteres, dígitos y símbolos 127 (C) 128 - 143 gráficos del modo G 144 - 164 UDGs 165 - 255 tokens (palabras reservadas del Basic) Los códigos del 0 al 31 no pueden ser impresos, así que de intentarlo dará un signo '?' o un error de código, deteníendo cualquier programa en ejecución. Luego notamos que solo CHR$ 13 se mantiene estandar y que los códigos del 8 al 11 hacen algo aproximado a los del ASCII original. PARA LO QUE SI SIRVEN REALMENTE A pesar de que en el manual del Spectrum, los códigos del 0 al 5, el 15 y del 24 al 31 son considerados "no utilizados", vamos a ver a continuación que eso no es del todo cierto. (Lo que sigue es lo que postee originalmente en el WOS) Chr$ 0 - 3 = no utilizables por el usuario: 0 = Flash 0 (video normal) - parpadeo apagado 1 = flash 1 - parp. encendido 2 = Bright 0 (video normal) - brillo apagado 3 = bright 1 - brillo activado Chr$ 4 = True video (CS + 4) Inverse 0 - video normal Chr$ 5 = Inv. video (CS + 3) Inverse 1 Chr$ 6 = imprime coma (CAPS LOCK = CS + 2) Chr$ 7 = Edit (CS + 1) Chr$ 8 = Cursor izquierda (CS + 5) Chr$ 9 = " derecha (CS + 8) Chr$ 10 = " abajo (CS + 6) Chr$ 11 = " arriba (CS + 7) Chr$ 12 = Delete (CS + 0) Chr$ 13 = Enter / CR Chr$ 14 = Número; (CS + SS) Modo EXT Chr$ 15 = Graph (CS + 9) Chr$ 16 = Ink , 0 - 9 Chr$ 17 = Paper , 0 - 9 Chr$ 18 = Flash , 0 - 1 Chr$ 19 = Bright , 0 - 1 Chr$ 20 = Inverse , 0 - 1 Chr$ 21 = Over , 0 - 1 Chr$ 22 = At , y, x Chr$ 23 = Tab ,x Chr$ 24 - Chr$ 31 = colores - uso interno: 24 = black 25 = blue 26 = red 27 = magenta 28 = green 29 = cyan 30 = yellow 31 = white Para las sigtes. notas aclaratorias voy a usar la sigtes. definiciones: I - in (entrada o lectura) generalmente con INKEY$ O - out (salida o escritura) normalmente con PRINT Y ahora sí, vamos a expandir más la información y ver esos códigos con mayor detenimiento: CHR$ 0 O - permite salvar un fichero ocultando el nombre Un truco muy usado en nombres de fichero con Microdrives y Opus Discovery. Ejemplo: SAVE *"m";1;CHR$ 0+"nombre" - atributo de fichero invisible Nota curiosa: CODE "" devuelve cero en referencia a NULL, pero CHR$ 0 da '?'. CHR$ 1 - 3 no usados - uso interno o posible lectura de existir teclas asociadas a ellas Todas imprimen '?' en pantalla. CHR$ 4 I - lee del teclado si se pulsó la tecla TR.VIDEO CHR$ 5 I - lee del teclado si se pulsó INV.VIDEO CHR$ 6 I - lee del teclado si se pulsó CAPS LOCK O - hace el efecto de "PRINT ," (efecto de tecla TAB de otros micros) CHR$ 7 I - lee del teclado si se pulsó EDIT O - nada, solo ?. En otros BASICs generaría un pitido. CHR$ 8 I - lee del teclado si se pulsó el cursor izquierda O - retrocede el cursor sin borrar CHR$ 9 I - lee del teclado si se pulsó el cursor derecho O - '?' o sea nada. Debería avanzar el cursor (**) CHR$ 10 I - lee del teclado si se pulsó el cursor abajo O - '?'. Debería descender el cursor (**) CHR$ 11 I - lee del teclado si se pulsó el cursor arriba O - '?'. Debería subir el cursor (**) CHR$ 12 I - lee del teclado si se pulsó DELETE O - '?'. Debería retrocer el cursor pero borrando CHR$ 13 I - lee del teclado si se pulsó ENTER O - imprime o salta a una nueva línea en pantalla CHR$ 14 I - lee del teclado si se pulsó EXTENDED MODE (tecla de modo extendido) internamente es el código de número ingresado en un listado como bytes. Ejemplo: 20 LET A=2 - se convierte en la RAM en los códigos 0 20 11 0 241 65 61 50 14 0 0 2 0 0 13 - en este caso se pùede leer mediante PEEKs. CHR$ 15 I - lee del teclado si se pulsó GRAPH (tecla gráficos) CHR$ 16 O - CHR$ 16 + CHR$ ink; imprime en tinta temporal un texto (*) CHR$ 17 O - CHR$ 17 + CHR$ paper; imprime en papel temporal un texto (*) CHR$ 18 O - CHR$ 18 + CHR$ flash; imprime con parpadeo temporal un texto (*) CHR$ 19 O - CHR$ 19 + CHR$ bright; imprime con brillo temporal un texto (*) CHR$ 20 O - CHR$ 20 + CHR$ inv; imprime en inversa temporal un texto (*) CHR$ 21 O - CHR$ 21 + CHR$ over; imprime con efecto over temporal un texto (*) CHR$ 22 O - CHR$ 22 + CHR$ y + CHR$ x; imprime texto como AT y,x; (*) CHR$ 23 O - CHR$ 23 + CHR$ n; imprime texto como TAB n; (*) CHR$ 24 - 31 son usados internamente para almacenar los colores temporales de CHR$ 17 y 18 CHR$ 27 O - envía ESC solamente cuando hay impresoras conectadas a una interfaz plenamente configurada para ello. Rutina para leer dichos códigos del teclado: 10 PRINT AT 5,5; CODE INKEY$;" " 20 GOTO 10 Para leerlos de una cadena: 30 LET a$= CHR$ 17+ CHR$ 2+"hola mundo" 40 PRINT a$' CODE a$(1) En suma: en situaciones normales, los códigos del 4 al 15 leen del teclado, mientras del 16 al 23 son para el manejo de la impresión en pantalla. (*) pueden leerse si son insertados en variables de cadena con LET, READ o INPUT. Los códigos 8 y del 16 al 21 pueden también ser usados como parte de nombres de archivos Microdrive. Ejemplo: SAVE "m";1;CHR$ 17+CHR$ 1+"nombre" el color también puede ser ingresado al nombre directamente en modo EXTendido. El objetivo es tener varios ficheros con el mismo nombre pero variando solo el atributo de color a falta o en lugar del uso de extensión. Lo mismo con los listados BASIC. Pueden usarse para diferenciar bloques o sólo resaltar algunas líneas. Incluso hacer que no se puedan ver con LIST. En cuanto al uso de tokens como parte de un nombre solamente tendrían sentido aquellos que indiquen algo relacionado al tipo de fichero. Por ejemplo, BIN o CODE para ficheros de código máquina, SCREEN$ para pantallas, DATA para matrices, también pueden ser usados VAL, VAL$, CHR$ y STR$ para designar textos o cadenas. Ejemplo: SAVE "matriz STR$ " DATA a$() (**) no funcionan debido a fallos en la ROM del Spectrum. Algunas extensiones al BASICs como BetaBasic, o ROMS modificadas han corregido dichos fallos. Como ya se dijo, la mayoría de los códigos de control son para impresión en pantalla, otros son solamente para lectura mediante el teclado, y unos cuantos son usados en nombres de ficheros con fines diversos. Con la única excepción de aquellos sistemas de disco con nombres y extensión tipo CP/M como son Timex FDD y el +3. Otro posible uso es elegirlos para códigos de nuevos tokens y así ampliar el BASIC del Spectrum, como por ejemplo, los códigos del 1 al 3 que aparentemente están libres. Un caso es el de TIMEX que usó un código para redirigir a una segunda tabla de tokens, expandiendo así el set de comandos del BASIC. Lo curioso es que algunos códigos como 4, 5 y 15 hayan sido etiquetados como no utilizados y sin embargo, vemos que estos (si no todos) sí pueden ser usados por el usuario. (c)2020 zx_if1@hotmail.com