uva 864 scheme pretty printing

Scheme Pretty-Printing 

Scheme is an expression language. This means that everything that is entered to the Scheme interpreter/compiler is an expression. Expressions are separated by blank space (blank, tabs, new-lines). Expressions can be in several forms:

  1. numbers - a sequence of digits, possibly preceded by a `+' or `-', possibly including a single `.' following at least one digit
  2. strings - a sequence of characters (not including newlines) preceded and followed by `"', with any included double-quote characters preceded by a `\', such as "This `\"' is a double-quote"
  3. special constants - a `#' followed by any characters up to blank space
  4. compound expressions - a (possibly empty) sequence of expressions surrounded by parentheses
  5. identifiers - a sequence of non-blank characters not including the characters: #"\(, and )

Input 

A sequence of Scheme expressions.

Output 

The same sequence of expressions, reformatted to make them more readable. The rules you must follow are:

  1. All top level expressions will start with no leading blanks on a line.
  2. A compound expression with the first sub-expression being the identifier `define' is a define-form. The second sub-expression will be an identifier and should go on the same line as the word `define'. If the third (and last) expression is compound it should start on the following line, indented 3 spaces. Otherwise, the whole define-form should be on a single line.
  3. A compound expressions with the first sub-expression being the identifier `lambda' is a lambda-form. The second sub-expression will be an identifier or compound expression and should go on the same line as the word `lambda'. All subsequent expressions should start on a new line, indented by an additional 3 spaces
  4. A compound expressions with the first sub-expression being the identifier `if' is an if-form. The second sub-expression will be an identifier or compound expression and should go on the same line as the word`if'. All subsequent expressions should start on a new line, indented by an additional 4 spaces
  5. All other compound expressions are function applications. If any of the sub-expressions are compound, the first two sub-expressions will be on the same line and all subsequent sub-expressions will be on new lines, indented to align with the second sub-expression.
  6. In all other cases, all blank space between elements of a compound expression will be replaced by a single space.

Sample Input 

(define abc+ (lambda (@1 $f) (if (if
$f a     b) (@1
 3 4) (bcdefg (d e) (f "g")))))
           (define
     a 42)
(+ a (- b c))

Sample Output 

(define abc+
   (lambda (@1 $f)
      (if (if $f
              a
              b)
          (@1 3 4)
          (bcdefg (d e)
                  (f "g")))))
(define a 42)
(+ a
   (- b c))



寫到我蛋都碎了,一提交竟然一次AC,不知有沒有人能寫的簡潔一點。

#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <cstring>
#include <cctype>

void print_spaces (int n)
/*
 * print 'n' number of spaces
 */
{
    assert (n >= 0);
    while (n--)
        printf (" ");
}

bool is_define_form (char *exp)
/*
 * return true if 'exp' is a 'define form compound',
 * otherwise return false.
 */
{
    char s1[100], s2[100];
    if (sscanf (exp, "%s%s", s1, s2) == EOF)
        return false;
    return *s1 == '(' && strcmp (s2, "define") == 0;
}

bool is_lambda_form (char *exp)
/*
 * return true if 'exp' is a 'lambda from compound'
 * otherwise return false.
 */
{
    char s1[100], s2[100];
    if (sscanf (exp, "%s%s", s1, s2) == EOF)
        return false;
    return *s1 == '(' && strcmp (s2, "lambda") == 0;
}

bool is_if_form (char *exp)
/*
 * return true if 'exp' is a 'if form compound'
 * otherwise return false.
 */
{
    char s1[100], s2[100];
    if (sscanf (exp, "%s%s", s1, s2) == EOF)
        return false;
    return *s1 == '(' && strcmp (s2, "if") == 0;
}

bool is_compound (char *exp)
/*
 * return true if 'exp' is a 'compound expression',
 * otherwise return false.
 */
{
    char s[100];
    if (sscanf (exp, "%s", s) == EOF)
        return false;
    return *s == '(';
}

