summaryrefslogtreecommitdiff
path: root/lexer/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'lexer/parse.c')
-rw-r--r--lexer/parse.c171
1 files changed, 171 insertions, 0 deletions
diff --git a/lexer/parse.c b/lexer/parse.c
new file mode 100644
index 0000000..0f26a0e
--- /dev/null
+++ b/lexer/parse.c
@@ -0,0 +1,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;
+}