martes, 22 de octubre de 2019

Tipos de Registros En lenguaje ensamblador

Registros de Lenguaje Ensamblador

REGISTROS INTERNOS DEL MICROPROCESADOR

La Unidad Central de Proceso (CPU, por sus siglas en inglés) tiene 14 registros internos cada uno de 16 bits. Los primeros cuatro, AX, BX, CX y DX, son de uso general y se pueden usar también como registros de 8 bits. Es decir, AX se puede dividir en AH y AL (AH es el byte alto, high, y AL es el byte bajo, low) Lo mismo es aplicable a los otros tres (BX en BH y BL, CX en CH y CL y DX en DH y DL).
Estos son los únicos registros que pueden usarse de modo dual (en 8 o 16 bits) Los registros de la CPU son conocidos por sus nombres propios, que son: ·

  • AX (acumulador). 
  • BX (registro base). 
  • CX (registro contador).
  • DX (registro de datos).
  •  DS (registro del segmento de datos).
  • ES (registro del segmento extra).
  • SS (registro del segmento de pila).
  • CS (registro del segmento de código).
  • BP (registro de apuntadores base).
  • SI (registro índice fuente).
  • DI (registro índice destino).
  • SP (registro del apuntador de pila).
  • IP (registro del apuntador de siguiente instrucción).
  • F (registro de banderas).


 El registro AX se usa para almacenar resultados, lectura o escritura desde o hacia los puertos. El BX sirve como apuntador base o índice. El CX se utiliza en operaciones de iteración, como un contador que automáticamente se incrementa o decrementa de acuerdo con el tipo de instrucción usada. El DX se usa como puente para el acceso de datos.

 El DS es un registro de segmento cuya función es actuar como policía donde se encuentran los datos. Cualquier dato, ya sea una variable inicializada o no, debe estar dentro de este segmento. La única excepción es cuando tenemos programas del tipo *.com, ya que en éstos sólo puede existir un segmento. El registro ES tiene el propósito general de permitir operaciones sobre cadenas, pero también puede ser una extensión del DS.

 El SS tiene la tarea exclusiva de manejar la posición de memoria donde se encuentra la pila (stack) Esta es una estructura usada para almacenar datos en forma temporal, tanto de un programa como de las operaciones internas de la computadora personal (PC, por sus siglas en inglés) En términos de operación interna, la CPU usa este segmento para almacenar las direcciones de retorno de las llamadas a rutinas. El registro de segmentos más importante es el CS o segmento de código. Es aquí donde se encuentra el código ejecutable de cada programa, el cual está directamente ligado a los diferentes modelos de memoria.

El registro BP (base pointer) se usa para manipular la pila sin afectar al registro de segmentos SS. Es útil cuando se usa interfaz entre lenguajes de alto nivel y el ensamblador. Puesto que dicha interfaz se basa en el concepto de la pila BP, nos permite acceder parámetros pasados sin alterar el registro de segmento SS. Los registros SI y DI son útiles para manejar bloques de cadenas en memoria, siendo el primero el índice fuente y el segundo el índice destino. En otras palabras, SI representa la dirección donde se encuentra la cadena y DI la dirección donde será copiada.

El registro SP apunta a un área específica de memoria que sirve para almacenar datos bajo la estructura LIFO (último en entrar, primero en salir), conocida como pila (stack) El registro IP (instruction pointer) apunta a la siguiente instrucción que será ejecutada en memoria.

A continuación se describe el significado de cada bit del registro F (banderas).

Todas las banderas apagadas:
NV   UP   DI   PL   NZ   NA   PO   NC
 Todas las banderas prendidas:
 OV   DN   EI   NG   ZR   AC   PE   CY

Significado de los bits:
 Overflow  NV = no hay desbordamiento
                  OV = Sí lo hay

 Direction  UP = hacia adelante
                  DN = hacia atrás

 Interrupts  DI = desactivadas
                   EI = activadas

 Sign   PL = positivo
           NG = negativo

 Zero   NZ = no es cero
            ZR = sí lo es

 Auxiliary Carry   NA = no hay acarreo auxiliar
                              AC = hay acarreo auxiliar

 Parity   PO = paridad non
              PE = paridad par

 Carry   NC = no hay acarreo
             CY = sí lo hay