bool is_identifier (char *exp)
/*
 * return true if 'exp' is a identifier,
 * otherwise return false.
 */
{
    char s[100];
    if (sscanf (exp, "%s", s) == EOF)
        return false;
    return *s && *s != ')' && *s != '(';
}

bool is_exp (char *exp)
/*
 * return true if 'exp' is a expression to be printed,
 * otherwise return false
 */
{
    return is_compound (exp) || is_identifier (exp);
}

bool has_compound (char *exp)
/*
 * return true if any sub-expression is a compound,
 * otherwise return false.
 */
{
    int bar = 0, n; // brackets
    char *p = exp, s[100];
    do {
        if (sscanf (p, "%s%n", s, &n) == EOF)
            return false;
        if (p != exp && is_compound (p))
            return true;
        if (*s == '(')
            ++bar;
        else if (*s == ')')
            --bar;
        p += n;
    } while (*p && bar);
    return false;
}

char *identifier (char *exp, int *len = NULL)
/*
 * print a identifier
 */
{
#ifdef _DEBUG
    printf ("identifier ()\n");
#endif
    char s[100];
    int n;
    if (sscanf (exp, "%s%n", s, &n) == EOF)
        return exp;
    printf ("%s", s);
    if (len)
        *len = strlen (s);
    return exp += n;
}

char *compound_on_one_line (char *exp, int *len = NULL)
/*
 * print a 'compound expression' on one single line
 */
{
#ifdef _DEBUG
    printf ("compound_on_one_line ()\n");
#endif
    if (len)
        *len = 0;
    int bar = 0, n;
    char *p = exp, s1[100], s2[100] = "";
    do {
        if (sscanf (p, "%s%n", s1, &n) == EOF)
            return p;

        if (p != exp && *s2 != '(' && *s1 != ')')
            printf (" ");
        printf ("%s", s1);
        strcpy (s2, s1);

        if (*s1 == ')')
            ++bar;
        else if (*s1 == '(')
            --bar;

        if (len)
            *len += strlen (s1) + (p==exp ? 0 : 1);

        p += n;
    } while (*p && bar);
    return p;
}

char *eat (char *exp, char ch)
/*
 * eats a 'ch' char in exp.
 */
{
    while (*exp && *exp != ch)
        ++exp;
    return ++exp;
}

char *compound (char *exp, int idents)
/*
 * print the 'compound expression',
 * try to distinguish 'if form', 'lambda form', 'define form' and 'normal form'.
 * 'idents' is the number of spaces we will ident
 */
{
#ifdef _DEBUG
    printf ("compound (idents = %d)\n", idents);
#endif
    char *if_form (char *, int);
    char *lambda_form (char *, int);
    char *define_form (char *, int);
    char *print_one_by_one (char *, int);

    if (is_if_form (exp))
        return if_form (exp, idents);
    else if (is_lambda_form (exp))
        return lambda_form (exp, idents);
    else if (is_define_form (exp))
        return define_form (exp, idents);

    // now it's a 'normal form compound'
    if (! has_compound (exp))
        return compound_on_one_line (exp);

    printf ("(");
    exp = eat (exp, '(');

    int n;
    if (is_compound (exp))
       exp = compound_on_one_line (exp, &n);
    else if (is_identifier (exp))
       exp = identifier (exp, &n);

    if (is_exp (exp)) {
        printf (" ");
        if (is_compound (exp))
           exp = compound_on_one_line (exp);
        else if (is_identifier (exp))
           exp = identifier (exp);
        else
            assert (false);
    }

    if (is_exp (exp)) {
        printf ("\n");
        print_spaces (idents + n + 2);
        exp = print_one_by_one (exp, idents + n + 2);
    }

    printf (")");
    return eat (exp, ')');
}

char *define_form (char *exp, int idents)
/*
 * print the 'define form compound', 
 * 'idents' specifies the number of spaces we ident.
 */
{
    printf ("(");
    exp = eat (exp, '(');

    char s1[100], s2[100];
    int n;

    if (sscanf (exp, "%s%s%n", s1, s2, &n) == EOF)
        return exp;
    exp += n;

    printf ("%s %s", s1, s2);

    if (is_compound (exp)) {
        printf ("\n");
        print_spaces (3 + idents);
        exp = compound (exp, 3 + idents);
    } else { 
        printf (" ");
        exp = identifier (exp);
    }
    printf (")");
    return eat (exp, ')');
}

char *if_form (char *exp, int idents)
/*
 * print the 'if form compound',
 * 'idents' specifies the number of spaces we ident.
 */
{
    printf ("(");
    exp = eat (exp, '(');

    char *print_one_by_one (char *, int);
    char s1[100];
    int n;

    if (sscanf (exp, "%s%n", s1, &n) == EOF)
        return exp;
    exp += n;

    printf ("%s ", s1);

    if (is_compound (exp))
        exp = compound (exp, strlen (s1) + 2 + idents);
    else
        exp = identifier (exp);

    printf ("\n");
    print_spaces (idents + 4);

    exp = print_one_by_one (exp, idents + 4);

    printf (")");
    return eat (exp, ')');
}

char *lambda_form (char *exp, int idents)
/*
 * print the 'lambda form compound',
 * 'idents' specifies the number of spaces we ident.
 */
{
    printf ("(");
    exp = eat (exp, '(');

    char *print_one_by_one (char *, int);
    char s1[100];
    int n;

    if (sscanf (exp, "%s%n", s1, &n) == EOF)
        return exp;
    exp += n;

    printf ("%s ", s1);

    if (is_compound (exp))
        exp = compound (exp, strlen (s1) + 2 + idents);
    else
        exp = identifier (exp);

    printf ("\n");
    print_spaces (idents + 3);

    exp = print_one_by_one (exp, idents + 3);

    printf (")");
    return eat (exp, ')');
}

char *print_one_by_one (char *exp, int idents)
/*
 * print a sequence of expression whitch may be
 * a single identifier or a compound expression.
 */
{
#ifdef _DEBUG
    printf ("print_one_by_one (idents = %d)\n", idents);
#endif
    if (is_compound (exp))
        exp = compound (exp, idents);
    else if (is_identifier (exp))
        exp = identifier (exp);
    else
        return exp;

    while (*exp) {
        if (is_exp (exp)) {
            printf ("\n");
            print_spaces (idents);
        } else {
            break;
        }
        if (is_compound (exp))
            exp = compound (exp, idents);
        else if (is_identifier (exp))
            exp = identifier (exp);
        else
            assert (false);
    }
    return exp;
}

void preprocess (char *exp)
/*
 * seperate all elements with spaces
 */
{
    char *buf = (char *) malloc (strlen (exp) * 3);
    char *src = exp;
    char *dest = buf;
    while (*src) {
        if (*src == '(') {
            dest = 3 + strcat (dest, " ( ");
        } else if (*src == ')') {
            dest = 3 + strcat (dest, " ) ");
        } else if (isblank (*src) || *src == '\n') {
            *dest++ = ' ';
        } else if (*src == '#') {
            *dest++ = ' ';
            while (*src && *src != ' ')
                *dest++ = *src++;
            *dest++ = ' ';
        } else if (*src == '\"') {
            *dest++ = ' ';
            do {
                if (*src == '\\')
                    *dest++ = *src++;
                if (*src == '\n')
                    ++src;
                else
                   *dest++ = *src++;
            } while (*src != '\"');
            *dest++ = '\"';
            *dest++ = ' ';
        } else {
            *dest++ = *src;
        }
        ++src;
    }
    *dest = 0;
    strcpy (exp, buf);
    free (buf);
}

int main ()
{
    static char all_lines [1024] = "";
    static char line [1024];
    while (gets (line)) {
        strcat (all_lines, line);
        strcat (all_lines, "\n");
    }
    preprocess (all_lines);
    print_one_by_one (all_lines, 0);
    printf ("\n");
    return 0;
}



發佈了94 篇原創文章 · 獲贊 1 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章