stamail

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

sexp.c (3811B)


      1 /*
      2  * ============================================================================
      3  * ███████╗████████╗ █████╗ ███╗   ███╗ █████╗ ██╗██╗     
      4  * ██╔════╝╚══██╔══╝██╔══██╗████╗ ████║██╔══██╗██║██║     
      5  * ███████╗   ██║   ███████║██╔████╔██║███████║██║██║     
      6  * ╚════██║   ██║   ██╔══██║██║╚██╔╝██║██╔══██║██║██║     
      7  * ███████║   ██║   ██║  ██║██║ ╚═╝ ██║██║  ██║██║███████╗
      8  * ╚══════╝   ╚═╝   ╚═╝  ╚═╝╚═╝     ╚═╝╚═╝  ╚═╝╚═╝╚══════╝
      9  * ============================================================================
     10  *
     11  * Copyright (C) 2026 Binkd.
     12  *
     13  * This file is part of stamail.
     14  *
     15  * stamail is free software: you can redistribute it and/or modify it under the
     16  * terms of the GNU General Public License as published by the Free Software
     17  * Foundation, either version 3 of the License, or (at your option) any later
     18  * version.
     19  *
     20  * stamail is distributed in the hope that it will be useful, but WITHOUT ANY
     21  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
     22  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
     23  * details.
     24  * 
     25  * You should have received a copy of the GNU General Public License
     26  * along with stamail. If not, see <https://www.gnu.org/licenses/>.
     27  *
     28  * =============================================================================
     29 */
     30 
     31 #include <stdlib.h>
     32 #include <ctype.h>
     33 #include <string.h>
     34 #include "sexp.h"
     35 
     36 static const char *p;
     37 static const char *end;
     38 
     39 static void skip_ws(void) {
     40     while (p < end && isspace((unsigned char)*p))
     41         p++;
     42 }
     43 
     44 static struct sexp *parse_expr(void);
     45 
     46 static struct sexp *new_sexp(enum sexp_type t, const char *s, int len) {
     47     struct sexp *x = calloc(1, sizeof(*x));
     48     x->type = t;
     49     x->start = s;
     50     x->len = len;
     51     return x;
     52 }
     53 
     54 static struct sexp *parse_list(void) {
     55     p++; /* skip '(' */
     56     struct sexp *list = new_sexp(SEXP_LIST, NULL, 0);
     57     struct sexp **tail = &list->child;
     58 
     59     for (;;) {
     60         skip_ws();
     61         if (p >= end)
     62             break;
     63         if (*p == ')') {
     64             p++;
     65             break;
     66         }
     67         struct sexp *e = parse_expr();
     68         if (!e) break;
     69         *tail = e;
     70         tail = &e->next;
     71     }
     72     return list;
     73 }
     74 
     75 static struct sexp *parse_string(void) {
     76     const char *s = ++p;
     77     while (p < end) {
     78         if (*p == '"' && p[-1] != '\\')
     79             break;
     80         p++;
     81     }
     82     int len = p - s;
     83     if (p < end) p++;
     84     return new_sexp(SEXP_STRING, s, len);
     85 }
     86 
     87 static struct sexp *parse_atom(void) {
     88     const char *s = p;
     89     while (p < end && !isspace((unsigned char)*p) && *p != '(' && *p != ')')
     90         p++;
     91     int len = p - s;
     92 
     93     int isnum = 1;
     94     for (int i = 0; i < len; i++) {
     95         if (!isdigit((unsigned char)s[i])) {
     96             isnum = 0;
     97             break;
     98         }
     99     }
    100 
    101     return new_sexp(isnum ? SEXP_INT : SEXP_SYMBOL, s, len);
    102 }
    103 
    104 static struct sexp *parse_expr(void) {
    105     skip_ws();
    106     if (p >= end) return NULL;
    107 
    108     if (*p == '(')
    109         return parse_list();
    110     if (*p == '"')
    111         return parse_string();
    112     return parse_atom();
    113 }
    114 
    115 struct sexp *sexp_parse(const char *buf, size_t len) {
    116     p = buf;
    117     end = buf + len;
    118     return parse_expr();
    119 }
    120 
    121 void sexp_free(struct sexp *s) {
    122     if (!s) return;
    123     sexp_free(s->child);
    124     sexp_free(s->next);
    125     free(s);
    126 }
    127