Los registros del procesador se emplean para controlar instrucciones en ejecución, manejar direccionamiento de memoria y proporcionar capacidad aritmética. Los registros son direccionables por medio de un nombre. Los bits por convención, se numeran de derecha a izquierda, como en:
… 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Los registros internos del procesador se puede clasificar en 6 tipos diferentes 
Registros de segmento
Registros de propósito general
Registros de apuntadores
Registros de banderas
Registros de Puntero de instrucción
Registros de Pila
Registros de segmento 
Un registro de segmento tiene 16 bits de longitud y facilita un área de memoria para direccionamiento conocida como el segmento actual.
Registro CS. El DOS almacena la dirección inicial del segmento de código de un programa en el registro CS. Esta dirección de segmento, mas un valor de desplazamiento en el registro apuntador de instrucción (IP), indica la dirección de una instrucción que es buscada para su ejecución.
Registro DS. La dirección inicial de un segmento de datos de programa es almacenada en el registro DS. En términos sencillos, esta dirección, mas un valor de desplazamiento en una instrucción, genera una referencia a la localidad de un byte especifico en el segmento de datos.
Registro SS. El registro SS permite la colocación en memoria de una pila, para almacenamiento temporal de direcciones y datos. El DOS almacena la dirección de inicio del segmento de pila de un programa en le registro SS. Esta dirección de segmento, mas un valor de desplazamiento en el registro del apuntador de pila (SP), indica la palabra actual en la pila que esta siendo direccionada.
Registros ES. Alguna operaciones con cadenas de caracteres (datos de caracteres) utilizan el registro extra de segmento para manejar el direccionamiento de memoria. En este contexto, el registro ES esta asociado con el registro DI (índice). Un programa que requiere el uso del registro ES puede inicializarlo con una dirección de segmento apropiada.
Registros FS y GS. Son registros extra de segmento en los procesadores 80386 y posteriores. 
Registros de propósito general. 
Los registros de propósito general AX, BX, CX y DX son los caballos de batalla del sistema. Son únicos en el sentido de que se puede direccionarlos como una palabra o como una parte de un byte. El ultimo byte de la izquierda es la parte “alta”, y el ultimo byte de la derecha es la parte “baja”. Por ejemplo, el registro CX consta de una parte CH (alta) y una parte Cl (baja), y usted puede referirse a cualquier parte por su nombre.
Registro AX. El registro AX, el acumulador principal, es utilizado para operaciones que implican entrada/salida y la mayor parte de la aritmética. Por ejemplo, las instrucciones para multiplicar , dividir y traducir suponen el uso del AX. También, algunas operaciones generan código mas eficiente si se refieren al AX en lugar de a los otros registros.
Registro BX. El BX es conocido como el registro base ya que es el único registro de propósito general que puede ser índice para direccionamiento indexado. También es común emplear el BX para cálculos.
Registro DX. El DX es conocido como l registro de datos. Alguna operaciones de entrada/salida requieren uso, y las operaciones de multiplicación y división con cifras grandes suponen al DX y al AX trabajando juntos.
Registro de Apuntador de Instrucciones. 
El registro apuntador de instrucciones (IP) de 16 bits contiene el desplazamiento de dirección de la siguiente instrucción que se ejecuta. El IP esta asociado con el registro CS en el sentido de que el IP indica la instrucción actual dentro del segmento de código que se esta ejecutando actualmente. Los procesadores 80386 y posteriores tienen un IP ampliado de 32 bits, llamado EIP.En el ejemplo siguiente, el registro CS contiene 25A4[0]H y el IP contiene 412H. Para encontrar la siguiente instrucción que será ejecutada, el procesador combina las direcciones en el CS y el IP:
Segmento de dirección en el registro CS: 25A40H Desplazamiento de dirección en el registro IP: + 412H Dirección de la siguiente instrucción: 25E52H 
Registros Apuntadores. 
Los registros SP (apuntador de la pila) Y BP (apuntador de base) están asociados con el registro SS y permiten al sistema accesar datos en el segmento de la pila.Registro SP. El apuntador de la pila de 16 bits esta asociado con el registro SS y proporciona un valor de desplazamiento que se refiere a la palabra actual que esta siendo procesada en la pila. Los procesadores 80386 y posteriores tienen un apuntador de pila de 32 bits, el registro ESP. El sistema maneja de forma automática estos registros.
En el ejemplo siguiente, el registro SS contiene la dirección de segmento 27B3[0]H y el SP el desplazamiento 312H. Para encontrar la palabra actual que esta siendo procesada en la pila, la computadora combina las direcciones en el SS y el SP:
Registro BP. El BP de 16 bits facilita la referencia de parámetros, los cuales son datos y direcciones transmitidos vía pila. Los procesadores 80386 y posteriores tienen un BP ampliado de 32 bits llamado el registro EBP.
Registros Indice.
Los registros SI y DI están disponibles para direccionamiento indexado y para sumas y restas.
Registro SI. El registro índice fuente de 16 bits es requerido por algunas operaciones con cadenas (de caracteres). En este contexto, el SI esta asociado con el registro DS. Los procesadores 80386 y posteriores permiten el uso de un registro ampliado de 32 bits, el ESI.
Registro DI. El registro índice destino también es requerido por algunas operaciones con cadenas de caracteres. En este contexto, el DI esta asociado con el registro ES. Los procesadores 80386 y posteriores permiten el uso de un registro ampliado de 32 bits, el EDI.
Registro de Banderas. 
De los 16 bits del registro de banderas, nueve son comunes a toda la familia de procesadores 8086, y sirven para indicar el estado actual de la maquina y el resultado del procesamiento. Muchas instrucciones que piden comparaciones y aritmética cambian el estado de las banderas, algunas cuyas instrucciones pueden realizar pruebas para determinar la acción subsecuente. En resumen, los bits de las banderas comunes son como sigue:
OF (Overflow, desbordamiento). Indica desbordamiento de un bit
de orden alto (mas a la izquierda) después de una operación aritmética.
DF (dirección). Designa la dirección hacia la izquierda o hacia la derecha para mover o comparar cadenas de caracteres.
IF (interrupción). Indica que una interrupción externa, como la entrada desde el teclado, sea procesada o ignorada.
TF (trampa). Permite la operación del procesador en modo de un paso. Los programas depuradores, como el DEBUG, activan esta bandera de manera que usted pueda avanzar en la ejecución de una sola instrucción a un tiempo, para examinar el efecto de esa instrucción sobre los registros de memoria.
SF (signo). Contiene el signo resultante de una operación aritmética (0 = positivo y 1 = negativo).
ZF (cero). Indica el resultado de una operación aritmética o de comparación (0 = resultado diferente de cero y 1 = resultado igual a cero).
AF (acarreo auxiliar). Contiene un acarreo externo del bit 3 en un dato de 8 bits para aritmética especializada.
PF (paridad). Indica paridad par o impar de una operación en datos de 8 bits de bajo orden (mas a la derecha).
CF (acarreo). Contiene el acarreo de orden mas alto (mas a la izquierda) después de una operación aritmética; también lleva el contenido del ultimo bit en una operación de corrimiento o de rotación. Las banderas están en el registro de banderas en las siguientes posiciones:
Las banderas mas importantes para la programación en ensamblador son O, S, Z y C, para operaciones de comparación y aritméticas, y D para operaciones de cadenas de caracteres. Los procesadores 80286 y posteriores tienen algunas banderas usadas para propósitos internos, en especial las que afectan al modo protegido. Los procesadores 80286 y posteriores tienen un registro extendido de banderas conocido como Eflags.
Registros de PILA 
La pila es un área de memoria importante y por ello tiene, en vez de uno, dos registros que se usan como desplazamiento (offset) para apuntar a su contenido. Se usan como complemento al registro y son:
-SP- Stack Pointer: Se traduce como puntero de pila y es el que se reserva el procesador para uso propio en instrucciones de manipulado de pila. Por lo general , el programador no debe alterar su contenido.
-BP- Base pointer: Se usa como registro auxiliar. El programador puede usarlo para su provecho.
Claro que estos nombres y tipos de registros son estándar, ya que cada fabricante puede utilizar otros registro que reemplacen a estos o los auxilien, aun así, los fabricantes que usan otros registro tienen la misma función que los anteriormente mencionados
Ejemplo 
Registros de uso general del 8086/8088: 
Tienen 16 bits cada uno y son ocho: 

