我最近一直在研究一种客户编程语言,我已经使用 c flex(词法分析器生成器)和 bison(解析器生成器)将数组和变量之类的东西实现到了客户语言中,我已经成功地制作了变量和数组(1维数组)解决了当我尝试将二维数组索引中存储的值存储到变量中时我注意到出现的问题,这是解析器
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hashtable.h"
int array_size;
int twod_array_size_row;
int twod_array_size_col;
%}
%union {
int num;
char *str;
struct ast *ast_node;
struct symlist *arg_list;
}
%token <str> EQUALS
%token <str> SEMICOLON
%token <str> PLUS
%token <str> MINUS
%token <str> MULTIPLY
%token <str> DIVIDE
%token LPAR
%token RPAR
%token <str> LCB
%token <str> RCB
%token MAIN
%token <str> CALL
%token VAR
%token <num> NUMBER
%token <str> IDENT
%token <str> LSB
%token <str> RSB
%token <str> COMMA
%type <num> expr
%type <str> var_declaration assignment display
%type <str> statement_list
%left PLUS MINUS
%left MULTIPLY DIVIDE
%%
mainprog: MAIN LCB statement_list RCB SEMICOLON;
statement_list: /* empty */
| statement_list statement SEMICOLON
;
statement: var_declaration | assignment | display;
var_declaration: IDENT LSB expr RSB { insert_array($1,$3); array_size = $3;}
| VAR IDENT { insert_variable($2); }
| IDENT LSB expr RSB LSB expr RSB {insert_2d_array($1, $3, $6);twod_array_size_col=$6; twod_array_size_row=$3;};
assignment: IDENT EQUALS expr { update_variable($1, $3); }
| IDENT LSB expr RSB EQUALS expr { update_array_element($1, $3, $6,array_size); }
| IDENT LSB expr RSB LSB expr RSB EQUALS expr { update_2d_array_element($1, $3, $6, $9,twod_array_size_row,twod_array_size_col); };
display: CALL IDENT { display_variable($2); }
| CALL IDENT LSB expr RSB { display_array_element($2, $4,array_size); }
| CALL IDENT LSB expr RSB LSB expr RSB { display_2d_array_element($2, $4, $7,twod_array_size_row,twod_array_size_col); };
expr: NUMBER { $$ = $1; }
| IDENT { $$ = get_variable_value($1); }
| IDENT LSB expr RSB { $$ = get_array_element_value($1, $3,array_size); }
| IDENT LSB expr RSB LSB expr RSB {get_2d_array_element_value($1, $6, $3, twod_array_size_row, twod_array_size_col);}
| expr PLUS expr { $$ = $1 + $3; }
| expr MINUS expr { $$ = $1 - $3; }
| expr MULTIPLY expr { $$ = $1 * $3; }
| expr DIVIDE expr {
if ($3 != 0) {
$$ = $1 / $3;
} else {
fprintf(stderr, "Error: Division by zero\n");
$$ = 0; // You can handle division by zero differently if needed
}
}
| '(' expr ')' { $$ = $2; }
;
%%
void yyerror(const char *s) {
fprintf(stderr, "Parse error: %s\n", s);
}
词法分析器:
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "parser.tab.h"
char* yytext;
%}
DIGIT [0-9]
WS [ \t\n]
IDENT [a-zA-Z]
%%
{WS} /* Ignore whitespace */
{DIGIT}+ { yylval.num = atoi(yytext); return NUMBER; }
{IDENT}+ { yylval.str = strdup(yytext); return IDENT; }
"+" { return PLUS; }
"-" { return MINUS; }
"*" { return MULTIPLY;}
"/" { return DIVIDE;}
"=" { return EQUALS;}
";" { return SEMICOLON;}
"(" { return LPAR; }
")" { return RPAR; }
"{" { return LCB; }
"}" { return RCB; }
"[" { return LSB;}
"]" {return RSB ;}
"##".* { }
"/#"[^#]*"#/" { }
"@var" {return VAR;}
"Void Main()" { return MAIN;}
"@call" {return CALL;}
. { fprintf(stderr, "Error: Unexpected character '%s'\n", yytext); }
%%
int yywrap() {
return 1;
}
用于词法分析器和解析器的功能位于:hashtable.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hashtable.h"
#define HASH_SIZE 101
struct Node {
char *name;
int is_array; // Indicates whether the variable is an array
void *value; // Value can be int or int array
int size; // Size of the array
int rows;
int cols;
struct Node *next;
};
static struct Node *hash_table[HASH_SIZE];
unsigned int hash(const char *str) {
unsigned int hash_val = 0;
while (*str) {
hash_val = (hash_val << 5) + *str++;
}
return hash_val % HASH_SIZE;
}
void initialize_hashtable() {
for (int i = 0; i < HASH_SIZE; ++i) {
hash_table[i] = NULL;
}
}
void insert_variable(const char *name) {
unsigned int index = hash(name);
struct Node *new_node = (struct Node *)malloc(sizeof(struct Node));
if (new_node == NULL) {
fprintf(stderr, "Error: Memory allocation failed\n");
return;
}
new_node->name = strdup(name);
new_node->is_array = 0;
new_node->value = malloc(sizeof(int)); // Allocate space for single int
if (new_node->value == NULL) {
fprintf(stderr, "Error: Memory allocation failed\n");
free(new_node->name);
free(new_node);
return;
}
*((int *)new_node->value) = 0; // Default value
new_node->next = hash_table[index];
hash_table[index] = new_node;
}
void insert_array(const char *name, int array_size) {
unsigned int index = hash(name);
struct Node *new_node = (struct Node *)malloc(sizeof(struct Node));
if (new_node == NULL) {
fprintf(stderr, "Error: Memory allocation failed\n");
return;
}
new_node->name = strdup(name);
new_node->is_array = 1;
new_node->size = array_size;
new_node->value = malloc(array_size * sizeof(int)); // Allocate space for the array
if (new_node->value == NULL) {
fprintf(stderr, "Error: Memory allocation failed\n");
free(new_node->name);
free(new_node);
return;
}
for (int i = 0; i < array_size; ++i) {
((int *)new_node->value)[i] = 0; // Default values for the array
}
new_node->next = hash_table[index];
hash_table[index] = new_node;
}
void insert_2d_array(const char *name, int rows, int cols) {
unsigned int index = hash(name);
printf("Inserting 2D array: %s[%d][%d]\n", name, rows, cols); // Debugging print
struct Node *new_node = (struct Node *)malloc(sizeof(struct Node));
if (new_node == NULL) {
fprintf(stderr, "Error: Memory allocation failed\n");
return;
}
new_node->name = strdup(name);
new_node->is_array = 1;
new_node->rows = rows;
new_node->cols = cols;
new_node->size = rows * cols;
new_node->value = malloc(rows * sizeof(int *)); // Allocate space for rows
if (new_node->value == NULL) {
fprintf(stderr, "Error: Memory allocation failed\n");
free(new_node->name);
free(new_node);
return;
}
// Initialize all row pointers to NULL
for (int i = 0; i < rows; ++i) {
((int **)new_node->value)[i] = NULL;
}
for (int i = 0; i < rows; ++i) {
((int **)new_node->value)[i] = malloc(cols * sizeof(int)); // Allocate space for columns
if (((int **)new_node->value)[i] == NULL) {
fprintf(stderr, "Error: Memory allocation failed\n");
// Free previously allocated memory
for (int j = 0; j < rows; ++j) {
free(((int **)new_node->value)[j]);
}
free(new_node->value);
free(new_node->name);
free(new_node);
return;
}
for (int j = 0; j < cols; ++j) {
((int **)new_node->value)[i][j] = i * cols + j; // Debug: Assign unique value to each element
}
}
new_node->next = hash_table[index];
hash_table[index] = new_node;
}
void update_variable(const char *name, int value) {
unsigned int index = hash(name);
struct Node *current = hash_table[index];
while (current != NULL) {
if (strcmp(current->name, name) == 0) {
if (current->is_array) {
if (current->rows == 0) {
// 1D Array
fprintf(stderr, "Error: Cannot update a variable with a value from a 1D array\n");
return;
} else {
// 2D Array
fprintf(stderr, "Error: Cannot update a variable with a value from a 2D array\n");
return;
}
}
*((int *)current->value) = value;
return;
}
current = current->next;
}
fprintf(stderr, "Error: Variable '%s' not declared\n", name);
}
void update_array_element(const char *name, int index, int value, int array_size) {
unsigned int array_index = hash(name);
struct Node *current = hash_table[array_index];
while (current != NULL) {
if (strcmp(current->name, name) == 0 && current->is_array) {
if (index >= 0 && index < current->size) {
((int *)current->value)[index] = value;
} else {
fprintf(stderr, "Error: Array index out of bounds\n");
}
return;
}
current = current->next;
}
fprintf(stderr, "Error: Variable '%s' not declared or is not an array\n", name);
}
void update_2d_array_element(const char *name, int row, int col, int value, int rows, int cols) {
unsigned int array_index = hash(name);
struct Node *current = hash_table[array_index];
while (current != NULL) {
if (strcmp(current->name, name) == 0 && current->is_array) {
if (row >= 0 && row < current->rows && col >= 0 && col < current->cols) {
((int **)current->value)[row][col] = value;
printf("the value is: %d\n", ((int **)current->value)[row][col]);
} else {
fprintf(stderr, "Error: 2D Array index out of bounds\n");
}
return; // Exiting the function after updating the array element
}
current = current->next;
}
fprintf(stderr, "Error: Variable '%s' not declared or is not a 2D array\n", name);
// Optionally, you could add an error message here or handle the error condition differently
}
int get_variable_value(const char *name) {
unsigned int index = hash(name);
struct Node *current = hash_table[index];
while (current != NULL) {
if (strcmp(current->name, name) == 0 && !current->is_array) {
return *((int *)current->value);
}
current = current->next;
}
fprintf(stderr, "Error: Variable '%s' not declared\n", name);
return 0; // Return a default value
}
int get_array_element_value(const char *name, int index, int array_size) {
unsigned int array_index = hash(name);
struct Node *current = hash_table[array_index];
while (current != NULL) {
if (strcmp(current->name, name) == 0 && current->is_array) {
if (index >= 0 && index < current->size) {
return ((int *)current->value)[index];
} else {
fprintf(stderr, "Error: Array index out of bounds\n");
return 0; // Return a default value
}
}
current = current->next;
}
fprintf(stderr, "Error: Variable '%s' not declared or is not an array\n", name);
return 0; // Return a default value
}
int get_2d_array_element_value(const char *name, int row, int col, int rows, int cols) {
unsigned int array_index = hash(name);
struct Node *current = hash_table[array_index];
while (current != NULL) {
if (strcmp(current->name, name) == 0 && current->is_array) {
if (row >= 0 && row < current->rows && col >= 0 && col < current->cols) {
return ((int **)current->value)[row][col];
} else {
fprintf(stderr, "Error: 2D Array index out of bounds\n");
return 0; // Return a default value
}
}
current = current->next;
}
fprintf(stderr, "Error: Variable '%s' not declared or is not a 2D array\n", name);
return 0; // Return a default value
}
void display_variable(const char *name) {
unsigned int index = hash(name);
struct Node *current = hash_table[index];
while (current != NULL) {
if (strcmp(current->name, name) == 0 && !current->is_array) {
printf("%s = %d\n", name, *((int *)current->value));
return;
}
current = current->next;
}
fprintf(stderr, "Error: Variable '%s' not declared\n", name);
}
void display_array_element(const char *name, int index, int array_size) {
unsigned int array_index = hash(name);
struct Node *current = hash_table[array_index];
while (current != NULL) {
if (strcmp(current->name, name) == 0 && current->is_array) {
if (index >= 0 && index < current->size) {
printf("%s[%d] = %d\n", name, index, ((int *)current->value)[index]);
} else {
fprintf(stderr, "Error: Array index out of bounds\n");
}
return;
}
current = current->next;
}
fprintf(stderr, "Error: Variable '%s' not declared or is not an array\n", name);
}
void display_2d_array_element(const char *name, int row, int col, int rows, int cols) {
unsigned int array_index = hash(name);
struct Node *current = hash_table[array_index];
while (current != NULL) {
if (strcmp(current->name, name) == 0 && current->is_array) {
if (row >= 0 && row < current->rows && col >= 0 && col < current->cols) {
printf("%s[%d][%d] = %d\n", name, row, col, ((int **)current->value)[row][col]);
} else {
fprintf(stderr, "Error: 2D Array index out of bounds\n");
}
return;
}
current = current->next;
}
fprintf(stderr, "Error: Variable '%s' not declared or is not a 2D array\n", name);
}
我尝试用我的语法测试这些文件:
Void Main() {
@var x;
@var y;
x = 10;
y = 20;
z[5];
z[0] = 1;
z[1] = 2;
z[2] = 3;
z[3] = 4;
z[4] = 5;
w[2][3];
w[0][0] = 1;
w[0][1] = 2;
w[0][2] = 3;
w[1][0] = 4;
w[1][1] = 5;
w[1][2] = 6;
@call x; ## Outputs: x = 10
@call y; ## Outputs: y = 20
@call z[3]; ## Outputs: z[3] = 4
@call w[1][2]; ## Outputs: w[1][2] = 6
/#
the issue is when i try to assign w[1][2] into a variable:
#/
@var result;
result = w[1][2];
@call result;
/# result keeps printing out random numers each time i run the program, so i am suspecting that this is a memory allocation issue but i am not quiet sure #/
};
问题在于规则
expr: ...
| IDENT LSB expr RSB LSB expr RSB {get_2d_array_element_value($1, $6, $3, twod_array_size_row, twod_array_size_col);}
...
赋值规则期望
expr
返回一个值,expr
应设置 $$
。
一维数组访问表达式可以做到这一点,但二维数组表达式不能。
您应该(我认为)将
$$
设置为 get_2d_array_element_value
返回的值:
| IDENT LSB expr RSB LSB expr RSB {$$ = get_2d_array_element_value($1, $6, $3, twod_array_size_row, twod_array_size_col);}