📄 pl0.c
字号:
} // condition
//////////////////////////////////////////////////////////////////////
void statement(symset fsys)
{
int i, cx1, cx2;
symset set1, set;
if (sym == SYM_IDENTIFIER)
{ // variable assignment
mask* mk;
if (! (i = position(id)))
{
error(11); // Undeclared identifier.
}
else if (table[i].kind != ID_VARIABLE)
{
error(12); // Illegal assignment.
i = 0;
}
getsym();
if (sym == SYM_BECOMES)
{
getsym();
}
else
{
error(13); // ':=' expected.
}
expression(fsys);
mk = (mask*) &table[i];
if (i)
{
gen(STO, level - mk->level, mk->address);
}
}
else if (sym == SYM_CALL)
{ // procedure call
getsym();
if (sym != SYM_IDENTIFIER)
{
error(14); // There must be an identifier to follow the 'call'.
}
else
{
if (! (i = position(id)))
{
error(11); // Undeclared identifier.
}
else if (table[i].kind == ID_PROCEDURE)
{
mask* mk;
mk = (mask*) &table[i];
gen(CAL, level - mk->level, mk->address);
}
else
{
error(15); // A constant or variable can not be called.
}
getsym();
}
}
else if (sym == SYM_IF)
{ // if statement
getsym();
set1 = createset(SYM_THEN, SYM_DO, SYM_NULL);
set = uniteset(set1, fsys);
condition(set);
destroyset(set1);
destroyset(set);
if (sym == SYM_THEN)
{
getsym();
}
else
{
error(16); // 'then' expected.
}
cx1 = cx;
gen(JPC, 0, 0);
statement(fsys);
code[cx1].a = cx;
}
else if (sym == SYM_BEGIN)
{ // block
getsym();
set1 = createset(SYM_SEMICOLON, SYM_END, SYM_NULL);
set = uniteset(set1, fsys);
statement(set);
while (sym == SYM_SEMICOLON || inset(sym, statbegsys))
{
if (sym == SYM_SEMICOLON)
{
getsym();
}
else
{
error(10);
}
statement(set);
} // while
destroyset(set1);
destroyset(set);
if (sym == SYM_END)
{
getsym();
}
else
{
error(17); // ';' or 'end' expected.
}
}
else if (sym == SYM_WHILE)
{ // while statement
cx1 = cx;
getsym();
set1 = createset(SYM_DO, SYM_NULL);
set = uniteset(set1, fsys);
condition(set);
destroyset(set1);
destroyset(set);
cx2 = cx;
gen(JPC, 0, 0);
if (sym == SYM_DO)
{
getsym();
}
else
{
error(18); // 'do' expected.
}
statement(fsys);
gen(JMP, 0, cx1);
code[cx2].a = cx;
}
test(fsys, phi, 19);
} // statement
//////////////////////////////////////////////////////////////////////
void block(symset fsys)
{
int cx0; // initial code index
mask* mk;
int block_dx;
int savedTx;
symset set1, set;
dx = 3;
block_dx = dx;
mk = (mask*) &table[tx];
mk->address = cx;
gen(JMP, 0, 0);
if (level > MAXLEVEL)
{
error(32); // There are too many levels.
}
do
{
if (sym == SYM_CONST)
{ // constant declarations
getsym();
do
{
constdeclaration();
while (sym == SYM_COMMA)
{
getsym();
constdeclaration();
}
if (sym == SYM_SEMICOLON)
{
getsym();
}
else
{
error(5); // Missing ',' or ';'.
}
}
while (sym == SYM_IDENTIFIER);
} // if
if (sym == SYM_VAR)
{ // variable declarations
getsym();
do
{
vardeclaration();
while (sym == SYM_COMMA)
{
getsym();
vardeclaration();
}
if (sym == SYM_SEMICOLON)
{
getsym();
}
else
{
error(5); // Missing ',' or ';'.
}
}
while (sym == SYM_IDENTIFIER);
// block = dx;
} // if
while (sym == SYM_PROCEDURE)
{ // procedure declarations
getsym();
if (sym == SYM_IDENTIFIER)
{
enter(ID_PROCEDURE);
getsym();
}
else
{
error(4); // There must be an identifier to follow 'const', 'var', or 'procedure'.
}
if (sym == SYM_SEMICOLON)
{
getsym();
}
else
{
error(5); // Missing ',' or ';'.
}
level++;
savedTx = tx;
set1 = createset(SYM_SEMICOLON, SYM_NULL);
set = uniteset(set1, fsys);
block(set);
destroyset(set1);
destroyset(set);
tx = savedTx;
level--;
if (sym == SYM_SEMICOLON)
{
getsym();
set1 = createset(SYM_IDENTIFIER, SYM_PROCEDURE, SYM_NULL);
set = uniteset(statbegsys, set1);
test(set, fsys, 6);
destroyset(set1);
destroyset(set);
}
else
{
error(5); // Missing ',' or ';'.
}
} // while
set1 = createset(SYM_IDENTIFIER, SYM_NULL);
set = uniteset(statbegsys, set1);
test(set, declbegsys, 7);
destroyset(set1);
destroyset(set);
}
while (inset(sym, declbegsys));
code[mk->address].a = cx;
mk->address = cx;
cx0 = cx;
gen(INT, 0, block_dx);
set1 = createset(SYM_SEMICOLON, SYM_END, SYM_NULL);
set = uniteset(set1, fsys);
statement(set);
destroyset(set1);
destroyset(set);
gen(OPR, 0, OPR_RET); // return
test(fsys, phi, 8); // test for error: Follow the statement is an incorrect symbol.
listcode(cx0, cx);
} // block
//////////////////////////////////////////////////////////////////////
int base(int stack[], int currentLevel, int levelDiff)
{
int b = currentLevel;
while (levelDiff--)
b = stack[b];
return b;
} // base
//////////////////////////////////////////////////////////////////////
// interprets and executes codes.
void interpret()
{
int pc; // program counter
int stack[STACKSIZE];
int top; // top of stack
int b; // program, base, and top-stack register
instruction i; // instruction register
printf("Begin executing PL/0 program.\n");
pc = 0;
b = 1;
top = 3;
stack[1] = stack[2] = stack[3] = 0;
do
{
i = code[pc++];
switch (i.f)
{
case LIT:
stack[++top] = i.a;
break;
case OPR:
switch (i.a) // operator
{
case OPR_RET:
top = b - 1;
pc = stack[top + 3];
b = stack[top + 2];
break;
case OPR_NEG:
stack[top] = -stack[top];
break;
case OPR_ADD:
top--;
stack[top] += stack[top + 1];
break;
case OPR_MIN:
top--;
stack[top] -= stack[top + 1];
break;
case OPR_MUL:
top--;
stack[top] *= stack[top + 1];
break;
case OPR_DIV:
top--;
if (stack[top + 1] == 0)
{
fprintf(stderr, "Runtime Error: Divided by zero.\n");
fprintf(stderr, "Program terminated.\n");
continue;
}
stack[top] /= stack[top + 1];
break;
case OPR_ODD:
stack[top] %= 2;
break;
case OPR_EQU:
top--;
stack[top] = stack[top] == stack[top + 1];
break;
case OPR_NEQ:
top--;
stack[top] = stack[top] != stack[top + 1];
case OPR_LES:
top--;
stack[top] = stack[top] < stack[top + 1];
break;
case OPR_GEQ:
top--;
stack[top] = stack[top] >= stack[top + 1];
case OPR_GTR:
top--;
stack[top] = stack[top] > stack[top + 1];
break;
case OPR_LEQ:
top--;
stack[top] = stack[top] <= stack[top + 1];
} // switch
break;
case LOD:
stack[++top] = stack[base(stack, b, i.l) + i.a];
break;
case STO:
stack[base(stack, b, i.l) + i.a] = stack[top];
printf("%d\n", stack[top]);
top--;
break;
case CAL:
stack[top + 1] = base(stack, b, i.l);
// generate new block mark
stack[top + 2] = b;
stack[top + 3] = pc;
b = top + 1;
pc = i.a;
break;
case INT:
top += i.a;
break;
case JMP:
pc = i.a;
break;
case JPC:
if (stack[top] == 0)
pc = i.a;
top--;
break;
} // switch
}
while (pc);
printf("End executing PL/0 program.\n");
} // interpret
//////////////////////////////////////////////////////////////////////
void main ()
{
FILE* hbin;
char s[80];
int i;
symset set, set1, set2;
printf("Please input source file name: "); // get file name to be compiled
scanf("%s", s);
if ((infile = fopen(s, "r")) == NULL)
{
printf("File %s can't be opened.\n", s);
exit(1);
}
phi = createset(SYM_NULL);
relset = createset(SYM_EQU, SYM_NEQ, SYM_LES, SYM_LEQ, SYM_GTR, SYM_GEQ, SYM_NULL);
// create begin symbol sets
declbegsys = createset(SYM_CONST, SYM_VAR, SYM_PROCEDURE, SYM_NULL);
statbegsys = createset(SYM_BEGIN, SYM_CALL, SYM_IF, SYM_WHILE, SYM_NULL);
facbegsys = createset(SYM_IDENTIFIER, SYM_NUMBER, SYM_LPAREN, SYM_NULL);
err = cc = cx = ll = 0; // initialize global variables
ch = ' ';
kk = MAXIDLEN;
getsym();
set1 = createset(SYM_PERIOD, SYM_NULL);
set2 = uniteset(declbegsys, statbegsys);
set = uniteset(set1, set2);
block(set);
destroyset(set1);
destroyset(set2);
destroyset(set);
destroyset(phi);
destroyset(relset);
destroyset(declbegsys);
destroyset(statbegsys);
destroyset(facbegsys);
if (sym != SYM_PERIOD)
error(9); // '.' expected.
if (err == 0)
{
hbin = fopen("hbin.txt", "w");
for (i = 0; i < cx; i++)
fwrite(&code[i], sizeof(instruction), 1, hbin);
fclose(hbin);
}
if (err == 0)
interpret();
else
printf("There are %d error(s) in PL/0 program.\n", err);
listcode(0, cx);
} // main
//////////////////////////////////////////////////////////////////////
// eof pl0.c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -