Skip to content
Snippets Groups Projects
Commit ab7112d3 authored by albruiz's avatar albruiz
Browse files

Profesor Dusan

parent 566f158a
Branches
No related tags found
1 merge request!1Arbol
_mk 0 → 100644
bison --defines -v inter05.y -o inter05.c
flex -o inter05.lex.c inter05.l
gcc inter05.c inter05.lex.c symtab.c stduse.c astree.c -o x_inter05 -lm
astree.c 0 → 100644
/**
* @Author: Dušan Kolář
* @Year: 2003-2018
* Copyright (c) 2018
* Licence: GLP 3.0
*/
#include "astree.h"
#include "stduse.h"
#include "inter05.h"
#include "symtab.h"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
extern int yylineno;
// Crear hoja String
ast_t *mkSlf(unsigned tag, char *str) {
ast_t *res = xmalloc(sizeof(ast_t));
lnum(res) = (unsigned)yylineno;
tag(res) = tag;
sv(res) = str;
return res;
}
// Crear hoja double (número)
ast_t *mkDlf(unsigned tag, double dval) {
ast_t *res = xmalloc(sizeof(ast_t));
lnum(res) = (unsigned)yylineno;
tag(res) = tag;
dv(res) = dval;
return res;
}
// Crear nodo (padre de l y r)
ast_t *mkNd(unsigned tag, ast_t *l, ast_t *r) {
ast_t *res = xmalloc(sizeof(ast_t));
lnum(res) = (unsigned)yylineno;
tag(res) = tag;
left(res) = l;
right(res) = r;
return res;
}
// Añadir nodo nd como hijo de lst
// Se busca por la derecha hasta que no se encuentra una nada
// Se añade como hijo derecho de la hoja (último nodo en el que se ha buscado)
// un nodo con nd como hijo izquierdo
ast_t *appR(unsigned tag, ast_t *lst, ast_t *nd) {
if (lst == NULL) {
if (nd == NULL) {
return NULL;
}
return mkNd(tag,nd,NULL);
}
if (nd == NULL) {
return lst;
}
ast_t *tmp = lst;
while (right(tmp) != NULL) {
tmp = right(tmp);
}
right(tmp) = mkNd(tag,nd,NULL);
return lst;
}
// ----------------------------------------------------------------------------
static double expr(ast_t *root) {
// Procesar un nodo terminal
switch (tag(root)) {
// Operador ternario (lo más complicado aquí)
case '?':
// Interpretar la expresión izquierda
if (expr(left(root)) != 0.0) {
// Es la expresión izquierda
return expr( left(right(root)) );
} else {
// Es la expresión derecha
return expr( right(right(root)) );
}
// Los operadores lógicos es símplemente ejecutarlos y ya
case OR:
if (expr(left(root)) != 0.0 || expr(right(root)) != 0.0) {
return 1.0;
} else {
return 0.0;
}
case AND:
if (expr(left(root)) != 0.0 && expr(right(root)) != 0.0) {
return 1.0;
} else {
return 0.0;
}
case EQ:
if (expr(left(root)) == expr(right(root))) {
return 1.0;
} else {
return 0.0;
}
case NE:
if (expr(left(root)) != expr(right(root))) {
return 1.0;
} else {
return 0.0;
}
case LE:
if (expr(left(root)) <= expr(right(root))) {
return 1.0;
} else {
return 0.0;
}
case GE:
if (expr(left(root)) >= expr(right(root))) {
return 1.0;
} else {
return 0.0;
}
case '<':
if (expr(left(root)) < expr(right(root))) {
return 1.0;
} else {
return 0.0;
}
case '>':
if (expr(left(root)) > expr(right(root))) {
return 1.0;
} else {
return 0.0;
}
// Las operaciones aritméticas, más de lo mismo: ejecutarlas
case '+':
return expr(left(root)) + expr(right(root));
case '-':
// Como operador unario (cambio de signo)
if (left(root) == NULL) {
return - expr(right(root));
// Como operador binario (resta)
} else {
return expr(left(root)) - expr(right(root));
}
case '*':
return expr(left(root)) * expr(right(root));
case '/':
return expr(left(root)) / expr(right(root));
case '^':
return pow( expr(left(root)), expr(right(root)) );
case '!':
if (expr( right(root) ) == 0.0) {
return 1.0;
} else {
return 0.0;
}
// Los terminales: devolver su valor correcto
case FLOAT:
return dv(root);
// Variables: leerlas de la tabla de símbolos
case IDENT:
return read( sv(root) );
// Funciones predefinidas: ejecutarlas
case SIN:
return sin( expr(left(root)) );
case COS:
return cos( expr(left(root)) );
case TAN:
return tan( expr(left(root)) );
// Strange coisas
default:
prError((unsigned short)lnum(root),"Unknown tag in expr AST %u\n",tag(root),NULL);
break;
}
}
// Procesar el árbol (un nodo de sentencia)
static void proc(ast_t *root) {
switch (tag(root)) {
case '=':
// Insertar en la table de símbolos el identificador (izquierda)
// y su valor (derecha)
// sv = valor de String del nodo (nombre de la variable)
insertModify( sv(left(root)), expr(right(root)) );
break;
case PRINT:
// Si no hay nodo izquierdo (String)
// imprimir solo la variable (nodo derecho)
if (left(root) == NULL) {
printf("%g\n", expr(right(root)) );
// Si no hay nodo derecho (variable)
// imprimir solo la String (nodo izquierdo)
} else if (right(root) == NULL) {
puts( sv(left(root)) );
// Si hay nodo derecho e izquierdo
// imprimir la String seguido de la variable
} else {
printf("%s%g\n", sv(left(root)), expr(right(root)) );
}
break;
case READ:
// No hay que imprimir
if (left(root) == NULL) {
double rval;
scanf("%lf",&rval);
// Cambiar el valor del símbolo en la tabla
insertModify(sv(right(root)), rval);
// Hay que imprimir (nodo izquierdo)
} else {
double rval;
printf("%s", sv(left(root)));
scanf("%lf", &rval);
// Cambiar el valor del símbolo en la tabla
insertModify( sv(right(root)), rval);
}
break;
default:
// Bro momento
prError((unsigned short)lnum(root),"Unknown tag in statement AST %u\n",tag(root),NULL);
break;
}
}
// Procesar el árbol entero (ejecutar el programa)
void evaluate(ast_t *root) {
while (root != NULL) {
// Ejecutar el subárbol izquierdo
proc(left(root));
// Pasar al subárbol derecho
root = right(root);
}
}
// ----- EOF ------
astree.h 0 → 100644
/**
* @Author: Dušan Kolář
* @Year: 2003-2018
* Copyright (c) 2018
* Licence: GLP 3.0
*/
#ifndef ___ASTREE_H___
#define ___ASTREE_H___
// Se define el tipo ast_t (tipo AST)
// como un alias para la estructura ast_s (estructura AST)
typedef struct ast_s {
unsigned tag; // Etiqueta del nodo
unsigned lineno; // Línea del nodo
union { // Solo 1 de entre 3 tipos de nodos:
struct {
struct ast_s *lft, *rgt; // Nodo con dos hijos (derecho e izquierdo)
} ptr;
char *sVal; // Nodo con una string.
double dVal; // Nodo con un número.
} u;
} ast_t;
#define tag(x) (x->tag)
#define lnum(x) (x->lineno)
#define left(x) (x->u.ptr.lft)
#define right(x) (x->u.ptr.rgt)
#define sv(x) (x->u.sVal)
#define dv(x) (x->u.dVal)
// Crear hoja String
ast_t *mkSlf(unsigned tag, char *str);
// Crear hoja double (número)
ast_t *mkDlf(unsigned tag, double dval);
// Crear nodo (padre de l y r)
ast_t *mkNd(unsigned tag, ast_t *l, ast_t *r);
ast_t *appR(unsigned tag, ast_t *lst, ast_t *nd);
void evaluate(ast_t *root);
#endif
inter05.l 0 → 100644
/**
* @Author: Dušan Kolář
* @Year: 2003-2018
* Copyright (c) 2018
* Licence: GLP 3.0
*/
%{
#include <stdio.h>
#include <string.h>
#include "stduse.h"
#include "inter05.h"
#include "token.h"
#include "astree.h"
#define KWLEN 6 /* Número de palabras clave del lenguaje */
/* Palabras clave del lenguaje
(Ordenadas alfabéticamente) */
char *keywords[KWLEN] = {
"cos",
"let",
"print",
"read",
"sin",
"tan",
};
/* Identificadores de las palabras clave */
unsigned keycodes[KWLEN] = {
COS,
LET,
PRINT,
READ,
SIN,
TAN,
};
static void lower(char *s); /* Pasar todas las letras a minúsculas (definida abajo) */
static char *readStr(void); /* Leer y guardar String como "variable" (definida abajo) */
int yywrap(void) { return 1; } /* Al terminar la lectura de un fichero, pista */
%}
LETTER ([_a-zA-Z])
DIGIT ([0-9])
DIGITS ({DIGIT}+)
EXP ([eE][-+]?{DIGITS}) /* Exponente de una float */
FLOAT1 ({DIGITS}"."{DIGITS})
FLOAT2 ({DIGITS}{EXP})
FLOAT3 ({DIGITS}"."{DIGITS}{EXP})
IDENT ({LETTER}({LETTER}|{DIGIT})*) /* Identificador */
COMSEP ([\n]) /* Separador de "comandos" (sentencias) */
WSPC ([ \t\f\r]) /* "Espacio en blanco", no se va a utilizar para nada */
WSPCS ({WSPC}+) /* Muchos espacios en blanco */
FLOAT ({FLOAT1}|{FLOAT2}|{FLOAT3})
OP1 ([-+/*=<>?:()!^]) /* Operadores aritméticos */
OP2 ("=="|"!="|"<="|">="|"&&"|"||") /* Operadores lógicos */
STRSTART (["]) /* Comienzo de cadena de caracteres: comillas dobles " /**/
%%
{WSPC} ; /* nothing to do, white space */
{IDENT} {
unsigned i = 0;
int r=-1;
char *res;
lower(yytext); /* Se pasa a minúsculas */
/* Se busca si es palabra una clave */
while (i<KWLEN && r<0) {
if ((r=strcmp(keywords[i],yytext))==0) return keycodes[i];
++i;
}
/* Si no es una palabra clave */
yyStr(yylval)=sdup(yytext); /* Se copia el identificador leído */
yyFlag(yylval)=fIDENT; /* Se apunta que es un identificador */
return IDENT; /* Se devuelve que se ha leído un identificador */
}
{COMSEP} {
/* Salto de línea: se aumenta el número de línea */
++yylineno; /* yylineno se define aquí (en este fichero) */
return yytext[0]; /* Se devuelve el salto de línea */
}
{DIGITS} {
/* Se lee el número entero */
long int li;
sscanf(yytext,"%ld",&li);
/* Se castea a double */
yyFloat(yylval) = (double)li;
yyFlag(yylval) = fFLOAT;
return FLOAT;
}
{FLOAT} {
/* Se lee el número decimal */
sscanf(yytext,"%lf",&( yyFloat(yylval) ));
yyFlag(yylval) = fFLOAT;
return FLOAT;
}
{STRSTART} {
/* Se lee la String */
yyStr(yylval) = readStr();
yyFlag(yylval) = fSTR;
return STR;
}
{OP1} return yytext[0]; /* Se lee el operador aritmético */
{OP2} {
switch (yytext[0]) { /* Se lee el operador lógico */
case '=':
return EQ;
case '!':
return NE;
case '<':
return LE;
case '>':
return GE;
case '&':
return AND;
case '|':
return OR;
}
}
. {
/* Cualquier otro caracter: error */
prError(yylineno,"Unexpected character in input: %c [%d]\n",yytext[0],yytext[0],NULL);
}
%%
/* Pasar la String s a minúsculas */
static void lower(char *s) {
unsigned l = strlen(s);
/* Vamos de atrás a adelante */
while (l>0) {
--l;
/* Si es una letra mayúscula, pues se hace minúscula. Easy */
if (s[l]>='A' && s[l]<='Z') s[l] = s[l]+'a'-'A';
}
}
/* Añadir caracter c a la String s, acutalizando su tamaño */
static void addStr(char **s, unsigned long *len, char c) {
char buf[2];
buf[0] = c;
buf[1] = '\0';
/* Si la cadena actualmente tiene tantos caracteres (o más) */
/* como undica su tamaño */
if (strlen(*s) >= *len) {
char *ss;
/* Se alocan 1024 caracteres más (más el \0 final) */
ss=xmalloc(*len+1025);
/* Se copia */
strcpy(ss,*s);
/* Se libera la anterior */
xfree(*s);
*s=ss;
/* Se actualiza el tamaño */
*len = *len+1024;
}
/* Se concatena la cadena actual con el caracter + \0 */
strcat(*s,buf);
}
/* Leer y almacenar una String */
static char *readStr(void) {
int c;
char *buff; /* Buffer donde se almacena la String */
unsigned long len = 256; /* Longitud máxima: 256 caracteres */
buff=xmalloc(257); /* Se aloca memoria para la String */
buff[0]='\0'; /* Se pone el primer caracter como '\0' */
/* Se van leyendo caracteres: */
do {
/* Se lee un caracter */
c = input();
/* Caracteres erróneos */
if (c < ' ') prError(yylineno,"Unexpected symbol in string literal [%d]\n",c,NULL);
/* Si se lee el terminador de cadena, se finaliza el bucle */
if (c == '"') break;
/* Las subcadenas '\\' y '\"' se leen como solo '\' y '"', respectivamente */
if (c=='\\') {
c == input();
if (c!='\\' && c !='"') {
unput(c);
c = '\\';
}
}
/* Se añade el caracter leído a la cadena */
addStr(&buff,&len,c);
} while (1);
return buff;
}
/* -- EOF -- */
inter05.y 0 → 100644
/**
* @Author: Dušan Kolář
* @Year: 2003-2018
* Copyright (c) 2018
* Licence: GLP 3.0
*/
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stduse.h"
#include "symtab.h"
#include "astree.h"
#include "token.h"
#define IN_PARSER
#include "inter05.h"
int yylex(void);
extern int yylineno;
FILE *fIn;
int yyerror(char *str);
static ast_t *astRoot = NULL; // Raíz del AST
%}
/* Los elementos sintácticos leídos pueden son una estructura sStackType: */
%union {
struct sStackType {
/* Flag: identificador del tipo */
unsigned char flag;
/* Unión con el valor del tipo correspondiente */
union {
double vFloat;
char *vStr;
struct ast_s *ast;
} u;
} s; /* Identificador del único campo de yylval **/
}
%left OR
%left AND
%nonassoc EQ NE
%nonassoc LE GE '<' '>'
%left '+' '-'
%left '*' '/'
%right '^'
%right '!'
%right UNOP
/* Todos los tokens son del tipo de s (sStackType) */
%token <s> IDENT
%term LET PRINT SIN COS TAN READ
%token <s> FLOAT
%token <s> STR
%type <s> expr ternary statement progelem prog
%%
/* Un programa es */
prog
: progelem // Un elemento de un programa
{
astRoot = appR(';', astRoot, $1.u.ast); // Se añade el nodo de elemento en el AST
}
| prog progelem // O un programa seguido de un elemento de un programa (= varios elementos)
{
astRoot = appR(';', astRoot, $2.u.ast);
}
;
// Un elemento del programa es
progelem
: statement '\n' // Una sentencia con un salto de línea
{
$$ = $1;
}
| '\n' // O un salto de línea (nada)
{
$$.flag = fAST;
$$.u.ast = NULL; // Nodo vacío en el AST (no se va a hacer nada con él)
}
;
// Una sentencia es
statement
: LET IDENT '=' ternary // Una asignación
{
$$.flag = fAST;
// Se añade el nodo con la asignación con hijos lado izquierdo-lado derecho
$$.u.ast = mkNd('=', mkSlf(IDENT,$2.u.vStr), $4.u.ast);
}
| PRINT ternary // Una impresión de una expresión
{
$$.flag = fAST;
$$.u.ast = mkNd(PRINT, NULL, $2.u.ast); // Nodo de impresión sin hijo izquierdo
}
| PRINT STR // Una impresión de una String
{
$$.flag = fAST;
$$.u.ast = mkNd(PRINT, mkSlf(STR,$2.u.vStr), NULL); // Nodo impresión sin hijo derecho
}
| PRINT STR ternary // Una impresión de una String y una variable
{
$$.flag = fAST;
$$.u.ast = mkNd(PRINT, mkSlf(STR,$2.u.vStr), $3.u.ast); // Nodo impresión con dos hijos
}
| READ IDENT // Lectura de una variable
{
$$.flag = fAST;
$$.u.ast = mkNd(READ, NULL, mkSlf(IDENT,$2.u.vStr)); // Nodo lectura sin hijo izquierdo
}
| READ STR IDENT // Impresión y lectura de una variable
{
$$.flag = fAST;
$$.u.ast = mkNd(READ, mkSlf(STR,$2.u.vStr), mkSlf(IDENT,$3.u.vStr)); // Nodo lectura con dos hijos
}
;
// Una expresión ternaria puede ser
ternary
// Una expresión ternaria de varias expresiones ternarias
: ternary '?' ternary ':' ternary
{
$$.flag = fAST;
$$.u.ast = mkNd('?', $1.u.ast, mkNd(':', $3.u.ast, $5.u.ast) );
}
// O una expresión
| expr
/* $$ = $1 */
;
// Expresiones. Simplemente se crean los nodos correspondientes
expr
: expr OR expr
{
$$.flag = fAST;
$$.u.ast = mkNd(OR, $1.u.ast, $3.u.ast);
}
| expr AND expr
{
$$.flag = fAST;
$$.u.ast = mkNd(AND, $1.u.ast, $3.u.ast);
}
| expr EQ expr
{
$$.flag = fAST;
$$.u.ast = mkNd(EQ, $1.u.ast, $3.u.ast);
}
| expr NE expr
{
$$.flag = fAST;
$$.u.ast = mkNd(NE, $1.u.ast, $3.u.ast);
}
| expr LE expr
{
$$.flag = fAST;
$$.u.ast = mkNd(LE, $1.u.ast, $3.u.ast);
}
| expr GE expr
{
$$.flag = fAST;
$$.u.ast = mkNd(GE, $1.u.ast, $3.u.ast);
}
| expr '<' expr
{
$$.flag = fAST;
$$.u.ast = mkNd('<', $1.u.ast, $3.u.ast);
}
| expr '>' expr
{
$$.flag = fAST;
$$.u.ast = mkNd('>', $1.u.ast, $3.u.ast);
}
| expr '+' expr
{
$$.flag = fAST;
$$.u.ast = mkNd('+', $1.u.ast, $3.u.ast);
}
| expr '-' expr
{
$$.flag = fAST;
$$.u.ast = mkNd('-', $1.u.ast, $3.u.ast);
}
| expr '*' expr
{
$$.flag = fAST;
$$.u.ast = mkNd('*', $1.u.ast, $3.u.ast);
}
| expr '/' expr
{
$$.flag = fAST;
$$.u.ast = mkNd('/', $1.u.ast, $3.u.ast);
}
| expr '^' expr
{
$$.flag = fAST;
$$.u.ast = mkNd('^', $1.u.ast, $3.u.ast);
}
| '!' expr
{
$$.flag = fAST;
$$.u.ast = mkNd('!',NULL,$2.u.ast);
}
| '+' expr %prec UNOP
{
$$ = $2;
}
| '-' expr %prec UNOP
{
$$.flag = fAST;
$$.u.ast = mkNd('-',NULL,$2.u.ast);
}
| '(' ternary ')'
{
$$ = $2;
}
| FLOAT
{
$$.flag = fAST;
$$.u.ast = mkDlf(FLOAT,$1.u.vFloat);
}
| IDENT
{
$$.flag = fAST;
$$.u.ast = mkSlf(IDENT,$1.u.vStr);
}
| SIN '(' ternary ')'
{
$$.flag = fAST;
$$.u.ast = mkNd(SIN,$3.u.ast,NULL);
}
| COS '(' ternary ')'
{
$$.flag = fAST;
$$.u.ast = mkNd(COS,$3.u.ast,NULL);
}
| TAN '(' ternary ')'
{
$$.flag = fAST;
$$.u.ast = mkNd(TAN,$3.u.ast,NULL);
}
;
%%
// Error sintáctico: impresión del error
int yyerror(char *str) {
prError(yylineno,"%s\n",str,NULL);
return 1;
}
extern FILE *yyin;
// Programa principal (lanzador)
int main(int argc, char *argv[]) {
exitOnError(); // Se indica que si hay errores se finaliza la ejecución
// Impresión de funcionamiento
if (argc!=2) {
puts("\nUsage: demo <filename>\n");
fflush(stdout);
return 1;
}
// Lectura del fichero (programa)
if ((fIn=fopen(argv[1],"rb"))==NULL) {
fprintf(stderr,"\nCannot open file: %s\n\n",argv[1]);
fflush(stderr);
return 1;
}
yyin = fIn;
// Asignación de nombre al programa
setFilename( argv[1] );
// Parseo del fichero (texto -> AST)
if (yyparse() != 0) {
fclose(fIn);
prError(yylineno,"Parsing aborted due to errors in input\n",NULL);
}
fclose(fIn); // Cierre del fichero
// Si hay raiz en el AST
if (astRoot != NULL) {
evaluate(astRoot); // Interpretación del AST
} else {
prError(yylineno,"No parse output provided, aborting evaluation\n",NULL);
}
return 0;
}
/* -- EOF -- */
read.me 0 → 100644
This is a small DEMO intepreter exploiting flex and bison compilers.
See end of read.me for versions used, even if other versions could be
used as well.
This software was created by Dušan Kolář solely for edicational purposes.
Absolutely no warranty.
It can be used under GPL 3.0 license
List of of files:
astree.c - abstract syntax tree creation and interpretation
astree.h - header file for abstract syntax tree module
inter01.l - lex analyzer specification for flex
inter01.y - syntax parser specification for bison
_mk - simple shell script to build the parser
read.me - this file
stduse.c - a small library of overrided standardly used functions
stduse.h - header file for this library
symtab.c - simple symbol table based on binary tree
symtab.h - header file for this symbol table implementation
token.h - definitions of tags and standard macros to use the attributes
Language parsed:
A very simple line oriented language, supported feattures:
empty line - no action
print expression - prints expression value to standard output
print string - prints string enclosed in double quoutes
print string expression - prints string and directly behind it value of the expression
let variable = expression - assigns value of the expression to the variable
read variable - reads floating point value from standard input, which stores to variable
read string variable - prints string to standard output and reads floating point value to variable
It is case insensitive language.
Expression supports floating point numbers only (integer is treated as a floating
point). Expression can contain variables, floating point constants, brackets,
standard binary operators for addition, subtraction, multiplication, division.
Also power operator (^) is included, it is right associative, though. Next,
C like operators for comparison of values (<, <=, ==, >=, >, !=), operators
for logical and (&&) and logical or (!!). As unary operators, unary plus, minus
and logical negation (!) can be used. Finally, C-like ternary operator can be used
( ? : ). Moreover, functions for sinus (sin), cosinus (cos), and tangets (tan)
are included.
---------------------------
Used versions of compiler compilers:
flex 2.6.4
bison (GNU Bison) 3.0.4
Written by Robert Corbett and Richard Stallman.
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
stduse.c 0 → 100644
/**
* @Author: Dušan Kolář
* @Year: 2003-2018
* Copyright (c) 2018
* Licence: GLP 3.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "stduse.h"
static char fName[10240] = "";
static unsigned char wasE = 0;
static unsigned char exitOnE = 0;
/* --------------------------------------------------------------------- */
// Nombre para el programa
void setFilename(const char *str) {
strcpy(fName,str);
}
/* --------------------------------------------------------------------- */
// Devolución de errores
int wasError(void) { return wasE; }
/* --------------------------------------------------------------------- */
// Apunta que los errores causan la finalización del programa
void exitOnError(void) { exitOnE = 1; }
/* --------------------------------------------------------------------- */
// Apunta que se ha producido un error
// Format es el error con formato C, tipo "Variable %s con valor %d"
// ... son las variables a sustituir en la String format: "x", x
void prError(unsigned short lineno, char *format, ...) {
va_list ap;
char *arg;
wasE = 1;
// va = variable arguments
// va_start asigna a ap los argumentos que van después de format
va_start(ap,format);
// Imprimir el nombre del fichero y el número de línea del error
fprintf(stderr,"%s (%u): ",fName,lineno);
// Imprimir el error en sí (format y sus variables)
vfprintf(stderr,format,ap);
fflush(stderr);
// Limpiar ap
va_end(ap);
if (exitOnE) exit(1);
}
/* --------------------------------------------------------------------- */
// Apunta que se ha producido un aviso
void prWarning(unsigned short lineno, char *format, ...) {
va_list ap;
char *arg;
// va = variable arguments
// va_start asigna a ap los argumentos que van después de format
va_start(ap,format);
// Imprimir el nombre del fichero y el número de línea del error
fprintf(stderr,"%s (%u): ",fName,lineno);
// Imprimir el error en sí (format y sus variables)
vfprintf(stderr,format,ap);
fflush(stderr);
// Limpiar ap
va_end(ap);
}
/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
// Un malloc(), pero fancy
void *xmalloc(unsigned short size) {
void *tmp;
if ((tmp=malloc(size))==NULL) {
fprintf(stderr,"Fatal error: Out of memory\n");
fflush(stderr);
exit(2);
}
return tmp;
}
/* --------------------------------------------------------------------- */
// El free() para nuestro malloc() fancy
void xfree(void *ptr) {
free(ptr);
}
/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
// Alocar/copiar una String en memoria
char *sdup(const char *s) {
char *res = xmalloc(strlen(s)+1);
strcpy(res,s);
return res;
}
/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
stduse.h 0 → 100644
/**
* @Author: Dušan Kolář
* @Year: 2003-2018
* Copyright (c) 2018
* Licence: GLP 3.0
*/
#ifndef ___STDUSE_H___
#define ___STDUSE_H___
void exitOnError(void);
void *xmalloc(unsigned short size);
void xfree(void *ptr);
void setFilename(const char *str);
void prError(unsigned short lineno, char *format, ...);
void prWarning(unsigned short lineno, char *format, ...);
int wasError(void);
char *sdup(const char *s);
#endif
symtab.c 0 → 100644
/**
* @Author: Dušan Kolář
* @Year: 2003-2018
* Copyright (c) 2018
* Licence: GLP 3.0
*/
#include "symtab.h"
#include "stduse.h"
#include <stdlib.h>
#include <string.h>
extern int yylineno;
// El tipo symtab_t es un alias para la estructura symtab
// symtab es una lista doblemente enlazada con pares (nombre, valor)
typedef struct symtab {
char *name; // Nombre de la variable
double value; // Valor de la variable
struct symtab *left, *right; // Variables a la "izquierda/derecha" en la tabla
// (En realidad es un árbol, así que serían sus hijos.
// La cosa es que indican orden)
} symtab_t;
static symtab_t *root = NULL; // Asignamos una "raíz" (entrada inicial) a la tabla
static char *wName;
static double wValue;
// La tabla está "ordenada alfabéticamente" (en realidad no, porque es un árbol, pero casi)
// ----------------------------------------------------------------------------
// Buscar entrada con respecto a la entrada nd
// (para modificarla)
static void inmod(symtab_t *nd) {
int res = strcmp(wName,nd->name);
// Si se encuentra una entrada para ese nombre
if (res == 0) { // the same string // Único comentario de Dusan lol
// Se modifica el valor de la entrada y ya
nd->value = wValue;
return;
}
// Si lo que se busca es anterior a donde estamos,
// se busca por la izquierda
if (res < 0) {
// Si hay entrada a la izquierda
if (nd->left != NULL) {
// Se busca con respecto a la entrada a la izquierda
inmod(nd->left);
// Si no hay entrada a la izquierda
} else {
// Se aloca espacio para una entrada
symtab_t *newr = xmalloc(sizeof(symtab_t));
// Se asigna a la entrada el nombre de la variable y su valor
newr->value = wValue;
newr->name = sdup(wName);
// Se indica que no tiene entradas "vecinas"
newr->left = NULL;
newr->right = NULL;
// Se añade esta entrada como vecina a la izquierda
// de la entrada en la que estábamos buscando
nd->left = newr;
}
// Si lo que se busca es posterior a donde estamos,
// se busca por la derecha
} else {
// Si hay entrada a la derecha
if (nd->right != NULL) {
// Se busca con respecto a la anetrada a la derecha
inmod(nd->right);
// Si no hay entrada a la derecha
} else {
// Se aloca espacio para una entrada
symtab_t *newr = xmalloc(sizeof(symtab_t));
// Se asigna a la entrada el nombre de la variable y su valor
newr->value = wValue;
newr->name = sdup(wName);
// Se indica que no tiene entradas "vecinas"
newr->left = NULL;
newr->right = NULL;
// Se añade esta entrada como vecina a la derecha
// de la entrada en la que estábamos buscando
nd->right = newr;
}
}
}
// ----------------------------------------------------------------------------
// Insertar o modificar una entrada
void insertModify(char *s, double val) {
// Si no hay entradas
if (root == NULL) {
// Se aloca espacio para una entrada
root = xmalloc(sizeof(symtab_t));
// Se añade el valor y nombre de la entrada
root->value = val;
root->name = sdup(s);
// Se indica que no tiene entradas "vecinas"
root->left = NULL;
root->right = NULL;
return;
}
// Si hay alguna entrada
// Se copian los valores
wName = s;
wValue = val;
// Se intenta buscar empezando en el root
inmod(root);
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Buscar entrada con respecto a la entrada nd
// (para obtener su valor)
static double get(symtab_t *nd) {
// Si hemos llegado a un nodo que no existe, pues error
if (nd == NULL) {
prError(yylineno,"Undefined variable %s!\n",wName);
}
// Comparamos con la entrada actual
int res = strcmp(wName,nd->name);
// Si es igual, devolvemos el valor
if (res == 0) { // the same string // Único comentario de Dusan lol x2
return nd->value;
}
// Si es anterior/posterior, nos movemos
if (res < 0) {
return get(nd->left);
} else {
return get(nd->right);
}
}
// ----------------------------------------------------------------------------
// Leer la variable s
double read(char *s) {
// Pues se copia el valor
wName = s;
// Y se busca con respecto a la raíz
return get(root);
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// EOF
symtab.h 0 → 100644
/**
* @Author: Dušan Kolář
* @Year: 2003-2018
* Copyright (c) 2018
* Licence: GLP 3.0
*/
#ifndef ___SYMTAB_H___
#define ___SYMTAB_H___
void insertModify(char *s, double val);
double read(char *s);
#endif
token.h 0 → 100644
/**
* @Author: Dušan Kolář
* @Year: 2003-2018
* Copyright (c) 2018
* Licence: GLP 3.0
*/
#ifndef ___TOKEN_H___
#define ___TOKEN_H___
// Macros para obtener el correspondiente valor de yylval
#define yyFlag(x) x.s.flag
#define yyFloat(x) x.s.u.vFloat
#define yyStr(x) x.s.u.vStr
#define yyAST(x) x.s.u.ast
// Identificadores de tipo (para la flag)
#define fIDENT 1 // Identificador
#define fFLOAT 2 // Número
#define fSTR 3 // Cadena
#define fAST 4 // Nodo del AST
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment