Construyendo el compilador Parte IV: ANTLR V4, y gramática de Cardelli
La entrada de hoy es algo corta. Solo quiero nombrar y enfatizar qué es una gramática de cardelli.
Una gramática de cardelli o los tipos de cardelli, es una manera de expresar formalmente las reglas semánticas que definen un lenguaje de programación. Para este proyecto, serán las siguientes.
Sistema de tipos
Definiendo Sintaxis de los Tipos
int
char
boolean
void
error
Tipo de ámbito
Ámbito estático-léxico
Consideraciones generales
Números son: [0..9]*
Palabras reservadas de bool: true, false
otras palabras reservadas: if, while, { },[ ],
Proposiciones
: En todos los posibles ámbitos
G : Ámbito Global
No.
Regla
Explicación
1
|- true: bool
|- false: bool
Los lexemas “true” y “false” serán tomados con tipo de dato bool en todo el programa.
2
G |- a: int
G |- b: int
------------------
G |- a + b: int
G |- a - b: int
G |- a * b: int
G |- a / b: int
G |- a % b: int
G |- a < b: bool
G |- a > b: bool
G |- a >= b: bool
G |- a <= b: bool
G |- a == b: bool
G |- a != b: bool
G |- a = b: void
Entre “a” y “b”, con tipos de datos “int”, la suma, resta, multiplicación, división y modular serán “int” también.
Las operaciones lógicas retornarán bool.
3
G |- a: char
G |- b: char
------------------
G |- a + b: char
G |- a - b: ERROR
G |- a * b: ERROR
G |- a / b: ERROR
G |- a == b: bool
G |- a != b: bool
G |- a = b: void
Entre “a” y “b”, con tipos de datos “char”, la suma resultará en la concatenación pero la resta, multiplicación y división generará ERROR.
Los tipos de operandos para los operadores de equivalencia deben de ser ambos operandos del mismo tipo.
4
G |- a: int
G |- b: char
------------
G |- a + b: int
G |- a - b: int
G |- a * b: int
G |- a / b: ERROR
G |- a % b: int
G |- a == b: ERROR
G |- a != b: ERROR
G |- a && b: ERROR
G |- a || b: ERROR
G |- !a || !b: ERROR
Con carácter global, las operaciones de suma, resta y multiplicación entre un int y un char resultan en un int. Sin embargo, la división generará ERROR.
5
|- <: bool
|- >: bool
|- <=: bool
|- >=: bool
Operaciones de comparación
6
|- ==: bool
|- !=: bool
Operaciones de equivalencia
7
|- &&: bool
|- ||: bool
Operaciones condicionales
8
|- a(): void
Existencia de métodos con valor de retorno vacío
9
G |- a: bool
G |- b: bool
------------------
G |- a && b: bool
G |- a || b: bool
G |- a == b: bool
G |- a != b: bool
G |- a = b: void
Con carácter global, las operaciones condicionales entre booleanos dan cómo resultado un booleano.
Los tipos de operandos para los operadores de equivalencia deben de ser ambos operandos del mismo tipo.
10
G |- a: int
G |- b: bool
------------------
G |- a + b: ERROR
G |- a - b: ERROR
G |- a * b: ERROR
G |- a / b: ERROR
G |- a % b: ERROR
G |- a == b: ERROR
G |- a != b: ERROR
G |- a && b: ERROR
G |- a || b: ERROR
G |- !a || !b: ERROR
Cualquier operación entre tipos de datos “int” y “bool”, la suma, resta, multiplicación y división resultará en ERROR.
11
, a: int, b: int |- a==b: ERROR
Dadas dos variables del tipo int o de cualquier tipo, si ambas son iguales, ERROR.
12
, a: int,bool,char |- a: ERROR
Dado una variable “a” de tipo int, bool o char, si se vuelve a definir otra variable a, genera ERROR.
13
, a: int |- w=10: ERROR
Dada una variable int o cualquier tipo, es teorema que si tratamos de usar otra que no sea la declarada, es error.
14
|- main(): void
El programa contiene una definición de un método main sin parámetros, en donde se empezará la ejecución del programa.
15
G |- a: void
G |- b: void
------------------
G |- a + b: ERROR
G |- a - b: ERROR
G |- a * b: ERROR
G |- a / b: ERROR
G |- a % b: ERROR
Funciones, variables, etc. de tipo void que no retornan un valor, no pueden realizar operaciones entre sí, por lo que generará ERROR.
16
num en la declaración de un arreglo debe de ser mayor a 0.
*
17
El número y tipos de argumentos en la llamada a un método deben de ser los mismos que los argumentos formales, es decir las firmas deben de ser idénticas.
*
18
|- expre<method>: return value
Si un método es utilizado en una expresión,este debe de devolver un resultado.*
19
G |- a: bool
G |- b: bool
--------------------
G |- a && b: bool
G |- a || b: bool
G |- !a || !b: bool
Los tipos de operandos para los operadores <cond_ops> y el operador ! deben de ser del tipo boolean.
20
G |- <expr>: bool
--------------------
G |- if(<expr>){...}: void
G |- while(<expr>){...}: void
Teniendo <expr> como un bool, dicha expresión está dentro de una condición if y while es correcto, de lo contrario ERROR.
21
G |- <expr>: int
G |- id: arreglo(tabla de símbolos)
--------------------
G |- id[<expr>]: void
Si se tiene la expresión id[<expr>], id debe de ser un arreglo y el tipo de <expr> debe de ser int.
22
G |- X: struct
G |- Y: struct
G |- x: int
G |- y: int
--------------------
G |- X a: void
G |- Y b: void
G |- a.x: int
G |- b.y: int
G |- a.x + a.y: int
G |- a.x - a.y: int
G |- a.x * a.y: int
G |- a.x / a.y: int
La definición de un tipo struct ocurre posicionando el struct utilizado y el nombre de la variable del struct, además, el contenido del struct (en este caso ocurre con int’s, pero puede ser cualquier tipo primitivo) puede operarse entre sí como se ha hecho en definiciones anteriores.
Comentarios
Publicar un comentario