sources/grammar_docs/ys.c (120 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ // Strips the C content of out a .y file for further post processing of the grammar #include <stdio.h> #include <stdlib.h> int32_t peeked = EOF; // read one character int32_t get() { // if we peeked use that instead of reading another character if (peeked != EOF) { int32_t ch = peeked; peeked = -1; return ch; } int32_t ch = getchar(); if (ch == EOF) { exit(0); } return ch; } // peek and the next character and remember it int32_t peek() { if (peeked == EOF) { peeked = getchar(); } return peeked; } int32_t in_code = 0; // emit a character unless we are "in code" void put(int32_t ch) { if (!in_code) { putchar(ch); } } // read up to a matching double quote, handles \" as well. void process_double_quote() { // note, put might be a no-op if in_code for (;;) { int32_t ch = get(); if (ch == '\\') { put(ch); ch = get(); put(ch); } else if (ch == '"') { put(ch); return; } else { put(ch); } } } // read up to a matching close paren, there are no escapes for these labels void process_non_terminal_label() { // note, put might be a no-op if in_code for (;;) { int32_t ch = get(); if (ch == EOF || ch == ']') { return; } } } // read up to a matching single quote, handles \' as well. void process_single_quote() { // note, put might be a no-op if in_code for (;;) { int32_t ch = get(); if (ch == '\\') { put(ch); ch = get(); put(ch); } else if (ch == '\'') { put(ch); return; } else { put(ch); } } } // skip code until we find the matching close brace void process_code() { in_code = 1; while (in_code) { int32_t ch = get(); if (ch == '"') { process_double_quote(); // output will be suppressed } else if (ch == '\'') { process_single_quote(); // output will be suppressed } else if (ch == '{') { in_code++; } else if (ch == '}') { in_code--; } } } // processes stdin: skip up to %% then process grammar skipping blocks end at the next %% int32_t main(int32_t argc, char **argv) { // skip up to the first %% for (;;) { int32_t ch = get(); if (ch == '%' && peek() == '%') { ch = get(); // read the second % break; } } for (;;) { int32_t ch = get(); if (ch == '[') { process_non_terminal_label(); } else if (ch == '{') { process_code(); } else if (ch == '"') { put(ch); process_double_quote(); } else if (ch == '\'') { put(ch); process_single_quote(); } else if (ch == '%' && peek() == '%') { // end of rules, ignore the code after break; } else { put(ch); } } }