AX = Registro acumulador, dividido en AH y AL (8 bits cada uno). Usándolo se produce (en general) una instrucción que ocupa un byte menos que si se utilizaran otros registros de uso general. Su parte más baja, AL, también tiene esta propiedad. El último registro mencionado es el equivalente al acumulador de los procesadores anteriores (8080 y 8085). Además hay instrucciones como DAA; DAS; AAA; AAS; AAM; AAD; LAHF; SAHF; CBW; IN y OUT que trabajan con AX o con uno de sus dos bytes (AH o AL). También se utiliza este registro (junto con DX a veces) en multiplicaciones y divisiones.

BX = Registro base, dividido en BH y BL. Es el registro base de propósito similar (se usa para direccionamiento indirecto) y es una versión más potente del par de registros HL de los procesadores anteriores.

CX = Registro contador, dividido en CH y CL. Se utiliza como contador en bucles (instrucción LOOP), en operaciones con cadenas (usando el prefijo REP) y en desplazamientos y rotaciones (usando el registro CL en los dos últimos casos).

DX = Registro de datos, dividido en DH y DL. Se utiliza junto con el registro AX en multiplicaciones y divisiones, en la instrucción CWD y en IN y OUT para direccionamiento indirecto de puertos (el registro DX indica el número de puerto de entrada/salida).

