Skip to content

Instantly share code, notes, and snippets.

@kjr247
Created April 11, 2014 21:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kjr247/10503476 to your computer and use it in GitHub Desktop.
Save kjr247/10503476 to your computer and use it in GitHub Desktop.
pascal compiler in C++ allowing concurrency without using semaphores
Kyle Rebstock <kjr247@gmail.com> Fri, Apr 11, 2014 at 1:10 PM
To : Kyle Rebstock <kjr247@gmail.com>
// -------------------------------------------
// Program: pascomp.cc (Version 1.8)//modified since 1.8 This is compiler before val/ref feature
//
// Description: This is a pascal like compiler with low-level code implementation.
// Student: Kyle Jackson Rebstock
// ID: 713599
// Date: February 8, 2014
// -------------------------------------------
//#include <fstream.h> // for handling files
#include <ctype.h>
#include <stdlib.h>
#include <string>
#include <iomanip>
#include <iostream>
#include <stack>
// -------------------------------------------
// These are some global definitions
// -------------------------------------------
#define TRUE 1
#define FALSE 0
#define MAX_TABLE 500
#define MAX_PCODE 1000
#define MAX_SYMBOL 47
#define MAX_SYM_SZ 20
#define MAX_PRAMS 31
#define MAX_STACK 1000
// -------------------------------------------
// These are some ERROR definitions
// -------------------------------------------
#define ERROR_SEMICOLON 1
#define ERROR_IDENT 2
#define ERROR_UNKNOWN 3
#define ERROR_ASSIGN 4
#define ERROR_ASSIGN_PROC 5
#define ERROR_PROCEDURE 6
#define ERROR_END_SYM 7
#define ERROR_DO_SYM 8
#define ERROR_THEN_SYM 9
#define ERROR_UNTIL_SYM 10
#define ERROR_VARIABLE 11
#define ERROR_OF_SYM 12
#define ERROR_CONSTANT 13
#define ERROR_COLON 14
#define ERROR_RPAREN 15
#define ERROR_IS_PROCEDURE 16
#define ERROR_REL 17
#define ERROR_PROG_SIZE 18
#define ERROR_END_PROG 19
#define ERROR_NUMBER 20
#define ERROR_IDENT_VAR 22
#define ERROR_LPAREN 23
#define ERROR_UNTIL 25
#define ERROR_TO_DOWNTO 26
#define ERROR_OF 27
#define ERROR_NUMBER_IDENT 28
#define ERROR_CEND 29
#define ERROR_NOPROCEDURE 30
#define ERROR_VAR 31
#define ERROR_ASSIGN 32
//Begin Modified
#define ERROR_FUNC 33
#define ERROR_FUNCLEVEL 34
//End Modified
// -------------------------------------------
// some enumerated data types
// -------------------------------------------
typedef enum tag_symbol
{
VARSYM,
CONSTSYM,
BEGINSYM,
ENDSYM,
CENDSYM,
PERIOD,
SEMICOLON,
COLON,
LPAREN,
RPAREN,
GRTHEN,
LSTHEN,
GREQL,
LSEQL,
EQL,
ASSIGN,
IFSYM,
IDENT,
NUMBER,
WRITESYM,
WRITELNSYM,
PROCSYM,
NOTEQL,
MINUS,
PLUS,
DIV,
MULT,
COMMA,
ODDSYM,
CALL,
ELSESYM,
THENSYM,
WHILESYM,
DOSYM,
REPEATSYM,
UNTILSYM,
CASESYM,
OFSYM,
CEND,
FOR,
DOWNTOSYM,
TOSYM,
FUNCSYM,
OR,
AND,
NOT,
COBEGIN, //MODIFIED COBEGIN" and "COEND
COEND //MODIFIED COBEGIN" and "COEND
}symbol;
// -------------------------------------------
typedef enum tag_Objtype
{
NOTYPE,
CONSTANT,
VARIABLE,
PROCEDURE,
FUNCTION //Modified
}Objtype;
// -------------------------------------------
typedef enum tag_psyms
{
OPR,
CAL,
INT,
JPC,
JMP,
LIT,
LOD,
STO,
CTS
}psyms;
typedef enum tag_intype
{
ALPHA,
DIGIT,
EOL,
NONE,
PUNCT,
SPACE
}intype;
// -------------------------------------------
typedef struct tag_symtable // Symbols Table Structure
{
char name[MAX_SYM_SZ]; // Symbol name
Objtype kind; // Type of symbol
int value, // Value of symbol
level, // Level of symbol
adr; // Symbol address
}symtable;
// -------------------------------------------
typedef struct tag_pcodetable // PCODE Table Structure
{
psyms function; // pcode function
int level, // pcode level static link
adr; // pcode address number into table
}pcodetable;//used to save the compile code
// -------------------------------------------
// These are some global variables
// -------------------------------------------
int linelength, // line length
linecount, // line counter
charcount, // a character counter
codeinx, // pcode index counter inc everytime
codeinx0, // init pcode index
varcount0, // Init variable counter
number;
symbol prevsym; // holds the previous symbol
symbol toORdowntonsym;
symbol writesym;
symbol gensym;
symbol expsym;
symbol termsym;
symtable table[MAX_TABLE]; // table array
pcodetable pcode[MAX_PCODE]; // pcode table
char line[MAX_SYM_SZ]; // an identification string
char punc[MAX_SYM_SZ]; // punction array
char symstr[MAX_SYMBOL][MAX_SYM_SZ]; // symbols array
// -------------------------------------------
// These are some function prototypes
// -------------------------------------------
void block(symbol &, int, int);
void statement(symbol &, int, int);
void genexp(symbol &, int, int);
void expression(symbol &, int, int);
void term(symbol &, int, int);
void factor(symbol &, int, int);
char getchar(char &);
void getsym(symbol &);
intype chartype(char ch);
void enter(Objtype, char[], symbol &, int &, int, int &);
int base(int, int, int &);
void gen(psyms, int, int);
void interpret(void);
int position(int);
void showpcode(void);
void openfile(void);
void error(int);
// -------------------------------------------
// This handles our system errors
// -------------------------------------------
void error(int num)
{
std::cout << std::endl;
switch (num)
{
case ERROR_NOPROCEDURE:
std::cout << "Procedure not accepted here";
break;
case ERROR_CEND:
std::cout << "cend sym expected";
break;
case ERROR_NUMBER_IDENT:
std::cout << "number or ident expected";
break;
case ERROR_OF:
std::cout << "of expected";
break;
case ERROR_TO_DOWNTO:
std::cout << "to or downto expected";
break;
case ERROR_UNTIL:
std::cout << "Until expected";
break;
case ERROR_ASSIGN:
std::cout << "Assignment operator expected";
break;
case ERROR_ASSIGN_PROC:
std::cout << "Assignment not allowed here";
break;
case ERROR_COLON:
std::cout << "COLON Expected";
break;
case ERROR_CONSTANT:
std::cout << "Constant Expected";
break;
case ERROR_END_PROG:
std::cout << "Premature end of program";
break;
case ERROR_DO_SYM:
std::cout << "DO symbol Expected";
break;
case ERROR_END_SYM:
std::cout << "END symbol Expected";
break;
case ERROR_REL:
std::cout << "Relational operator expected";
break;
case ERROR_IDENT:
std::cout << "Identifier Expected";
break;
case ERROR_IS_PROCEDURE:
std::cout << "Assignment to PROCEDURE not allowed";
break;
case ERROR_NUMBER:
std::cout << "A number was Expected";
break;
case ERROR_PROG_SIZE:
std::cout << "Program size is too large...";
break;
case ERROR_OF_SYM:
std::cout << "OF symbol Expected";
break;
case ERROR_RPAREN:
std::cout << "RIGHT Parenthesis Expected";
break;
case ERROR_LPAREN:
std::cout << "LEFT Parenthesis Expected";
break;
case ERROR_SEMICOLON:
std::cout << "Semicolon Expected";
break;
case ERROR_THEN_SYM:
std::cout << "THEN symbol Expected";
break;
case ERROR_UNKNOWN:
std::cout << "Unknown Identifier";
break;
case ERROR_UNTIL_SYM:
std::cout << "UNTIL symbol Expected";
break;
case ERROR_VARIABLE:
std::cout << "Variable or Expression Expected";
break;
case ERROR_IDENT_VAR:
std::cout << "Ident - Variable Expected";
break;
case ERROR_VAR:
std::cout << "VAR Expected";
break;
//Begin Modified
case ERROR_FUNCLEVEL:
std::cout << "Must be inside function body";
break;
case ERROR_FUNC:
std::cout << "Function Expected";
break;
//End Modified
}
std::cout << std::endl;
exit(1);
}
// -------------------------------------------
// Insert Block Identifier
// -------------------------------------------
void enter(Objtype kind, char name[], symbol &sym, int &varcount, int level, int &tableinx)
{
tableinx++;
strcpy(table[tableinx].name, name);
table[tableinx].kind = kind;
if (kind == CONSTANT)
{
if (sym != IDENT)
error(ERROR_IDENT);
getsym(sym);
if (sym != EQL)
error(ERROR_ASSIGN);
getsym(sym);
if (sym != NUMBER)
error(ERROR_NUMBER);
table[tableinx].value = number;//for const only value matters
}
else if ((kind == VARIABLE))
{
if (sym != IDENT)
error(ERROR_IDENT);
table[tableinx].level = level; // store variable level for static link level
table[tableinx].adr = varcount++; // store address offset from base
}
else if (kind == PROCEDURE)
table[tableinx].level = level; // store procedure level
//Begin Modified
else if (kind == FUNCTION)
if (sym != IDENT)
error(ERROR_IDENT);
table[tableinx].level = level; // store funciton level
//End Modified
getsym(sym);
}
// -------------------------------------------
// Locate Position
// -------------------------------------------
int position(int tableinx)
{
int i = tableinx;
for (strcpy(table[0].name, line); strcmp(table[i].name, line) != 0; i--);
return i;
}
// -------------------------------------------
// Block
// -------------------------------------------
void block(symbol &sym, int level, int tableinx)
{ //this is our dx, set to 3 for static link
int varcount = 3; //,dynamic link,and return address implicitly set
int count = 0;
// save symbol table count used to
int tableinx0 = tableinx; //fix after CONST,VAR,and PROCEDURES DECLARE
table[tableinx].adr = codeinx; // save pcode code index
gen(JMP, 0, 0); // Generate our init JMP Function,level,adr in pcode table
while (sym == CONSTSYM || sym == VARSYM || sym == PROCSYM || sym == FUNCSYM)
{
if (sym == CONSTSYM)
{
// ---- CONSTANT SYM ----
getsym(sym);
enter(CONSTANT, line, sym, varcount, level, tableinx);
while (sym == COMMA)
{
getsym(sym);
enter(CONSTANT, line, sym, varcount, level, tableinx);//int tableinx for all,set value of table line = name
}
if (sym != SEMICOLON)
error(ERROR_SEMICOLON);
getsym(sym);
}
// ---- VARIABLE SYM ----
if (sym == VARSYM)
{
getsym(sym);
enter(VARIABLE, line, sym, varcount, level, tableinx);//inc (dx) varcount and tableinx,used for INT 0,varcount
while (sym == COMMA)
{
getsym(sym);
enter(VARIABLE, line, sym, varcount, level, tableinx);
}
if (sym != SEMICOLON)
error(ERROR_SEMICOLON);
getsym(sym);
}
// ---- PROCEDURE SYM ----
//BEGIN MODIFIED
while (sym == PROCSYM || sym == FUNCSYM) //Procedure or Function
{
prevsym = sym; //Save sym
getsym(sym);
if (sym != IDENT)
error(ERROR_IDENT);
//If sym = procedure then enter procedure
if (prevsym == PROCSYM){
enter(PROCEDURE, line, sym, varcount, level, tableinx);//int tableinx and add level
}
//If sym = function enter function
if (prevsym == FUNCSYM){
enter(FUNCTION, line, sym, varcount, level, tableinx);//int tableinx and add level
}
if (sym != SEMICOLON)
error(ERROR_SEMICOLON);
getsym(sym);
block(sym, level + 1, tableinx);//inc static link for functions inside of functions, table current pointer
if (sym != SEMICOLON)
error(ERROR_SEMICOLON);
getsym(sym);
}
//End Modified
}
pcode[table[tableinx0].adr].adr = codeinx;//tableinx0 is used to fix the original jump when u go into a block
table[tableinx0].adr = codeinx;
codeinx0 = codeinx; //fix proc addr in ST
gen(INT, 0, varcount);//inc the top of the stack by 3 + number of variable
statement(sym, level, tableinx); // ident can also now be a function and now stores variables and handles function storing
gen(OPR, 0, 0);
showpcode();
}
// -------------------------------------------
// Statement
// -------------------------------------------
void statement(symbol &sym, int level, int tableinx)
{
int i, i3, cx1, cx2, cx3, cx4, i2, cx5, cx6, cx7, cx8, cxa, cxb;
int first;
bool FirstCase = true;
int count = 0;
switch (sym)
{
//COBEGIN
case COBEGIN:
gen(COBEGIN, level - table[i].level, table[i].adr);
int* arr[]; = new arr[n];
//delete[] array;
getsym();
do {
gen(COEND, level - table[i].level, table[i].adr);
arr[codeIndx]
getsym(sym);
getsym(sym);
getsym(sym);
} while{!COEND}
// IDENT
case IDENT:
i = position(tableinx);
if (i == 0)
error(ERROR_UNKNOWN);
switch (table[i].kind)
{
case VARIABLE:
getsym(sym);
if (sym != ASSIGN)
error(ERROR_ASSIGN);
getsym(sym);
expression(sym, level, tableinx);//8 * B2 *example* put 8 and B2 onto stack and run OPR
gen(STO, level - table[i].level, table[i].adr);
break;
//Begin Modified
case FUNCTION:
getsym(sym);
if (sym != ASSIGN)
error(ERROR_ASSIGN);
getsym(sym);
expression(sym, level, tableinx);//8 * B2 *example* put 8 and B2 onto stack and run OPR
if (i == tableinx){ // if kind is function
gen(STO, 0, -1); // then STO 0, -1
}
else
error(ERROR_FUNCLEVEL);
break;
default:
error(ERROR_ASSIGN_PROC);
//End Modified
}
break;
// PROCEDURE CALL
case CALL:
getsym(sym);
if (sym != IDENT)
error(ERROR_IDENT);
i = position(tableinx);
if (i == 0)
error(ERROR_UNKNOWN);
if (table[i].kind != PROCEDURE)
error(ERROR_PROCEDURE);
getsym(sym);
gen(CAL, level - table[i].level, table[i].adr);
break;
// BEGIN and END block
case BEGINSYM:
getsym(sym);
statement(sym, level, tableinx);
while (sym == SEMICOLON)
{
getsym(sym);
statement(sym, level, tableinx);
}
if (sym != ENDSYM)
error(ERROR_END_SYM);
getsym(sym);
break;
// WHILE SYMBOL
case WHILESYM:
getsym(sym);
cx1 = codeinx;
genexp(sym, level, tableinx);
cx2 = codeinx;
gen(JPC, 0, 0);
if (sym != DOSYM)
error(ERROR_DO_SYM);
getsym(sym);
statement(sym, level, tableinx);
gen(JMP, 0, cx1);
pcode[cx2].adr = codeinx;
break;
// IF - THEN - ELSE //Modified
case IFSYM:
getsym(sym);
genexp(sym, level, tableinx);
cxa = codeinx; //Save cx1
gen(JPC, 0, 0); // JPC 0,0
if (sym != THENSYM)
error(ERROR_THEN_SYM);
getsym(sym);
statement(sym, level, tableinx);
pcode[cxa].adr = codeinx; //Fix JPC @ cx1
/* add your code for ELSE here */
if (sym == ELSESYM) // Begin Modified -----
{
getsym(sym);
cxb = codeinx; //Save cx2
gen(JMP, 0, 0); //JMP 0,0
pcode[cxa].adr = codeinx; //Fix JPC @ cx1
statement(sym, level, tableinx);
pcode[cxb].adr = codeinx; //Fix JMP @ cx2
}
//End Modified -------
break;
case REPEATSYM:
/* add your code for REPEAT-UNTIL here */
// Begin Modified -------
cx1 = codeinx; //Save cx
do {
getsym(sym);
statement(sym, level, tableinx);
} while (sym == SEMICOLON);
if (sym != UNTILSYM)
error(ERROR_UNTIL_SYM);
getsym(sym);
genexp(sym, level, tableinx);
gen(JPC, 0, cx1); //JPC 0,cx
break;
case FOR:
/* add your code for FOR-DO here */
getsym(sym);
if (sym != IDENT)
error(ERROR_IDENT_VAR);
i3 = position(tableinx);
if (i3 == 0)
error(ERROR_VAR);
if (table[i3].kind != VARIABLE)
error(ERROR_VAR);
getsym(sym);
if (sym != ASSIGN)
error(ERROR_ASSIGN);
getsym(sym);
expression(sym, level, tableinx);
gen(STO, level - table[i3].level, table[i3].adr); //STO
if (sym != TOSYM && sym != DOWNTOSYM)
error(ERROR_TO_DOWNTO);
toORdowntonsym = sym; //Save sym
getsym(sym);
expression(sym, level, tableinx);
//Modified
cx7 = codeinx; //Save cx7
gen(CTS, 0, 0); //CTS 0,0
gen(LOD, level - table[i3].level, table[i3].adr); //LOD
if (toORdowntonsym == TOSYM) //If sym is TO
gen(OPR, 0, 11); //OPR 0, >=
else if (toORdowntonsym == DOWNTOSYM) //If sym is DOWNTO
gen(OPR, 0, 13); //OPR 0, <=
cx8 = codeinx; //Save cx8
gen(JPC, 0, 0); //JPC 0,0
//End Mod
if (sym != DOSYM)
error(ERROR_DO_SYM);
getsym(sym);
statement(sym, level, tableinx);
//Modified
gen(LOD, level - table[i3].level, table[i3].adr); //LOD
gen(LIT, 0, 1); //LIT 0,1
if (toORdowntonsym == TOSYM) //If sym is TO
gen(OPR, 0, 2); //OPR 0, +
else if (toORdowntonsym == DOWNTOSYM) //If sym is DOWNTO
gen(OPR, 0, 3); //OPR 0,-
gen(STO, level - table[i3].level, table[i3].adr); //STO
gen(JMP, 0, cx7); //JMP 0,cx7
pcode[cx8].adr = codeinx; //fix JPC @ cx8
gen(INT, 0, -1); //INT 0,-1
//End Mod
break;
case CASESYM:
/* add your code for CASE here */
//Begin Modified ------
getsym(sym);
i2 = position(tableinx);
expression(sym, level, tableinx);
if (sym != OFSYM)
error(ERROR_OF_SYM);
getsym(sym);
while (sym == NUMBER || sym == IDENT) {
if (sym == IDENT)
{
i2 = position(tableinx);
if (i2 == 0)
error(ERROR_VAR);
if (table[i2].kind != CONSTANT)
error(ERROR_CONSTANT);
}
//getsym(sym);
gen(CTS, 0, 0); // CTS 0,0
if (sym == NUMBER)
gen(LIT, 0, number); //If Number then LIT 0,num
else if (sym == CONSTANT)
gen(LIT, 0, table[i2].value); //If constant then LIT 0, table[i].value
gen(OPR, 0, 8); //OPR 0,=
cx5 = codeinx; //Save cx5
gen(JPC, 0, 0); // JPC 0,0
getsym(sym);
if (sym != COLON)
error(ERROR_COLON);
getsym(sym);
statement(sym, level, tableinx);
if (sym != SEMICOLON)
error(ERROR_SEMICOLON);
if (FirstCase == true){
cx6 = codeinx; //Save cx6
gen(JMP, 0, 0); //JMP 0,0
FirstCase = false;
}
else {
gen(JMP, 0, cx6); //JMP 0,cx6
}
pcode[cx5].adr = codeinx; //fix JPC @ cx5
getsym(sym);
}
if (sym != CENDSYM)
error(ERROR_CEND);
pcode[cx6].adr = codeinx; //fix JPC @ cx6
gen(INT, 0, -1);// int 0,-1
getsym(sym);
break;
//End Modified ------
case WRITESYM:
/* add your code for WRITE here */
//Begin Modified ------
writesym = sym; //Save sym
getsym(sym);
if (sym != LPAREN)
error(ERROR_LPAREN);
do {
getsym(sym);
expression(sym, level, tableinx);
gen(OPR, 0, 14); //OPR 0,14
} while (sym == COMMA);
if (sym != RPAREN)
error(ERROR_RPAREN);
getsym(sym);
/*if (prevsym == WRITELNSYM)
gen(OPR, 0, 15);*/
// End Modified -------
break;
case WRITELNSYM:
/* add your code for WRITELN here */
// Begin Modified -------
writesym = sym; //Save sym
getsym(sym);
if (sym != LPAREN)
error(ERROR_LPAREN);
do {
getsym(sym);
expression(sym, level, tableinx);
gen(OPR, 0, 14); //OPR 0,14
} while (sym == COMMA);
if (sym != RPAREN)
error(ERROR_RPAREN);
getsym(sym);
//if (prevsym == WRITELNSYM) //If sym is writeln
gen(OPR, 0, 15); //OPR 0,15
break;
// End Modified -------
} // END of SWITCH
}
// -------------------------------------------
// genexp
// -------------------------------------------
//Modified from "condition" to "genexp"
void genexp(symbol &sym, int level, int tableinx)
{
symbol gensym;
// ODD symbol
if (sym == ODDSYM)
{
getsym(sym);
expression(sym, level, tableinx);
gen(OPR, 0, 6);
}
else
{
expression(sym, level, tableinx);
if ((sym == EQL) || (sym == NOTEQL) || (sym == LSTHEN) || (sym == LSEQL) || (sym == GRTHEN) || (sym == GREQL))
{
gensym = sym;
getsym(sym);
expression(sym, level, tableinx);
switch (gensym)
{
case EQL:
gen(OPR, 0, 8);
break;
case GREQL:
gen(OPR, 0, 11);
break;
case GRTHEN:
gen(OPR, 0, 12);
break;
case LSEQL:
gen(OPR, 0, 13);
break;
case LSTHEN:
gen(OPR, 0, 10);
break;
case NOTEQL:
gen(OPR, 0, 9);
break;
}
//may need to save sym, call expression, then gen(OPR, 0, symop)------------------------------------------?
}
//Modified
//General Experession doesn't have to be a relational operator, it can be nothing
//else error(ERROR_REL);
}
}
// -------------------------------------------
// Expression
// -------------------------------------------
void expression(symbol &sym, int level, int tableinx)
{
symbol expsym;
if ((sym == PLUS) || (sym == MINUS))
{
expsym = sym;
getsym(sym); // save sym
term(sym, level, tableinx);
if (expsym == MINUS)
gen(OPR, 0, 1);
}
else
term(sym, level, tableinx);
//Begin Modified
//Add or sym
while (sym == PLUS || sym == MINUS || sym == OR)
{
expsym = sym;
getsym(sym);
term(sym, level, tableinx);
if (expsym == MINUS)
gen(OPR, 0, 3);
else
gen(OPR, 0, 2);//Can be + or "OR"
}
//End modified
}
// -------------------------------------------
// TERM
// -------------------------------------------
void term(symbol &sym, int level, int tableinx)
{
symbol termsym;
factor(sym, level, tableinx);
//Modified
while ((sym == MULT) || (sym == DIV) || (sym == AND))
{
termsym = sym; // save sym
getsym(sym);
factor(sym, level, tableinx);
if (termsym == DIV)
gen(OPR, 0, 5);
else // else if (sym == MULT)
gen(OPR, 0, 4);//Can be * or "AND"
//End Modified
}
} // End Void term
// -------------------------------------------
// FACTOR
// -------------------------------------------
void factor(symbol &sym, int level, int tableinx)
{
int i;
int count = 0;
switch (sym)
{
// IDENTIFER
case IDENT:
i = position(tableinx);
if (i == 0)
error(ERROR_UNKNOWN);
//Modified
if (table[i].kind == PROCEDURE || table[i].kind == FUNCTION)
error(ERROR_IS_PROCEDURE);
switch (table[i].kind)
{
case VARIABLE:
gen(LOD, level - table[i].level, table[i].adr);
break;
case CONSTANT:
gen(LIT, 0, table[i].value);
break;
}
getsym(sym);
break;
// NUMBER
case NUMBER:
gen(LIT, 0, number);
getsym(sym);
break;
// LEFT PARENTHESE
case LPAREN:
getsym(sym);
genexp(sym, level, tableinx);
if (sym != RPAREN)
error(ERROR_RPAREN);
getsym(sym);
break;
case CALL:
getsym(sym);
i = position(tableinx);
if (i == 0)
error(ERROR_UNKNOWN);
/*if (sym != FUNCSYM || sym != PROCSYM)
error(ERROR_FUNC);*/
if (sym != IDENT)
error(ERROR_IDENT);
if (table[i].kind != FUNCTION)
error(ERROR_FUNC);
gen(INT, 0, 1); //INT 0,1
gen(CAL, level - table[i].level, table[i].adr);// Call
getsym(sym);
break;
case NOT:
getsym(sym);
factor(sym, level, tableinx);
gen(LIT, 0, 0); // Lit 0 and check inequality
gen(OPR, 0, 8); // opr, =
break;
default:
error(ERROR_VARIABLE);
}
//End Modified
}
// -------------------------------------------
// Generate the PCODE
// -------------------------------------------
void gen(psyms function, int level, int adr)
{
if (codeinx > MAX_PCODE)
error(ERROR_PROG_SIZE);
pcode[codeinx].function = function;
pcode[codeinx].level = level;
pcode[codeinx].adr = adr;
codeinx++;
}
// -------------------------------------------
// This is our GET CHARACTER function
// -------------------------------------------
char getchar(char &ch)
{
static char line[255]; // local array
if (charcount == linelength)
{
charcount = linelength = 0; // zero out counters
std::cin.get(ch);
while (chartype(ch) != EOL && std::cin)
{
line[linelength] = ch;
std::cin.get(ch);
linelength++;
}
if (linelength == 0 && charcount == 0 && !std::cin)
error(ERROR_END_PROG);
line[linelength] = 0;
std::cout << line << std::endl;
line[linelength] = ' ';
linecount++; // count lines
linelength++; //
}
ch = toupper(line[charcount]);
charcount++; // count characters
return ch;
}
// -------------------------------------------
// This is our GETSYM
// -------------------------------------------
void getsym(symbol &sym)
{
char ch;
int index = 0;
do
getchar(ch);
while (chartype(ch) == SPACE || chartype(ch) == EOL);
if (chartype(ch) == ALPHA)
{
do
{
line[index++] = ch;
getchar(ch);
} while (chartype(ch) == ALPHA || chartype(ch) == DIGIT || ch == '_');
line[index] = '\0';
charcount--;
if (strcmp(line, "BEGIN") == 0)
sym = BEGINSYM;
else if (strcmp(line, "CALL") == 0)
sym = CALL;
else if (strcmp(line, "CASE") == 0)
sym = CASESYM;
else if (strcmp(line, "CONST") == 0)
sym = CONSTSYM;
else if (strcmp(line, "DO") == 0)
sym = DOSYM;
else if (strcmp(line, "CEND") == 0)
sym = CENDSYM;
else if (strcmp(line, "REPEAT") == 0)
sym = REPEATSYM;
else if (strcmp(line, "FOR") == 0)
sym = FOR;
else if (strcmp(line, "UNTIL") == 0)
sym = UNTILSYM;
else if (strcmp(line, "TO") == 0)
sym = TOSYM;
else if (strcmp(line, "ELSE") == 0)
sym = ELSESYM;
else if (strcmp(line, "DOWNTO") == 0)
sym = DOWNTOSYM;
else if (strcmp(line, "WRITELN") == 0)
sym = WRITELNSYM;
else if (strcmp(line, "WRITE") == 0)
sym = WRITESYM;
else if (strcmp(line, "END") == 0)
sym = ENDSYM;
else if (strcmp(line, "IF") == 0)
sym = IFSYM;
else if (strcmp(line, "ODD") == 0)
sym = ODDSYM;
else if (strcmp(line, "OF") == 0)
sym = OFSYM;
else if (strcmp(line, "PROCEDURE") == 0)
sym = PROCSYM;
else if (strcmp(line, "THEN") == 0)
sym = THENSYM;
else if (strcmp(line, "VAR") == 0)
sym = VARSYM;
else if (strcmp(line, "WHILE") == 0)
sym = WHILESYM;
else if (strcmp(line, "FUNCTION") == 0)
sym = FUNCSYM;
//MODIFIED
else if (strcmp(line, "AND") == 0)
sym = AND;
else if (strcmp(line, "OR") == 0)
sym = OR;
else if (strcmp(line, "NOT") == 0)
sym = NOT;
//END MODIFIED
else
sym = IDENT;
strcpy(symstr[sym], line);
return;
}
if (chartype(ch) == DIGIT)
{
char strnum[10];
sym = NUMBER;
number = 0;
do
{
strnum[index++] = ch;
number = 10 * number + int(ch - 48);
getchar(ch);
} while (chartype(ch) == DIGIT);
charcount--;
strnum[index] = '\0';
strcpy(symstr[sym], strnum);
return;
}
if (chartype(ch) == PUNCT)
{
punc[index++] = ch;
if (ch == ':' || ch == '<' || ch == '>')
{
getchar(ch);
if (chartype(ch) == PUNCT && (ch == '=') || (ch == '>'))
punc[index++] = ch;
else
charcount--;
}
punc[index] = '\0';
if (strcmp(punc, ":=") == 0)
sym = ASSIGN;
else if (strcmp(punc, ":") == 0)
sym = COLON;
else if (strcmp(punc, ",") == 0)
sym = COMMA;
else if (strcmp(punc, "/") == 0)
sym = DIV;
else if (strcmp(punc, "=") == 0)
sym = EQL;
else if (strcmp(punc, ">=") == 0)
sym = GREQL;
else if (strcmp(punc, ">") == 0)
sym = GRTHEN;
else if (strcmp(punc, "(") == 0)
sym = LPAREN;
else if (strcmp(punc, "<=") == 0)
sym = LSEQL;
else if (strcmp(punc, "<") == 0)
sym = LSTHEN;
else if (strcmp(punc, "-") == 0)
sym = MINUS;
else if (strcmp(punc, "*") == 0)
sym = MULT;
else if (strcmp(punc, "<>") == 0)
sym = NOTEQL;
else if (strcmp(punc, ".") == 0)
sym = PERIOD;
else if (strcmp(punc, "+") == 0)
sym = PLUS;
else if (strcmp(punc, ")") == 0)
sym = RPAREN;
else if (strcmp(punc, ";") == 0)
sym = SEMICOLON;
strcpy(symstr[sym], punc);
return;
}
}
// -------------------------------------------
// determine a character type
// -------------------------------------------
intype chartype(char ch)
{
if (ch == '\n' || ch == '\r')
return EOL; // character END-OF-LINE
if (isspace(ch))
return SPACE; // character SPACE
if (isdigit(ch))
return DIGIT; // character DIGIT
if (isalpha(ch))
return ALPHA; // character ALPHA
if (ispunct(ch))
return PUNCT; // character PUNCTUATION
return NONE;
}
// -------------------------------------------
// Find the base
// -------------------------------------------
int base(int lev, int basereg, int stack[stack[]])
{
int base1;
for (base1 = basereg; lev > 0; base1 = stack[base1], lev--);
return base1;
}
// -------------------------------------------
// This is our Interpreter
// -------------------------------------------
//You'll also need to change the top, base, and position variables inside of Interpret to be arrays too. Don't forget to change the stuff in your Base function.
void interpret(void)
{
// You'll need to go into your Interpret() function and change everything to work through a stack of stacks. (stackz on stackz on stackz).
// So you'll have an array with 4 arrays inside of it, pretty much. Each of those will be a full "stack" unto itself.
int progreg[] = 0, basereg[] = 0, top[] = 0, stack[ stack[MAX_STACK] ] = { 0 };
pcodetable inst;
std::cout << std::endl << "Start PL/0" << std::endl;
do
{
inst = pcode[progreg];
progreg++;
switch (inst.function)
{
case LIT:
top++;
stack[top] = inst.adr;
continue;
case OPR:
switch (inst.adr)
{
case 0:
top = basereg - 1;
basereg = stack[ stack[top + 2] ];
progreg = stack[ stack[top + 3] ];
continue;
case 1:
stack[ stack[top] ] = -stack[ stack[top] ];
continue;
case 2:
top--;
stack[ stack[top] ] = stack[ stack[top] ] + stack[ stack[top + 1] ];
continue;
case 3:
top--;
stack[ stack[top] ] = stack[ stack[top] ] - stack[ stack[top + 1] ];
continue;
case 4:
top--;
stack[ stack[top] ] = stack[ stack[top] ] * stack[ stack[top + 1] ];
continue;
case 5:
top--;
stack[ stack[top] ] = stack[ stack[top] ] / stack[ stack[top + 1] ];
continue;
case 6:
stack[ stack[top] ] = (stack[ stack[top] % 2 > 0 ]);
continue;
case 8:
top--;
stack[ stack[top] ] = (stack[ stack[top] ] == stack[ stack[top + 1] ]);
continue;
case 9:
top--;
stack[ stack[top] ] = (stack[ stack[top] ] != stack[ stack[top + 1] ]);
continue;
case 10:
top--;
stack[ stack[top] ] = (stack[ stack[top] ] < stack[ stack[top + 1] ]);
continue;
case 11:
top--;
stack[ stack[top] ] = (stack[ stack[top] ] >= stack[ stack[top + 1] ]);
continue;
case 12:
top--;
stack[ stack[top] ] = (stack[ stack[top] ] > stack[ stack[top + 1] ]);
continue;
case 13:
top--;
stack[top] = (stack[top] <= stack[top + 1]);
continue;
// Begin Modified -------
case 14:
std::cout << stack[top] << " ";
top--;
continue;
case 15:
std::cout << std::endl;
//top--;
continue;
// End Modified -------
}
continue;
case LOD:
top++;
stack[top] = stack[base(inst.level, basereg, stack) + inst.adr];
continue;
case STO:
stack[base(inst.level, basereg, stack) + inst.adr] = stack[top];
top--;
continue;
case CAL:
stack[top + 1] = base(inst.level, basereg, stack);
stack[top + 2] = basereg;
stack[top + 3] = progreg;
basereg = top + 1;
progreg = inst.adr;
continue;
case INT:
top = top + inst.adr;
continue;
case JMP:
progreg = inst.adr;
continue;
case JPC:
if (stack[top] == inst.level)
progreg = inst.adr;
top--;
continue;
case CTS:
top++;
stack[top] = stack[top - 1];
continue;
}
} while (progreg != 0);
std::cout << "End PL/0\n";
}
// -------------------------------------------
// This shows our PCODE
// -------------------------------------------
void showpcode(void)
{
int startpoint;
startpoint = codeinx0;
std::cout << std::endl;
for (int i = startpoint; i < codeinx; ++i)
{
std::cout << i << " ";
switch (pcode[i].function)
{
case CAL:
std::cout << "CAL ";
break;
case INT:
std::cout << "INT ";
break;
case JMP:
std::cout << "JMP ";
break;
case JPC:
std::cout << "JPC ";
break;
case LIT:
std::cout << "LIT ";
break;
case LOD:
std::cout << "LOD ";
break;
case OPR:
std::cout << "OPR ";
break;
case STO:
std::cout << "STO ";
break;
case CTS:
std::cout << "CTS ";
break;
}
std::cout << pcode[i].level << ' ' << pcode[i].adr << std::endl;
}
}
// -------------------------------------------
// This is our main program entry
// -------------------------------------------
int main(int argc, char* argv[])
{
symbol sym;
int i;
char filen[40];
FILE *stream;
// Initialize some variables
linelength = 0;
charcount = 0;
linecount = 0;
codeinx = 0;
freopen_s(&stream, "Output.txt", "w", stdout);
getsym(sym); // get the first symbol
block(sym, 0, 0); // start processing
std::cout << "\nSuccessful compilation!\n";
interpret();
return 0;
}
On Thu, Apr 10, 2014 at 8:08 PM, Kyle Rebstock <kjr247@gmail.com> wrote :
// -------------------------------------------
// Program: pascomp.cc (Version 1.8)//modified since 1.8 This is compiler before val/ref feature
//
// Description: This is a pascal like compiler with low-level code implementation.
// Student: Kyle Jackson Rebstock
// ID: 713599
// Date: February 8, 2014
// -------------------------------------------
//#include <fstream.h> // for handling files
#include <ctype.h>
#include <stdlib.h>
#include <string>
#include <iomanip>
#include <iostream>
// -------------------------------------------
// These are some global definitions
// -------------------------------------------
#define TRUE 1
#define FALSE 0
#define MAX_TABLE 500
#define MAX_PCODE 1000
#define MAX_SYMBOL 47
#define MAX_SYM_SZ 20
#define MAX_PRAMS 31
#define MAX_STACK 1000
// -------------------------------------------
// These are some ERROR definitions
// -------------------------------------------
#define ERROR_SEMICOLON 1
#define ERROR_IDENT 2
#define ERROR_UNKNOWN 3
#define ERROR_ASSIGN 4
#define ERROR_ASSIGN_PROC 5
#define ERROR_PROCEDURE 6
#define ERROR_END_SYM 7
#define ERROR_DO_SYM 8
#define ERROR_THEN_SYM 9
#define ERROR_UNTIL_SYM 10
#define ERROR_VARIABLE 11
#define ERROR_OF_SYM 12
#define ERROR_CONSTANT 13
#define ERROR_COLON 14
#define ERROR_RPAREN 15
#define ERROR_IS_PROCEDURE 16
#define ERROR_REL 17
#define ERROR_PROG_SIZE 18
#define ERROR_END_PROG 19
#define ERROR_NUMBER 20
#define ERROR_IDENT_VAR 22
#define ERROR_LPAREN 23
#define ERROR_UNTIL 25
#define ERROR_TO_DOWNTO 26
#define ERROR_OF 27
#define ERROR_NUMBER_IDENT 28
#define ERROR_CEND 29
#define ERROR_NOPROCEDURE 30
#define ERROR_VAR 31
#define ERROR_ASSIGN 32
//Begin Modified
#define ERROR_FUNC 33
#define ERROR_FUNCLEVEL 34
//End Modified
// -------------------------------------------
// some enumerated data types
// -------------------------------------------
typedef enum tag_symbol
{
VARSYM,
CONSTSYM,
BEGINSYM,
ENDSYM,
CENDSYM,
PERIOD,
SEMICOLON,
COLON,
LPAREN,
RPAREN,
GRTHEN,
LSTHEN,
GREQL,
LSEQL,
EQL,
ASSIGN,
IFSYM,
IDENT,
NUMBER,
WRITESYM,
WRITELNSYM,
PROCSYM,
NOTEQL,
MINUS,
PLUS,
DIV,
MULT,
COMMA,
ODDSYM,
CALL,
ELSESYM,
THENSYM,
WHILESYM,
DOSYM,
REPEATSYM,
UNTILSYM,
CASESYM,
OFSYM,
CEND,
FOR,
DOWNTOSYM,
TOSYM,
FUNCSYM,
OR,
AND,
NOT,
COBEGIN, //MODIFIED COBEGIN" and "COEND
COEND //MODIFIED COBEGIN" and "COEND
}symbol;
// -------------------------------------------
typedef enum tag_Objtype
{
NOTYPE,
CONSTANT,
VARIABLE,
PROCEDURE,
FUNCTION //Modified
}Objtype;
// -------------------------------------------
typedef enum tag_psyms
{
OPR,
CAL,
INT,
JPC,
JMP,
LIT,
LOD,
STO,
CTS
}psyms;
typedef enum tag_intype
{
ALPHA,
DIGIT,
EOL,
NONE,
PUNCT,
SPACE
}intype;
// -------------------------------------------
typedef struct tag_symtable // Symbols Table Structure
{
char name[MAX_SYM_SZ]; // Symbol name
Objtype kind; // Type of symbol
int value, // Value of symbol
level, // Level of symbol
adr; // Symbol address
}symtable;
// -------------------------------------------
typedef struct tag_pcodetable // PCODE Table Structure
{
psyms function; // pcode function
int level, // pcode level static link
adr; // pcode address number into table
}pcodetable;//used to save the compile code
// -------------------------------------------
// These are some global variables
// -------------------------------------------
int linelength, // line length
linecount, // line counter
charcount, // a character counter
codeinx, // pcode index counter inc everytime
codeinx0, // init pcode index
varcount0, // Init variable counter
number;
symbol prevsym; // holds the previous symbol
symbol toORdowntonsym;
symbol writesym;
symbol gensym;
symbol expsym;
symbol termsym;
symtable table[MAX_TABLE]; // table array
pcodetable pcode[MAX_PCODE]; // pcode table
char line[MAX_SYM_SZ]; // an identification string
char punc[MAX_SYM_SZ]; // punction array
char symstr[MAX_SYMBOL][MAX_SYM_SZ]; // symbols array
// -------------------------------------------
// These are some function prototypes
// -------------------------------------------
void block(symbol &, int, int);
void statement(symbol &, int, int);
void genexp(symbol &, int, int);
void expression(symbol &, int, int);
void term(symbol &, int, int);
void factor(symbol &, int, int);
char getchar(char &);
void getsym(symbol &);
intype chartype(char ch);
void enter(Objtype, char[], symbol &, int &, int, int &);
int base(int, int, int &);
void gen(psyms, int, int);
void interpret(void);
int position(int);
void showpcode(void);
void openfile(void);
void error(int);
// -------------------------------------------
// This handles our system errors
// -------------------------------------------
void error(int num)
{
std::cout << std::endl;
switch (num)
{
case ERROR_NOPROCEDURE:
std::cout << "Procedure not accepted here";
break;
case ERROR_CEND:
std::cout << "cend sym expected";
break;
case ERROR_NUMBER_IDENT:
std::cout << "number or ident expected";
break;
case ERROR_OF:
std::cout << "of expected";
break;
case ERROR_TO_DOWNTO:
std::cout << "to or downto expected";
break;
case ERROR_UNTIL:
std::cout << "Until expected";
break;
case ERROR_ASSIGN:
std::cout << "Assignment operator expected";
break;
case ERROR_ASSIGN_PROC:
std::cout << "Assignment not allowed here";
break;
case ERROR_COLON:
std::cout << "COLON Expected";
break;
case ERROR_CONSTANT:
std::cout << "Constant Expected";
break;
case ERROR_END_PROG:
std::cout << "Premature end of program";
break;
case ERROR_DO_SYM:
std::cout << "DO symbol Expected";
break;
case ERROR_END_SYM:
std::cout << "END symbol Expected";
break;
case ERROR_REL:
std::cout << "Relational operator expected";
break;
case ERROR_IDENT:
std::cout << "Identifier Expected";
break;
case ERROR_IS_PROCEDURE:
std::cout << "Assignment to PROCEDURE not allowed";
break;
case ERROR_NUMBER:
std::cout << "A number was Expected";
break;
case ERROR_PROG_SIZE:
std::cout << "Program size is too large...";
break;
case ERROR_OF_SYM:
std::cout << "OF symbol Expected";
break;
case ERROR_RPAREN:
std::cout << "RIGHT Parenthesis Expected";
break;
case ERROR_LPAREN:
std::cout << "LEFT Parenthesis Expected";
break;
case ERROR_SEMICOLON:
std::cout << "Semicolon Expected";
break;
case ERROR_THEN_SYM:
std::cout << "THEN symbol Expected";
break;
case ERROR_UNKNOWN:
std::cout << "Unknown Identifier";
break;
case ERROR_UNTIL_SYM:
std::cout << "UNTIL symbol Expected";
break;
case ERROR_VARIABLE:
std::cout << "Variable or Expression Expected";
break;
case ERROR_IDENT_VAR:
std::cout << "Ident - Variable Expected";
break;
case ERROR_VAR:
std::cout << "VAR Expected";
break;
//Begin Modified
case ERROR_FUNCLEVEL:
std::cout << "Must be inside function body";
break;
case ERROR_FUNC:
std::cout << "Function Expected";
break;
//End Modified
}
std::cout << std::endl;
exit(1);
}
// -------------------------------------------
// Insert Block Identifier
// -------------------------------------------
void enter(Objtype kind, char name[], symbol &sym, int &varcount, int level, int &tableinx)
{
tableinx++;
strcpy(table[tableinx].name, name);
table[tableinx].kind = kind;
if (kind == CONSTANT)
{
if (sym != IDENT)
error(ERROR_IDENT);
getsym(sym);
if (sym != EQL)
error(ERROR_ASSIGN);
getsym(sym);
if (sym != NUMBER)
error(ERROR_NUMBER);
table[tableinx].value = number;//for const only value matters
}
else if ((kind == VARIABLE))
{
if (sym != IDENT)
error(ERROR_IDENT);
table[tableinx].level = level; // store variable level for static link level
table[tableinx].adr = varcount++; // store address offset from base
}
else if (kind == PROCEDURE)
table[tableinx].level = level; // store procedure level
//Begin Modified
else if (kind == FUNCTION)
if (sym != IDENT)
error(ERROR_IDENT);
table[tableinx].level = level; // store funciton level
//End Modified
getsym(sym);
}
// -------------------------------------------
// Locate Position
// -------------------------------------------
int position(int tableinx)
{
int i = tableinx;
for (strcpy(table[0].name, line); strcmp(table[i].name, line) != 0; i--);
return i;
}
// -------------------------------------------
// Block
// -------------------------------------------
void block(symbol &sym, int level, int tableinx)
{ //this is our dx, set to 3 for static link
int varcount = 3; //,dynamic link,and return address implicitly set
int count = 0;
// save symbol table count used to
int tableinx0 = tableinx; //fix after CONST,VAR,and PROCEDURES DECLARE
table[tableinx].adr = codeinx; // save pcode code index
gen(JMP, 0, 0); // Generate our init JMP Function,level,adr in pcode table
while (sym == CONSTSYM || sym == VARSYM || sym == PROCSYM || sym == FUNCSYM)
{
if (sym == CONSTSYM)
{
// ---- CONSTANT SYM ----
getsym(sym);
enter(CONSTANT, line, sym, varcount, level, tableinx);
while (sym == COMMA)
{
getsym(sym);
enter(CONSTANT, line, sym, varcount, level, tableinx);//int tableinx for all,set value of table line = name
}
if (sym != SEMICOLON)
error(ERROR_SEMICOLON);
getsym(sym);
}
// ---- VARIABLE SYM ----
if (sym == VARSYM)
{
getsym(sym);
enter(VARIABLE, line, sym, varcount, level, tableinx);//inc (dx) varcount and tableinx,used for INT 0,varcount
while (sym == COMMA)
{
getsym(sym);
enter(VARIABLE, line, sym, varcount, level, tableinx);
}
if (sym != SEMICOLON)
error(ERROR_SEMICOLON);
getsym(sym);
}
// ---- PROCEDURE SYM ----
//BEGIN MODIFIED
while (sym == PROCSYM || sym == FUNCSYM) //Procedure or Function
{
prevsym = sym; //Save sym
getsym(sym);
if (sym != IDENT)
error(ERROR_IDENT);
//If sym = procedure then enter procedure
if (prevsym == PROCSYM){
enter(PROCEDURE, line, sym, varcount, level, tableinx);//int tableinx and add level
}
//If sym = function enter function
if (prevsym == FUNCSYM){
enter(FUNCTION, line, sym, varcount, level, tableinx);//int tableinx and add level
}
if (sym != SEMICOLON)
error(ERROR_SEMICOLON);
getsym(sym);
block(sym, level + 1, tableinx);//inc static link for functions inside of functions, table current pointer
if (sym != SEMICOLON)
error(ERROR_SEMICOLON);
getsym(sym);
}
//End Modified
}
pcode[table[tableinx0].adr].adr = codeinx;//tableinx0 is used to fix the original jump when u go into a block
table[tableinx0].adr = codeinx;
codeinx0 = codeinx; //fix proc addr in ST
gen(INT, 0, varcount);//inc the top of the stack by 3 + number of variable
statement(sym, level, tableinx); // ident can also now be a function and now stores variables and handles function storing
gen(OPR, 0, 0);
showpcode();
}
// -------------------------------------------
// Statement
// -------------------------------------------
void statement(symbol &sym, int level, int tableinx)
{
int i, i3, cx1, cx2, cx3, cx4, i2, cx5, cx6, cx7, cx8, cxa, cxb;
int first;
bool FirstCase = true;
int count = 0;
switch (sym)
{
// IDENT
case IDENT:
i = position(tableinx);
if (i == 0)
error(ERROR_UNKNOWN);
switch (table[i].kind)
{
case VARIABLE:
getsym(sym);
if (sym != ASSIGN)
error(ERROR_ASSIGN);
getsym(sym);
expression(sym, level, tableinx);//8 * B2 *example* put 8 and B2 onto stack and run OPR
gen(STO, level - table[i].level, table[i].adr);
break;
//Begin Modified
case FUNCTION:
getsym(sym);
if (sym != ASSIGN)
error(ERROR_ASSIGN);
getsym(sym);
expression(sym, level, tableinx);//8 * B2 *example* put 8 and B2 onto stack and run OPR
if (i == tableinx){ // if kind is function
gen(STO, 0, -1); // then STO 0, -1
}
else
error(ERROR_FUNCLEVEL);
break;
default:
error(ERROR_ASSIGN_PROC);
//End Modified
}
break;
// PROCEDURE CALL
case CALL:
getsym(sym);
if (sym != IDENT)
error(ERROR_IDENT);
i = position(tableinx);
if (i == 0)
error(ERROR_UNKNOWN);
if (table[i].kind != PROCEDURE)
error(ERROR_PROCEDURE);
getsym(sym);
gen(CAL, level - table[i].level, table[i].adr);
break;
// BEGIN and END block
case BEGINSYM:
getsym(sym);
statement(sym, level, tableinx);
while (sym == SEMICOLON)
{
getsym(sym);
statement(sym, level, tableinx);
}
if (sym != ENDSYM)
error(ERROR_END_SYM);
getsym(sym);
break;
// WHILE SYMBOL
case WHILESYM:
getsym(sym);
cx1 = codeinx;
genexp(sym, level, tableinx);
cx2 = codeinx;
gen(JPC, 0, 0);
if (sym != DOSYM)
error(ERROR_DO_SYM);
getsym(sym);
statement(sym, level, tableinx);
gen(JMP, 0, cx1);
pcode[cx2].adr = codeinx;
break;
// IF - THEN - ELSE //Modified
case IFSYM:
getsym(sym);
genexp(sym, level, tableinx);
cxa = codeinx; //Save cx1
gen(JPC, 0, 0); // JPC 0,0
if (sym != THENSYM)
error(ERROR_THEN_SYM);
getsym(sym);
statement(sym, level, tableinx);
pcode[cxa].adr = codeinx; //Fix JPC @ cx1
/* add your code for ELSE here */
if (sym == ELSESYM) // Begin Modified -----
{
getsym(sym);
cxb = codeinx; //Save cx2
gen(JMP, 0, 0); //JMP 0,0
pcode[cxa].adr = codeinx; //Fix JPC @ cx1
statement(sym, level, tableinx);
pcode[cxb].adr = codeinx; //Fix JMP @ cx2
}
//End Modified -------
break;
case REPEATSYM:
/* add your code for REPEAT-UNTIL here */
// Begin Modified -------
cx1 = codeinx; //Save cx
do {
getsym(sym);
statement(sym, level, tableinx);
} while (sym == SEMICOLON);
if (sym != UNTILSYM)
error(ERROR_UNTIL_SYM);
getsym(sym);
genexp(sym, level, tableinx);
gen(JPC, 0, cx1); //JPC 0,cx
break;
case FOR:
/* add your code for FOR-DO here */
getsym(sym);
if (sym != IDENT)
error(ERROR_IDENT_VAR);
i3 = position(tableinx);
if (i3 == 0)
error(ERROR_VAR);
if (table[i3].kind != VARIABLE)
error(ERROR_VAR);
getsym(sym);
if (sym != ASSIGN)
error(ERROR_ASSIGN);
getsym(sym);
expression(sym, level, tableinx);
gen(STO, level - table[i3].level, table[i3].adr); //STO
if (sym != TOSYM && sym != DOWNTOSYM)
error(ERROR_TO_DOWNTO);
toORdowntonsym = sym; //Save sym
getsym(sym);
expression(sym, level, tableinx);
//Modified
cx7 = codeinx; //Save cx7
gen(CTS, 0, 0); //CTS 0,0
gen(LOD, level - table[i3].level, table[i3].adr); //LOD
if (toORdowntonsym == TOSYM) //If sym is TO
gen(OPR, 0, 11); //OPR 0, >=
else if (toORdowntonsym == DOWNTOSYM) //If sym is DOWNTO
gen(OPR, 0, 13); //OPR 0, <=
cx8 = codeinx; //Save cx8
gen(JPC, 0, 0); //JPC 0,0
//End Mod
if (sym != DOSYM)
error(ERROR_DO_SYM);
getsym(sym);
statement(sym, level, tableinx);
//Modified
gen(LOD, level - table[i3].level, table[i3].adr); //LOD
gen(LIT, 0, 1); //LIT 0,1
if (toORdowntonsym == TOSYM) //If sym is TO
gen(OPR, 0, 2); //OPR 0, +
else if (toORdowntonsym == DOWNTOSYM) //If sym is DOWNTO
gen(OPR, 0, 3); //OPR 0,-
gen(STO, level - table[i3].level, table[i3].adr); //STO
gen(JMP, 0, cx7); //JMP 0,cx7
pcode[cx8].adr = codeinx; //fix JPC @ cx8
gen(INT, 0, -1); //INT 0,-1
//End Mod
break;
case CASESYM:
/* add your code for CASE here */
//Begin Modified ------
getsym(sym);
i2 = position(tableinx);
expression(sym, level, tableinx);
if (sym != OFSYM)
error(ERROR_OF_SYM);
getsym(sym);
while (sym == NUMBER || sym == IDENT) {
if (sym == IDENT)
{
i2 = position(tableinx);
if (i2 == 0)
error(ERROR_VAR);
if (table[i2].kind != CONSTANT)
error(ERROR_CONSTANT);
}
//getsym(sym);
gen(CTS, 0, 0); // CTS 0,0
if (sym == NUMBER)
gen(LIT, 0, number); //If Number then LIT 0,num
else if (sym == CONSTANT)
gen(LIT, 0, table[i2].value); //If constant then LIT 0, table[i].value
gen(OPR, 0, 8); //OPR 0,=
cx5 = codeinx; //Save cx5
gen(JPC, 0, 0); // JPC 0,0
getsym(sym);
if (sym != COLON)
error(ERROR_COLON);
getsym(sym);
statement(sym, level, tableinx);
if (sym != SEMICOLON)
error(ERROR_SEMICOLON);
if (FirstCase == true){
cx6 = codeinx; //Save cx6
gen(JMP, 0, 0); //JMP 0,0
FirstCase = false;
}
else {
gen(JMP, 0, cx6); //JMP 0,cx6
}
pcode[cx5].adr = codeinx; //fix JPC @ cx5
getsym(sym);
}
if (sym != CENDSYM)
error(ERROR_CEND);
pcode[cx6].adr = codeinx; //fix JPC @ cx6
gen(INT, 0, -1);// int 0,-1
getsym(sym);
break;
//End Modified ------
case WRITESYM:
/* add your code for WRITE here */
//Begin Modified ------
writesym = sym; //Save sym
getsym(sym);
if (sym != LPAREN)
error(ERROR_LPAREN);
do {
getsym(sym);
expression(sym, level, tableinx);
gen(OPR, 0, 14); //OPR 0,14
} while (sym == COMMA);
if (sym != RPAREN)
error(ERROR_RPAREN);
getsym(sym);
/*if (prevsym == WRITELNSYM)
gen(OPR, 0, 15);*/
// End Modified -------
break;
case WRITELNSYM:
/* add your code for WRITELN here */
// Begin Modified -------
writesym = sym; //Save sym
getsym(sym);
if (sym != LPAREN)
error(ERROR_LPAREN);
do {
getsym(sym);
expression(sym, level, tableinx);
gen(OPR, 0, 14); //OPR 0,14
} while (sym == COMMA);
if (sym != RPAREN)
error(ERROR_RPAREN);
getsym(sym);
//if (prevsym == WRITELNSYM) //If sym is writeln
gen(OPR, 0, 15); //OPR 0,15
break;
// End Modified -------
} // END of SWITCH
}
// -------------------------------------------
// genexp
// -------------------------------------------
//Modified from "condition" to "genexp"
void genexp(symbol &sym, int level, int tableinx)
{
symbol gensym;
// ODD symbol
if (sym == ODDSYM)
{
getsym(sym);
expression(sym, level, tableinx);
gen(OPR, 0, 6);
}
else
{
expression(sym, level, tableinx);
if ((sym == EQL) || (sym == NOTEQL) || (sym == LSTHEN) || (sym == LSEQL) || (sym == GRTHEN) || (sym == GREQL))
{
gensym = sym;
getsym(sym);
expression(sym, level, tableinx);
switch (gensym)
{
case EQL:
gen(OPR, 0, 8);
break;
case GREQL:
gen(OPR, 0, 11);
break;
case GRTHEN:
gen(OPR, 0, 12);
break;
case LSEQL:
gen(OPR, 0, 13);
break;
case LSTHEN:
gen(OPR, 0, 10);
break;
case NOTEQL:
gen(OPR, 0, 9);
break;
}
//may need to save sym, call expression, then gen(OPR, 0, symop)------------------------------------------?
}
//Modified
//General Experession doesn't have to be a relational operator, it can be nothing
//else error(ERROR_REL);
}
}
// -------------------------------------------
// Expression
// -------------------------------------------
void expression(symbol &sym, int level, int tableinx)
{
symbol expsym;
if ((sym == PLUS) || (sym == MINUS))
{
expsym = sym;
getsym(sym); // save sym
term(sym, level, tableinx);
if (expsym == MINUS)
gen(OPR, 0, 1);
}
else
term(sym, level, tableinx);
//Begin Modified
//Add or sym
while (sym == PLUS || sym == MINUS || sym == OR)
{
expsym = sym;
getsym(sym);
term(sym, level, tableinx);
if (expsym == MINUS)
gen(OPR, 0, 3);
else
gen(OPR, 0, 2);//Can be + or "OR"
}
//End modified
}
// -------------------------------------------
// TERM
// -------------------------------------------
void term(symbol &sym, int level, int tableinx)
{
symbol termsym;
factor(sym, level, tableinx);
//Modified
while ((sym == MULT) || (sym == DIV) || (sym == AND))
{
termsym = sym; // save sym
getsym(sym);
factor(sym, level, tableinx);
if (termsym == DIV)
gen(OPR, 0, 5);
else // else if (sym == MULT)
gen(OPR, 0, 4);//Can be * or "AND"
//End Modified
}
} // End Void term
// -------------------------------------------
// FACTOR
// -------------------------------------------
void factor(symbol &sym, int level, int tableinx)
{
int i;
int count = 0;
switch (sym)
{
// IDENTIFER
case IDENT:
i = position(tableinx);
if (i == 0)
error(ERROR_UNKNOWN);
//Modified
if (table[i].kind == PROCEDURE || table[i].kind == FUNCTION)
error(ERROR_IS_PROCEDURE);
switch (table[i].kind)
{
case VARIABLE:
gen(LOD, level - table[i].level, table[i].adr);
break;
case CONSTANT:
gen(LIT, 0, table[i].value);
break;
}
getsym(sym);
break;
// NUMBER
case NUMBER:
gen(LIT, 0, number);
getsym(sym);
break;
// LEFT PARENTHESE
case LPAREN:
getsym(sym);
genexp(sym, level, tableinx);
if (sym != RPAREN)
error(ERROR_RPAREN);
getsym(sym);
break;
case CALL:
getsym(sym);
i = position(tableinx);
if (i == 0)
error(ERROR_UNKNOWN);
/*if (sym != FUNCSYM || sym != PROCSYM)
error(ERROR_FUNC);*/
if (sym != IDENT)
error(ERROR_IDENT);
if (table[i].kind != FUNCTION)
error(ERROR_FUNC);
gen(INT, 0, 1); //INT 0,1
gen(CAL, level - table[i].level, table[i].adr);// Call
getsym(sym);
break;
case NOT:
getsym(sym);
factor(sym, level, tableinx);
gen(LIT, 0, 0); // Lit 0 and check inequality
gen(OPR, 0, 8); // opr, =
break;
default:
error(ERROR_VARIABLE);
}
//End Modified
}
// -------------------------------------------
// Generate the PCODE
// -------------------------------------------
void gen(psyms function, int level, int adr)
{
if (codeinx > MAX_PCODE)
error(ERROR_PROG_SIZE);
pcode[codeinx].function = function;
pcode[codeinx].level = level;
pcode[codeinx].adr = adr;
codeinx++;
}
// -------------------------------------------
// This is our GET CHARACTER function
// -------------------------------------------
char getchar(char &ch)
{
static char line[255]; // local array
if (charcount == linelength)
{
charcount = linelength = 0; // zero out counters
std::cin.get(ch);
while (chartype(ch) != EOL && std::cin)
{
line[linelength] = ch;
std::cin.get(ch);
linelength++;
}
if (linelength == 0 && charcount == 0 && !std::cin)
error(ERROR_END_PROG);
line[linelength] = 0;
std::cout << line << std::endl;
line[linelength] = ' ';
linecount++; // count lines
linelength++; //
}
ch = toupper(line[charcount]);
charcount++; // count characters
return ch;
}
// -------------------------------------------
// This is our GETSYM
// -------------------------------------------
void getsym(symbol &sym)
{
char ch;
int index = 0;
do
getchar(ch);
while (chartype(ch) == SPACE || chartype(ch) == EOL);
if (chartype(ch) == ALPHA)
{
do
{
line[index++] = ch;
getchar(ch);
} while (chartype(ch) == ALPHA || chartype(ch) == DIGIT || ch == '_');
line[index] = '\0';
charcount--;
if (strcmp(line, "BEGIN") == 0)
sym = BEGINSYM;
else if (strcmp(line, "CALL") == 0)
sym = CALL;
else if (strcmp(line, "CASE") == 0)
sym = CASESYM;
else if (strcmp(line, "CONST") == 0)
sym = CONSTSYM;
else if (strcmp(line, "DO") == 0)
sym = DOSYM;
else if (strcmp(line, "CEND") == 0)
sym = CENDSYM;
else if (strcmp(line, "REPEAT") == 0)
sym = REPEATSYM;
else if (strcmp(line, "FOR") == 0)
sym = FOR;
else if (strcmp(line, "UNTIL") == 0)
sym = UNTILSYM;
else if (strcmp(line, "TO") == 0)
sym = TOSYM;
else if (strcmp(line, "ELSE") == 0)
sym = ELSESYM;
else if (strcmp(line, "DOWNTO") == 0)
sym = DOWNTOSYM;
else if (strcmp(line, "WRITELN") == 0)
sym = WRITELNSYM;
else if (strcmp(line, "WRITE") == 0)
sym = WRITESYM;
else if (strcmp(line, "END") == 0)
sym = ENDSYM;
else if (strcmp(line, "IF") == 0)
sym = IFSYM;
else if (strcmp(line, "ODD") == 0)
sym = ODDSYM;
else if (strcmp(line, "OF") == 0)
sym = OFSYM;
else if (strcmp(line, "PROCEDURE") == 0)
sym = PROCSYM;
else if (strcmp(line, "THEN") == 0)
sym = THENSYM;
else if (strcmp(line, "VAR") == 0)
sym = VARSYM;
else if (strcmp(line, "WHILE") == 0)
sym = WHILESYM;
else if (strcmp(line, "FUNCTION") == 0)
sym = FUNCSYM;
//MODIFIED
else if (strcmp(line, "AND") == 0)
sym = AND;
else if (strcmp(line, "OR") == 0)
sym = OR;
else if (strcmp(line, "NOT") == 0)
sym = NOT;
//END MODIFIED
else
sym = IDENT;
strcpy(symstr[sym], line);
return;
}
if (chartype(ch) == DIGIT)
{
char strnum[10];
sym = NUMBER;
number = 0;
do
{
strnum[index++] = ch;
number = 10 * number + int(ch - 48);
getchar(ch);
} while (chartype(ch) == DIGIT);
charcount--;
strnum[index] = '\0';
strcpy(symstr[sym], strnum);
return;
}
if (chartype(ch) == PUNCT)
{
punc[index++] = ch;
if (ch == ':' || ch == '<' || ch == '>')
{
getchar(ch);
if (chartype(ch) == PUNCT && (ch == '=') || (ch == '>'))
punc[index++] = ch;
else
charcount--;
}
punc[index] = '\0';
if (strcmp(punc, ":=") == 0)
sym = ASSIGN;
else if (strcmp(punc, ":") == 0)
sym = COLON;
else if (strcmp(punc, ",") == 0)
sym = COMMA;
else if (strcmp(punc, "/") == 0)
sym = DIV;
else if (strcmp(punc, "=") == 0)
sym = EQL;
else if (strcmp(punc, ">=") == 0)
sym = GREQL;
else if (strcmp(punc, ">") == 0)
sym = GRTHEN;
else if (strcmp(punc, "(") == 0)
sym = LPAREN;
else if (strcmp(punc, "<=") == 0)
sym = LSEQL;
else if (strcmp(punc, "<") == 0)
sym = LSTHEN;
else if (strcmp(punc, "-") == 0)
sym = MINUS;
else if (strcmp(punc, "*") == 0)
sym = MULT;
else if (strcmp(punc, "<>") == 0)
sym = NOTEQL;
else if (strcmp(punc, ".") == 0)
sym = PERIOD;
else if (strcmp(punc, "+") == 0)
sym = PLUS;
else if (strcmp(punc, ")") == 0)
sym = RPAREN;
else if (strcmp(punc, ";") == 0)
sym = SEMICOLON;
strcpy(symstr[sym], punc);
return;
}
}
// -------------------------------------------
// determine a character type
// -------------------------------------------
intype chartype(char ch)
{
if (ch == '\n' || ch == '\r')
return EOL; // character END-OF-LINE
if (isspace(ch))
return SPACE; // character SPACE
if (isdigit(ch))
return DIGIT; // character DIGIT
if (isalpha(ch))
return ALPHA; // character ALPHA
if (ispunct(ch))
return PUNCT; // character PUNCTUATION
return NONE;
}
// -------------------------------------------
// Find the base
// -------------------------------------------
int base(int lev, int basereg, int stack[])
{
int base1;
for (base1 = basereg; lev > 0; base1 = stack[base1], lev--);
return base1;
}
// -------------------------------------------
// This is our Interpreter
// -------------------------------------------
void interpret(void)
{
int progreg = 0, basereg = 0, top = 0, stack[MAX_STACK] = { 0 };
pcodetable inst;
std::cout << std::endl << "Start PL/0" << std::endl;
do
{
inst = pcode[progreg];
progreg++;
switch (inst.function)
{
case LIT:
top++;
stack[top] = inst.adr;
continue;
case OPR:
switch (inst.adr)
{
case 0:
top = basereg - 1;
basereg = stack[top + 2];
progreg = stack[top + 3];
continue;
case 1:
stack[top] = -stack[top];
continue;
case 2:
top--;
stack[top] = stack[top] + stack[top + 1];
continue;
case 3:
top--;
stack[top] = stack[top] - stack[top + 1];
continue;
case 4:
top--;
stack[top] = stack[top] * stack[top + 1];
continue;
case 5:
top--;
stack[top] = stack[top] / stack[top + 1];
continue;
case 6:
stack[top] = (stack[top] % 2 > 0);
continue;
case 8:
top--;
stack[top] = (stack[top] == stack[top + 1]);
continue;
case 9:
top--;
stack[top] = (stack[top] != stack[top + 1]);
continue;
case 10:
top--;
stack[top] = (stack[top] < stack[top + 1]);
continue;
case 11:
top--;
stack[top] = (stack[top] >= stack[top + 1]);
continue;
case 12:
top--;
stack[top] = (stack[top] > stack[top + 1]);
continue;
case 13:
top--;
stack[top] = (stack[top] <= stack[top + 1]);
continue;
// Begin Modified -------
case 14:
std::cout << stack[top] << " ";
top--;
continue;
case 15:
std::cout << std::endl;
//top--;
continue;
// End Modified -------
}
continue;
case LOD:
top++;
stack[top] = stack[base(inst.level, basereg, stack) + inst.adr];
continue;
case STO:
stack[base(inst.level, basereg, stack) + inst.adr] = stack[top];
top--;
continue;
case CAL:
stack[top + 1] = base(inst.level, basereg, stack);
stack[top + 2] = basereg;
stack[top + 3] = progreg;
basereg = top + 1;
progreg = inst.adr;
continue;
case INT:
top = top + inst.adr;
continue;
case JMP:
progreg = inst.adr;
continue;
case JPC:
if (stack[top] == inst.level)
progreg = inst.adr;
top--;
continue;
case CTS:
top++;
stack[top] = stack[top - 1];
continue;
}
} while (progreg != 0);
std::cout << "End PL/0\n";
}
// -------------------------------------------
// This shows our PCODE
// -------------------------------------------
void showpcode(void)
{
int startpoint;
startpoint = codeinx0;
std::cout << std::endl;
for (int i = startpoint; i < codeinx; ++i)
{
std::cout << i << " ";
switch (pcode[i].function)
{
case CAL:
std::cout << "CAL ";
break;
case INT:
std::cout << "INT ";
break;
case JMP:
std::cout << "JMP ";
break;
case JPC:
std::cout << "JPC ";
break;
case LIT:
std::cout << "LIT ";
break;
case LOD:
std::cout << "LOD ";
break;
case OPR:
std::cout << "OPR ";
break;
case STO:
std::cout << "STO ";
break;
case CTS:
std::cout << "CTS ";
break;
}
std::cout << pcode[i].level << ' ' << pcode[i].adr << std::endl;
}
}
// -------------------------------------------
// This is our main program entry
// -------------------------------------------
int main(int argc, char* argv[])
{
symbol sym;
int i;
char filen[40];
FILE *stream;
// Initialize some variables
linelength = 0;
charcount = 0;
linecount = 0;
codeinx = 0;
freopen_s(&stream, "Output.txt", "w", stdout);
getsym(sym); // get the first symbol
block(sym, 0, 0); // start processing
std::cout << "\nSuccessful compilation!\n";
interpret();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment