pl0语言允许过程嵌套定义和递归调用,试问他的编译程序如何解决运行时的存储管理

pl0语言允许过程嵌套定义和递归调用,试问他的编译程序如何解决运行时的存储管理,第1张

答案: PL/0 语言允许过程嵌套定义和递归调用,它的编译程序在运行时采用了栈式动态存储管理。(数组 CODE 存放的只读目标程序,它在运行时不改变。)运行时的数据区 S 是由解释程序定义的一维整型数组,解释执行时竖信对数据空间 S 的管举袭理遵循后进先出规则,当每个过程包括主程序被调用时,才分配数据空间,退出过程时,则所正纤兄分配的数据空间被释放。应用动态链和静态链的方式分别解决递归调用和非局部变量的引用问题。

// pl0 compiler source code

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <ctype.h>

#include "set.h"

#include "pl0.h"

//////////////////////////////////////////////////////////////////////

// print error message.

void error(n)

{

int i

printf(" ")

for (i = 1i <= cc - 1i++)

printf(" ")

fprintf(outfile, " ")

fprintf(outfile, "^\n")

printf("^\n")

fprintf(outfile, "Error %3d: %s\n", n, err_msg[n])

printf("Error %3d: %s\n", n, err_msg[n])

err++

} // error

/////////////////////////////////////空梁橘/渣吵////////斗团////////////////////////

void getch(void)

{

if (cc == ll)

{

if (feof(infile))

{

printf("\nPROGRAM INCOMPLETE\n")

exit(1)

}

ll = cc = 0

fprintf(outfile, "%5d ", cx)

printf("%5d ", cx)

while ( (!feof(infile)) // added &modified by alex 01-02-09

&&((ch = getc(infile)) != '\n'))

{

fprintf(outfile, "%c", ch)

printf("%c", ch)

line[++ll] = ch

} // while

fprintf(outfile, "\n")

printf("\n")

line[++ll] = ' '

}

ch = line[++cc]

} // getch

//////////////////////////////////////////////////////////////////////

// gets a symbol from input stream.

void getsym(void)

{

int i, k

char a[MAXIDLEN + 1]

while (ch == ' '|| ch == '\t')

// modified by yzhang 02-03-12,add some white space

getch()

if (isalpha(ch))

{ // symbol is a reserved word or an identifier.

k = 0

do

{

if (k <MAXIDLEN)

a[k++] = ch

getch()

}

while (isalpha(ch) || isdigit(ch))

a[k] = 0

strcpy(id, a)

word[0] = id

i = NRW

while (strcmp(id, word[i--]))

if (++i)

sym = wsym[i]// symbol is a reserved word

else

sym = SYM_IDENTIFIER // symbol is an identifier

}

else if (isdigit(ch))

{ // symbol is a number.

k = num = 0

sym = SYM_NUMBER

do

{

num = num * 10 + ch - '0'

k++

getch()

}

while (isdigit(ch))

if (k >MAXNUMLEN)

error(25)// The number is too great.

}

else if (ch == ':')

{

getch()

if (ch == '=')

{

sym = SYM_BECOMES// :=

getch()

}

else

{

sym = SYM_NULL // illegal?

}

}

else if (ch == '>')

{

getch()

if (ch == '=')

{

sym = SYM_GEQ// >=

getch()

}

else

{

sym = SYM_GTR// >

}

}

else if (ch == '<')

{

getch()

if (ch == '=')

{

sym = SYM_LEQ// <=

getch()

}

else if (ch == '>')

{

sym = SYM_NEQ// <>

getch()

}

else

{

sym = SYM_LES// <

}

}

else

{ // other tokens

i = NSYM

csym[0] = ch

while (csym[i--] != ch)

if (++i)

{

sym = ssym[i]

getch()

}

else

{

printf("Fatal Error: Unknown character.\n")

fprintf(outfile, "Fatal Error: Unknown character.\n")

exit(1)

}

}

} // getsym

//////////////////////////////////////////////////////////////////////

// generates (assembles) an instruction.

void gen(int x, int y, int z)

{

if (cx >CXMAX)

{

fprintf(outfile, "Fatal Error: Program too long.\n")

printf("Fatal Error: Program too long.\n")

exit(1)

}

code[cx].f = x

code[cx].l = y

code[cx++].a = z

} // gen

//////////////////////////////////////////////////////////////////////

// tests if error occurs and skips all symbols that do not belongs to s1 or s2.

void test(symset s1, symset s2, int n)

{

symset s

if (! inset(sym, s1))

{

showset(s1)

showset(s2)

printf("sym=%d, id=%s\n", sym, id)

error(n)

s = uniteset(s1, s2)

while(! inset(sym, s))

getsym()

destroyset(s)

}

} // test

//////////////////////////////////////////////////////////////////////

int dx // data allocation index

// enter object(constant, variable or procedre) into table.

void enter(int kind)

{

mask* mk

// added by yzhang 02-02-28

if ( position(id)>0 ){

error(26)//Redeclared identifier.

}

// end

tx++

strcpy(table[tx].name, id)

table[tx].kind = kind

switch (kind)

{

case ID_CONSTANT:

if (num >MAXADDRESS)

{

error(25)// The number is too great.

num = 0

}

table[tx].value = num

break

case ID_VARIABLE:

mk = (mask*) &table[tx]

mk->level = level

mk->address = dx++

break

case ID_PROCEDURE:

mk = (mask*) &table[tx]

mk->level = level

break

} // switch

} // enter

//////////////////////////////////////////////////////////////////////

// locates identifier in symbol table.

int position(char* id)

{

int i

strcpy(table[0].name, id)

i = tx + 1

while (strcmp(table[--i].name, id) != 0)

return i

} // position

//////////////////////////////////////////////////////////////////////

void constdeclaration()

{

if (sym == SYM_IDENTIFIER)

{

getsym()

if (sym == SYM_EQU || sym == SYM_BECOMES)

{

if (sym == SYM_BECOMES)

error(1)// Found ':=' when expecting '='.

getsym()

if (sym == SYM_NUMBER)

{

enter(ID_CONSTANT)

getsym()

}

else

{

error(2)// There must be a number to follow '='.

}

}

else

{

error(3)// There must be an '=' to follow the identifier.

}

}

else //added by yzhang 02-02-28

error(4)// There must be an identifier to follow 'const', 'var', or 'procedure'.

} // constdeclaration

//////////////////////////////////////////////////////////////////////

void vardeclaration(void)

{

if (sym == SYM_IDENTIFIER)

{

enter(ID_VARIABLE)

getsym()

}

else

{

error(4)// There must be an identifier to follow 'const', 'var', or 'procedure'.

}

} // vardeclaration

//////////////////////////////////////////////////////////////////////

void listcode(int from, int to)

{

int i

printf("\n")

fprintf(outfile, "\n")

for (i = fromi <toi++)

{

printf("%5d %s\t%d\t%d\n", i, mnemonic[code[i].f], code[i].l, code[i].a)

fprintf(outfile, "%5d %s\t%d\t%d\n", i, mnemonic[code[i].f], code[i].l, code[i].a)

}

printf("\n")

fprintf(outfile, "\n")

} // listcode

//////////////////////////////////////////////////////////////////////

void factor(symset fsys)

{

void expression()

int i

symset set

test(facbegsys, fsys, 24)// The symbol can not be as the beginning of an expression.

while (inset(sym, facbegsys))

{

if (sym == SYM_IDENTIFIER)

{

if ((i = position(id)) == 0)

{

error(11)// Undeclared identifier.

}

else

{

switch (table[i].kind)

{

mask* mk

case ID_CONSTANT:

gen(LIT, 0, table[i].value)

break

case ID_VARIABLE:

mk = (mask*) &table[i]

gen(LOD, level - mk->level, mk->address)

break

case ID_PROCEDURE:

error(21)// Procedure identifier can not be in an expression.

break

} // switch

}

getsym()

}

else if (sym == SYM_NUMBER)

{

if (num >MAXADDRESS)

{

error(25)// The number is too great.

num = 0

}

gen(LIT, 0, num)

getsym()

}

else if (sym == SYM_LPAREN)

{

getsym()

set = uniteset(createset(SYM_RPAREN, SYM_NULL), fsys)

expression(set)

destroyset(set)

if (sym == SYM_RPAREN)

{

getsym()

}

else

{

error(22)// Missing ')'.

}

}

else // added by yzhang 02-02-28

test(fsys, createset(SYM_LPAREN, SYM_NULL), 23)

} // while

} // factor

//////////////////////////////////////////////////////////////////////

void term(symset fsys)

{

int mulop

symset set

set = uniteset(fsys, createset(SYM_TIMES, SYM_SLASH, SYM_NULL))

factor(set)

while (sym == SYM_TIMES || sym == SYM_SLASH)

{

mulop = sym

getsym()

factor(set)

if (mulop == SYM_TIMES)

{

gen(OPR, 0, OPR_MUL)

}

else

{

gen(OPR, 0, OPR_DIV)

}

} // while

destroyset(set)

} // term

//////////////////////////////////////////////////////////////////////

void expression(symset fsys)

{

int addop

symset set

set = uniteset(fsys, createset(SYM_PLUS, SYM_MINUS, SYM_NULL))

if (sym == SYM_PLUS || sym == SYM_MINUS)

{

addop = sym

getsym()

term(set)

if (addop == SYM_MINUS)

{

gen(OPR, 0, OPR_NEG)

}

}

else

{

term(set)

}

while (sym == SYM_PLUS || sym == SYM_MINUS)

{

addop = sym

getsym()

term(set)

if (addop == SYM_PLUS)

{

gen(OPR, 0, OPR_ADD)

}

else

{

gen(OPR, 0, OPR_MIN)

}

} // while

destroyset(set)

} // expression

//////////////////////////////////////////////////////////////////////

void condition(symset fsys)

{

int relop

symset set

if (sym == SYM_ODD)

{

getsym()

expression(fsys)

gen(OPR, 0, 6)

}

else

{

set = uniteset(relset, fsys)

expression(set)

destroyset(set)

if (! inset(sym, relset))

{

error(20)

}

else

{

relop = sym

getsym()

expression(fsys)

switch (relop)

{

case SYM_EQU:

gen(OPR, 0, OPR_EQU)

break

case SYM_NEQ:

gen(OPR, 0, OPR_NEQ)

break

case SYM_LES:

gen(OPR, 0, OPR_LES)

break

case SYM_GEQ:

gen(OPR, 0, OPR_GEQ)

break

case SYM_GTR:

gen(OPR, 0, OPR_GTR)

break

case SYM_LEQ:

gen(OPR, 0, OPR_LEQ)

break

} // switch

} // else

} // else

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

}

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

}

else //added by yzhang 02-02-28

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 = dx// modified by yzhang 02-03-15

} // 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")

fprintf(outfile, "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])

fprintf(outfile, "%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")

fprintf(outfile, "End executing PL/0 program.\n")

} // interpret

//////////////////////////////////////////////////////////////////////

void main ()

{

FILE* hbin

char s[80],*finddot

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)

}

#if 1 // added by yzhang 02-02-28

// open the output file

finddot = strchr(s,'.')

if (finddot!=NULL){

strcpy(finddot, ".out")

}else{

strcat(s, ".out")

printf("%s\n", s)

}

printf("Output File is %s\n", s)

if ((outfile = fopen(s, "w")) == NULL)

{

printf("File %s can't be opened.\n", s)

exit(1)

}

#endif

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 = 0i <cxi++)

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)

// close all files, added by yzhang, 02-02-28

fclose(infile)

fclose(outfile)

} // main

//////////////////////////////////////////////////////////////////////

// eof pl0.c


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/8239969.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-14
下一篇 2023-04-14

发表评论

登录后才能评论

评论列表(0条)

保存