SP = Puntero de pila (no se puede subdividir). Aunque es un registro de uso general, debe utilizarse sólo como puntero de pila, la cual sirve para almacenar las direcciones de retorno de subrutinas y los datos temporarios (mediante las instrucciones PUSH y POP). Al introducir (push) un valor en la pila a este registro se le resta dos, mientras que al extraer (pop) un valor de la pila este a registro se le suma dos.

BP = Puntero base (no se puede subdividir). Generalmente se utiliza para realizar direccionamiento indirecto dentro de la pila.

SI = Puntero índice (no se puede subdividir). Sirve como puntero fuente para las operaciones con cadenas. También sirve para realizar direccionamiento indirecto.

DI = Puntero destino (no se puede subdividir). Sirve como puntero destino para las operaciones con cadenas. También sirve para realizar direccionamiento indirecto.
Cualquiera de estos registros puede utilizarse como fuente o destino en operaciones aritméticas y lógicas 
 Indicadores (flags) 
Hay nueve indicadores de un bit en este registro de 16 bits. Los cuatro bits más significativos están indefinidos, mientras que hay tres bits con valores determinados: los bits 5 y 3 siempre valen cero y el bit 1 siempre vale uno (esto también ocurría en los procesadores anteriores).
CF (Carry Flag, bit 0): Si vale 1, indica que hubo “arrastre” (en caso de suma) hacia, o “préstamo” (en caso de resta) desde el bit de orden más significativo del resultado. Este indicador es usado por instrucciones que suman o restan números que ocupan varios bytes. Las instrucciones de rotación pueden aislar un bit de la memoria o de un registro poniéndolo en el CF.
PF (Parity Flag, bit 2): Si vale uno, el resultado tiene paridad par, es decir, un número par de bits a 1. Este indicador se puede utilizar para detectar errores en transmisiones.
AF (Auxiliary carry Flag, bit 4): Si vale 1, indica que hubo “arrastre” o “préstamo” del nibble (cuatro bits) menos significativo al nibble más significativo. Este indicador se usa con las instrucciones de ajuste decimal.
ZF (Zero Flag, bit 6): Si este indicador vale 1, el resultado de la operación es cero. 
SF (Sign Flag, bit 7): Refleja el bit más significativo del resultado. Como los números negativos se representan en la notación de complemento a dos, este bit representa el signo: 0 si es positivo, 1 si es negativo.
TF (Trap Flag, bit 8): Si vale 1, el procesador está en modo paso a paso. En este modo, la CPU automáticamente genera una interrupción interna después de cada instrucción, permitiendo inspeccionar los resultados del programa a medida que se ejecuta instrucción por instrucción.
IF (Interrupt Flag, bit 9): Si vale 1, la CPU reconoce pedidos de interrupción externas enmascarables (por el pin INTR). Si vale 0, no se reconocen tales interrupciones. Las interrupciones no enmascarables y las internas siempre se reconocen independientemente del valor de IF. DF (Direction Flag, bit 10): Si vale 1, las instrucciones con cadenas sufrirán “auto-decremento”, esto es, se procesarán las cadenas desde las direcciones más altas de memoria hacia las más bajas. Si vale 0, habrá “auto-incremento”, lo que quiere decir que las cadenas se procesarán de “izquierda a derecha”.
OF (Overflow flag, bit 11): Si vale 1, hubo un desborde en una operación aritmética con signo, esto es, un dígito significativo se perdió debido a que tamaño del resultado es mayor que el tamaño del destino.
El procesador Z80 
Registros de propósito general 
El Z80 posee 14 registros de propósito general de 8 bits denominados A, B, C, D, H, L y A’, B’, C’, D’, H’ , L’. Solamente un set de siete registros y el correspondiente registro de Flags F pueden estar activos al mismo tiempo. Una instrucción especial selecciona A y F o A’ y F’ mientras que otra instrucción selecciona B, C, D, E, H, L o C’, D’, E’ ,H’ L’.
El programador puede cambiar rápidamente de un conjunto de registros de propósito general a otro. Esto proporciona una mayor capacidad de almacenamiento en registros. El acceso a datos presentes en registros de la CPU es mucho más rápido que el acceso a datos en memoria.
Los registros pueden agruparse de a pares formando registros de 16 bits. Estos son los pares BC, DE y HL (sus equivalentes primas también pueden agruparse).
Flags 
Aunque los Flags existen físicamente dentro de la CPU están agrupados lógicamente formando un registro. Los Flags del Z80 son los siguientes: 
Flag de Cero(Z): Toma el valor 1 si el resultado de una operación es cero. Es el bit seis. 
Flag de signo(S): Toma el valor 1 si el resultado de una operación es negativo. Es el bit siete. 
Flag de Carry(C): Este flag es afectado por las instrucciones de desplazamiento y es puesto en 1 ó 0 según el valor del bit desplazado. También es afectado por las operaciones aritméticas. Este flag es el bit cero.
Flag de Paridad y overflow(P/V): En el caso de paridad, se pone en 1 si el resultado de una operación posee un número par de unos. Cuando el flag P/V se usa para representar overflow, el flag se pone en 1 si ocurre un overflow después de una operación aritmética. Este flag es el bit 2.
Flag H y N: Son dos Flip Flop que no pueden ser examinados por las instrucciones de salto condicional. El Z80 los usa para las operaciones BCD. H representa el rebalse que genera considerando los cuatro bits menos significativos del resultado y N es el flag de resta, el cual se activa para indicar si la última instrucción ejecutada fue suma o resta. En el caso general, una instrucción de resta coloca en 1 el flag N y una instrucción de suma lo coloca en 0. Los Flags H y N son los bits 4 y 1 respectivamente.
Registros de propósito especial 
Program Counter: 
Es un registro de 16 bits que indica la dirección de la próxima instrucción ejecutar. Las instrucciones del Z80 pueden contar de uno, dos, tres o cuatro bytes. 
Stack-Pointer: 
Es un registro de 16 bits que indica la dirección de una memoria RAM externa denominada Stack. El objetivo de esta área de memoria es proporcionar un medio de almacenamiento temporal de los registros del usuario, registro de Flags y del program Counter. La provisión de Stack es fundamental para operaciones tales como los llamados a sub-rutinas e interrupciones.
Registros índices IX e IY: Estos registros son de 16 bits, diseñados para permitir un direccionamiento indexado en los programas del Z80. Cuando se ejecuta una instrucción en un modo de direccionamiento indexado, se usa uno de los dos registros índices para calcular la dirección del operando.
Registro de interrupciones I: Es un registro de 8 bits que puede ser cargado para especificar el byte más significativo de una dirección de memoria. El byte menos significativo es proporcionado por el dispositivo que solicita la interrupción.
Registro de refresh de memoria R: Es un registro especial diseñado para proporcionar un refresh automático de las memorias RAM dinámicas. 
Registro de instrucciones: 
El registro de instrucciones tiene por misión almacenar el código de operación de la instrucción leída desde memoria. Este código es descodificado y con esta información se dirigen todos los micro-pasos. 


