/* l_io.c - Input and output routines for L. Samuel A. Rebelsky Version 0.1 of 3 March 2007 */ #include #include #include "l.h" /* Predeclarations for simplicity. */ pair _l_parse(); pair _l_parsetail(); /* The following two variables are used to keep track of our position in the parse. */ static int pos; static char *parseme; int is_letter(char ch) { return (('a' <= ch) && (ch <= 'z')) || (('A' <= ch) && (ch <= 'Z')); } /* is_letter(char) */ int is_digit(char ch) { return ('0' <= ch) && (ch <= '9'); } /* is_digit(char) */ int is_whitespace(char ch) { return (' ' == ch) || ('\n' == ch) || ('\t' == ch); } /* is_whitespace(char) */ void skip_whitespace() { while (is_whitespace(parseme[pos])) { pos++; } } /* skip_whitespace() */ /* Parse the tail of a list. Assumes we've read the first value. */ pair _l_parsetail() { skip_whitespace(); /* Special case: Out of input. Crash. */ if (!parseme[pos]) { fprintf(stderr, "Parse error: Early end of input in '%s'.\n", parseme); return L_ERROR; } /* Special case: End of list. Return NIL. */ else if (parseme[pos] == ')') { pos++; return L_NIL; } /* Special case: Dotted end of list. Return the next thing. */ else if (parseme[pos] == '.') { pos++; pair right = _l_parse(); skip_whitespace(); if (parseme[pos] != ')') { fprintf(stderr, "Parse error: Expected ')', found '%c' at position %d of '%s'\n", parseme[pos], pos, parseme); return L_ERROR; } pos++; return right; } /* Regular case: Normal position in the list. */ else { pair left = _l_parse(); pair right = _l_parsetail(); return allocate_pair(left, right); } } /* _l_parsetail() */ /* * Parse the substring of parseme starting at pos, advancing pos to immediately * beyond what we just parsed. Returned the parsed value. */ pair _l_parse() { char ch; int newpos; pair tmp; skip_whitespace(); /* Check for end of stuff. */ if (!parseme[pos]) { fprintf(stderr, "Parse error: Early end of input in '%s'.\n", parseme); return L_ERROR; } /* whoops! ran out of string */ if (is_digit(parseme[pos])) { /* Assumption: ASCII ordering. */ int result = 0; while (is_digit(parseme[pos])) { result = result*10 + (parseme[pos] - '0'); pos++; } /* while */ return make_int(result); } /* is_digit() */ else if (parseme[pos] == '"') { newpos = pos; while (parseme[++newpos] != '"') ; parseme[newpos] = '\0'; tmp = make_string(parseme + pos + 1); parseme[newpos] = '"'; pos = newpos + 1; return tmp; } else if (is_letter(parseme[pos])) { newpos = pos + 1; while (is_digit(parseme[newpos]) || (is_letter(parseme[newpos]))) { newpos++; } ch = parseme[newpos]; parseme[newpos] = '\0'; tmp = make_symbol(parseme + pos); parseme[newpos] = ch; pos = newpos; return tmp; } /* is_letter */ else if (parseme[pos] == '(') { pos++; pair left = _l_parse(); pair right = _l_parsetail(); return allocate_pair(left, right); } else { fprintf(stderr, "Parse error in position %d of '%s'\n", pos, parseme); return L_ERROR; } } /* _l_parse(char *) */ pair l_parse(char *str) { pos = 0; parseme = str; return _l_parse(); } /* l_parse(char *) */ void l_print(FILE *stream, pair root) { if (is_symbol(root)) { fprintf(stream, "%s", CDR(root)); } else if (is_int(root)) { fprintf(stream, "%d", CDR(root)); } else if (is_string(root)) { fprintf(stream, "\"%s\"", CDR(root)); } else if (is_pair(root)) { fprintf(stream, "("); l_print(stream, CAR(root)); fprintf(stream, " . "); l_print(stream, CDR(root)); fprintf(stream, ")"); } else { fprintf(stream, "", CAR(root), CDR(root)); } } /* l_print(pair) */