-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpreasm.c
More file actions
181 lines (164 loc) · 6.53 KB
/
preasm.c
File metadata and controls
181 lines (164 loc) · 6.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#include "preasm.h"
int pre_assembler(char *filename, MacroNode *head)
{
FILE *input_file, *output_file;
if (!filename || !head)
{
return ERROR_NULL_PARAM;
}
/*Open the .as file for reading and create the .am file for writing*/
input_file = open_file(filename, "r", PRE_MACRO_EXT);
output_file = open_file(filename, "w", POST_MACRO_EXT);
/*If either file failed to open, return an error and move to next file*/
if (input_file == NULL || output_file == NULL)
{
return ERROR;
}
/*Expand macros in the .as file and write the expanded content to the .am file*/
if (macro_expansion(input_file, output_file, head) == ERROR)
{
printf("Error: Macro expansion failed\n");
fclose(input_file);
fclose(output_file);
return ERROR;
}
fclose(input_file);
fclose(output_file);
return SUCCESS;
}
int macro_expansion(FILE *input_file, FILE *output_file, MacroNode *head)
{
char line[MAX_LINE] = {0}; /*Buffer to hold each line in the file (fgets)*/
char line_copy[MAX_LINE] = {0}; /*Copy of the line buffer to be used because strtok changes line*/
char *word = NULL; /*Pointer to the current word in the line*/
int in_macro_creation = FALSE; /*Flag to indicate if the current line is inside a macro creation*/
Macro *current_macro = NULL; /*Pointer to the current macro being created*/
ErrorObject error = {0}; /*Error object to be filled and passed to handle_error*/
int line_number = 0;
int is_error = FALSE;
if (!input_file || !output_file || !head)
{
return ERROR_NULL_PARAM;
}
/*Loop over every line in the input file*/
while (fgets(line, MAX_LINE, input_file))
{
line_number++;
/*Copy the line to be used by strtok and keeping the original*/
strcpy(line_copy, line);
word = strtok(line, " \t\n");
/*If the line is empty or a comment, write it to the output file as is*/
if (!word || word[0] == ';')
{
fprintf(output_file, "%s", line_copy);
continue;
}
if (!in_macro_creation)
{
process_line(head, output_file, word, &in_macro_creation, line_copy, &error);
if (error.code != SUCCESS)
{
/*If there was an error in the macro expansion, return an error*/
error.line_number = line_number;
handle_error(&error);
is_error = TRUE;
continue;
}
}
else
{
/*The line is inside a macro creation, get the current macro being created (last one added)*/
current_macro = get_current_macro(head);
/*If the macro was not added, or content space was not allocated, return an error and move to the next line*/
if (!current_macro && !current_macro->content)
{
fill_error_object(ERROR_MACRO_NOT_DEFINED, line_number, NULL, &error);
handle_error(&error);
is_error = TRUE;
continue;
}
/*If the word is the end of the macro creation, set the flag to indicate that we are no longer in macro creation*/
/*do not print this line to the file*/
if (strcmp(word, MACRO_DECLARATION_SUFFIX) == 0)
{
in_macro_creation = FALSE;
}
else
{
/*If the word is not the end of the macro creation, its a macro's content.
add it to the macro content to be expanded later*/
strcat(current_macro->content, line_copy);
}
}
}
/*If there was an error in the macro expansion, return an error*/
return is_error ? ERROR : SUCCESS;
}
int process_line(MacroNode *head, FILE *output_file, char *word, int *in_macro_creation, char *line_copy, ErrorObject *error)
{
Macro *current_macro = NULL;
char *extra_content = NULL; /*Extra content after the macro name / declartion*/
if (!head || !output_file || !word || !in_macro_creation || !line_copy || !error)
{
return ERROR_NULL_PARAM;
}
error->code = SUCCESS; /*Reset Error Code*/
/*If not in macro creation, check if the current word is an existing macro*/
current_macro = find_macro(head, word);
if (current_macro != NULL && current_macro->content != NULL)
{
/*If the word is a macro, write the macro content to the output file instead of the macro name*/
extra_content = strtok(NULL, " \n\t");
if (extra_content != NULL)
{
/*If there are extra words after the macro name, return an error and move to the next line*/
fill_error_object(ERROR_MACRO_EXTRA_CONTENT, 0, word, error);
return 1;
}
/*Write the macro content to the output file instead of the origianl line*/
fprintf(output_file, "%s", current_macro->content);
}
else if (strcmp(word, MACRO_DECLARATION_PREFIX) == 0)
{
/* If started macro creating, move word pointer to next word in the line*/
word = strtok(NULL, " \n\t");
if (word == NULL)
{
/*If no macro name was given, return an error and move to the next line*/
fill_error_object(ERROR_MACRO_EMPTY_NAME, 0, NULL, error);
return 1;
}
/*Validate the macro name and add it to the macro list*/
error->code = validate_macro_name(word, head);
if (error->code != SUCCESS)
{
/*If the macro name is invalid, return an error and move to the next line*/
fill_error_object(error->code, 0, word, error);
return 1;
}
else
{
extra_content = strtok(NULL, " \n\t");
if (extra_content != NULL)
{
/*If there are extra words / chars after the macro name*/
fill_error_object(ERROR_MACRO_DEC_EXTRA_CONTENT, 0, word, error);
return 1;
}
/*Add the macro to the macro list and set the flag to indicate that we are in macro creation*/
error->code = add_macro(head, word);
if (error->code != SUCCESS)
{
fill_error_object(error->code, 0, word, error);
return 1;
}
*in_macro_creation = TRUE;
}
}
else
{
/*If the word is not a macro, and not a macro creation, write the line to the output file as is*/
fprintf(output_file, "%s", line_copy);
}
return SUCCESS;
}