My program , developed with C using win_flex , implements lexical, syntatic and semantic analysis , given defined grammar rules.
I would like to know if you any suggestion for improving or refactoring this.
Here is my code:
main.c
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "LEXYY.h"
#include "PARSER.h"
#include "semantic.h"
char *yytext;
FILE *yyin;
int yylex();
void printToken() {
const char *TokenNames[11] = {
"PROGRAM", "END",
"INTEGER", "REAL", "INT_NUMBER", "REAL_NUMBER",
"ID", "VOID", "RETURN",
"COMMA", "SEMICOLON",
};
char buffer[] = { (char)token->kind, '\0' };
const char *token_name = token->kind >= PROGRAM ? TokenNames[token->kind - PROGRAM] : buffer;
token->count = strlen(token->lexeme);
fprintf(yyout, "Token of kind '%s' was found at line: %d, lexeme: '%s'\n", token_name, token->line, token->lexeme);
}
int main(int argc, char *argv[]) {
int current_token;
for (int i = 1; i < 3; i++) {
if (i == 1) {
yyin = fopen("C:\\temp\\test1.txt", "r");
yyout = fopen("C:\\temp\\test1_200419513_lex.txt", "w");
}
else {
yyin = fopen("C:\\temp\\test2.txt", "r");
yyout = fopen("C:\\temp\\test2_200419513_lex.txt", "w");
}
if (yyin == NULL) {
printf("Cannot find file.\nPlease use standard input.\n");
yyin = stdin;
}
if (yyout == NULL) {
printf("Cannot open output file.\n");
yyout = stdout;
}
initLexer();
while ((current_token = yylex()) != 0) {
create_and_store_token(current_token, (char *)yytext, line_number);
printToken();
}
if (i == 1) {
yyout = fopen("C:\\temp\\test1_200419513_syntatic.txt", "w");
}
else {
yyout = fopen("C:\\temp\\test2_200419513_syntatic.txt", "w");
}
if (yyout == NULL) {
printf("Cannot open output file.\n");
yyout = stdout;
}
if (lexer_errors) {
fprintf(yyout, "Detected Errors by lexical analysis.\nPlease first fix lexical error.\n");
continue;
}
parser();
if (i == 1) {
yyout = fopen("C:\\temp\\test1_200419513_semantic.txt", "w");
}
else {
yyout = fopen("C:\\temp\\test2_200419513_semantic.txt", "w");
}
if (yyout == NULL) {
printf("Cannot open output file.\n");
yyout = stdout;
}
if (parser_errors) {
fprintf(yyout, "Detected Errors by syntatic analysis.\nPlease first fix syntax error.\n");
continue;
}
semantic();
}
return 0;
}
LEXYY.Y
program : PROGRAM var_definitions ';' statements END func_definitions
;
var_definitions : var_definition
| var_definition ';' var_definitions
;
var_definition : type variables_list
;
type : REAL
| INTEGER
;
variables_list : variable
| variables_list ',' variable
;
variable : ID
| ID '[' INT_NUMBER ']'
;
func_definitions : func_definition
| func_definitions func_definition
;
func_definition : returned_type ID '(' param_definitions ')' block
;
returned_type : VOID
| type
;
param_definitions : /* empty */
| var_definitions
;
block : '{' var_definitions ';' statements '}'
;
statements : statement ';'
| statement ';' statements
;
statement : variable '=' expression
| block
| RETURN
| RETURN expression
| function_call
;
function_call : ID '(' parameters_list ')'
;
parameters_list : /* empty */
| variables_list
;
expression : INT_NUMBER
| REAL_NUMBER
| variable
| ID ar_op expression
;
ar_op : '*'
| '/'
;
LEXYY.h
#pragma once
#include <stdio.h>
typedef struct YYTYPE {
int kind;
char *lexeme;
int line;
int count;
struct YYTYPE *next;
struct YYTYPE *prev;
} YYSTYPE;
YYSTYPE *token;
YYSTYPE *tokens;
int line_number;
int lexer_errors;
void initLexer();
void create_and_store_token(int, char *, int);
#define PROGRAM 256
#define END 257
#define INTEGER 258
#define REAL 259
#define INT_NUMBER 260
#define REAL_NUMBER 261
#define ID 262
#define VOID 263
#define RETURN 264
#define COMMA 265
#define SEMICOLON 266
YYSTYPE *next_token();
YYSTYPE *back_token();
int match(int);
int type();
int ar_op();
int returned_type();
int not_var_definitions();
int not_statements();
LEXYY.C
%option nounistd
%option noyywrap
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#include "LEXYY.h"
#define isatty _isatty
#define fileno _fileno
void initLexer();
void create_and_store_token(int, char *, int);
void errorPrint(char);
void illegalError(const char *, const char *);
%}
WHITESPACE ([ \t]+)
NEWLINE (\r|\n|\r\n)
COMMENT ("--"[^\r\n]*)
ID ([A-Za-z]([_]?[A-Za-z0-9]+)*)
ILLEGALID ([_][A-Za-z0-9_]*|[A-Za-z][A-Za-z0-9_]*[_]|[0-9][A-Za-z0-9]*|[A-Za-z]([_]*[A-Za-z0-9]*)*)
INTEGER (0|[0-9]+)
REAL (0\.[0-9]+|[0-9]+\.[0-9]+)
WRONGNUMBER ([0][0-9]+|[0][0-9]+[.][0-9]*|[.][0-9]+|[0-9]+[.])
OPERATOR ([*/=])
SEPARATION ([[\]{}\(\)])
%%
{NEWLINE} { line_number++; }
{WHITESPACE}+ {}
{COMMENT} {}
"program" { return PROGRAM; }
"end" { return END; }
"real" { return REAL; }
"integer" { return INTEGER; }
"void" { return VOID; }
"return" { return RETURN; }
{INTEGER} { return INT_NUMBER; }
{REAL} { return REAL_NUMBER; }
{WRONGNUMBER} { illegalError(yytext, "Number"); }
"," { return COMMA; }
";" { return SEMICOLON; }
{ID} { return ID; }
{ILLEGALID} { illegalError(yytext, "ID"); }
{OPERATOR} { return yytext[0]; }
{SEPARATION} { return yytext[0]; }
. { errorPrint(yytext[0]); }
%%
void initLexer() {
line_number = 1;
lexer_errors = 0;
tokens = NULL;
token = NULL;
}
void create_and_store_token(int kind, char *lexeme, int line) {
if (token == NULL) {
tokens = (YYSTYPE *)malloc(sizeof(YYSTYPE));
token = tokens;
token->next = NULL;
token->prev = NULL;
} else {
token->next = (YYSTYPE *)malloc(sizeof(YYSTYPE));
token->next->next = NULL;
token->next->prev = token;
token = token->next;
}
token->kind = kind;
token->line = line;
token->lexeme = (char *)malloc(sizeof(lexeme) + 1);
#ifdef _WIN32
strcpy_s(token->lexeme, strlen(lexeme) + 1, lexeme);
#else
strcpy(token->lexeme, lexeme);
#endif
}
YYSTYPE *next_token() {
if (token)
return (token = token->next);
return NULL;
}
YYSTYPE *back_token() {
if (token)
return (token = token->prev);
return NULL;
}
int match(int kind) {
if (token && token->kind == kind)
return kind;
return 0;
}
int type() {
return (match(REAL) ? REAL : match(INTEGER));
}
int ar_op() {
if (match('*') || match('/'))
return 1;
return 0;
}
int returned_type() {
return (match(VOID) ? VOID : type());
}
int not_var_definitions() {
int flag = 0;
if (!token)
flag = 1;
else if (match(ID)) {
next_token();
if (match('=') || match('('))
flag = 2;
if (match('[')) {
next_token();
next_token();
next_token();
if (match('=') || match('('))
flag = 2;
back_token();
back_token();
back_token();
}
back_token();
}
else
flag = 3;
return flag;
}
int not_statements() {
if (!token)
return 1;
if (!match(ID) && !match(RETURN) && !match('{'))
return 1;
return 0;
}
void errorPrint(char ch) {
fprintf(yyout, "The character '%c' at line: %d does not begin any legal token in the language.\n", ch, line_number);
}
void illegalError(const char *text, const char *type) {
fprintf(yyout, "Illegal %s '%s' was found at line %d\n", type, text, line_number);
}
parser.c
#pragma once
#include "LEXYY.h"
int parser_errors, recovery;
FILE *yyout;
void error_handle(char *, YYSTYPE *);
void print_token(char *, YYSTYPE *);
int parser();
void var_definitions();
void var_definition();
void variables_list();
void variable();
void statements();
void statement();
void function_call();
void parameters_list();
int expression();
void block();
void func_definitions();
void func_definition();
void param_definitions();
parser.c
#include <stdio.h>
#include "PARSER.h"
void error_handle(char *expected, YYSTYPE *token) {
if (token) {
fprintf(yyout, "Error: Expected token is { %s }, but actual token is [ %s ] at line %d\n", expected, token->lexeme, token->line);
parser_errors++;
recovery = 1;
}
}
void print_token(char *str, YYSTYPE *token) {
if (token)
fprintf(yyout, str, token->lexeme, token->line);
}
int parser() {
parser_errors = 0;
recovery = 0;
token = tokens;
if (!token)
return 0;
fprintf(yyout, "Starting Program...\n");
if (!match(PROGRAM)) {
error_handle("program", token);
recovery = 0;
}
else
print_token("[ %s ] at line %d\n", token);
next_token();
var_definitions();
statements();
if (!match(END)) {
error_handle("end", token);
recovery = 0;
}
else
print_token("[ %s ] at line %d\n", token);
next_token();
func_definitions();
return parser_errors;
}
void var_definitions() {
if (!type())
if (not_var_definitions())
return;
fprintf(yyout, "Variable Definitions...\n");
while (token) {
if (!type()) {
if (not_var_definitions()) {
recovery = 0;
break;
}
}
var_definition();
if (match(')'))
break;
if (!match(SEMICOLON))
error_handle(";", token);
next_token();
}
}
void var_definition() {
if (type())
print_token("Variable Type [ %s ] at line %d\n", token);
else if (!type())
error_handle("integer, real", token);
next_token();
variables_list();
}
void variables_list() {
int error;
do {
error = not_var_definitions();
variable();
if (error == 2) {
error_handle(",", token);
while (!match(COMMA) && !match(SEMICOLON)) next_token();
recovery = 0;
}
} while (match(COMMA) && next_token());
}
void variable() {
token->lexeme[token->count] = '\0';
if (!match(ID)) {
if (recovery) {
while (!match(ID) && !match(COMMA) && !match(SEMICOLON)) next_token();
recovery = 0;
if (!match(ID)) return;
}
else error_handle("Variable Name(id)", token);
}
next_token();
if (match('[')) {
if (!recovery) {
back_token();
if (token) fprintf(yyout, "Array Variable %s\n", token->lexeme);
next_token();
}
next_token();
if (!match(INT_NUMBER)) {
error_handle("int number", token);
}
else print_token("Array Size [%s] at line %d\n", token);
next_token();
if (!match(']') && token) {
if (recovery) {
while (!match(']')) next_token();
recovery = 0;
}
else error_handle("]", token);
}
next_token();
}
else {
if (!recovery) {
back_token();
print_token("Variable [ %s ] at line %d\n", token);
next_token();
}
}
}
void statements() {
if (not_statements()) return;
fprintf(yyout, "Statement List...\n");
while (!not_statements()) {
statement();
if (!match(SEMICOLON)) {
if (recovery) {
while (!match(SEMICOLON) && !match('{') && !match(END))
if (!next_token())
break;
recovery = 0;
}
else
error_handle(";", token);
}
if (match(END))
break;
if (match('{'))
continue;
next_token();
if (match(SEMICOLON))
next_token();
}
}
void statement() {
fprintf(yyout, "Statement...\n");
if (match(ID)) {
next_token();
if (match('(')) {
back_token();
function_call();
}
else {
back_token();
fprintf(yyout, "Variable Assignment...\n");
variable();
if (!match('=')) {
if (!match(SEMICOLON))
error_handle("=", token);
if (recovery) {
while (!match('=') && !match(SEMICOLON) && !match('{') && !match(END))
next_token();
recovery = 0;
if (match(SEMICOLON) || match('{') || match(END))
return;
print_token("Assign Operator [ %s ] at line %d\n", token);
}
}
else
print_token("Assign Operator [ %s ] at line %d\n", token);
next_token();
if (!expression()) {
if (match(END) || match('{'))
return;
error_handle("int number, real number, id", token);
next_token();
}
}
}
else if (match(RETURN)) {
fprintf(yyout, "Return Statement...\n");
next_token();
if (match(SEMICOLON)) fprintf(yyout, "Empty Statement\n");
else {
if (!expression())
error_handle("ID, int number, real number", token);
expression();
}
}
else if (match('{')) {
block();
}
}
void function_call() {
fprintf(yyout, "Function Call...\n");
print_token("Function Name [ %s ] at line %d\n", token);
next_token();
next_token();
parameters_list();
if (!match(')')) {
error_handle(", or )", token);
next_token();
while (!match(')') && !match(SEMICOLON))
next_token();
back_token();
}
next_token();
}
void parameters_list() {
fprintf(yyout, "Parameters List...\n");
if (match(')')) {
fprintf(yyout, "Empty Parameter\n");
}
else
variables_list();
}
int expression() {
fprintf(yyout, "Expression...\n");
if (recovery) {
while (!match(INT_NUMBER) && !match(REAL_NUMBER) && !match(ID) && !match('{')) next_token();
recovery = 0;
if (match('{'))
return 0;
}
if (match(INT_NUMBER)) {
print_token("int number [ %s ] at line %d\n", token);
next_token();
}
else if (match(REAL_NUMBER)) {
print_token("real number [ %s ] at line %d\n", token);
next_token();
}
else if (match(ID)) {
next_token();
if (ar_op()) {
back_token();
print_token("ID [ %s ] at line %d\n", token);
next_token();
print_token("Arithmetic Operator [ %s ] at line %d\n", token);
next_token();
if (!expression()) {
error_handle("int number, real number, id", token);
next_token();
}
}
else {
back_token();
variable();
}
}
else
return 0;
return 1;
}
void block() {
fprintf(yyout, "Block Statement...\n");
if (!match('{')) {
if (match(END))
return;
error_handle("{", token);
}
next_token();
var_definitions();
back_token();
if (!match(SEMICOLON) && !match('{')) {
if (match(END))
return;
error_handle(";", token);
}
next_token();
statements();
if (!match('}')) {
if (match(END))
return;
error_handle("}", token);
}
next_token();
}
void func_definitions() {
fprintf(yyout, "Function Definitions List...\n");
while (token)
func_definition();
}
void func_definition() {
if (!returned_type()) {
error_handle("integer, real, void", token);
while (!returned_type() && !match(ID))
next_token();
}
recovery = 0;
fprintf(yyout, "Function Definition...\n");
if (returned_type())
print_token("Return Type [ %s ] at line %d\n", token);
else
error_handle("integer, real, void", token);
next_token();
if (!match(ID))
error_handle("id", token);
else
print_token("Function Name [ %s ] at line %d\n", token);
next_token();
if (!match('('))
error_handle("(", token);
next_token();
param_definitions();
if (!match(')'))
error_handle(")", token);
next_token();
block();
if (recovery) {
while (!match('}')) next_token();
next_token();
recovery = 0;
}
}
void param_definitions() {
fprintf(yyout, "Parameter definitions List...\n");
if (match(')'))
fprintf(yyout, "Empty Parameter\n");
else
var_definitions();
semantic.h
#pragma once
#include "LEXYY.h"
typedef struct SCOPES {
struct SCOPES *parent;
struct SCOPES *first_child; /*for right */
struct SCOPES *next_sibling; /*for left*/
struct SYMBOLS *symbols;
} SCOPE;
typedef struct SYMBOLS {
char *name;
int type;
int size;
int initialized;
int used;
int line;
struct SYMBOLS *next;
struct SYMBOLS *prev;
} SYMBOL;
typedef struct FUNCTIONS {
char *name;
int returnd_type;
int param_number;
int line;
struct SYMBOLS *params;
struct SCOPES *scope;
struct FUNCTIONS *prev_func;
struct FUNCTIONS *next_func;
} FUNCTION;
SCOPE *root;
FUNCTION *func;
int semantic_errors, semantic_warnings;
FILE *yyout;
int return_statement;
FUNCTION *find_func(char *);
SYMBOL *find_symbol(SCOPE *, char *, SYMBOL *);
void semantic_error_handle(char *, char *, int);
int semantic();
FUNCTION *get_function_list();
FUNCTION *get_function();
SYMBOL *semantic_var_definitions(SCOPE *, SYMBOL *, int);
SYMBOL *semantic_var_definition(SCOPE *);
SYMBOL *semantic_vars_list(SCOPE *, int);
SYMBOL *semantic_var(SCOPE *, int);
SCOPE *semantic_statements(SCOPE *, int, SYMBOL *);
void semantic_statement(SCOPE *, int, SYMBOL *);
void semantic_function_call(SCOPE *, SYMBOL *);
int semantic_expression(SCOPE *, SYMBOL *);
SCOPE *semantic_block(SCOPE *, int, SYMBOL *);
void semantic_func_definitions();
void semantic_func_definition(FUNCTION *f);
void check_unused_in_scope(SCOPE *);
void check_unused_in_function(FUNCTION *);
semantic.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "semantic.h"
/*find function definition*/
FUNCTION *find_func(char *name) {
FUNCTION *f = func;
while (f && strcmp(f->name, name))
f = f->prev_func;
return f;
}
/*finding variable definition*/
SYMBOL *find_symbol(SCOPE *scope, char *name, SYMBOL *params) {
SYMBOL *symbols;
/*if function definition, searching in function parameters*/
if (params) {
symbols = params;
while (symbols) {
if (!strcmp(symbols->name, name))
return symbols;
symbols = symbols->next;
}
}
if (!scope)
return NULL;
/*searchinf in scope variables*/
symbols = scope->symbols;
while (symbols) {
if (!strcmp(symbols->name, name))
return symbols;
symbols = symbols->next;
}
return find_symbol(scope->parent, name, NULL);
}
void semantic_error_handle(char *str, char *name, int line) {
fprintf(yyout, str, name, line);
semantic_errors++;
}
/*processing semantic analysis*/
int semantic() {
semantic_errors = semantic_warnings = 0;
token = tokens;
if (!token)
return 0;
//preload function definitions for function call
while (!match(END))
next_token();
func = get_function_list();
token = tokens;
next_token();
/*creating new scope for main program*/
root = (SCOPE *)malloc(sizeof(SCOPE));
root->parent = root->first_child = root->next_sibling = NULL;
root->symbols = NULL;
/*get variable definitions in current scope*/
root->symbols = semantic_var_definitions(root, NULL, 1);
/*analysing statements and get sub scope*/
root->first_child = semantic_statements(root, VOID, NULL);
next_token();
check_unused_in_scope(root);
semantic_func_definitions();
if (!semantic_errors)
fprintf(yyout, "Semantic analysis success!\n");
return semantic_errors;
}
/*getting function definition list before start analysis*/
FUNCTION *get_function_list() {
FUNCTION *functions = NULL;
next_token();
while (token) {
if (functions) {
functions->next_func = get_function();
functions->next_func->prev_func = functions;
functions = functions->next_func;
}
else
functions = get_function();
}
return functions;
}
/*getting function definition before start of analysis*/
FUNCTION *get_function() {
FUNCTION *f = (FUNCTION *)malloc(sizeof(FUNCTION));
SYMBOL *temp;
f->next_func = f->prev_func = NULL;
f->scope = NULL;
int block_number = 0;
f->returnd_type = returned_type();
next_token();
f->name = token->lexeme;
f->line = token->line;
next_token();
next_token();
/*getting function parameters list and number*/
f->params = semantic_var_definitions(NULL, NULL, 0);
f->param_number = 0;
temp = f->params;
while (temp) {
f->param_number++;
temp = temp->next;
}
next_token();
do {
if (match('{'))
block_number++;
if (match('}'))
block_number--;
next_token();
} while (block_number);
return f;
}
/*get variables definitions*/
SYMBOL *semantic_var_definitions(SCOPE *scope, SYMBOL *params, int check) {
SYMBOL *symbols = NULL, *temp = NULL, *temp1;
/*creating symbol table for current scope*/
while (token) {
if (!type())
break;
if (symbols) {
while (temp->next) temp = temp->next;
temp->next = semantic_var_definition(scope);
temp->next->prev = temp;
}
else {
temp = symbols = semantic_var_definition(scope);
while (temp->next) temp = temp->next;
}
if (match(')'))
break;
next_token();
}
/*after getting variables, checking for duplicated definitions. if function definition, checking function parameters*/
if (params) {
temp = symbols;
while (temp) {
/*if varialble name is function name, then error*/
if (find_func(temp->name)) {
semantic_error_handle("Error: Cannot use function name [ %s ] with varaible at line [ %d ]\n", temp->name, temp->line);
if (scope) {
if (temp->prev) {
temp->prev->next = temp->next;
if (temp->next)
temp->next->prev = temp->prev;
temp1 = temp;
temp = temp->next;
free(temp1);
}
else {
symbols = temp->next;
if (symbols)
symbols->prev = NULL;
free(temp);
temp = symbols;
}
}
continue;
}
temp1 = params;
/*check in parameter definitions*/
while (temp1) {
if (!strcmp(temp->name, temp1->name))
break;
temp1 = temp1->next;
}
/*if duplicated definition*/
if (temp1) {
semantic_error_handle("Error: Duplicated variable [ %s ] declaration with parameters at line %d\n", temp->name, temp->line);
if (scope) {
if (temp->prev) {
temp->prev->next = temp->next;
if (temp->next)
temp->next->prev = temp->prev;
temp1 = temp;
temp = temp->next;
free(temp1);
}
else {
symbols = temp->next;
if (symbols)
symbols->prev = NULL;
free(temp);
temp = symbols;
}
}
else
temp = temp->next;
}
else
temp = temp->next;
}
}
/*checking scope variables*/
if (check) {
temp = symbols;
while (temp) {
/*if varialble name is function name - error*/
if (find_func(temp->name)) {
semantic_error_handle("Error: Cannot use function name [ %s ] with varaible at line [ %d ]\n", temp->name, temp->line);
if (scope) {
if (temp->prev) {
temp->prev->next = temp->next;
if (temp->next)
temp->next->prev = temp->prev;
temp1 = temp;
temp = temp->next;
free(temp1);
}
else {
symbols = temp->next;
if (symbols)
symbols->prev = NULL;
free(temp);
temp = symbols;
}
}
continue;
}
if (!temp->size)
semantic_error_handle("Error: Array size cannot be zero at line %s%d\n", "", temp->line);
temp1 = temp->prev;
while (temp1) {
if (!strcmp(temp->name, temp1->name))
break;
temp1 = temp1->prev;
}
if (temp1) {
semantic_error_handle("Error: Duplicated variable [ %s ] declaration within same scope at line %d\n", temp->name, temp->line);
if (scope) {
if (temp->prev) {
temp->prev->next = temp->next;
if (temp->next)
temp->next->prev = temp->prev;
temp1 = temp;
temp = temp->next;
free(temp1);
}
else {
symbols = temp->next;
if (symbols)
symbols->prev = NULL;
free(temp);
temp = symbols;
}
}
else
temp = temp->next;
}
else
temp = temp->next;
}
}
return symbols;
}
/*getting variable definition*/
SYMBOL *semantic_var_definition(SCOPE *scope) {
int var_type = type();
next_token();
return semantic_vars_list(scope, var_type);
}
/*getting variables list, each variable separated by comma, and insert into symbol table*/
SYMBOL *semantic_vars_list(SCOPE *scope, int var_type) {
SYMBOL *symbols = NULL, *temp = NULL;
do {
if (symbols) {
temp->next = semantic_var(scope, var_type);
temp->next->prev = temp;
temp = temp->next;
}
else
temp = symbols = semantic_var(scope, var_type);
} while (match(COMMA) && next_token());
return symbols;
}
/*getting variables separated by comma and make symbol item for symbol table*/
SYMBOL *semantic_var(SCOPE *scope, int var_type) {
SYMBOL *symbol;
if (!match(ID))
return NULL;
symbol = (SYMBOL *)malloc(sizeof(SYMBOL));
symbol->type = var_type;
symbol->name = token->lexeme;
symbol->line = token->line;
symbol->initialized = 0;
symbol->used = 0;
next_token();
/*check if array varaible*/
if (match('[')) {
next_token();
symbol->size = atoi(token->lexeme);
next_token(); next_token();
}
else
symbol->size = -1;
symbol->next = symbol->prev = NULL;
return symbol;
}
/*analysis statements and get sub scopes*/
SCOPE *semantic_statements(SCOPE *parent, int return_type, SYMBOL *params) {
SCOPE *scope = NULL, *temp = NULL;
while (!not_statements()) {
/* new scope for sub scope*/
if (!scope) {
scope = (SCOPE *)malloc(sizeof(SCOPE));
scope->parent = parent;
scope->first_child = scope->next_sibling = NULL;
scope->symbols = NULL;
}
/*analysising each statementand get symbols for sub scope*/
semantic_statement(scope, return_type, params);
if (match(END))
break;
if (match('{'))
continue;
next_token();
}
return scope;
}
/*analysinf each statement*/
void semantic_statement(SCOPE *scope, int return_type, SYMBOL *params) {
SYMBOL *symbol, *cur_symbol;
FUNCTION *f_temp = NULL;
int type, line;
/*if current statement is assignment or function call */
if (match(ID)) {
next_token();
/*if function call*/
if (match('(')) {
back_token();
semantic_function_call(scope, params);
}
/*assignment*/
else {
back_token();
/*getting variable for assignment*/
symbol = semantic_var(scope, 0);
/*check if current variable is declaration*/
cur_symbol = find_symbol(scope, symbol->name, params);
/*if current variable is declaration*/
if (cur_symbol) {
cur_symbol->initialized = 1;
cur_symbol->used = 1;
symbol->type = cur_symbol->type;
/*if variable is arra*/
if (cur_symbol->size > -1) {
/*check array size for array index */
if (symbol->size > cur_symbol->size)
semantic_error_handle("Error: Exceed bound of array [ %s ] at line %d\n", symbol->name, symbol->line);
else if (symbol->size < 0)
semantic_error_handle("Error: Expressions can't refer to entire array [ %s ] at line %d\n", symbol->name, symbol->line);
}
else if (symbol->size > -1)
semantic_error_handle("Error: Not array variable [ %s ] at line %d\n", symbol->name, symbol->line);
}
/*if current variable is not declared*/
else {
f_temp = find_func(symbol->name);
/*if symbole is function*/
if (f_temp)
semantic_error_handle("Error: Cannot assign to function name [ %s ] at line %d\n", symbol->name, symbol->line);
/*undefined variable*/
else
semantic_error_handle("Error: Undefined variable [ %s ] at line %d\n", symbol->name, symbol->line);
}
next_token();
type = semantic_expression(scope, params);
/*if erro type, then error*/
if (!type)
semantic_error_handle("Error: Cannot eval expression type [ %s ] at line %d\n", "error_type", symbol->line);
/*if type mismatch, then error */
if (!f_temp && (!type || (symbol->type != type && !(symbol->type == REAL && type == INTEGER))))
semantic_error_handle("Error: Cannot assign variable [ %s ] type mismatch at line %d\n", symbol->name, symbol->line);
}
}
/*return statement*/
else if (match(RETURN)) {
next_token();
line = token->line;
if (match(SEMICOLON)) {
if (return_type != VOID)
semantic_error_handle("Error: Return type mismatch %s at line %d\n", "", line);
}
/*if return type mismatch */
else {
type = semantic_expression(scope, params);
if (return_type == VOID || (return_type != type && return_type != REAL && type != INTEGER))
semantic_error_handle("Error: Return type mismatch %s at line %d\n", "", line);
}
return_statement = 1;
}
/*block statement*/
else if (match('{'))
semantic_block(scope, return_type, params);
}
/*analysis function call*/
void semantic_function_call(SCOPE *scope, SYMBOL *params) {
/*check function definition*/
FUNCTION *f = find_func(token->lexeme), *f_temp;
SYMBOL *actual_params, *func_params = NULL, *cur_symbol;
int param_number = 0, call_line = token->line;
if (!f)
semantic_error_handle("Error: Undefined function [ %s ] at line %d\n", token->lexeme, token->line);
next_token(); next_token();
/*getting parameters list of function call*/
actual_params = semantic_vars_list(NULL, 0);
/*get parameters list of function definition*/
if (f)
func_params = f->params;
/*compare function call parameters with function definition parameters*/
while (actual_params) {
param_number++;
/*checking parameter of funciton call in scopes*/
cur_symbol = find_symbol(scope, actual_params->name, params);
/*if found*/
if (cur_symbol) {
cur_symbol->used = 1;
/*if variable is array*/
if (cur_symbol->size > -1) {
if (actual_params->size > cur_symbol->size)
semantic_error_handle("Error: Exceed bound of array [ %s ] at line %d\n", actual_params->name, actual_params->line);
else if (actual_params->size < -1)
semantic_error_handle("Error: Expressions can't refer to entire array [ %s ] at line %d\n", actual_params->name, actual_params->line);
}
/*if variable is not array but it's as sucj, then error*/
else if (actual_params->size > -1)
semantic_error_handle("Error: Not array variable [ %s ] at line %d\n", actual_params->name, actual_params->line);
/*if variable type of function call doesn't mismatch with varaible type of function definition*/
if (func_params && cur_symbol->type != func_params->type && !(cur_symbol->type == INTEGER && func_params->type == REAL))
semantic_error_handle("Error: Variable type [ %s ] does not match with function parameters at line %d\n", cur_symbol->type == INTEGER ? "integer" : "real", actual_params->line);
}
/*if not found*/
else {
f_temp = find_func(actual_params->name);
/*if symbole is function*/
if (f_temp)
semantic_error_handle("Error: Cannot use function name as variable [ %s ] at line %d\n", actual_params->name, actual_params->line);
/*undefined variable*/
else
semantic_error_handle("Error: Undefined variable [ %s ] at line %d\n", actual_params->name, actual_params->line);
}
actual_params = actual_params->next;
if (func_params)
func_params = func_params->next;
if (actual_params)
free(actual_params->prev);
}
/*check function parameters number*/
if (f && param_number > f->param_number)
semantic_error_handle("Error: Too much parameters for [ %s ] at line %d\n", f->name, call_line);
else if (f && param_number < f->param_number)
semantic_error_handle("Error: Too few parameters for [ %s ] at line %d\n", f->name, call_line);
next_token();
}
/*analysis expression and get its type*/
int semantic_expression(SCOPE *scope, SYMBOL *params) {
SYMBOL *symbol, *cur_symbol;
FUNCTION *f_temp;
int type = 0;
/*int number is integer*/
if (match(INT_NUMBER)) {
next_token();
type = INTEGER;
}
/*real number is real*/
else if (match(REAL_NUMBER)) {
next_token();
type = REAL;
}
else if (match(ID)) {
symbol = semantic_var(scope, 0);
cur_symbol = find_symbol(scope, symbol->name, params);
/*if it is declared*/
if (cur_symbol) {
cur_symbol->used = 1;
symbol->type = cur_symbol->type;
type = symbol->type;
/*if variable is array*/
if (cur_symbol->size > -1) {
/*checking array size*/
if (symbol->size > cur_symbol->size)
semantic_error_handle("Error: Exceed bound of array [ %s ] at line %d\n", symbol->name, symbol->line);
else if (symbol->size < 0)
semantic_error_handle("Error: Expressions can't refer to entire array [ %s ] at line %d\n", symbol->name, symbol->line);
}
/*if variable is not array but it's used with as such- then error*/
else if (symbol->size > -1)
semantic_error_handle("Error: Not array variable [ %s ] at line %d\n", symbol->name, symbol->line);
}
/*if declaration of variable is not found*/
else {
f_temp = find_func(symbol->name);
if (f_temp)
semantic_error_handle("Error: Cannot use function name as variable [ %s ] at line %d\n", symbol->name, symbol->line);
else
semantic_error_handle("Error: Undefined variable [ %s ] at line %d\n", symbol->name, symbol->line);
}
/*if arithmetic operation, geting next expression's type*/
if (ar_op()) {
next_token();
type = semantic_expression(scope, params);
if (type && (symbol->type == REAL || !symbol->type))
type = symbol->type;
}
}
return type;
}
/*analysing block and get sub scope */
SCOPE *semantic_block(SCOPE *parent, int return_type, SYMBOL *params) {
/*createing new scope for sub scope*/
SCOPE *scope = (SCOPE *)malloc(sizeof(SCOPE)), *temp = parent;
scope->parent = parent;
scope->first_child = scope->next_sibling = NULL;
next_token();
/*getting variables list in sub scope*/
scope->symbols = semantic_var_definitions(scope, params, 1);
/*analysing statements in sub scope*/
scope->first_child = semantic_statements(scope, return_type, params);
next_token();
/*linking with parent scope*/
if (temp) {
if (temp->first_child) {
while (temp->next_sibling->next_sibling) temp = temp->next_sibling;
temp->next_sibling = scope;
}
else
temp->first_child = scope;
}
return scope;
}
/*analysing function definitions*/
void semantic_func_definitions() {
FUNCTION *f;
func = NULL;
/*get function definitions list*/
while (token) {
f = (FUNCTION *)malloc(sizeof(FUNCTION));
f->next_func = f->prev_func = NULL;
if (func) {
func->next_func = f;
func->next_func->prev_func = func;
func = func->next_func;
}
else
func = f;
semantic_func_definition(f);
}
}
/*analysing function definition and getting scopes for each function*/
void semantic_func_definition(FUNCTION *f) {
FUNCTION *f_temp = func->prev_func;
SYMBOL *temp;
/*type of function*/
f->returnd_type = returned_type();
next_token();
f->name = token->lexeme;
f->line = token->line;
/*checking if definition deplicated*/
while (f_temp) {
if (!strcmp(f->name, f_temp->name))
break;
f_temp = f_temp->prev_func;
}
if (f_temp)
semantic_error_handle("Error: Function [ %s ] overloading at line %d\n", f->name, f->line);
next_token();
next_token();
if (token->line == 100)
token->line = token->line;
f->params = semantic_var_definitions(NULL, NULL, 1);
f->param_number = 0;
temp = f->params;
while (temp) {
f->param_number++;
temp = temp->next;
}
next_token();
return_statement = 0;
/*sub scope of this function*/
f->scope = semantic_block(NULL, f->returnd_type, f->params);
if (!return_statement && f->returnd_type != VOID)
semantic_error_handle("Error: No return statement in function [ %s ]\n", f->name, 0);
/*checking if any variable is not used in function*/
check_unused_in_function(f);
}
/*check if any variables are not declared in scope*/
void check_unused_in_scope(SCOPE *root) {
if (!root)
return;
while (root->symbols) {
if (!root->symbols->used) {
semantic_error_handle("Error: Unused variable [ %s ] at line %d\n", root->symbols->name, root->symbols->line);
}
root->symbols = root->symbols->next;
}
if (root->first_child)
check_unused_in_scope(root->first_child);
if (root->next_sibling)
check_unused_in_scope(root->next_sibling);
}
/*checking if any variables are not declared in function*/
void check_unused_in_function(FUNCTION *func) {
if (func->params) {
SYMBOL *symbol = func->params, *temp;
while (symbol) {
temp = symbol->prev;
while (temp) {
if (!strcmp(temp->name, symbol->name))
break;
temp = temp->prev;
}
if (!temp && !symbol->used)
semantic_error_handle("Error: Unused variable [ %s ] at line %d\n", symbol->name, symbol->line);
symbol = symbol->next;
}
}
if (func->scope)
check_unused_in_scope(func->scope);
}
LexorFlexfor the lexical analyzer orYACCorBisonfor the parser? If so please indicte which parts. \$\endgroup\$