448 lines
13 KiB
Plaintext
448 lines
13 KiB
Plaintext
%{
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stack>
|
|
#include <string>
|
|
#include <map>
|
|
#include <vector>
|
|
#include <cctype>
|
|
#define INFILE_ERROR 1
|
|
#define OUTFILE_ERROR 2
|
|
|
|
extern int yylineno;
|
|
extern FILE *yyin;
|
|
extern FILE *yyout;
|
|
int yylex();
|
|
|
|
void yyerror(const char *msg, ...);
|
|
|
|
struct StackElement {
|
|
std::string value;
|
|
enum { INT, VAR } type;
|
|
};
|
|
|
|
struct SymbolInfo {
|
|
std::string type;
|
|
int memoryLocation;
|
|
};
|
|
|
|
std::map<std::string, SymbolInfo> symbolTable;
|
|
int memoryCounter = 0;
|
|
|
|
std::stack<StackElement> expressionsStack;
|
|
std::stack<std::string> labelStack;
|
|
FILE *tripletFile;
|
|
int tempVarCounter = 0;
|
|
int stringCounter = 0;
|
|
int labelCounter = 0;
|
|
|
|
std::vector<std::string> asmCode;
|
|
std::map<std::string, std::string> stringLiterals;
|
|
|
|
bool isNumber(const std::string& s) {
|
|
if (s.empty()) return false;
|
|
size_t start = 0;
|
|
if (s[0] == '-') start = 1;
|
|
for (size_t i = start; i < s.length(); i++) {
|
|
if (!isdigit(s[i])) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void addSymbol(const std::string& name, const std::string& type) {
|
|
if (symbolTable.find(name) == symbolTable.end()) {
|
|
SymbolInfo info;
|
|
info.type = type;
|
|
info.memoryLocation = memoryCounter++;
|
|
symbolTable[name] = info;
|
|
}
|
|
}
|
|
|
|
std::string generateLabel() {
|
|
return "LBL" + std::to_string(labelCounter++);
|
|
}
|
|
|
|
// ASM
|
|
|
|
std::string generateLoad(const std::string& reg, const std::string& value) {
|
|
if (isNumber(value)) {
|
|
return "li " + reg + ", " + value;
|
|
} else {
|
|
return "lw " + reg + ", " + value;
|
|
}
|
|
}
|
|
|
|
void generateAsm(const std::string& result, const std::string& arg1,
|
|
const std::string& arg2, const std::string& op) {
|
|
|
|
if (op == "=" && arg2.empty()) {
|
|
asmCode.push_back(generateLoad("$t0", arg1));
|
|
asmCode.push_back("sw $t0, " + result);
|
|
} else {
|
|
asmCode.push_back(generateLoad("$t0", arg1));
|
|
asmCode.push_back(generateLoad("$t1", arg2));
|
|
|
|
std::string asmOp;
|
|
if (op == "+") asmOp = "add";
|
|
else if (op == "-") asmOp = "sub";
|
|
else if (op == "*") asmOp = "mul";
|
|
else if (op == "/") asmOp = "div";
|
|
asmCode.push_back(asmOp + " $t2, $t0, $t1");
|
|
|
|
asmCode.push_back("sw $t2, " + result);
|
|
}
|
|
}
|
|
|
|
void generatePrintInt(const std::string& var) {
|
|
asmCode.push_back("# print_integer(" + var + ")");
|
|
asmCode.push_back(generateLoad("$a0", var));
|
|
asmCode.push_back("li $v0, 1");
|
|
asmCode.push_back("syscall");
|
|
}
|
|
|
|
void generatePrintFloat(const std::string& var) {
|
|
asmCode.push_back("# print_float(" + var + ")");
|
|
asmCode.push_back("lwc1 $f12, " + var);
|
|
asmCode.push_back("li $v0, 2");
|
|
asmCode.push_back("syscall");
|
|
}
|
|
|
|
void generatePrintString(const std::string& strLabel) {
|
|
asmCode.push_back("# print_string(" + strLabel + ")");
|
|
asmCode.push_back("la $a0, " + strLabel);
|
|
asmCode.push_back("li $v0, 4");
|
|
asmCode.push_back("syscall");
|
|
}
|
|
|
|
void generateReadInt(const std::string& var) {
|
|
asmCode.push_back("# read_integer -> " + var);
|
|
asmCode.push_back("li $v0, 5");
|
|
asmCode.push_back("syscall");
|
|
asmCode.push_back("sw $v0, " + var);
|
|
}
|
|
|
|
void generateReadFloat(const std::string& var) {
|
|
asmCode.push_back("# read_float -> " + var);
|
|
asmCode.push_back("li $v0, 6");
|
|
asmCode.push_back("syscall");
|
|
asmCode.push_back("swc1 $f0, " + var);
|
|
}
|
|
|
|
void writeDataSection(FILE* out) {
|
|
fprintf(out, ".data\n");
|
|
for (auto& pair : symbolTable) {
|
|
fprintf(out, "%s: .word 0\n", pair.first.c_str());
|
|
}
|
|
for (auto& pair : stringLiterals) {
|
|
fprintf(out, "%s: .asciiz %s\n", pair.first.c_str(), pair.second.c_str());
|
|
}
|
|
fprintf(out, "\n");
|
|
}
|
|
|
|
void writeCodeSection(FILE* out) {
|
|
fprintf(out, ".text\n");
|
|
fprintf(out, ".globl main\n");
|
|
fprintf(out, "main:\n");
|
|
for (const auto& line : asmCode) {
|
|
fprintf(out, " %s\n", line.c_str());
|
|
}
|
|
fprintf(out, "\n # Exit program\n");
|
|
fprintf(out, " li $v0, 10\n");
|
|
fprintf(out, " syscall\n");
|
|
}
|
|
|
|
void saveSymbolTable() {
|
|
FILE* symbolFile = fopen("symbols.txt", "w");
|
|
if (symbolFile) {
|
|
for (auto& pair : symbolTable) {
|
|
fprintf(symbolFile, "%s: type=%s, location=%d\n",
|
|
pair.first.c_str(), pair.second.type.c_str(), pair.second.memoryLocation);
|
|
}
|
|
fclose(symbolFile);
|
|
}
|
|
}
|
|
|
|
// triplets
|
|
|
|
std::string generateTempVar() {
|
|
std::string result = "result" + std::to_string(tempVarCounter++);
|
|
addSymbol(result, "Int");
|
|
return result;
|
|
}
|
|
|
|
void writeTriplet(const std::string& result, const std::string& arg1,
|
|
const std::string& arg2, const std::string& op) {
|
|
fprintf(tripletFile, "%s= %s %s %s\n", result.c_str(), arg1.c_str(), arg2.c_str(), op.c_str());
|
|
generateAsm(result, arg1, arg2, op);
|
|
}
|
|
|
|
void generateIfJumpStatement(const std::string& op) {
|
|
if (expressionsStack.size() < 2) {
|
|
yyerror("Blad: niewystarczajaca liczba elementów w warunku");
|
|
return;
|
|
}
|
|
|
|
StackElement rhs = expressionsStack.top();
|
|
expressionsStack.pop();
|
|
StackElement lhs = expressionsStack.top();
|
|
expressionsStack.pop();
|
|
|
|
std::string label = generateLabel();
|
|
labelStack.push(label);
|
|
|
|
asmCode.push_back(generateLoad("$t2", lhs.value));
|
|
asmCode.push_back(generateLoad("$t3", rhs.value));
|
|
|
|
std::string jumpInstr;
|
|
if (op == "<") jumpInstr = "bge";
|
|
else if (op == ">") jumpInstr = "ble";
|
|
else if (op == "<=") jumpInstr = "bgt";
|
|
else if (op == ">=") jumpInstr = "blt";
|
|
else if (op == "==") jumpInstr = "bne";
|
|
else if (op == "!=") jumpInstr = "beq";
|
|
|
|
asmCode.push_back(jumpInstr + " $t2, $t3, " + label);
|
|
}
|
|
|
|
void generateIfEndStatement() {
|
|
if (!labelStack.empty()) {
|
|
std::string label = labelStack.top();
|
|
labelStack.pop();
|
|
asmCode.push_back(label + ":");
|
|
}
|
|
}
|
|
|
|
%}
|
|
|
|
%union {
|
|
char *text;
|
|
int ival;
|
|
}
|
|
|
|
%token <text> ID
|
|
%token <text> STRING_LIT
|
|
%token <ival> INT_LIT
|
|
%token IF
|
|
%token LET PRINT_INT PRINT_FLOAT PRINT_STRING READ_INT READ_FLOAT
|
|
%token INT_TYPE
|
|
%token SEMICOLON COLON
|
|
%token LE GE EQ NE
|
|
|
|
%left '<' '>' LE GE EQ NE
|
|
%left '+' '-'
|
|
%left '*' '/'
|
|
|
|
%start program
|
|
|
|
%%
|
|
|
|
program
|
|
: statement_list { printf("koniec\n"); }
|
|
;
|
|
|
|
statement_list
|
|
: statement
|
|
| statement_list statement
|
|
;
|
|
|
|
statement
|
|
: variable_declaration { printf("Deklaracja zmiennej\n"); }
|
|
| assignment { printf("Instrukcja przypisania\n"); }
|
|
| print_statement { printf("Instrukcja wypisania\n"); }
|
|
| read_statement { printf("Instrukcja odczytu\n"); }
|
|
| if_expr { printf("Instrukcja warunkowa\n"); }
|
|
| expression SEMICOLON {
|
|
printf("instrukcja\n");
|
|
if (!expressionsStack.empty()) {
|
|
expressionsStack.pop();
|
|
}
|
|
}
|
|
;
|
|
|
|
if_expr
|
|
: if_begin code_block { generateIfEndStatement(); }
|
|
;
|
|
|
|
if_begin
|
|
: IF '(' cond_expr ')' { generateIfJumpStatement($<text>3); }
|
|
;
|
|
|
|
code_block
|
|
: '{' statement_list '}'
|
|
;
|
|
|
|
cond_expr
|
|
: expression '<' expression { $<text>$ = strdup("<"); }
|
|
| expression '>' expression { $<text>$ = strdup(">"); }
|
|
| expression LE expression { $<text>$ = strdup("<="); }
|
|
| expression GE expression { $<text>$ = strdup(">="); }
|
|
| expression EQ expression { $<text>$ = strdup("=="); }
|
|
| expression NE expression { $<text>$ = strdup("!="); }
|
|
;
|
|
|
|
variable_declaration
|
|
: LET ID COLON INT_TYPE '=' expression SEMICOLON
|
|
{
|
|
printf("Deklaracja zmiennej: %s\n", $2);
|
|
addSymbol(std::string($2), "Int");
|
|
if (!expressionsStack.empty()) {
|
|
StackElement expression = expressionsStack.top();
|
|
expressionsStack.pop();
|
|
writeTriplet(std::string($2), expression.value, "", "=");
|
|
}
|
|
}
|
|
;
|
|
|
|
assignment
|
|
: ID '=' expression SEMICOLON
|
|
{
|
|
printf("Przypisanie do zmiennej: %s\n", $1);
|
|
if (!expressionsStack.empty()) {
|
|
StackElement expression = expressionsStack.top();
|
|
expressionsStack.pop();
|
|
writeTriplet(std::string($1), expression.value, "", "=");
|
|
}
|
|
}
|
|
;
|
|
|
|
print_statement
|
|
: PRINT_INT '(' expression ')' SEMICOLON
|
|
{
|
|
printf("print_integer\n");
|
|
if (!expressionsStack.empty()) {
|
|
StackElement expr = expressionsStack.top();
|
|
expressionsStack.pop();
|
|
generatePrintInt(expr.value);
|
|
}
|
|
}
|
|
| PRINT_FLOAT '(' expression ')' SEMICOLON
|
|
{
|
|
printf("print_float\n");
|
|
if (!expressionsStack.empty()) {
|
|
StackElement expr = expressionsStack.top();
|
|
expressionsStack.pop();
|
|
generatePrintFloat(expr.value);
|
|
}
|
|
}
|
|
| PRINT_STRING '(' STRING_LIT ')' SEMICOLON
|
|
{
|
|
printf("print_string: %s\n", $3);
|
|
std::string label = "str" + std::to_string(stringCounter++);
|
|
stringLiterals[label] = std::string($3);
|
|
generatePrintString(label);
|
|
}
|
|
;
|
|
|
|
read_statement
|
|
: READ_INT '(' ID ')' SEMICOLON
|
|
{
|
|
printf("read_integer -> %s\n", $3);
|
|
generateReadInt(std::string($3));
|
|
}
|
|
| READ_FLOAT '(' ID ')' SEMICOLON
|
|
{
|
|
printf("read_float -> %s\n", $3);
|
|
generateReadFloat(std::string($3));
|
|
}
|
|
;
|
|
|
|
expression
|
|
: expression '+' expression {
|
|
printf("Wyrazenie z +\n");
|
|
StackElement rhs = expressionsStack.top();
|
|
expressionsStack.pop();
|
|
StackElement lhs = expressionsStack.top();
|
|
expressionsStack.pop();
|
|
std::string temp = generateTempVar();
|
|
writeTriplet(temp, lhs.value, rhs.value, "+");
|
|
StackElement element;
|
|
element.value = temp;
|
|
element.type = StackElement::VAR;
|
|
expressionsStack.push(element);
|
|
}
|
|
| expression '-' expression {
|
|
printf("Wyrazenie z -\n");
|
|
StackElement rhs = expressionsStack.top();
|
|
expressionsStack.pop();
|
|
StackElement lhs = expressionsStack.top();
|
|
expressionsStack.pop();
|
|
std::string temp = generateTempVar();
|
|
writeTriplet(temp, lhs.value, rhs.value, "-");
|
|
StackElement element;
|
|
element.value = temp;
|
|
element.type = StackElement::VAR;
|
|
expressionsStack.push(element);
|
|
}
|
|
| expression '*' expression {
|
|
printf("Wyrazenie z *\n");
|
|
StackElement rhs = expressionsStack.top();
|
|
expressionsStack.pop();
|
|
StackElement lhs = expressionsStack.top();
|
|
expressionsStack.pop();
|
|
std::string temp = generateTempVar();
|
|
writeTriplet(temp, lhs.value, rhs.value, "*");
|
|
StackElement element;
|
|
element.value = temp;
|
|
element.type = StackElement::VAR;
|
|
expressionsStack.push(element);
|
|
}
|
|
| expression '/' expression {
|
|
printf("Wyrazenie z /\n");
|
|
StackElement rhs = expressionsStack.top();
|
|
expressionsStack.pop();
|
|
StackElement lhs = expressionsStack.top();
|
|
expressionsStack.pop();
|
|
std::string temp = generateTempVar();
|
|
writeTriplet(temp, lhs.value, rhs.value, "/");
|
|
StackElement element;
|
|
element.value = temp;
|
|
element.type = StackElement::VAR;
|
|
expressionsStack.push(element);
|
|
}
|
|
| '(' expression ')' { printf("Wyrazenie w nawiasach\n"); }
|
|
| INT_LIT {
|
|
printf("Literal calkowity: %d\n", $1);
|
|
StackElement element;
|
|
element.value = std::to_string($1);
|
|
element.type = StackElement::INT;
|
|
expressionsStack.push(element);
|
|
}
|
|
| ID {
|
|
printf("Identyfikator: %s\n", $1);
|
|
StackElement element;
|
|
element.value = std::string($1);
|
|
element.type = StackElement::VAR;
|
|
expressionsStack.push(element);
|
|
}
|
|
;
|
|
|
|
%%
|
|
|
|
int main(int argc, char *argv[]) {
|
|
tripletFile = fopen("triplets.txt", "w");
|
|
if (!tripletFile) {
|
|
fprintf(stderr, "Blad triplets.txt\n");
|
|
return OUTFILE_ERROR;
|
|
}
|
|
|
|
yyout = fopen("output.asm", "w");
|
|
if (!yyout) {
|
|
fprintf(stderr, "Blad output.asm\n");
|
|
fclose(tripletFile);
|
|
return OUTFILE_ERROR;
|
|
}
|
|
|
|
yyparse();
|
|
|
|
fclose(tripletFile);
|
|
writeDataSection(yyout);
|
|
|
|
writeCodeSection(yyout);
|
|
|
|
fclose(yyout);
|
|
|
|
saveSymbolTable();
|
|
return 0;
|
|
}
|