float parse_float(char** c) { char* curr = *c; while(is_whitespace(*curr)) curr++; if(!is_number_char(*curr) && *curr != '-' && *curr != '.') return 0.0f; char* start = curr; while(is_number_char(*curr) || *curr == '.' || *curr == '-') { curr++; } char* buffer = (char*)alloca((curr + 1 - start) * sizeof(char)); strncpy(buffer, start, (curr - start)); buffer[curr-start] = '\0'; *c = curr; return atof(buffer); }
int parse_int(char** c) { char* curr = *c; while(is_whitespace(*curr)) curr++; if(!is_number_char(*curr)) return 0; char* start = curr; while(is_number_char(*curr)) { curr++; } char* buffer = (char*)alloca((curr + 1 - start) * sizeof(char)); strncpy(buffer, start, (curr - start)); buffer[curr-start] = '\0'; *c = curr; return strtol(buffer, NULL, 10); }
pointer parse_expr(parser* parse) { eat_whitespace(parse); pointer ret_car; pointer ret_cdr; switch(*parse->curr) { case '(': parse->curr++; ret_car = parse_expr(parse); ret_cdr = parse_expr(parse); return create_pair(ret_car, ret_cdr); case '"': ret_car = parse_string(parse); ret_cdr = parse_expr(parse); return create_pair(ret_car, ret_cdr); case '\'': parse->curr++; ret_car = parse_quote(parse); ret_cdr = parse_expr(parse); return create_pair(ret_car, ret_cdr); case ')': parse->curr++; return NIL; case '+': case '-': case 'b': ret_car = parse_number_or_symbol(parse); ret_cdr = parse_expr(parse); return create_pair(ret_car, ret_cdr); case '.': return parse_number_or_pair(parse); case '\\': parse->curr++; ret_car = create_char(*(parse->curr++)); ret_cdr = parse_expr(parse); return create_pair(ret_car, ret_cdr); case ';': while(!is_newline(*parse->curr) && *parse->curr != '\0') parse->curr++; return parse_expr(parse); case 0: return NIL; default: if(is_number_char(*parse->curr)) { ret_car = parse_number(parse); ret_cdr = parse_expr(parse); return create_pair(ret_car, ret_cdr); } else if(is_symbol_char(*parse->curr)) { ret_car = parse_symbol(parse); ret_cdr = parse_expr(parse); return create_pair(ret_car, ret_cdr); } else return parser_error(parse, "Unexpected char in expression."); } parse->curr++; }
pointer parse_quote(parser* parse) { if(is_whitespace(*parse->curr)) return parser_error(parse, "unexpected whitespace after quote."); switch(*parse->curr) { case '(': return create_pair(create_symbol(parse->symbols, "QUOTE"), parse_expr(parse)); default: if(is_symbol_char(*parse->curr) && !is_number_char(*parse->curr)) return create_pair(create_symbol(parse->symbols, "QUOTE"), parse_symbol(parse)); else return parser_error(parse, "Unexpected token after quote."); } }
pointer parse_number(parser* parse) { size_t len = 0; bool isFloat = false; bool isHex = false; bool isBinary = false; const char* Start = parse->curr; while(!is_delimiter(*parse->curr)) { if(*parse->curr == '.') isFloat = true; if(is_number_char(*parse->curr) || (isHex && is_extended_hex_char(*parse->curr))) len++; else if(len == 1 && *parse->curr == 'x' && *Start == '0') { len++; isHex = true; } else if(len == 0 && *parse->curr == 'b') isBinary = true; else return parser_error(parse, "Unexpected char '%c' in number literal.", *parse->curr); parse->curr++; } { int TotalIs = isHex + isBinary + isFloat; if(TotalIs > true) { char* buffer = new char[len+1]; strncpy(buffer, Start, len); buffer[len] = '\0'; parser_error(parse, "Unexpected number literal: %s.", buffer); delete buffer; return NIL; } } if(isFloat) { char* buffer = new char[len+1]; strncpy(buffer, Start, len); buffer[len] = '\0'; float ret = atof(buffer); delete buffer; return create_real(ret); } else { // Might be smart to use a buffer here, in case strtol doesn't see all delimiters as we do. int ret; if(isHex) ret = strtol(Start + 2, NULL, 16); else if(isBinary) ret = strtol(Start + 1, NULL, 2); else ret = strtol(Start, NULL, 10); return create_int(ret); } }
/* _agstrcanon: * Canonicalize ordinary strings. * Assumes buf is large enough to hold output. */ static char *_agstrcanon(char *arg, char *buf) { char *s, *p; unsigned char uc; int cnt = 0; int needs_quotes = FALSE; int maybe_num; int backslash_pending = FALSE; static const char *tokenlist[] /* must agree with scan.l */ = { "node", "edge", "strict", "graph", "digraph", "subgraph", NIL(char *) }; const char **tok; if (EMPTY(arg)) return "\"\""; s = arg; p = buf; *p++ = '\"'; uc = *(unsigned char *) s++; maybe_num = is_number_char(uc); while (uc) { if (uc == '\"') { *p++ = '\\'; needs_quotes = TRUE; } else { if (!ISALNUM(uc)) needs_quotes = TRUE; else if (maybe_num && !is_number_char(uc)) needs_quotes = TRUE; } *p++ = (char) uc; uc = *(unsigned char *) s++; cnt++; if (uc && backslash_pending && !((is_number_char(p[-1]) || isalpha(p[-1]) || (p[-1] == '\\')) && (is_number_char(uc) || isalpha(uc)))) { *p++ = '\\'; *p++ = '\n'; needs_quotes = TRUE; backslash_pending = FALSE; cnt = 0; } else if (uc && (cnt >= MAX_OUTPUTLINE)) { if (!((is_number_char(p[-1]) || isalpha(p[-1]) || (p[-1] == '\\')) && (is_number_char(uc) || isalpha(uc)))) { *p++ = '\\'; *p++ = '\n'; needs_quotes = TRUE; cnt = 0; } else { backslash_pending = TRUE; } } } *p++ = '\"'; *p = '\0'; if (needs_quotes) return buf; /* Use quotes to protect tokens (example, a node named "node") */ /* It would be great if it were easier to use flex here. */ for (tok = tokenlist; *tok; tok++) if (!strcasecmp(*tok, arg)) return buf; return arg; }