求一个c语言编写的pl0编译器
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求一个c语言编写的pl0编译器相关的知识,希望对你有一定的参考价值。
最好带中文注释,邮箱1176567556@qq.com
谢谢!
#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语言小程序,为啥执行后显示段错误?求各位大神的说明或解决方法。