martes, 1 de octubre de 2019

Unidad 2

Notación polaca

La notación polaca, también conocida como notación de prefijo o notación prefija, es una forma de notación para la lógica, la aritmética, el álgebra y la computación. Su característica distintiva es que coloca los operadores a la izquierda de sus operandos. Si la aridad de los operadores es fija, el resultado es una sintaxis que carece de paréntesis u otros signos de agrupación, y todavía puede ser analizada sin ambigüedad. El lógico polaco Jan Łukasiewicz inventó esta notación alrededor de 1920 para simplificar la lógica proposicional.
La notaciones de prefijo (o polaca, en homenaje a Jan Łukasiewicz), de infijo y de postfijo (o polaca inversa) son formas de escritura de expresiones algebraicas que se diferencian por la posición relativa que toman los operadores y los operandos. En la notación de prefijo, el operador se escribe delante de los operandos (+ 3 4), entre los operandos en la notación de infijo (3 + 4) y tras los operandos en la de posfijo (3 4 +).
La notación de prefijo fue propuesta en 1924 por el matemático, lógico y filósofo polaco Jan Łukasiewicz (1878-1956), de allí el nombre alternativo por la que se conoce.
Al igual que la de postfijo, la notación polaca permite prescindir de los paréntesis en el caso de operadores de paridad fija conocida. Por ejemplo, la operación 5 * (12 + 4).puede escribirse en prefijo como: * 5 (+ 12 4); o sencillamente: * 5 + 12 4 (y como 5 12 4 + *en postfijo).
Łukasiewicz introdujo esta notación con la intención de simplificar la lógica proposicional. El matemático y lógico Alonzo Church la mencionaba en su libro clásico Introduction to Mathematical Logic (1956) como una notación digna de observación. Aunque dejó pronto de utilizarse en lógica, encontró su lugar en las ciencias de la computación. Por ejemplo, el lenguaje de programación LISP basa precisamente su sintaxis en la notación polaca.
Las calculadoras Hewlett-Packard usan la notación polaca inversa, económica en número de entradas, pero que requiere un esfuerzo adicional para la interpretación del resultado. Esta empresa utilizó este sistema por primera vez en 1968, en la calculadora de sobremesa HP-9100A. Y fue también ésta la notación de la primera calculadora científica de bolsillo, la HP-35, usada entre 1972 y 1975.

código p


El código P comenzó como un código ensamblador objetivo estándar producido por varios compiladores Pascal en la década de 1970 y principios de la de 1980. Fue diseñado para código real para una maquina de pila hipotética la idea era hacer que los compiladores de Pascal se transportaran fácilmente requiriendo solo que se volviera a escribir el interprete de la maquina P para una plataforma, el código P también a probado ser útil como código intermedio y sean utilizado varias extensiones y modificaciones del mismo en diverso compiladores de código nativo,
La mayor parte para lenguaje tipo Pascal.
*Como el código P fue diseñado para ser directamente ejecutable, contiene una descripción implícita de un ambiente de ejecución particular que incluye tamaños de datos, además de mucha información especifica para la maquina P, que debe conocer si se desea que un programa de código P se comprensible. La maquina P esta compuesta por una memoria de código, una memoria de datos no específica para variables nombre das y una pila para datos temporales, junto como cualquiera registro que sea necesario para mantener la pila y apoyar la ejecución.
        COMPARACIÓN
*El código P en muchos aspectos está más código de maquina real que al código de tres direcciones. Las instrucciones en código P también requiere menos de tres direcciones: tosas las instrucciones que hemos visto son instrucciones de "una dirección" o "cero direcciones". Por otra parte, el código P es menos compacto que el código de tres direcciones en términos de números de instrucciones, y el código P no esta "auto contenido" en el sentido que las instrucciones funciones implícitas en una pila (y las localidades de pila implícitas son de hecho las direcciones "perdidas"). La ventaja respecto a la pila es que contiene los valores temporales necesarios en cada punto del código, y el compilador no necesita asignar nombre a ninguno de ellos, como el código de tres direcciones.

Triplos


En la historia de los compiladores han sido utilizadas una amplia variedad de representaciones intermedias como lo es la siguiente clase de representación de código intermedio de un árbol de 3 direcciones,2 para los operandos y una para la ubicación del resultado. esta clase incluye un amplio numero de representaciones diferentes entre las cuales encontramos cuadruplos y triples. la principal diferencia entre estas notaciones y la notación postfija es que ellos incluyen referencias explicitas para los resultados de los cálculos intermedios, mientras que la notación posfija los resultados son implícitos al representarlos en una pila.
  • La diferencia entre triples y cuadruplos es que con los triples es referenciado el valor intermedio hacia el numero del triple que lo creo, pero en los cuádruplos requiere que ellos tengan nombre implícitos.
  • Los triples tienen una ventaja obvia de ser mas consistente, pero ellos dependen de su posición, y hacen que la optimización presente cambios de código mucho mas compleja.
Para evitar tener que introducir nombres temporales en la tabla de símbolos, se hace referencia a un valor temporal según la posición de la proposición que lo calcula. Las propias instrucciones representan el valor del nombre temporal. La implementación se hace mediante registros de solo tres campos (op, arg1, arg2).
  • En la notación de tripletes se necesita menor espacio y el compilador no necesita generar los nombres temporales. Sin embargo, en esta notación, trasladar una proposición que defina un valor temporal exige que se modifiquen todas las referencias a esa proposición. Lo cual supone un inconveniente a la hora de optimizar el código, pues a menudo es necesario cambiar proposiciones de lugar.
  • Una forma de solucionar esto consiste en listar las posiciones a las tripletas en lugar de listar las tripletas mismas. De esta manera, un optimizador podría mover una instrucción reordenando la lista, sin tener que mover las tripletas en si.

Cuadruplos

Es una estructura tipo registro con cuatros campos que se llaman:
Operador
Operando1
Operando2
Resultado
Donde operando1, operando2 y resultado pueden ser constantes, identificadores y variables temporales definidos por el compilador mientras que operador representa una operación arbitraria.
Operador
Operando1
Operando2
Resultado
*
C
D
T1
+
B
T1
T2
=
T2
A
EJEMPLO:
A := B + C * D
Esquemas de generación.
¿Que son?
 Los esquemas de generación son las estrategias o acciones que deberán realizarse y tomarse en cuenta en el momento de generar código intermedio.
Declaración de variables y constantes.
Las declaraciones de variables y constantes deben separarse de tal manera que queden las expresiones una por una de manera simple.

• Por ejemplo int a,b,c;
se descompone a int a;
int b; intc; respectivamente.
Las variables utilizadas en los programas se clasifican en dos tipos:
variables locales y variables globales.

Esquema de generación


Una forma de hacer esto es mediante el llamado código de tres direcciones. Una sentencia en código de tres direcciones es: A := B op C, donde A, B y C son operandos y op es un operador binario. También permite condiciones simples y saltos. Por ejemplo, para la siguiente sentencia:
WHILE (A > B) AND (A < = 2 * B – 5) DO A : = A + B
el código intermedio generado ( código en tres direcciones) será:

L1 : IF A > B GOTO L2
GOTO L3
L2 : T1 : = 2 * B (*nivel más alto que ensamblador*)
T2 : = T1 – 5 (*pero más sencillo que Pascal*)
IF A < T2 GOTO L4
GOTO L3
L4 : A : = A + B
GOTO L1
L3 : . . . . . . .


Variables y constantes




Declaración de variables y constantes.
Las declaraciones de variables y constantes deben separarse de tal manera que queden las expresiones una por una de manera simple.

• Por ejemplo int a,b,c;
se descompone a int a;
int b; intc; respectivamente.
Las variables utilizadas en los programas se clasifican en dos tipos:
variables locales y variables globales.
Variables locales:
Aquella que está declarada para el programa o algoritmo completo.
 Para definir variables locales, la definición debe hacerse inmediatamente después de una llave de inicio ({), y la variable deja de existir fuera de la llave de fin(}) que corresponde a la llave de inicio después del cuál fue definida la variable.
Ejemplo:
{
int a,b;
a=5;
b=a + 100;
}
Variables globales:
Aquella que está declarada y definida dentro de una función y sólo es válida dentro de la misma función y no podrá utilizarse en otra parte del programa.
 Una variable global se declara fuera de cualquier función y primero que cualquier función que requiera de ella. Una variable se declara de la siguiente forma:
 tipo identificador1, identificador2..ident n;
Ejemplos:
 Algunos ejemplos de cómo definir variables son los siguientes:
 int alumnos, contador;
 float A,B,C;
 char Letra;
Declaracion de Constantes.
Para declarar constantes en el lenguaje C, sólo basta anteponer el calificador const seguido del tipo de dato que manejará esa constante (int,char,etc), y por último el valor que tomará esa variable.
Ejemplo:
const int k = 12

Expresiones


Es un equivalente algebraico para un autómata. Utilizado en muchos lugares como un lenguaje para describir patrones en texto que son sencillos pero muy útiles. Pueden definir exactamente los mismos lenguajes que los autómatas pueden describir: Lenguajes regulares.
Ofrecen algo que los autómatas no: Manera declarativa de expresar las cadenas que queremos aceptar.
Dado un alfabeto Σ, una , expresión regular sobre expresión regular sobre Σ se define de forma recursiva:
ER primitivas: Φ, λ, {a | a ЄЄЄ Σ Є}
Si α y β son ER, entonces son también ER: α + β (unión), α β (concatenación), α* (cierre), (α).
No existen otras reglas para la construcción de ER sobre Σ.
Ejemplos de usos.
Comandos de búsqueda, e.g., grep de UNIX.
sistema de formato de texto: Usan notación de tipo expresión regular para describir patrones.
Convierte la expresión regular a un DFA o un NFA y simula el autómata en el archivo de búsqueda.
Generadores de analizadores - Léxicos. Como Lex o Flex.
Los analizadores léxicos son parte de un compilador. Dividen el programa fuente en unidades lógicas (tokens) divide el programa fuente en unidades.
Produce un DFA que reconoce el token.
Las expresiones regulares denotan lenguajes.
Por ejemplo, la expresión regular: 01* + 10* denota todas las cadenas que son o un 0 seguido de cualquier cantidad 1's o un 1 seguida de cualquier cantidad de 0's.
Operaciones de los lenguajes:
Unión: Si L y M  son dos lenguajes, su unión se denota por L U M.
Concatenación: La concatenación es: LM o L.M.
Cerradura (o cerradura de Kleene): Si L es un lenguaje su cerradura se denota por L *.
Si E es una expresión regular, entonces L(E) denota el lenguaje que define E. Las expresiones se construyen de la manera siguiente:
Las contantes  y  son expresiones regulares que representan a los lenguajes L (Q) = {Q} y L (Φ) L = Φ respectivamente.
Si a es un símbolo, entonces es una expresión regular que representan al lenguaje: L (a) = {a}.

