#include //for c I/o #include // for exit() #include // for isalpha(), isalnum(), ... enum tokenType { READ, WRITE, ID, NUMBER, LPAREN, RPAREN, SEMICOLON, COMMA, ASSIGN, PLUS, MINUS, TIMES, DIV, SCAN_EOF }; char* mnemonic[] = { "READ", "WRITE", "ID", "NUMBER", "LPAREN", "RPAREN", "SEMICOLON", "COMMA", "ASSIGN", "PLUS", "MINUS", "TIMES", "DIV", "SCAN_EOF" }; void lexical_error(char ch) { fprintf(stderr, "Lexical Error. Unexpected character: %c.\n", ch); exit(1); } char lexeme[256] = { '\0' }; unsigned int lexLen = 0; FILE* src; enum tokenType currentToken; enum tokenType scan() { static int currentCh = ' '; static int tempCh = ' '; char* reserved[2] = { "read", "write" }; lexLen = 0; // clear lexeme buffer for each scan lexeme[0] = '\0'; extern FILE* src; //pointer to FILE handle that binds to source file. if (feof(src)) { return SCAN_EOF; } while ((currentCh = fgetc(src)) != EOF) { if (isspace(currentCh)) { continue; } else if (isalpha(currentCh) || currentCh == '_') { lexeme[0] = currentCh; lexLen = 1; for (tempCh = fgetc(src); isalnum(tempCh) || tempCh == '_'; tempCh = fgetc(src)) { //build identifier lexeme lexeme[lexLen] = tempCh; lexLen += 1; } lexeme[lexLen] = '\0'; ungetc(tempCh, src); //put back character that is not a alpha/digit or ‘_’ // see if lexeme is a reserved word if (stricmp(mnemonic[0], lexeme, 4) == 0) return READ; else if (stricmp(mnemonic[1], lexeme, 5) == 0) return WRITE; //if not, return ID return ID; } else if (isdigit(currentCh)) { // build lexeme for number lexeme[0] = currentCh; lexLen = 1; for (tempCh = fgetc(src); isdigit(tempCh); tempCh = fgetc(src)) { lexeme[lexLen] = tempCh; lexLen += 1; } // finish fixing lexeme string, ungetc the last character read that is not a digit and then return NUMBER lexeme[lexLen] = '\0'; ungetc(tempCh, src); //put back character that is not a alpha/digit or ‘_’ // see if lexeme is a reserved word, if not, return ID. return NUMBER; } // use selection statements to look for tokens for operators and delimiters and assignment (:=) else if (currentCh == '(') return LPAREN; else if (currentCh == ')') return RPAREN; else if (currentCh == ';') return SEMICOLON; else if (currentCh == ',') return COMMA; else if (currentCh == ':' && fgetc(src) == '=') return ASSIGN; else if (currentCh == '+') return PLUS; else if (currentCh == '-') return MINUS; else if (currentCh == '*') return TIMES; else if (currentCh == '/') return DIV; else { lexical_error(currentCh); } } return SCAN_EOF; } //parser function declarations void term(); void expr(); void factor(); void match(enum tokenType expected); void parse_error(char* errMsg, char* lexeme); int main(int argc, char* argv[]) { extern FILE* src; if (argc > 1) { if (fopen_s(&src, argv[1], "r")) { fprintf(stderr, "Error opening source file: %s ", argv[1]); exit(1); } } currentToken = scan(); parse(); fclose(src); printf("%s\n", "Parsing complete. No errors."); return 0; } parse() { while (currentToken != SCAN_EOF) { if (currentToken == ID) { currentToken = scan(); match(ASSIGN); expr(); match(SEMICOLON); } else if (currentToken == READ) { currentToken = scan(); match(LPAREN); int x = 1; while (x) { match(ID); if (currentToken != COMMA) { match(RPAREN); x = 0; } else currentToken = scan(); } match(SEMICOLON); } else if (currentToken == WRITE) { currentToken = scan(); match(LPAREN); int x = 1; while (x) { expr(); if (currentToken != COMMA) { match(RPAREN); x = 0; } else currentToken = scan(); } match(SEMICOLON); } else { printf("%s%s%s\n", "Unexpected symbol: ", mnemonic[currentToken], ". Expected ID, READ, or WRITE."); exit(1); } } } void parse_error(char* errMsg, char* lexeme) { fprintf(stderr, "%s: %s\n", errMsg, lexeme); } void match(enum tokenType expected) { if (currentToken == expected) { currentToken = scan(); } else { parse_error("Expected symbol", mnemonic[expected]); exit(1); } } void expr() { int x = 1; while (x) { term(); if (currentToken == PLUS || currentToken == MINUS) currentToken = scan(); else x = 0; } } void term() { int x = 1; while (x) { factor(); if (currentToken == TIMES || currentToken == DIV) currentToken = scan(); else x = 0; } } void factor() { if (currentToken == LPAREN) { currentToken = scan(); expr(); match(RPAREN); } else if (currentToken == ID || currentToken == NUMBER) currentToken = scan(); else { printf("%s\n", "Error in expression: Expected ID, NUMBER, or '('."); exit(1); } }