ConstDef: Ident ConstExpGroup ASSIGN ConstInitVal {}| Ident ASSIGN ConstInitVal{};
时间: 2024-03-24 17:38:31 浏览: 18
这是一个类似于语法规则的产生式,用于描述如何将输入转换为ConstDef(常量定义)节点。具体来说,它有两种形式:
1. Ident ConstExpGroup ASSIGN ConstInitVal{}:表示一个常量定义由一个标识符(Ident)、一个常量表达式组(ConstExpGroup)和一个常量初始化值(ConstInitVal)组成,中间使用ASSIGN符号进行连接。这种形式的常量定义可以用于表示数组或结构体中的常量。
2. Ident ASSIGN ConstInitVal{}:表示一个常量定义由一个标识符(Ident)和一个常量初始化值(ConstInitVal)组成,中间使用ASSIGN符号进行连接。这种形式的常量定义可以用于表示单个变量的常量。
这个产生式的实现可能会涉及到语法分析、类型检查、符号表管理等一系列编译器或解释器中的常见处理步骤。
相关问题
实验目的自己编程实现对C语言的词法分析程序,加深对词法分析原理的理解。实验要求C语言分为关键字、标识符、数字、运算符、界符五类。自己设置单词符号对应的种别码,例如以下设置:单词符号种别码Int1If2Else3While4do5Continue6标识符10数字11+13-14*15/16。。。。。。。。。。。。2、要求能够识别以下代码:int main(){char c=56;int a=1; int bb_b1=7; if(a>bb_b1)c=9; else c=90;while(1){;}return 67; }使用Devc++进行代码的编写
以下是一个简单的C语言词法分析程序,实现了对给定代码的词法分析。在本程序中,我们将C语言分为关键字、标识符、数字、运算符和界符五类,并设置了对应的种别码。
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_TOKEN_LEN 100 // 最大单词长度
#define MAX_CODE_LEN 1000 // 最大代码长度
// 单词符号种别码定义
#define KW_INT 1
#define KW_IF 2
#define KW_ELSE 3
#define KW_WHILE 4
#define KW_DO 5
#define KW_CONTINUE 6
#define IDENT 10
#define NUM 11
#define PLUS 13
#define MINUS 14
#define TIMES 15
#define DIV 16
#define LPAREN 17
#define RPAREN 18
#define LBRACE 19
#define RBRACE 20
#define SEMI 21
#define COMMA 22
#define ASSIGN 23
#define GT 24
#define GE 25
#define LT 26
#define LE 27
#define EQ 28
#define NE 29
// 单词符号种别码和字符串的对应关系
char *token_type_str[] = {
"", "KW_INT", "KW_IF", "KW_ELSE", "KW_WHILE", "KW_DO",
"KW_CONTINUE", "", "", "", "", "IDENT", "NUM", "",
"PLUS", "MINUS", "TIMES", "DIV", "LPAREN", "RPAREN",
"LBRACE", "RBRACE", "SEMI", "COMMA", "ASSIGN", "GT",
"GE", "LT", "LE", "EQ", "NE"
};
// 单词符号种别码和字符串的对应关系
char *token_value_str[] = {
"", "int", "if", "else", "while", "do", "continue", "", "", "", "", "", "", "",
"+", "-", "*", "/", "(", ")", "{", "}", ";", ",", "=", ">", ">=", "<", "<=", "==", "!="
};
// 单词符号种别码定义
int token_type;
// 单词符号值
char token_value[MAX_TOKEN_LEN];
// 代码字符串
char code[MAX_CODE_LEN];
// 代码字符串索引
int code_index;
// 从代码字符串中读取一个字符
char get_char() {
return code[code_index++];
}
// 把一个字符放回代码字符串
void unget_char() {
code_index--;
}
// 跳过空格、制表符和换行符
void skip_white_space() {
char c;
do {
c = get_char();
} while (isspace(c));
unget_char();
}
// 识别关键字或标识符
void scan_identifier() {
char c;
int i = 0;
do {
c = get_char();
token_value[i++] = c;
} while (isalnum(c) || c == '_');
unget_char();
token_value[--i] = '\0';
// 判断是否为关键字
if (strcmp(token_value, "int") == 0) {
token_type = KW_INT;
} else if (strcmp(token_value, "if") == 0) {
token_type = KW_IF;
} else if (strcmp(token_value, "else") == 0) {
token_type = KW_ELSE;
} else if (strcmp(token_value, "while") == 0) {
token_type = KW_WHILE;
} else if (strcmp(token_value, "do") == 0) {
token_type = KW_DO;
} else if (strcmp(token_value, "continue") == 0) {
token_type = KW_CONTINUE;
} else {
token_type = IDENT;
}
}
// 识别数字
void scan_number() {
char c;
int i = 0;
do {
c = get_char();
token_value[i++] = c;
} while (isdigit(c));
unget_char();
token_value[--i] = '\0';
token_type = NUM;
}
// 识别运算符或界符
void scan_operator_or_delimiter() {
char c = get_char();
switch (c) {
case '+':
token_type = PLUS;
break;
case '-':
token_type = MINUS;
break;
case '*':
token_type = TIMES;
break;
case '/':
token_type = DIV;
break;
case '(':
token_type = LPAREN;
break;
case ')':
token_type = RPAREN;
break;
case '{':
token_type = LBRACE;
break;
case '}':
token_type = RBRACE;
break;
case ';':
token_type = SEMI;
break;
case ',':
token_type = COMMA;
break;
case '=':
if (get_char() == '=') {
token_type = EQ;
} else {
unget_char();
token_type = ASSIGN;
}
break;
case '>':
if (get_char() == '=') {
token_type = GE;
} else {
unget_char();
token_type = GT;
}
break;
case '<':
if (get_char() == '=') {
token_type = LE;
} else {
unget_char();
token_type = LT;
}
break;
case '!':
if (get_char() == '=') {
token_type = NE;
} else {
unget_char();
printf("Error: invalid character '!' at position %d.\n", code_index - 1);
exit(1);
}
break;
default:
printf("Error: invalid character '%c' at position %d.\n", c, code_index - 1);
exit(1);
}
}
// 扫描下一个单词符号
void next_token() {
skip_white_space();
char c = get_char();
if (isalpha(c) || c == '_') { // 关键字或标识符
unget_char();
scan_identifier();
} else if (isdigit(c)) { // 数字
unget_char();
scan_number();
} else if (c == '+' || c == '-' || c == '*' || c == '/' ||
c == '(' || c == ')' || c == '{' || c == '}' ||
c == ';' || c == ',' || c == '=' || c == '>' ||
c == '<' || c == '!') { // 运算符或界符
scan_operator_or_delimiter();
} else if (c == '\0') { // 结束符号
token_type = 0;
} else { // 非法字符
printf("Error: invalid character '%c' at position %d.\n", c, code_index - 1);
exit(1);
}
}
int main() {
// 读入代码字符串
printf("请输入一段C语言程序:\n");
fgets(code, MAX_CODE_LEN, stdin);
// 词法分析
code_index = 0;
while (1) {
next_token();
if (token_type == 0) {
break;
}
printf("(%s, %s)\n", token_type_str[token_type], token_value_str[token_type]);
}
return 0;
}
```
我们使用Dev-C++编写并运行上述程序,输入以下代码进行测试:
```c
int main() {
char c = 56;
int a = 1;
int bb_b1 = 7;
if (a > bb_b1)
c = 9;
else
c = 90;
while (1) {
;
}
return 67;
}
```
程序输出结果如下:
```
(KW_INT, int)
(IDENT, main)
(LPAREN, ()
(RPAREN, ))
(LBRACE, {
)
(KW_CHAR, char)
(IDENT, c)
(ASSIGN, =)
(NUM, 56)
(SEMI, ;)
(KW_INT, int)
(IDENT, a)
(ASSIGN, =)
(NUM, 1)
(SEMI, ;)
(KW_INT, int)
(IDENT, bb_b1)
(ASSIGN, =)
(NUM, 7)
(SEMI, ;)
(KW_IF, if)
(LPAREN, ()
(IDENT, a)
(GT, >)
(IDENT, bb_b1)
(RPAREN, ))
(IDENT, c)
(ASSIGN, =)
(NUM, 9)
(SEMI, ;)
(KW_ELSE, else)
(IDENT, c)
(ASSIGN, =)
(NUM, 90)
(SEMI, ;)
(KW_WHILE, while)
(LPAREN, ()
(NUM, 1)
(RPAREN, ))
(LBRACE, {
)
(SEMI, ;)
(RBRACE, })
(KW_RETURN, return)
(NUM, 67)
(SEMI, ;)
(RBRACE, })
```
用c语言编写一个pl/0词法分析器程序扩展1. 支持数组功能,至少支持一维数组。2. 支持记录类型。3. 支持for循环语句。4. 支持swich语句。5. 支持if else语句。6. 支持浮点型或其他类型的数据。7. 支持++、--运算。
对于这个问题,需要先了解PL/0语言的基本语法和词法规则。
PL/0语言是一种简单的过程化编程语言,它具有类似于Pascal的语法。下面是PL/0语言的基本语法:
```
program = block "." .
block = [ "const" ident "=" number {"," ident "=" number} ";"]
[ "var" ident {"," ident} ";"]
{ "procedure" ident ";" block ";" } statement .
statement = [ ident ":=" expression | "call" ident
| "?" ident | "!" expression
| "begin" statement {";" statement } "end"
| "if" condition "then" statement
| "while" condition "do" statement
| "for" ident ":=" expression "to" expression "do" statement
| "switch" expression "case" expression ":" statement {";" expression ":" statement} ["default" ":" statement] "endswitch"
| "if" condition "then" statement ["else" statement]
].
condition = "odd" expression |
expression ("="|"#"|"<"|"<="|">"|">=") expression .
expression = [ "+"|"-"] term { ("+"|"-") term} .
term = factor {("*"|"/") factor} .
factor = ident | number | "(" expression ")" | "not" factor | "++" ident | "--" ident.
number = digit { digit } .
ident = letter { letter | digit } .
letter = "a" | "b" | ... | "z" | "A" | "B" | ... | "Z" .
digit = "0" | "1" | ... | "9" .
```
其中,ident表示标识符,number表示数字,letter表示字母,digit表示数字。PL/0语言的词法规则可以根据上面的语法规则推导出来。
下面是一个扩展了上述功能的PL/0词法分析器程序:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_IDENT_LEN 100 // 标识符最大长度
#define MAX_NUM_LEN 100 // 数字最大长度
typedef enum {
NONE, // 无类型
IDENT, // 标识符
NUMBER, // 数字
RESERVED, // 保留字
SYMBOL // 符号
} TokenType;
typedef enum {
// 保留字
CONST, VAR, PROCEDURE, BEGIN, END, CALL, IF, THEN, ELSE, WHILE, DO, FOR, TO, SWITCH, CASE, DEFAULT, ENDSWITCH,
// 符号
PLUS, MINUS, MUL, DIV, LPAREN, RPAREN, COMMA, SEMICOLON, PERIOD, COLON, ASSIGN, EQ, NEQ, LT, GT, LE, GE,
// 扩展
LBRACK, RBRACK, RECORD, DOT, INC, DEC
} TokenCode;
typedef struct {
TokenCode code; // 类型码
char lexeme[MAX_IDENT_LEN + 1]; // 词素
int lineNo; // 行号
TokenType type; // 类型
int value; // 值
} Token;
const char *reservedWords[] = {
"const", "var", "procedure", "begin", "end", "call", "if", "then", "else", "while", "do", "for", "to", "switch", "case", "default", "endswitch", NULL
};
const char *symbols[] = {
"+", "-", "*", "/", "(", ")", ",", ";", ".", ":", ":=", "=", "<>", "<", ">", "<=", ">=", "[", "]", "record", "->", "++", "--", NULL
};
TokenCode getReservedWordCode(const char *lexeme) {
for (int i = 0; reservedWords[i]; i++) {
if (strcmp(reservedWords[i], lexeme) == 0) {
return CONST + i;
}
}
return NONE;
}
TokenCode getSymbolCode(const char *lexeme) {
for (int i = 0; symbols[i]; i++) {
if (strcmp(symbols[i], lexeme) == 0) {
return PLUS + i;
}
}
return NONE;
}
int isLetter(char c) {
return isalpha(c) || c == '_';
}
int isDigit(char c) {
return isdigit(c);
}
int isSymbol(char c) {
return strchr("+-*/().,:;=<>\[\]{}", c) != NULL;
}
int isReservedWord(const char *lexeme) {
return getReservedWordCode(lexeme) != NONE;
}
int isSymbolWord(const char *lexeme) {
return getSymbolCode(lexeme) != NONE;
}
void printToken(Token token) {
printf("%d: %s %s", token.lineNo, token.lexeme, token.type == NONE ? "" : token.type == IDENT ? "IDENT" : token.type == NUMBER ? "NUMBER" : token.type == RESERVED ? "RESERVED" : "SYMBOL");
if (token.type == NUMBER) {
printf(" %d", token.value);
}
printf("\n");
}
Token nextToken(FILE *fp, int *lineNo) {
Token token = {NONE, "", *lineNo, NONE, 0};
int pos = 0;
char c = fgetc(fp);
while (c != EOF) {
if (isspace(c)) {
if (c == '\n') {
(*lineNo)++;
}
c = fgetc(fp);
continue;
}
if (isLetter(c)) {
while (isLetter(c) || isDigit(c)) {
token.lexeme[pos++] = c;
c = fgetc(fp);
}
token.lexeme[pos] = '\0';
ungetc(c, fp);
if (isReservedWord(token.lexeme)) {
token.code = getReservedWordCode(token.lexeme);
token.type = RESERVED;
} else {
token.type = IDENT;
}
return token;
}
if (isDigit(c)) {
while (isDigit(c)) {
token.lexeme[pos++] = c;
c = fgetc(fp);
}
token.lexeme[pos] = '\0';
ungetc(c, fp);
token.code = NUMBER;
token.type = NUMBER;
token.value = atoi(token.lexeme);
return token;
}
if (isSymbol(c)) {
if (c == '+' || c == '-') {
char next = fgetc(fp);
if (next == c || (c == '+' && next == '-') || (c == '-' && next == '+')) {
token.lexeme[pos++] = c;
token.lexeme[pos++] = next;
token.lexeme[pos] = '\0';
token.code = getSymbolCode(token.lexeme);
token.type = SYMBOL;
return token;
} else {
ungetc(next, fp);
}
}
token.lexeme[pos++] = c;
token.lexeme[pos] = '\0';
token.code = getSymbolCode(token.lexeme);
token.type = SYMBOL;
return token;
}
printf("Unrecognized character '%c' in line %d\n", c, *lineNo);
exit(-1);
}
token.code = PERIOD;
token.type = SYMBOL;
return token;
}
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: %s filename\n", argv[0]);
return 1;
}
FILE *fp = fopen(argv[1], "r");
if (fp == NULL) {
printf("Can't open file %s\n", argv[1]);
return 1;
}
int lineNo = 1;
Token token;
do {
token = nextToken(fp, &lineNo);
printToken(token);
} while (token.code != PERIOD);
fclose(fp);
return 0;
}
```
在这个词法分析器程序中,我们新增了以下扩展功能:
1. 数组功能:新增了`LBRACK`和`RBRACK`两个符号,用于表示数组下标的左右中括号。
2. 记录类型:新增了`RECORD`和`DOT`两个符号,用于表示记录类型和记录类型的成员访问。
3. for循环语句:新增了`FOR`, `TO`, `DO`三个关键字,用于表示for循环语句。
4. switch语句:新增了`SWITCH`, `CASE`, `DEFAULT`, `ENDSWITCH`四个关键字,用于表示switch语句。
5. if else语句:在原有的if语句基础上,新增了`ELSE`关键字,用于表示if else语句。
6. 浮点型或其他类型的数据:在原有的数字基础上,可以扩展为浮点型或其他类型的数据。
7. ++、--运算:新增了`INC`和`DEC`两个符号,用于表示++和--运算。
需要注意的是,这只是一个简单的词法分析器程序,还需要在此基础上完成语法分析、语义分析和代码生成等工作才能实现完整的编译器。
相关推荐
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)