Instrucciones de asignación


Ahora que tenemos claro lo que es una variable veremos cómo almacenar información en ellas, para esto utilizamos la instrucción de asignación.


La instrucción de asignación se encarga de guardar un valor en una variable, para esto es importante tener en cuenta que el valor que se guarde debe ser del mismo tipo que se ha definido a la variable, es decir, si defino una variable de tipo entero no podré asignarle un decimal.

La instrucción de asignación tiene la siguiente sintaxis:

nombre variable receptora = valor que se le asigna;

Siempre la variable que recibe el valor va del lado izquierdo al “=”.

Cuando nos referimos a valor que se le asigna puede ser representado de varias formas, que describiremos a continuación:

Asignación de un valor fijo
Se asigna directamente un valor, por ejemplo:
edad = 18;
nombre = “juan”;
precio = 3.5;

Asignación del valor de una variable
Se asigna el valor que contiene otra variable
int edad, edad2; //definimos 2 variables de tipo entero
edad = 18; //inicializamos la variable edad con un valor fijo
edad2 = edad; //inicializamos la variable edad2 con el valor de la variable edad, es decir con 18

Asignación del valor del resultado de una operación
Se asigna el valor del resultado de una operación

Ejemplo con una variable de tipo entero
int edad, edad2; //definimos 2 variables de tipo entero
edad = 18 + 2; //inicializamos la variable edad con el valor resultante de la suma, edad = 20
edad2 = edad - 2; //inicializamos la variable edad2 con el valor de la operación resultante de la resta, edad2 = 18

Ejemplo con una variable de tipo cadena de caracteres
String cadena, cadena2; //definimos 2 variables de tipo cadena de caracteres
cadena = “Juan”;//se incializa con el valor fijo “juan”
cadena2 = cadena + “ “ + “Pérez”; //se inicializa con e valor resultante de la concatencación con “ “ y “Pérez”, queda como resultante “Juan Pérez”

Asignación del valor del resultado de una función
Se asigna el valor del resultado de una función, para esto es necesario que el tipo de dato que retorna la función sea del mismo tipo que el de la variable.

float area, lado; //definimos 2 variable de tipo decimal
lado = 3.5; //inicializamos el la variable lado con la longitud del lado de un cuadrado
area = calcularAreaCuadrado(lado); //invocamos a la función calcularAreaCuadrado que retorna una variable de tipo decimal con el resultado del cálculo del aréa de un cuadrado cuyo lado tiene el valor almacenado en la variable lado


Instrucciones de Control 



Como ya se ha mencionado, C es un ejemplo de programación estructurada. En este tipo de programación, es necesario contar con ciertas estructuras que permitan controlar el flujo del programa, es decir, tomar decisiones y repetir acciones.

En la gran mayoría de los programas será necesario tomar decisiones sobre qué acciones realizar. Esas decisiones pueden depender de los datos que introduzca el usuario, de si se ha producido algún error o de cualquier otra cosa.
La estructura condicional if ... else es la que nos permite tomar ese tipo de decisiones. Traducida literalmente del inglés, se la podría llamar la estructura "si...si no", es decir, "si se cumple la condición, haz esto, y sino, haz esto otro".
Un ejemplo sencillo sería el siguiente (no se trata de un programa completo, sino tan sólo una porción de código):
 if (edad < 18) 
  printf("No puedes acceder.\n");
 else
  printf("Bienvenido.\n");
Este código de ejemplo dice que si el valor de la variable edad es menor que 18 se imprimirá "No puedes acceder.\n", mientras que en caso contrario se imprimirá "Bienvenido.\n".
Como se ve en el ejemplo, la estructura de un condicional es bastante simple:
 if (condición) {
  sentencias_si_verdadero;
 } else {
  sentencias_si_falso;
 }