Wikipedia para siempre
Permalink: http://www.treeweb.es/u/1056/ 01/04/2011

Compilador

compilador.cpp

//============================================================================ // 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

/* * 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

/* * 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

/* * 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

/* * 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

/* * 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

/* * 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 }