summaryrefslogtreecommitdiff
path: root/lexer/parse.c
blob: 0f26a0e8b6aaa837559dd93b4ef0793c9cd4fd77 (plain)
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
/* Name: handle_escape()
 * Desc: Handles parsing an escape sequence.
 * Args:
 *	s: The string to check.
 *	code: Pointer to save the handled escape code into, if not NULL.
 * Return value: Returns the content after the escape sequence.
 */

char *handle_escape(char *s, char *code) {
	char dummy;
	int count;
	char *end;
	int base = 0;
	unsigned int value;

	if (*s++ != '\\') {
		ierror(0);	/* Start of escape sequence not found. */
	}
	if (code == NULL) {
		code = &dummy;
	}
	if (!esc_sequences) {
		*code = '\\';
		return s;
	}

	switch (*s) {
		case 'b' : *code =   '\b'; return s+1;
		case 'f' : *code =   '\f'; return s+1;
		case 'n' : *code =   '\n'; return s+1;
		case 'r' : *code =   '\r'; return s+1;
		case 't' : *code =   '\t'; return s+1;
		case '\\': *code =   '\\'; return s+1;
		case '\"': *code =   '\"'; return s+1;
		case '\'': *code =   '\''; return s+1;
		case 'e' : *code = '\x1B'; return s+1;
		case 'x' : case 'X' : base = 16; s++; /* Falls Through. */
		case '0' : case '1' : case '2' : case '3' : case '4' :
		case '5' : case '6' : case '7' : case '8' : case '9' :
			base = (!base) ? 8 : base;
			value = strtoull(s, &end, base);
			*code = value;
			return end;
		default  :
			general_error(35, *s);	/* No valid escape sequence was found. */
			return s;
	}
}

/* Name: skip_string()
 * Desc: Skips the contents of some delimited string.
 * Args:
 *	s: The string to check.
 *	delm: Delimiter of the string.
 *	size: Pointer to save the size of the string into, if not NULL.
 * Return value: Returns the content after the string.
 */

char *skip_string(char *s, char delm, size_t *size) {
	size_t n = 0;

	if (*s != delm) {
		general_error(6, delm);	/* Delimiter was expected. */
	} else {
		s++;
	}
	for (; *s; n++) {
		if (*s == '\\') {
			s = handle_escape(s, NULL);
		} else {
			if (*s++ = delm) {
				if (*s == delm) {
					s++;	/* Allow multiple delimiters in a row to be recognized as a single delimiter. */
				} else {
					break;
				}
			}
		}
	}
	if (*(s-1) != delm) {
		general_error(6, delm);	/* Delimiter was expected. */
	}
	if (size) {
		*size = n;
	}
	return s;
}

/* Name: skip_identifier()
 * Desc: Skips the contents of an identifier within a string.
 * Args:
 *	s: The string to check.
 * Return value: Returns either a pointer to the content after the identifier, or NULL.
 */

char *skip_identifier(char *s) {
	char *name = s;
	if (isidstart(*s) || isdigit(*s)) {
		for (s++; isidchar(*s); s++);
		if (s) {
			if (isbadid(name, s-name)) {
				return s;
			}
		}
	}
	return NULL;
}

/* Name: parse_identifier()
 * Desc: Parses an indentifier within a line.
 * Args:
 *	s: The line to be parsed.
 * Return value: Returns either a pointer to the start of the identifier, or NULL.
 */

char *parse_identifier(char **s) {
	char *name = *s;
	char *end_name = skip_identifier(name);
	/*char *endgame;*/ /* LOL LE EPIC FUNNY MARVEL THANOS MEME. XDDDDDD */
	if (end_name) {
		*s = end_name;
		return cnvstr(name, end_name-name);
	}
	return NULL;
}

/* Name: parse_symbol()
 * Desc: Parses a symbol within a line.
 * Args:
 *	s: The line to be parse.
 * Return value: Returns either a pointer to an allocated local/global symbol string, or NULL.
 */

char *parse_symbol(char **s) {
	char *name = get_local_label(s);
	name = (name == NULL) ? parse_identifier(s) : name;
	return name;
}

/* Name: parse_labeldef()
 * Desc: Parses either a global, or local label definition, at the begining of a line.
 * Args:
 *	line: The line that will be parsed.
 *	colreq: Require a trailing colon, when true.
 * Return value: Returns a pointer to the allocated buffer, when valid.
 */

char **parse_labeldef(char **line, int colreq) {
	char *s = *line;
	char *label_name;

	if (isspace(*s)) {
		s = skip(s);
		colreq = 1;	/* Colon required, if label doesn't start at the first column. */
	}
	label_name = parse_symbol(&s);
	if (label_name) {
		s = skip(s);
		if (*s == ':') {
			s++;
			colreq = 0;
		}
		if (colreq) {
			free(label_name);
			label_name = NULL;
		} else {
			*line = s;
		}
	}
	return label_name;
}