Permalink: http://www.treeweb.es/u/1056/
01/04/2011
Compilador
//============================================================================
// Name : practica2.cpp
// Author : gerardooscarjt@gmail.com
// Version :
// Copyright : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
#include <fstream>
#include <iostream>
#include <string>
#include "Queue.h"
#include "Sintactico.h"
using namespace std;
int main(int argc, char *argv[]){
Sintactico syn = Sintactico(stdin, stdout);
syn.compile();
return 0;
}
/*
* Token.h
*
* Created on: 31/03/2011
* Author: gerardooscarjt@gmail.com
*/
#ifndef TOKEN_H_
#define TOKEN_H_
#include <string>
using namespace std;
enum token_type {TOKEN_NUMBER, TOKEN_IDENTIFIER, TOKEN_PUNTUATION, TOKEN_OPERATOR};
enum token_puntuation{PUNTUATION_POPEN, PUNTUATION_PCLOSE, PUNTUATION_EOF, PUNTUATION_EOL};
class Token {
private:
token_type _type;
int _value_num;
string _value_txt;
public:
Token(token_type, int, string);
Token(token_type, string);
int getType();
string* getValueString();
int getValueInt();
virtual ~Token();
};
#endif /* TOKEN_H_ */
/*
* Token.cpp
*
* Created on: 31/03/2011
* Author: gerardooscarjt@gmail.com
*/
#include "Token.h"
Token::Token(token_type type, int number, string identifier) {
// TODO Auto-generated constructor stub
_type = type;
_value_num = number;
_value_txt = identifier;
}
Token::Token(token_type type, string identifier) {
// TODO Auto-generated constructor stub
_type = type;
_value_txt = identifier;
}
int Token::getType() {
return _type;
}
string* Token::getValueString() {
return &_value_txt;
}
int Token::getValueInt() {
return _value_num;
}
Token::~Token() {
// TODO Auto-generated destructor stub
}
/*
* Lexico.h
*
* Created on: 31/03/2011
* Author: gerardooscarjt@gmail.com
*/
#ifndef LEXICO_H_
#define LEXICO_H_
#include <fstream>
#include "Token.h"
using namespace std;
class Lexico {
public:
Lexico(FILE* __stream);
virtual ~Lexico();
Token* nextToken();
private:
FILE* _stream;
char _c;
int nextChar();
void prevChar();
bool isDigit(char);
bool isLetter(char);
bool isOperator(char);
bool isPuntuation(char);
bool isBlank(char);
};
#endif /* LEXICO_H_ */
/*
* Lexico.cpp
*
* Created on: 31/03/2011
* Author: gerardooscarjt@gmail.com
*/
#include "Lexico.h"
Lexico::Lexico(FILE* __stream) {
// TODO Auto-generated constructor stub
_stream = __stream;
}
int Lexico::nextChar() {
_c = getc(_stream);
return _c;
}
void Lexico::prevChar() {
ungetc(_c, _stream);
}
Token* Lexico::nextToken() {
int number = 0;
string identifier;
int state = 1;
char c;
while (true) {
c = nextChar();
//if (!feof(_stream)) {
if (c != -1) {
switch (state) {
case 1:
if (isDigit(c)) {
number = c-48;
identifier.clear();
identifier.push_back(c);
state = 2;
} else if (isLetter(c)) {
state = 3;
identifier.clear();
identifier.push_back(c);
} else if (isBlank(c)) {
// No hace nada :)
} else if (isOperator(c)) {
// Ya veremos que hace...
state = 4;
identifier.clear();
identifier.push_back(c);
} else if (isPuntuation(c)) {
if (c == '(') return new Token(TOKEN_PUNTUATION, PUNTUATION_POPEN, "(");
if (c == ')') return new Token(TOKEN_PUNTUATION, PUNTUATION_PCLOSE, ")");
if (c == ';') return new Token(TOKEN_PUNTUATION, PUNTUATION_EOL, ";");
} else {
// Lanzar error, caracter inesperado, esperaba dígito, letra, operador, puntuación o blanco.
printf("Error: caracter '%c' inesperado, esperaba dígito, letra, operador, puntuación o blanco", c);
}
break;
case 2:
if (isDigit(c)) {
number *=10;
number += (c-48);
identifier.push_back(c);
} else {
prevChar();
return new Token(TOKEN_NUMBER, number, identifier);
}
break;
case 3:
if (isLetter(c) || isDigit(c)) {
identifier.push_back(c);
} else {
prevChar();
return new Token(TOKEN_IDENTIFIER, identifier);
}
break;
case 4:
if (isOperator(c)) {
identifier.push_back(c);
} else {
prevChar();
// comprobar en una lista si el operador existe
return new Token(TOKEN_OPERATOR, identifier);
}
}
} else {
return new Token(TOKEN_PUNTUATION, PUNTUATION_EOF, "");
}
}
}
bool Lexico::isDigit(char c) {
return c>47 && c<58;
}
bool Lexico::isLetter(char c) {
return (c>96 && c<123) || (c>64 && c<91);
}
bool Lexico::isOperator(char c) {
return c == '+' || c == '=' || c == '-' || c == '/' || c == '\\' || c == '*' || c == '%';
}
bool Lexico::isPuntuation(char c) {
return c == '(' || c == ')' || c == ';';
}
bool Lexico::isBlank(char c) {
return c == ' ' || c == '\n';
}
Lexico::~Lexico() {
// TODO Auto-generated destructor stub
}
/*
* Sintactico.h
*
* Created on: 31/03/2011
* Author: gerardooscarjt@gmail.com
*/
#include "Lexico.h"
#ifndef SINTACTICO_H_
#define SINTACTICO_H_
class Sintactico {
public:
Sintactico(FILE* source, FILE* destination);
void compile();
virtual ~Sintactico();
private:
FILE* _source;
FILE* _destination;
Lexico* _lexical_analyzer;
Token* nextToken();
void output(string output);
void error(string error);
void parseRead();
void parsePrint();
void parseExpression();
void parseAssignment(Token* id);
void parsePopOperator(string*);
};
#endif /* SINTACTICO_H_ */
/*
* Sintactico.cpp
*
* Created on: 31/03/2011
* Author: gerardooscarjt@gmail.com
*/
#include "Sintactico.h"
#include <stdlib.h>
#include <stack>
Sintactico::Sintactico(FILE* source, FILE* destination) {
// TODO Auto-generated constructor stub
_source = source;
_destination = destination;
_lexical_analyzer = new Lexico(_source);
}
void Sintactico::compile() {
Token* t;
do {
t = nextToken();
if (t->getType() == TOKEN_IDENTIFIER) {
if (t->getValueString()->compare("read")==0) {
output("read ");
parseRead();
} else if (t->getValueString()->compare("print")==0) {
output("print ");
parsePrint();
} else {
parseAssignment(t);
}
} else if (t->getType() == TOKEN_PUNTUATION && t->getValueInt() == PUNTUATION_EOF) {
// En realidad no es un error, simplemente el mensaje de que todo ha salido de puta madre :)
error("Compilación terminada con éxito.\n");
} else {
error("Se esperaba identificador o palabra clave read o print.\n");
exit(0);
}
} while(!(t->getType() == TOKEN_PUNTUATION && t->getValueInt() == PUNTUATION_EOF));
}
Token* Sintactico::nextToken() {
return _lexical_analyzer->nextToken();
}
void Sintactico::parseRead(){
Token* t = nextToken();
if (t->getType() == TOKEN_IDENTIFIER) {
output(t->getValueString()->data());
t = nextToken();
if (t->getType() == TOKEN_PUNTUATION && t->getValueInt() == PUNTUATION_EOL) {
output("\n");
} else {
error("Se esperaba punto y coma.\n");
exit(0);
}
} else {
error("Se esperaba identificador.\n");
exit(0);
}
}
void Sintactico::parsePrint(){
Token* t = nextToken();
if (t->getType() == TOKEN_IDENTIFIER) {
output(t->getValueString()->data());
t = nextToken();
if (t->getType() == TOKEN_PUNTUATION && t->getValueInt() == PUNTUATION_EOL) {
output("\n");
} else {
error("Se esperaba punto y coma.\n");
exit(0);
}
} else {
error("Se esperaba identificador.\n");
exit(0);
}
}
void Sintactico::parseExpression(){
stack<Token*>* exp_stack = new stack<Token*>();
Token* t;
do {
t = nextToken();
if (t->getType()==TOKEN_IDENTIFIER ) {
// Es un operando (variable): directamente a la salida
output("load ");
output(t->getValueString()->data());
output("\n");
} else if (t->getType()==TOKEN_NUMBER) {
// Es un operando (constante): directamente a la salida
output("const ");
output(t->getValueString()->data());
output("\n");
} else if (t->getType()==TOKEN_OPERATOR) {
exp_stack->push(t);
} else if ((t->getType()==TOKEN_PUNTUATION) && (t->getValueInt()==PUNTUATION_POPEN)) {
exp_stack->push(t);
} else if (t->getType()==TOKEN_PUNTUATION && t->getValueInt()==PUNTUATION_PCLOSE) {
if (exp_stack->empty()) {
error("Fallo en la expresión. Falta al menos un paréntesis de cierre ')'.\n");
exit(0);
} else {
Token* b;
do {
b = exp_stack->top();
if (b->getType()==TOKEN_OPERATOR) {
parsePopOperator(b->getValueString());
exp_stack->pop();
}
} while (!exp_stack->empty() && b->getType()==TOKEN_OPERATOR);
if (b->getType()==TOKEN_PUNTUATION && b->getValueInt() == PUNTUATION_POPEN) {
exp_stack->pop();
} else {
error("Sobra un paréntesis de cierre.\n");
exit(0);
}
}
} else if (t->getType() == TOKEN_PUNTUATION && t->getValueInt() == PUNTUATION_EOF) {
error("Se esperaba punto y coma.\n");
exit(0);
} else if (t->getType() == TOKEN_PUNTUATION && t->getValueInt() == PUNTUATION_EOL) {
Token* b;
while (!exp_stack->empty()) {
b = exp_stack->top();
parsePopOperator(b->getValueString());
exp_stack->pop();
}
}
} while (!(t->getType() == TOKEN_PUNTUATION && t->getValueInt() == PUNTUATION_EOL));
}
void Sintactico::parsePopOperator(string* op) {
if (op->compare("+") == 0) {
output("add\n");
} else if (op->compare("-") == 0) {
output("sub\n");
} else if (op->compare("*") == 0) {
output("mul\n");
} else if (op->compare("/") == 0) {
output("div\n");
} else {
error("Operador no válido.\n");
exit(0);
}
}
void Sintactico::parseAssignment(Token* id){
string* identifier = id->getValueString();
Token* t = nextToken();
if(t->getType() == TOKEN_OPERATOR && t->getValueString()->compare("=")==0) {
parseExpression();
output("store ");
output(identifier->data());
output("\n");
} else {
error("Se esperaba operador de asignación '='.\n");
exit(0);
}
}
void Sintactico::output(string output) {
fputs(output.data(), _destination);
}
void Sintactico::error(string error) {
fputs("> ", stderr);
fputs(error.data(), stderr);
}
Sintactico::~Sintactico() {
// TODO Auto-generated destructor stub
}