求一个c语言编写的pl0编译器

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求一个c语言编写的pl0编译器相关的知识,希望对你有一定的参考价值。

最好带中文注释,邮箱1176567556@qq.com
谢谢!

// 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 = 1; i <= cc - 1; i++)
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 = from; i < to; i++)

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 = 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);

// close all files, added by yzhang, 02-02-28
fclose(infile);
fclose(outfile);
// main
//////////////////////////////////////////////////////////////////////
// eof pl0.c
参考技术A 已发送追问

我想要一个 'C语言' 写的 'PL0' 的编译器,这个不是哦!

追答

好吧,这个是c++写的,在VC6.0和vs2008、vs2010下都能通过编译,应该有很多可以借鉴的地方吧

求高手,两道c语言编写题

第一题,头文件是
#include <math.h>

第二题,对于不超过3位的int x,x/100是它的百位,x%10是它的个位,x/10%10是它的十位。

做题求严谨,输入x以后判断它是不是在范围内,不在直接退出。
参考技术A 1.第一个图的解答如下,由于引用了“math.h”头文件,在linux下编译的时候需引用数学库,
加上-lm参数,假设源文件名为test.c,则编译语句为gcc test.c -lm,生成a.out
可执行文件,也可用-o指明可执行文件名称,如gcc -o test test.c -lm。
#include "math.h"
#include "stdio.h"

int main()

float x = 0 ;
double result = 0.0;
do

printf("please input x (Ctrl+C for exit):");
scanf("%f",&x);//从键盘读取x值
if(x <= 1)

result = exp(x) + 1;
printf("e^%f+1=%lf\\n",x,result );

else if(x >1 && x <=5 )

result = (-4)*x + 5;
printf("-4*%f+5=%lf\\n",x,result );

else if(x >5 && x <=10 )

result = 2*x -1;
printf("2*%f-1=%lf\\n",x,result );

else

result = 3*x - 11;
printf("3*%f-11=%lf\\n",x,result );

while(1);
return 0;

2.图二答案如下,有注释解释,不懂欢迎提问

#include "stdio.h"
#include "stdlib.h"
int main()

int num;
int ret;//返回值
unsigned char a;//存放百位数
unsigned char b;//存放十位数
unsigned char c;//存放个位数
unsigned char num_count;//位数统计
int num_invert;//逆序
do

printf("please input a num between(0,999](Ctrl+C for exit):");
ret = scanf("%d",&num);
/*输入不是整数,强制退出*/
if(ret != 1)

printf("please input a int num,now is to exit\\n");
exit(1);

/*输入超过范围,重新输入*/
if(num <= 0 || num > 999)

printf("input invalid,please input again\\n");
continue;//回到循环开始的地方

else

if(num/100 != 0)

num_count = 3;
a=num/100; //除以100得到百位数
b=(num/10)%10; //先除以10去掉个位数,然后取10余数就是十位数
c=num%10; //直接取10余数就是个位数
num_invert = c*100 + b*10 +a; //逆序数

else if(num/10 != 0)

num_count =2;
a = 0;
b = num/10;
c = num%10;
num_invert = c*10 + b;

else

num_count = 1;
a = 0;
b = 0;
c = num;
num_invert = c;

printf("%d 是 %d 位数,每一位的和是:%d,逆序打印为:%d\\n",num,num_count,a+b+c,num_invert );


while(1);
return 0;

本回答被提问者采纳
参考技术B 第一个用if else语句就可以吧

以上是关于求一个c语言编写的pl0编译器的主要内容,如果未能解决你的问题,请参考以下文章

为啥在网上找的一些c语言程序的代码在vc++6.0中编译总是出现错误?求指教

kali linux的gcc编译完的C语言小程序,为啥执行后显示段错误?求各位大神的说明或解决方法。

编译原理—运行时存储PL0活动记录

求一个用C语言编写的小游戏代码

pl0 编辑器 语法分析 syntax 部分 (内附github代码链接)

在cygwin下用gcc编译一个程序的详细步骤,求详解