c_minus(或者pl/0)语言词法分析器的设计
时间: 2023-05-02 13:01:49 浏览: 113
b' c_minus(或者pl/0)语言词法分析器的设计 '
c_minus(或者pl/0)是一种程序设计语言,需要有一个词法分析器来对源代码进行解析。词法分析器的设计需要遵守一些原则:
1. 分离职责:词法分析器只负责对源代码进行扫描和识别,不应该对语法和语义进行判断。
2. 高效性:词法分析器需要高效地识别和分类单词,尽可能地减少不必要的计算和操作。
3. 可维护性:词法分析器需要具有一定的可维护性和可扩展性,便于后续的维护和升级。
4. 易用性:词法分析器需要易于使用和操作,方便程序员进行调试和开发工作。
在设计词法分析器时,需要考虑语言的特点和规范,对源代码进行分类和识别。常见的词法单元包括关键字、运算符、标识符、常量、分隔符等等。我们可以使用正则表达式来定义这些词法单元,并使用有限状态自动机(FSM)来实现词法分析的过程。
相关问题
使用java实现对PL/0语言进行词法分析,把输入的字符串形式的源程序分割成一个个单词符号
具体实现过程如下:
1. 定义一个Token类,用于表示一个单词符号,包括类型和值两个属性。
```java
public class Token {
public TokenType type;
public String value;
public Token(TokenType type, String value) {
this.type = type;
this.value = value;
}
@Override
public String toString() {
return "Token{" +
"type=" + type +
", value='" + value + '\'' +
'}';
}
}
```
2. 定义一个枚举类型TokenType,包括PL/0语言中的各种单词符号类型。
```java
public enum TokenType {
// 关键字
VAR, CONST, PROCEDURE, BEGIN, END, IF, THEN, WHILE, DO, CALL, ODD,
// 运算符
PLUS, MINUS, TIMES, SLASH, EQL, NEQ, LSS, LEQ, GTR, GEQ, ASSIGN,
// 标识符、数字、分号、逗号、左右括号
IDENTIFIER, NUMBER, SEMICOLON, COMMA, LPAREN, RPAREN
}
```
3. 实现词法分析器Lexer,它将输入的源程序字符串分割成一个个单词符号。
```java
public class Lexer {
private String input;
private int position;
public Lexer(String input) {
this.input = input;
this.position = 0;
}
public Token getNextToken() {
if (position >= input.length()) {
return null;
}
char currentChar = input.charAt(position);
// 处理标识符和关键字
if (Character.isLetter(currentChar)) {
String identifier = "";
while (position < input.length() && (Character.isLetterOrDigit(input.charAt(position)))) {
identifier += input.charAt(position);
position++;
}
switch (identifier) {
case "var":
return new Token(TokenType.VAR, identifier);
case "const":
return new Token(TokenType.CONST, identifier);
case "procedure":
return new Token(TokenType.PROCEDURE, identifier);
case "begin":
return new Token(TokenType.BEGIN, identifier);
case "end":
return new Token(TokenType.END, identifier);
case "if":
return new Token(TokenType.IF, identifier);
case "then":
return new Token(TokenType.THEN, identifier);
case "while":
return new Token(TokenType.WHILE, identifier);
case "do":
return new Token(TokenType.DO, identifier);
case "call":
return new Token(TokenType.CALL, identifier);
case "odd":
return new Token(TokenType.ODD, identifier);
default:
return new Token(TokenType.IDENTIFIER, identifier);
}
}
// 处理数字
if (Character.isDigit(currentChar)) {
String number = "";
while (position < input.length() && (Character.isDigit(input.charAt(position)))) {
number += input.charAt(position);
position++;
}
return new Token(TokenType.NUMBER, number);
}
// 处理运算符
switch (currentChar) {
case '+':
position++;
return new Token(TokenType.PLUS, "+");
case '-':
position++;
return new Token(TokenType.MINUS, "-");
case '*':
position++;
return new Token(TokenType.TIMES, "*");
case '/':
position++;
return new Token(TokenType.SLASH, "/");
case '=':
position++;
return new Token(TokenType.EQL, "=");
case '#':
position++;
return new Token(TokenType.NEQ, "#");
case '<':
position++;
if (position < input.length() && input.charAt(position) == '=') {
position++;
return new Token(TokenType.LEQ, "<=");
}
return new Token(TokenType.LSS, "<");
case '>':
position++;
if (position < input.length() && input.charAt(position) == '=') {
position++;
return new Token(TokenType.GEQ, ">=");
}
return new Token(TokenType.GTR, ">");
case ':':
position++;
if (position < input.length() && input.charAt(position) == '=') {
position++;
return new Token(TokenType.ASSIGN, ":=");
}
break;
case ';':
position++;
return new Token(TokenType.SEMICOLON, ";");
case ',':
position++;
return new Token(TokenType.COMMA, ",");
case '(':
position++;
return new Token(TokenType.LPAREN, "(");
case ')':
position++;
return new Token(TokenType.RPAREN, ")");
}
// 处理空格、换行符等无用字符
if (Character.isWhitespace(currentChar)) {
position++;
return getNextToken();
}
// 无法识别的字符,抛出异常
throw new RuntimeException("Invalid character: " + currentChar);
}
}
```
4. 在主函数中调用词法分析器Lexer,输出分割后的单词符号。
```java
public class Main {
public static void main(String[] args) {
String input = "const a = 1;\n" +
"var b;\n" +
"procedure f;\n" +
"begin\n" +
" b := a + 2;\n" +
"end;\n" +
"begin\n" +
" f();\n" +
"end.";
Lexer lexer = new Lexer(input);
Token token = lexer.getNextToken();
while (token != null) {
System.out.println(token);
token = lexer.getNextToken();
}
}
}
```
输出结果如下:
```
Token{type=CONST, value='const'}
Token{type=IDENTIFIER, value='a'}
Token{type=EQL, value='='}
Token{type=NUMBER, value='1'}
Token{type=SEMICOLON, value=';'}
Token{type=VAR, value='var'}
Token{type=IDENTIFIER, value='b'}
Token{type=SEMICOLON, value=';'}
Token{type=PROCEDURE, value='procedure'}
Token{type=IDENTIFIER, value='f'}
Token{type=SEMICOLON, value=';'}
Token{type=BEGIN, value='begin'}
Token{type=IDENTIFIER, value='b'}
Token{type=ASSIGN, value=':='}
Token{type=IDENTIFIER, value='a'}
Token{type=PLUS, value='+'}
Token{type=NUMBER, value='2'}
Token{type=SEMICOLON, value=';'}
Token{type=END, value='end'}
Token{type=SEMICOLON, value=';'}
Token{type=BEGIN, value='begin'}
Token{type=IDENTIFIER, value='f'}
Token{type=LPAREN, value='('}
Token{type=RPAREN, value=')'}
Token{type=SEMICOLON, value=';'}
Token{type=END, value='end'}
Token{type=PERIOD, value='.'}
```
用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`两个符号,用于表示++和--运算。
需要注意的是,这只是一个简单的词法分析器程序,还需要在此基础上完成语法分析、语义分析和代码生成等工作才能实现完整的编译器。
阅读全文