Propósito: Crear un intérprete de instrucciones en ensamblador para un robot-dron capaz de dibujar sobre un lienzo. Este proyecto es una secuencia del Examen01. El conjunto de instrucciones del robot debe ser extendido para permitir ciclos y subrutinas. Para lograr esto, cualquier instrucción puede iniciar con una etiqueta de la forma label:, y las instrucciones pueden recibir en sus argumentos tanto números enteros largos (long) como registros de CPU (en inglés, register) r0 a r9. El siguiente es un ejemplo de un programa con estas nuevas características:

Ejemplo de entrada 31:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
10 10 .

call main
exit

spiral: jmple r0 1 end ; If length <= 1, return
  ink ^ ; Ink for ascending path
  up r0 ; Draw ascending path (e.g: up 11)
  sub r0 2; Decreases length by 2 (e.g: length := length - 2)
  jmpz r0 end ; If length = 0, return
  ink < ; Ink for left path
  left r0 ; Draw left path (e.g: left 9)
  jmple r0 1 end ; If length <= 1, return
  ink v ; Ink for descending path
  down r0 ; Descending path has same length than left path (e.g: down 9)
  sub r0 2; Decreases length by 2 (e.g: length := length - 2)
  jmple r0 0 end ; If length <= 0, return
  ink > ; Ink for right path
  right r0 ; Draw right path (e.g: right 7)
  call spiral ; Call subroutine recursively
end: ret ; Return subroutine, pop register array and resume program counter

main: fly r1 r2 ; Fly to last row and col (e.g: fly 10 10)
  set r0 r2 ; r0 := cols, will be initial length of path (e.g: length := 10)
  inc r0 ; r0 := r0 + 1, first up will be longer (e.g: r0 := 11)
  call spiral ; Call subroutine, program counter and registers are stacked
  _draw
ret

Ejemplo de salida 31:

v < < < < < < < < <
v . . . . . . . . ^
v . v < < < < < . ^
v . v . . . . ^ . ^
v . v . . < . ^ . ^
v . v . . ^ . ^ . ^
v . v . . ^ . ^ . ^
v . > > > ^ . ^ . ^
v . . . . . . ^ . ^
> > > > > > > ^ . ^

Las nuevas instrucciones se listan en la siguiente tabla, donde el argumento r siempre tiene que ser un registro de CPU (r0 a r9) y el argumento v puede ser o un valor entero literal o un registro de CPU. Si v es un registro, se evaluará por el valor entero que tenga el registro correspondiente. El texto pc se refiere al registro program counter cuyo valor entero indica cual será la próxima instrucción a ser ejecutada. El argumento lbl se refiere a una etiqueta que debe existir en otra instrucción del programa y se reemplaza por su número de instrucción.

# Instrucción Psudocódigo Efecto

8

set r v

r := v

Asigna el valor v al registro r

9

inc r

r := r + 1

Incrementa en 1 el registro r

10

dec r

r := r - 1

Decrementa en 1 el registro r

11

add r v

r := r + v

Suma el valor v al registro r

12

sub r v

r := r - v

Disminuye a r en v

13

call lbl

lbl()

Apila (push) una copia del arreglo de registros e invoca la subrutina cuya primera instrucción está indicada por la etiqueta.

14

ret

return

Retorna de la subrutina actual. Des-apila (pop) el arreglo de registros de la vieja subrutina y restablece el contador de programa (program counter).

15

jmpeq v1 v2 lbl

if v1 == v2 then
pc := lbl

Si v1 y v2 son iguales, la próxima instrucción a ejecutar será la indicada por lbl

16

jmpge v1 v2 lbl

if v1 >= v2 then
pc := lbl

Si v1 es mayor o igual que v2, la próxima instrucción a ejecutar será la indicada por lbl

17

jmpgt v1 v2 lbl

if v1 > v2 then
pc := lbl

Si v1 es mayor estricto que v2, la próxima instrucción a ejecutar será la indicada por lbl

18

jmple v1 v2 lbl

if v1 <= v2 then
pc := lbl

Si v1 es menor o igual que v2, la próxima instrucción a ejecutar será la indicada por lbl

19

jmplt v1 v2 lbl

if v1 < v2 then
pc := lbl

Si v1 es menor estricto que v2, la próxima instrucción a ejecutar será la indicada por lbl

20

jmpz v lbl

if v == 0 then
pc := lbl

Si v es cero, la próxima instrucción a ejecutar será la indicada por lbl

Proyecto01: solución procedimental

Fecha límite de entrega 15 de junio a la medianoche en repositorio de control de versiones.

  1. [5%] Buen uso de control de versiones (commits, ignores). Estructura de directorios y archivos.

  2. [10%] Análisis (readme): problema a resolver, compilación de la solución (build), manual de usuario. Construcción automática (Makefile).

  3. [10%] Apego a una convención de estilos (linting).

  4. [10%] Documentación de interfaces (Doxygen): propósito, parámetros, supuestos (contratos). Documentación de implementaciones: comentarios en los cuerpos de subrutinas de lo que no es trivial.

  5. [15%] Estructuras de datos (registros de memoria) para representar el estado de la máquina (programa, lienzo, robot). Creación, inicialización y liberación de estructuras de datos. Buen manejo de memoria (ASan).

  6. [15%] Cargado del programa y etiquetas. Ejecución de instrucciones. Reporte de errores.

  7. [15%] Invocación y retorno de subrutinas. Apilar y des-apilar el arreglo de registros. Actualizar el program counter.

  8. [10%] Asignación, incremento, decremento, suma y resta de registros.

  9. [10%] Los seis tipos de saltos. Evaluación de las expresiones y actualización del program counter.

Proyecto02: solución genérica-polimórfica

Es normal que los proyectos de software crezcan ante nuevos requerimientos de las personas clientes/usuarias. Es muy valioso producir código fuente que de forma fácil pueda ser modificado para implementar esas nuevas necesidades rápidamente. En este propósito ayudan los paradigmas de programación genérica y orientada a objetos. Su propósito en este proyecto es agregar las siguientes mejoras a su solución:

  1. [30%] Migrar el código fuente de C a C++:

    1. Diseño orientado a objetos en un diagrama de clases UML.

    2. Cambiar los registros de memoria (ej.: programa, lienzo, robot) por objetos modelo, cada uno en su propio archivo fuente.

    3. Agregar un objeto controlador.

    4. Impedir violaciones de encapsulación.

    5. Impedir mal manejo de copias de objetos (regla de los 5).

    6. Cambiar el segmento de código por una sección de código de tamaño arbitrario con arreglos dinámicos (std::vector).

    7. Hacer la tabla de símbolos (etiquetas) de tamaño dinámico (std::map).

    8. Hacer que la pila de invocaciones sea de tamaño dinámico (std::stack).

    9. Permitir que las instrucciones sean de tamaño variable (std::string).

    10. Manejo de excepciones (try-catch).

    11. Aplicar buenas prácticas de programación.

  2. [20%] Lienzo genérico. Permita que su programa pueda trabajar con lienzos, tinta, y relleno, con tipos de datos arbitrarios. Los casos de prueba permitirán indicar en la primer línea un identificador del tipo de datos a usar (ej.: char, string, int…​).

  3. [20%] Jerarquía de instrucciones polimórficas. Factorice código redundante de las instrucciones mediante herencia y polimorfismo. Provea una clase base abstracta para las instrucciones que imponga una interfaz que ayude a crear nuevos tipos de instrucciones. Derive familias de instrucciones (ejemplo: la familia de asignaciones, familia de saltos, véase la evaluación del primer entregable).

  4. [10%] Nuevas instrucciones. Ponga a prueba su base de código ante nuevos requerimientos de su cliente. Agregue instrucciones para multiplicación entera (mul r v), división entera (div r v), residuo de la división entera (mod r v), salto incondicional (jmp lbl), y salto condicional diferente-de (jmpne v1 v2 lbl).

  5. [5%] Buen uso de control de versiones (commits, ignores). Estructura de directorios y archivos. Construcción automática (Makefile). Manual de usuario en el readme.ext.

  6. [8%] Apego a una convención de estilos (linting).

  7. [7%] Documentación de clases y métodos (Doxygen): propósito, parámetros, supuestos (contratos). Documentación de implementaciones: comentarios en los cuerpos de subrutinas de lo que no es trivial.

Fecha límite de entrega jueves 04 de julio a la medianoche en repositorio de control de versiones.

Proyecto03: interfaz gráfica de usuario [opcional]

Implemente una versión realista de su proyecto que provea una interfaz gráfica que permita a sus usuarios escribir programas y correrlos para ver su efecto en un lienzo hecho con pixeles. Utilice alguna tecnología que lo aísle de la plataforma (ej.: Qt). Su programa debe proveer:

  1. [20%] Un controlador general de la aplicación. Una pantalla principal (vista), con un menú o barra de herramientas, un editor de texto para el segmento de código, una ventana de lienzo, y controles de reproducción de la ejecución. Estos componentes gráficos deben estar bien maquetados para aprovechar el área de la pantalla.

  2. [20%] El editor de texto (sección de código) permite abrir archivos existentes, cerrarlos, crear nuevos archivos, guardarlos, y modificarlos. Provea resaltado sintáctico (syntax highlighting) del código ensamblador.

  3. [25%] Un lienzo gráfico que donde el robot pinte con pixeles. Puede extender una ventana (widget) y modificar sus rutinas de pintado para dibujar la matriz de pixeles. Permita a las personas usuarias indicar tinta de colores en su código ensamblador. Sugerencia, puede usar notación hexadecimal para los pixeles (ej.: ink ffff00 indica amarillo). Sugerencia: mantenga ajustado el tamaño del lienzo al tamaño de la ventana.

  4. [25%] Permita a las personas usuarias controlar la ejecución de su programa usando la interfaz de un reproductor de medios. Diseñe un autómata (máquina de estados finito) con los estados y eventos de su programa. Provea un control deslizante (slider) para ajustar la velocidad de ejecución del código y botones para:

    1. Ejecutar (play) que al activarse muestra el lienzo, y ejecuta las instrucciones una tras otra a la velocidad indicada en el control deslizante.

    2. Pausar (pause), que sólo está activo mientras la ejecución esté en progreso. Puede usar el mismo control de Ejecutar, si lo prefiere. Al activarse suspende temporalmente la ejecución del programa.

    3. Detener (stop) que sólo está activo si la ejecución está en progreso o pausada. Al activarse detiene la ejecución del programa y retira el lienzo de la pantalla.

    4. Siguiente instrucción (forward). Sólo está activo cuando la ejecución está pausada. Al activarse ejecuta la siguiente instrucción del programa y muestra su efecto en el lienzo.

  5. [10%] Mientras el programa está en ejecución, resalte en la sección de código la línea actualmente en ejecución (program counter). Necesitará mapear la instrucción al número de línea en el archivo fuente. Provea una vista de los registros de CPU (r0 a r9) de la subrutina actualmente en ejecución.

Fecha límite de entrega sábado 13 de julio a la medianoche en repositorio de control de versiones.