{"id":208,"date":"2022-07-30T12:04:02","date_gmt":"2022-07-30T11:04:02","guid":{"rendered":"https:\/\/specnext.dev\/es\/?p=208"},"modified":"2022-07-30T12:04:02","modified_gmt":"2022-07-30T11:04:02","slug":"de-sinclair-zx-basic-a-boriel-zx-basic","status":"publish","type":"post","link":"https:\/\/specnext.dev\/es\/2022\/07\/30\/de-sinclair-zx-basic-a-boriel-zx-basic\/","title":{"rendered":"De Sinclair ZX Basic a Boriel ZX Basic"},"content":{"rendered":"<p>En este art\u00edculo explicaremos una serie de conceptos de Boriel ZX Basic, orientados a los programadores que vienen del cl\u00e1sico Sinclair ZX Basic, y que quieren empezar a programar en Boriel ZX Basic. Y ya que estamos, aunque los conceptos sirven para el ZX Spectrum cl\u00e1sico, nos enfocaremos m\u00e1s hacia el Sinclair ZX Spectrum Next.<br \/>\nNo se puede resumir ni explicar todo en un simple art\u00edculo, y tampoco es un camino que se recorra en 2 minutos, as\u00ed que en este texto explicaremos conceptos gen\u00e9ricos sin entrar en excesivos detalles ni cuestiones avanzadas.<\/p>\n<p>Para seguir los pasos de este art\u00edculo, es mejor tener preparado el ambiente de programaci\u00f3n NextBuild, que explicamos en el post \u201c<a href=\"https:\/\/specnext.dev\/es\/2022\/07\/28\/preparando-el-ambiente-para-programar-para-next-con-boriel-zx-basic-y-nextbuild\/\">Preparando el ambiente para programar para Next con Boriel ZX Basic y NextBuild<\/a>\u201d.<\/p>\n<p>Para probar los ejemplos, crearemos una carpeta \u201cTest\u201d dentro de \u201cC:\\ZXNext\\NextBuildv7\\Sources\\\u201d. Una vez creada esa carpeta, podemos crear un archivo \u201cTest1.bas\u201d, por ejemplo, e ir haciendo las pruebas en \u00e9l.<\/p>\n<p>&nbsp;<\/p>\n<h1>\u00bfPero que me aporta Boriel ZX Basic?<\/h1>\n<p>Esta es la primera pregunta que se suelen hacer los programadores al o\u00edr hablar de Boriel ZX Basic (Boriel de aqu\u00ed en adelante). Y la respuesta no es sencilla, no por ser complicado explicar que aporta, sino porqu\u00e9 es una respuesta larga:<\/p>\n<ul>\n<li><strong>Compila el c\u00f3digo:<\/strong> Boriel es un compilador, lo que significa que Boriel \u201cconvierte\u201d nuestro c\u00f3digo BASIC a c\u00f3digo m\u00e1quina. Sinclair ZX BASIC es un lenguaje interpretado, lo que significa que cada vez que se va a ejecutar un comando, la ROM lo tiene que leer, decodificar y ejecutar. En cambio, el c\u00f3digo compilado se ejecuta mucho m\u00e1s r\u00e1pido.<\/li>\n<li><strong>Optimiza el c\u00f3digo:<\/strong> Boriel es capaz de, una vez compilado nuestro c\u00f3digo, optimizarlo para que a\u00fan sea m\u00e1s r\u00e1pido y ocupe menos memoria. Por ejemplo, la mayor\u00eda de las operaciones matem\u00e1ticas son m\u00e1s r\u00e1pidas, CIRCLE corre m\u00e1s, PRINT vuela, y as\u00ed un largo etc\u00e9tera. Otro aspecto importante, es que el c\u00f3digo que no se ejecuta nunca, es eliminado, reduciendo la memoria utilizada.<\/li>\n<li><strong>Incorpora mejoras del lenguaje:<\/strong> Boriel a\u00f1ade caracter\u00edsticas de los lenguajes modernos, como el C o el Visual Basic, incluso permite el uso de assembler y permite una interacci\u00f3n sencilla entre este y Boriel, por ejemplo, facilitando el acceso a las variables de BASIC desde assembler.<\/li>\n<li><strong>Permite estructurar el c\u00f3digo:<\/strong> La estructuraci\u00f3n de c\u00f3digo hace que este sea m\u00e1s sencillo de leer, y al mismo tiempo de reutilizable en otros proyectos.<\/li>\n<li><strong>Rompe la barrera del assembler:<\/strong> Muchos de nosotros, o al menos yo, nos encontramos con la barrera de la velocidad. Los juegos en BASIC eran lentos y el assembler era muy complicado. Boriel permite ir integrando el assembler en nuestros programas de forma gradual y muy natural.<\/li>\n<li><strong>Soporte:<\/strong> El canal de Telegram de \u201cBoriel ZX Basic\u201d o el <a href=\"https:\/\/www.boriel.com\/mybb\/forumdisplay.php?fid=11\">foro de Boriel<\/a>\u00a0son muy activos, y el creador del compilador \u201cBoriel\u201d, se pasa por esos canales bastante a menudo.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h1>Diferencias entre Sinclair ZX Basic y Boriel ZX Basic<\/h1>\n<p>Boriel es compatible al 95% con Sinclair ZX Basic. En el siguiente listado podemos ver las principales diferencias:<\/p>\n<p>&nbsp;<\/p>\n<h2>N\u00fameros de l\u00ednea<\/h2>\n<p>En Boriel son opcionales, es decir, no hace falta poner n\u00fameros de l\u00ednea, lo que supone un problema menos al no tener que preocuparlos por la numeraci\u00f3n o el l\u00edmite de 9999 l\u00edneas.<\/p>\n<p><code>10 BORDER 0: PAPER 0: INK 6: CLS<\/code><br \/>\n<code>20 FOR N=0 TO 20<br \/>\n<\/code><code>30 PRINT N<\/code><br \/>\n<code>40 NEXT N<\/code><\/p>\n<p>Esto se traduce como:<\/p>\n<p><code>BORDER 0: PAPER 0: INK 6: CLS<\/code><br \/>\n<code>FOR N=0 TO 20<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0PRINT N<\/code><br \/>\n<code>NEXT N<\/code><\/p>\n<p>Fijaos que el PRINT lo separamos con un tabulador delante, lo que hace que el c\u00f3digo sea m\u00e1s f\u00e1cil de leer.<\/p>\n<p>&nbsp;<\/p>\n<h2>Etiquetas<\/h2>\n<p>Este mecanismo de Boriel, es el que nos permite eliminar los n\u00fameros de l\u00ednea. En vez de usar \u201cGO TO 1000\u201d o \u201cGO SUB 1000\u201d podemos usar \u201cGO TO MiEtiqueta\u201d o \u201cGO SUB MiEtiqueta\u201d, y en vez de la l\u00ednea 1000 ponemos \u201cMiEtiqueta:\u201d<\/p>\n<p><code>10 LET A=0<\/code><br \/>\n<code>20 LET A=A+1<\/code><br \/>\n<code>30 PRINT AT 0,0;A<\/code><br \/>\n<code>40 IF A&lt;100 THEN GOTO 20<\/code><br \/>\n<code>50 PRINT \"FIN\"<\/code><\/p>\n<p>Se puede escribir como:<br \/>\n<code>LET A=0<\/code><br \/>\n<code>Bucle:<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0LET A=A+1<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0PRINT AT 0,0;A<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0IF A&lt;100 THEN GOTO Bucle<\/code><br \/>\n<code>PRINT \"FIN\"<\/code><\/p>\n<p>&nbsp;<\/p>\n<h2>Saltos calculados<\/h2>\n<p>Boriel no permite saltos del tipo \u201cGO TO 1000+variable\u201d o \u201cGO TO variable\u201d. En este caso hay que cambiar un poco el concepto o usar tablas de salto con el comando \u201cON GOTO\u201d u \u201cON GOSUB\u201d, por ejemplo: \u201cON variable GOTO 1000,1100,1200\u201d saltar\u00e1 a la l\u00ednea 1000 si variable vale 0, a 1100 si vale 1, a 1200 si vale 2, y no saltar\u00e1 si tiene cualquier otro valor.<\/p>\n<p><code>10 GOTO 1000+(variable*100)<\/code><\/p>\n<p>Ese traduce como:<\/p>\n<p><code>ON variable GOTO 1000,1100,1200<\/code><\/p>\n<p>&nbsp;<\/p>\n<h2>Base de las matrices (arrays)<\/h2>\n<p>Aunque el par\u00e1metro \u201c&#8211;sinclair\u00bb de Boriel, cambia este comportamiento, por defecto, los \u00edndices de arrays \u201cDIM a(100)\u201d empiezan en 0 en Boriel, mientras que en Sinclair ZX Basic empiezan en 1. Esto implica que este \u201cDIM a(100)\u201d en Boriel tendr\u00e1 101 elementos (del 0 a 100), mientras que en Sinclair ZX Basic solo tendr\u00e1 100 (del 1 al 100).<\/p>\n<p>Esta base 0 tambi\u00e9n se aplica a operador \u201cTO\u201d en operaciones con cadenas:<\/p>\n<p><code>LET A$=\"12345\"<\/code><br \/>\n<code>PRINT A$(1 TO 4)<\/code><\/p>\n<p>En Sinclair ZX Basic imprimir\u00e1 \u201c1234\u201d, mientras que en Boriel se mostrar\u00e1 \u201c2345\u201d.<\/p>\n<p>Todo este comportamiento se puede modificar con los par\u00e1metros \u201c&#8211;sinclair\u00bb, \u201c&#8211;array-base\u00bb y \u201c&#8211;string-base\u201d, pero lo m\u00e1s normal es acostumbrarse a usar el 0 como elemento base.<\/p>\n<p>&nbsp;<\/p>\n<h2>Variables de cadena sin $<\/h2>\n<p>El uso de $ para referirnos a una variable de texto ya no es necesario, es decir, podemos usar a=\u201dHola\u201d en vez de a$=\u201dHola\u201d.<\/p>\n<p>Esto tambi\u00e9n significa que A es la misma variable que A$<\/p>\n<p>&nbsp;<\/p>\n<h2>Comandos por defecto<\/h2>\n<p>A menos que indiquemos lo contrario, no todos los comandos de Sinclair ZX Basic est\u00e1n disponibles si no usamos el modificador \u201c&#8211;sinclair\u00bb, aunque esto no es un problema, ni mucho menos, como veremos m\u00e1s adelante. Algunos de estos comandos son INPUT, ATTR y SCREEN$.<\/p>\n<p>&nbsp;<\/p>\n<h1>Mejoras de Boriel ZX Basic<\/h1>\n<p>Boriel mejora Sinclair ZX BASIC, ampliando y flexibilizando, lo que nos permite usar t\u00e9cnicas modernas que hasta el momento solo estaban disponibles en otros lenguajes como el C.<\/p>\n<p>&nbsp;<\/p>\n<h2>Ampliaci\u00f3n del tipo de variables<\/h2>\n<p>Las variables en Sinclair ZX Basic solo pueden ser de dos tipos, num\u00e9ricas o de texto.<\/p>\n<p>Las variables num\u00e9ricas son siempre del tipo FLOAT, y ocupan 5 bytes siempre. Todas las operaciones matem\u00e1ticas, por simples que sean, pasan por una calculadora de punto flotante, lo que ralentiza la ejecuci\u00f3n much\u00edsimo.<\/p>\n<p>En Boriel se incorporan 6 tipos de variables para n\u00fameros enteros, dos tipos para n\u00fameros con decimales y una para cadenas de texto. Si no indicamos el tipo de variable, Boriel intentar\u00e1 asignar la m\u00e1s adecuada, pero esto es un tanto peligroso, as\u00ed que es conveniente definir siempre el tipo de variable.<\/p>\n<p>En la siguiente tabla se muestran los tipos de variables num\u00e9ricas:<\/p>\n<table width=\"557\">\n<thead>\n<tr>\n<td width=\"104\">Tipo<\/td>\n<td width=\"84\">Tama\u00f1o (bytes)<\/td>\n<td width=\"170\">Rango<\/td>\n<td width=\"198\">Descripci\u00f3n<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td width=\"104\">Byte<\/td>\n<td width=\"84\">1<\/td>\n<td width=\"170\">-128..127<\/td>\n<td width=\"198\">Entero de 8 bits con signo<\/td>\n<\/tr>\n<tr>\n<td width=\"104\">UByte<\/td>\n<td width=\"84\">1<\/td>\n<td width=\"170\">0..255<\/td>\n<td width=\"198\">Entero de 8 bits sin signo<\/td>\n<\/tr>\n<tr>\n<td width=\"104\">Integer<\/td>\n<td width=\"84\">2<\/td>\n<td width=\"170\">-32768..32767<\/td>\n<td width=\"198\">Entero de 16 bits con signo<\/td>\n<\/tr>\n<tr>\n<td width=\"104\">UInteger<\/td>\n<td width=\"84\">2<\/td>\n<td width=\"170\">0..65535<\/td>\n<td width=\"198\">Entero de 16 bits sin signo<\/td>\n<\/tr>\n<tr>\n<td width=\"104\">Long<\/td>\n<td width=\"84\">4<\/td>\n<td width=\"170\">\u22122,147,483,648 .. +2,147,483,647<\/td>\n<td width=\"198\">Entero de 32 bits con signo<\/td>\n<\/tr>\n<tr>\n<td width=\"104\">ULong<\/td>\n<td width=\"84\">4<\/td>\n<td width=\"170\">0 .. 4,294,967,295<\/td>\n<td width=\"198\">Entero de 32 bits sin signo<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<p>En cuanto a los decimales, tenemos los siguientes tipos:<\/p>\n<table width=\"557\">\n<thead>\n<tr>\n<td width=\"104\">Tipo<\/td>\n<td width=\"84\">Tama\u00f1o (bytes)<\/td>\n<td width=\"132\">Rango<\/td>\n<td width=\"236\">Descripci\u00f3n<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td width=\"104\">Fixed<\/td>\n<td width=\"84\">4<\/td>\n<td width=\"132\">-32767.9999847 .. 32767.9999847<\/td>\n<td width=\"236\">16 bits para la parte entera y 16 para la parte decimal<\/td>\n<\/tr>\n<tr>\n<td width=\"104\">Float<\/td>\n<td width=\"84\">5<\/td>\n<td width=\"132\">Pierde precisi\u00f3n con muchos decimales o con n\u00fameros muy grandes<\/td>\n<td width=\"236\">Es el tipo que usa Sinclair ZX Basic. 8 bits para el exponente y 24 bits para la mantisa (datos)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<p>Las cadenas de texto no tienen un tama\u00f1o asignado, y ocupan 2 bytes m\u00e1s el contenido del texto. Eso dos bytes extra contienen el tama\u00f1o actual del texto. Las variables de texto se definen con la clave \u201cstring\u201d.<\/p>\n<p>Boriel permite definir el tipo de variables que queremos usar, lo que permite acelerar las operaciones realizadas con esta variable. Podemos definir variables de la siguiente forma:<\/p>\n<p><code>DIM numeroPeque AS BYTE<\/code><br \/>\n<code>DIM numeroPequeSinSigno AS UBYTE<\/code><br \/>\n<code>DIM numeroEntero1, numeroEntero2 AS UINTEGER<\/code><br \/>\n<code>DIM cadena AS STRING<\/code><br \/>\n<code>DIM arrayEntero(100) AS UINTEGER<\/code><br \/>\n<code>DIM arrayBidimensional(10,5) AS UBYTE<\/code><\/p>\n<p>Hay que tener en cuenta que el valor indicado al declarar un array, indica el n\u00famero de elementos +1, ya que los \u00edndices empiezan por el 0. En pocas palabras, 100 define que tiene 101 elementos, del 0 al 100.<\/p>\n<p>La recomendaci\u00f3n es utilizar el tipo de variable m\u00e1s peque\u00f1o posible, pero hay que ir con mucho cuidado a no rebasar los valores m\u00e1ximos y m\u00ednimos.<\/p>\n<p>&nbsp;<\/p>\n<h2>SUBrutinas<\/h2>\n<p>En Sinclair ZX Basic las subrutinas se llaman con el comando \u201cGOSUB l\u00ednea\u201d y volvemos de ella con \u201dRETURN\u201d:<\/p>\n<p><code>10 LET Y=10<\/code><br \/>\n<code>20 LET X=5<\/code><br \/>\n<code>30 LET A$=\"HOLA\"<\/code><br \/>\n<code>30 GOSUB 1000<\/code><br \/>\n<code>\u2026<\/code><br \/>\n<code>1000 PRINT AT Y,X;A$<\/code><br \/>\n<code>1010 RETURN<\/code><\/p>\n<p>Las subrutinas tienen una serie de pegas, por ejemplo, la rutina del ejemplo imprime el texto contenido por A$ en la fila Y y la columna X, pero no tenemos ninguna referencia de las variables que se requieren.<\/p>\n<p>En Boriel podemos implementarlas de esta forma:<\/p>\n<p><code>Imprime(10,5,\"Hola\")<\/code><br \/>\n<code>\u2026<\/code><br \/>\n<code>SUB Imprime(Y AS UBYTE, X AS UBYTE, TEXTO AS STRING)<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0PRINT AT Y,X;TEXTO<\/code><br \/>\n<code>END SUB<\/code><\/p>\n<p>Como se puede ver en el ejemplo de Boriel, se entiende de forma sencilla las variables que requiere la subrutina. Por cierto, que estas variables se llaman \u201cpar\u00e1metros\u201d, es decir, son los par\u00e1metros de la subrutina.<\/p>\n<p>En cierta forma, los SUB nos permiten crear nuestros propios comandos.<\/p>\n<p>Veamos algunas variaciones:<\/p>\n<p><code>DIM Fila, Columna AS UBYTE<\/code><br \/>\n<code>Fila=10<\/code><br \/>\n<code>Columna=5<\/code><br \/>\n<code>Imprime(Fila,Columna,\"Hola\")<\/code><br \/>\n<code>\u2026<\/code><br \/>\n<code>SUB Imprime(Y AS UBYTE, X AS UBYTE, TEXTO AS STRING)<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0PRINT AT Y,X;TEXTO<\/code><br \/>\n<code>END SUB<\/code><\/p>\n<p>Aqu\u00ed podemos ver que se pueden usar variables como par\u00e1metros.<\/p>\n<p>Ahora vamos a mejorar la rutina de impresi\u00f3n:<\/p>\n<p><code>SUB Imprime(Y AS UBYTE, X AS UBYTE, TEXTO AS STRING)<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0DIM N, COLOR AS UBYTE<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0COLOR=0<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0PRINT AT Y,X;\"\";<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0FOR N=0 TO LEN(TEXTO)-1<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PRINT INK COLOR;TEXTO(N);<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 COLOR=COLOR+1<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0NEXT N<\/code><br \/>\n<code>END SUB<\/code><\/p>\n<p>En este ejemplo hemos mejorado la subrutina Imprime, que ahora imprime el texto en colores, pero lo m\u00e1s interesante es que hemos definido dos variables (\u201cN\u201d y \u201cCOLOR\u201d). Pero estas variables solo \u201cviven\u201d dentro del SUB, es decir, al llamar a la subrutina, se crean dos variables nuevas que al salir de esta, se eliminar\u00e1n.<br \/>\nLa nota curios es que podemos tener una variable con el mismo nombre fuera del SUB, por ejemplo:<br \/>\n<code>DIM N AS UBYTE<\/code><br \/>\n<code>FOR N=0 TO 10<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0Imprime(N,0,\"HOLA \"+STR(N))<\/code><br \/>\n<code>NEXT N<\/code><br \/>\n<code>\u2026<\/code><br \/>\n<code>SUB Imprime(Y AS UBYTE, X AS UBYTE, TEXTO AS STRING)<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0DIM N, COLOR AS UBYTE<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0COLOR=0<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0PRINT AT Y,X;\"\";<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0FOR N=0 TO LEN(TEXTO)-1<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PRINT INK COLOR;TEXTO(N);<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 COLOR=COLOR+1<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0NEXT N<\/code><br \/>\n<code>END SUB<\/code><\/p>\n<p>Este ejemplo imprime el texto \u201cHOLA 0\u201d, \u201cHOLA 1\u201d, \u201cHOLA 2\u201d, hasta \u201cHOLA 10\u201d, en diferentes filas. Pero lo m\u00e1s curioso es que tenemos un primer bucle que usa la variable \u201cN\u201d (que se trata de una variable global), y otra variable con el mismo nombre \u201cN\u201d dentro del SUB (que se denomina variable local), pero estas son diferentes y no se mezcla su valor.<\/p>\n<p>&nbsp;<\/p>\n<h2>FUNCTION<\/h2>\n<p>Una FUNCTION es una SUBrutina que devuelve un valor. Veamos un ejemplo:<br \/>\n<code>PRINT Suma(10,3)<\/code><br \/>\n<code>\u2026<\/code><br \/>\n<code>FUNCTION Suma(A AS INTEGER, B AS INTEGER) AS INTEGER<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0DIM R AS INTEGER<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0R=A+B<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0RETURN R<\/code><br \/>\n<code>END FUNTION<\/code><\/p>\n<p>En este ejemplo estamos definir una funci\u00f3n llamada \u201cSuma\u201d, que suma dos valores del tipo INTEGER, y devuelve el resultado en forma de INTEGER. Evidentemente se puede, y deber\u00eda, simplificar con un simple RETURN A+B, pero as\u00ed vemos que tambi\u00e9n se pueden crear variables \u201clocales\u201d.<\/p>\n<p>&nbsp;<\/p>\n<h2>Integraci\u00f3n con assembler<\/h2>\n<p>Aunque sea una caracter\u00edstica avanzada, explicaremos de forma sencilla como a\u00f1adir unas l\u00edneas de assembler a nuestro c\u00f3digo. Veamos este ejemplo sacado de NextLib:<\/p>\n<p><code>function GetReg(byval nextRegister as ubyte) as ubyte<br \/>\n<\/code><code>asm<br \/>\n<\/code><code>\u00a0 \u00a0 \u00a0push bc<br \/>\n<\/code><code>\u00a0 \u00a0 \u00a0ld bc,$243B\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ; Register Select<br \/>\n<\/code><code>\u00a0 \u00a0 \u00a0out(c),a<br \/>\n<\/code><code>\u00a0 \u00a0 \u00a0ld bc,$253B\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ; reg access<br \/>\n<\/code><code>\u00a0 \u00a0 \u00a0in a,(c)<br \/>\n<\/code><code>\u00a0 \u00a0 \u00a0pop bc<br \/>\n<\/code><code>end asm<br \/>\n<\/code><code>end function<\/code><\/p>\n<p>Este ejemplo implementa el comando GetReg, que lee el valor de un registro de Next (NextReg). Se puede observar que dentro de la funci\u00f3n el c\u00f3digo assembler se incluye entre las l\u00edneas marcadas por \u201cASM\u201d y \u201cEND ASM\u201d.<\/p>\n<p>En este caso el par\u00e1metro \u201cnextRegisterse coloca en el registro A del procesador, y el valor que retorna la funci\u00f3n tambi\u00e9n es el que se alm en dicho registro A.<\/p>\n<p>El c\u00f3digo assembler hace un OUT en el puerto $243B y acto seguido hace un IN en el puerto $253B. Como resultado, el valor del registro NextReg indicado por el par\u00e1metro \u201cnextRegister\u201d<\/p>\n<p>Esto tambi\u00e9n nos permite a\u00f1adir datos a nuestro c\u00f3digo, por ejemplo las definiciones de una fuente o unos Sprites, como se puede ver en este ejemplo:<\/p>\n<p><code>Bola:<\/code><br \/>\n<code>ASM<\/code><br \/>\n<code>db\u00a0 $E3, $E3, $E3, $E3, $E3, $F5, $F5, $F4, $F4, $F5, $F5, $E3, $E3, $E3, $E3, $E3;<\/code><br \/>\n<code>db\u00a0 $E3, $E3, $E3, $FA, $F4, $F4, $F4, $F4, $F4, $F4, $F0, $ED, $F6, $E3, $E3, $E3;<\/code><br \/>\n<code>db\u00a0 $E3, $E3, $F9, $F8, $F4, $F4, $F4, $F4, $F4, $F4, $F4, $ED, $E9, $F2, $E3, $E3;<\/code><br \/>\n<code>db\u00a0 $E3, $FA, $F8, $F8, $F8, $F8, $F4, $F4, $F4, $F4, $F4, $EC, $E9, $E9, $F6, $E3;<\/code><br \/>\n<code>db\u00a0 $E3, $F8, $F8, $F8, $F8, $F8, $F8, $F4, $F4, $F4, $F4, $ED, $E9, $E9, $ED, $E3;<\/code><br \/>\n<code>db\u00a0 $F9, $F8, $F8, $F8, $F8, $F8, $F8, $F8, $F4, $F4, $F0, $ED, $E9, $E9, $E9, $F2;<\/code><br \/>\n<code>db\u00a0 $F9, $F8, $F8, $D8, $B8, $B8, $D8, $F8, $F4, $F0, $ED, $E9, $E9, $E9, $E9, $ED;<\/code><br \/>\n<code>db\u00a0 $F8, $D8, $98, $78, $58, $78, $78, $B4, $F0, $ED, $E9, $E9, $E9, $E9, $E9, $CE;<\/code><br \/>\n<code>db\u00a0 $D8, $98, $58, $58, $59, $58, $55, $52, $CE, $E9, $E9, $E9, $E9, $E9, $CE, $AE;<\/code><br \/>\n<code>db\u00a0 $B9, $58, $59, $58, $58, $55, $37, $53, $AF, $CE, $CE, $CE, $CE, $AE, $AE, $AF;<\/code><br \/>\n<code>db\u00a0 $99, $58, $58, $58, $59, $36, $33, $33, $AF, $AE, $AE, $AE, $AE, $AE, $AE, $D3;<\/code><br \/>\n<code>db\u00a0 $E3, $79, $58, $58, $55, $37, $33, $37, $6F, $AE, $AE, $AE, $AE, $AE, $AE, $E3;<\/code><br \/>\n<code>db\u00a0 $E3, $9A, $58, $58, $55, $37, $33, $33, $33, $8F, $AF, $AE, $AE, $AE, $D7, $E3;<\/code><br \/>\n<code>db\u00a0 $E3, $E3, $99, $58, $55, $37, $33, $33, $33, $37, $53, $8F, $8F, $B3, $E3, $E3;<\/code><br \/>\n<code>db\u00a0 $E3, $E3, $E3, $99, $79, $36, $33, $33, $33, $33, $33, $37, $77, $E3, $E3, $E3;<\/code><br \/>\n<code>db\u00a0 $E3, $E3, $E3, $E3, $E3, $7A, $37, $33, $33, $37, $77, $E3, $E3, $E3, $E3, $E3;<\/code><br \/>\n<code>end asm<\/code><\/p>\n<p>La diferencia entre usas este sistema y usar DATA es que con DB los datos ya est\u00e1n \u201cpokeados\u201d en la memoria. No hace falta leerlos con READ y hacer el POKE. Lo veremos m\u00e1s adelante, pero es una gran ventaja.<\/p>\n<p>Otro detalle muy importante es que no hace falta poner ORG en assembler. Boriel coloca el c\u00f3digo en la memoria ocupando todos los huecos y recolocando el c\u00f3digo a medida que vamos programando. Esto nos permite olvidarnos un poco del mapa de memoria, pero no del todo si queremos jugar con el mapeo de memoria.<\/p>\n<p>&nbsp;<\/p>\n<h2>Uso de librer\u00edas<\/h2>\n<p>Una librer\u00eda es un fichero de c\u00f3digo que contiene una serie de SUBrutinas y FUNCTIONes que ampl\u00edan los comandos disponibles.<\/p>\n<p>Boriel incluye un paquete bastante nutrido de librer\u00edas, que incluyen, entro otras muchas, funciones para leer teclas pulsadas de forma simult\u00e1nea, funciones para trabajar con cadenas, sprites, acceso a disco y tarjetas SD, scroll, etc\u2026<\/p>\n<p>Para usar una librer\u00eda integrada utilizamos la directiva \u201c#include\u201d indicando el nombre de la librer\u00eda entre signos de mayor y menor ( &lt; &gt; )<\/p>\n<p><code>#include &lt;Keys.bas&gt;<\/code><br \/>\n<code>\u2026<\/code><br \/>\n<code>IF MultiKeys(KEYSYMBOL)&lt;&gt;0 THEN PRINT \"Se ha pulsado Symbol Shift\"<\/code><\/p>\n<p>En este ejemplo, se incluye la librer\u00eda \u201cKeys.bas\u201d, que implementa los m\u00e9todos \u201cGetKey\u201d, \u201cMultiKeys\u201d y \u201cGetKeyScanCode\u201d, adem\u00e1s de definir una serie de constantes que nos permite leer cada una de las teclas de nuestro querido Spectrum.<\/p>\n<p>Otro ejemplo:<\/p>\n<div>\n<div><code>#include &lt;Scroll.bas&gt;<\/code><\/div>\n<div><code>DIM Y, X, N AS UBYTE<\/code><\/div>\n<div><code>FOR Y=0 TO 23<\/code><\/div>\n<div><code>\u00a0 \u00a0 \u00a0FOR X=0 TO 31<\/code><\/div>\n<div><code>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PRINT AT Y,X;\"#\";<\/code><\/div>\n<div><code>\u00a0 \u00a0 \u00a0NEXT X<\/code><\/div>\n<div><code>NEXT Y<\/code><\/div>\n<div><code>WHILE INKEY$=\"\"<\/code><\/div>\n<div><code>\u00a0 \u00a0 PRINT AT 10,11;N;<\/code><\/div>\n<div><code>\u00a0 \u00a0 N=N+1<\/code><\/div>\n<div><code>\u00a0 \u00a0 ScrollRight(80,40,200,120)<\/code><\/div>\n<div><code>WEND<\/code><\/div>\n<\/div>\n<p>Este ejemplo llena la pantalla con el s\u00edmbolo \u201c#\u201d y despu\u00e9s hace un scroll pixel a pixel en una ventana hasta que pulsemos una tecla.<\/p>\n<p>El bucle formado por WHILE .. WEND hace que se repita todo lo que hay dentro mientras se cumple una condici\u00f3n. En este caso se har\u00e1 el scroll hasta que se pulse una tecla, es decir, cuando INKEY$ no sea igual a una cadena vac\u00eda.<\/p>\n<p>&nbsp;<\/p>\n<p>Si lo que queremos hacer es usar una librer\u00eda que no est\u00e1 integrada en Boriel, la podemos incluir con el nombre entre comillas:<\/p>\n<p><code>#include \"MiLibreria.bas\"<\/code><\/p>\n<p>&nbsp;<\/p>\n<h2>WHILE\u2026WEND<\/h2>\n<p>Este tipo de bucle hace que se repita su contenido mientras se cumpla una condici\u00f3n. Por ejemplo:<\/p>\n<p><code>10 LET A=0<\/code><br \/>\n<code>20 PRINT AT 0,0;A<\/code><br \/>\n<code>30 LET A=A+1<\/code><br \/>\n<code>40 IF INKEY$=\"\" THEN GOTO 20<\/code><\/p>\n<p>Esto se traduce como:<\/p>\n<p><code>DIM A AS UINTEGER<\/code><br \/>\n<code>A=0<\/code><br \/>\n<code>WHILE INKEY$=\"\"<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0PRINT AT 0,0;A<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0A=A+1<\/code><br \/>\n<code>WEND<\/code><\/p>\n<p>A primera vista se ve que no ganamos en l\u00edneas, tecleamos lo mismo o incluso m\u00e1s, pero si que ganamos en visibilidad. El c\u00f3digo se ve m\u00e1s limpio, no hay que buscar la l\u00ednea 20 del GOTO y adem\u00e1s podemos \u201cindentar\u201d el contenido del bucle.<\/p>\n<p><code>WHILE 1<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0PRINT \"Bucle infinito \";<\/code><br \/>\n<code>WEND<\/code><\/p>\n<p>Esto hace que el bucle se repita de forma infinita. Tambien podemos forzar la salida del bucle con un BREAK WHILE, por ejemplo:<\/p>\n<p><code>WHILE 1<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0PRINT \"Bucle infinito \";<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0IF INKEY$&lt;&gt;\"\" THEN BREAK WHILE<\/code><br \/>\n<code>WEND<\/code><\/p>\n<p>Aunque poco \u00fatil, este ejemplo nos sirve para ver como se puede salir de este bucle.<\/p>\n<p>&nbsp;<\/p>\n<h2>DO\u2026LOOP<\/h2>\n<p>Este tipo de bucle es una variante del anterior. Al igual que WHILE\u2026WEND, el contenido se ejecuta mientras se cumple una condici\u00f3n. La diferencia es que la condici\u00f3n puede ponerse al principio del bucle, al final o no ponerse.<br \/>\n<code>DO<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0PRINT \"Bucle infinito \";<\/code><br \/>\n<code>LOOP<\/code><\/p>\n<p>Otro ejemplo:<br \/>\n<code>DO<\/code><br \/>\n<code>\u00a0 \u00a0 \u00a0PRINT \"Hasta que se pulse una tecla\u2026 \";<\/code><br \/>\n<code>LOOP WHILE INKEY$=\"\"<\/code><br \/>\nHay m\u00e1s posibilidades, como que se repitas hasta que se cumpla una condici\u00f3n, pero lo dejaremos para otro d\u00eda\u2026<\/p>\n<p>Quedan muchas cosas en el tintero, pero esto solo pretende ser una peque\u00f1a introducci\u00f3n a Boriel ZX Basic.<\/p>\n<p>&nbsp;<\/p>\n<h1>Agradecimientos y atribuciones<\/h1>\n<p>Algunos ejemplos de c\u00f3digo est\u00e1n sacados de los ejemplos que vienen con NextBuild de David Saphier AKA em00K<\/p>\n<p>Gracias a Jos\u00e9 Rodriguez AKA Boriel por su ayuda y por su trabajo con el compilador Boriel ZX Basic.<\/p>\n<p><a href=\"http:\/\/www.freepik.com\">Imagen principal del art\u00edculo dise\u00f1ada por vectorpouch \/ Freepik\u00a0<\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Recordad, para dudas me pod\u00e9is encontrar en twitter \u201c@Duefectu\u201d o Facebook, o en el canal de \u201cBoriel ZX Basic\u201d en Telegram.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>En este art\u00edculo explicaremos una serie de conceptos de Boriel ZX Basic, orientados a los programadores que vienen del cl\u00e1sico Sinclair ZX Basic, y que quieren empezar a programar en Boriel ZX Basic. Y ya que estamos, aunque los conceptos sirven para el ZX Spectrum cl\u00e1sico, nos enfocaremos m\u00e1s hacia el Sinclair ZX Spectrum Next. [&hellip;]<\/p>\n","protected":false},"author":16,"featured_media":210,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[13,3,14],"tags":[7,10,15,9],"class_list":["post-208","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-boriel-zx-basic","category-desarrollo","category-herramientas","tag-boriel-zx-basic","tag-compiladores","tag-herramientas","tag-nextbuild"],"jetpack_featured_media_url":"https:\/\/specnext.dev\/es\/wp-content\/uploads\/sites\/2\/2022\/07\/Evolucion.jpg","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/specnext.dev\/es\/wp-json\/wp\/v2\/posts\/208","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/specnext.dev\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/specnext.dev\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/specnext.dev\/es\/wp-json\/wp\/v2\/users\/16"}],"replies":[{"embeddable":true,"href":"https:\/\/specnext.dev\/es\/wp-json\/wp\/v2\/comments?post=208"}],"version-history":[{"count":5,"href":"https:\/\/specnext.dev\/es\/wp-json\/wp\/v2\/posts\/208\/revisions"}],"predecessor-version":[{"id":214,"href":"https:\/\/specnext.dev\/es\/wp-json\/wp\/v2\/posts\/208\/revisions\/214"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/specnext.dev\/es\/wp-json\/wp\/v2\/media\/210"}],"wp:attachment":[{"href":"https:\/\/specnext.dev\/es\/wp-json\/wp\/v2\/media?parent=208"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/specnext.dev\/es\/wp-json\/wp\/v2\/categories?post=208"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/specnext.dev\/es\/wp-json\/wp\/v2\/tags?post=208"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}