--- /dev/null
+struct CYExpression {
+};
+
+struct CYToken {
+ virtual const char *Text() const = 0;
+};
+
+struct CYTokenPrefix :
+ virtual CYToken
+{
+};
+
+struct CYTokenInfix :
+ virtual CYToken
+{
+ virtual unsigned Precedence() const = 0;
+};
+
+struct CYTokenPostfix :
+ virtual CYToken
+{
+};
+
+struct CYTokenAssignment :
+ virtual CYToken
+{
+};
+
+struct CYTokenAccess :
+ virtual CYToken
+{
+};
+
+struct CYTokenLiteral :
+ CYExpression,
+ virtual CYToken
+{
+};
+
+struct CYTokenString :
+ CYTokenLiteral
+{
+};
+
+struct CYTokenNumber :
+ CYTokenLiteral
+{
+};
+
+struct CYTokenWord :
+ virtual CYToken
+{
+};
+
+struct CYTokenIdentifier :
+ CYExpression,
+ CYTokenWord
+{
+ const char *word_;
+
+ virtual const char *Text() const {
+ return word_;
+ }
+};
+
+struct CYTokenColon :
+ CYToken
+{
+};
+
+struct CYTokenComma :
+ CYToken
+{
+};
+
+struct CYTokenSemi :
+ CYToken
+{
+};
+
+struct CYTokenQuestion :
+ CYToken
+{
+};
+
+std::set<const char *, CStringMapLess> OperatorWords_;
+
+struct CYParser {
+ FILE *fin_;
+ FILE *fout_;
+
+ size_t capacity_;
+ char *data_;
+
+ size_t offset_;
+ size_t size_;
+
+ CYPool pool_;
+
+ CYParser(FILE *fin, FILE *fout) :
+ fin_(fin),
+ fout_(fout),
+ capacity_(1024),
+ data_(reinterpret_cast<char *>(malloc(capacity_))),
+ offset_(0),
+ size_(0)
+ {
+ }
+
+ ~CYParser() {
+ // XXX: this will not deconstruct in constructor failures
+ free(data_);
+ }
+
+ bool ReadLine(const char *prompt) {
+ offset_ = 0;
+ data_[capacity_ - 1] = ~'\0';
+
+ start:
+ if (fout_ != NULL) {
+ fputs(prompt, fout_);
+ fputs(" ", fout_);
+ fflush(fout_);
+ }
+
+ if (fgets(data_, capacity_, fin_) == NULL)
+ return false;
+
+ check:
+ if (data_[capacity_ - 1] != '\0') {
+ size_ = strlen(data_);
+ if (size_ == 0)
+ goto start;
+ if (data_[size_ - 1] == '\n') {
+ --size_;
+ goto newline;
+ }
+ } else if (data_[capacity_ - 2] == '\n') {
+ size_ = capacity_ - 2;
+ newline:
+ data_[size_] = '\0';
+ } else {
+ size_t capacity(capacity_ * 2);
+ char *data(reinterpret_cast<char *>(realloc(data_, capacity)));
+ _assert(data != NULL);
+ data_ = data;
+ size_ = capacity_ - 1;
+ capacity_ = capacity;
+ fgets(data_ + size_, capacity_ - size_, fin_);
+ goto check;
+ }
+
+ return true;
+ }
+
+ _finline void ScanRange(const CYRange &range) {
+ while (range[data_[offset_]])
+ ++offset_;
+ }
+
+ CYToken *ParseToken(const char *prompt) {
+ char next;
+
+ do {
+ if (offset_ == size_ && (prompt == NULL || !ReadLine(prompt)))
+ return false;
+ next = data_[offset_++];
+ } while (next == ' ' || next == '\t');
+
+ CYTokenType type;
+ size_t index(offset_ - 1);
+
+ if (WordStartRange_[next]) {
+ ScanRange(WordEndRange_);
+ type = CYTokenWord;
+ } else if (next == '.') {
+ char after(data_[offset_]);
+ if (after >= '0' && after <= '9')
+ goto number;
+ goto punctuation;
+ } else if (next >= '0' && next <= '9') {
+ number:
+ ScanRange(NumberRange_);
+ type = CYTokenLiteral;
+ } else if (PunctuationRange_[next]) {
+ punctuation:
+ ScanRange(PunctuationRange_);
+ type = CYTokenPunctuation;
+ } else if (next == '"' || next == '\'') {
+ for (;;) {
+ char after(data_[offset_++]);
+ if (after == '\\') {
+ after = data_[offset_++];
+ _assert(after != '\0');
+ if (after == 'u') {
+ offset_ += 4;
+ _assert(offset_ < size_);
+ }
+ } else if (after == next)
+ break;
+ }
+
+ type = CYTokenLiteral;
+ } else if (next == '(' || next == '{' || next == '[') {
+ type = CYTokenOpen;
+ } else if (next == ')' || next == '}' || next == ']') {
+ type = CYTokenClose;
+ } else if (next == ';') {
+ type = CYTokenSemiColon;
+ } else {
+ printf(":( %u\n", next);
+ _assert(false);
+ }
+
+ char *value(pool_(data_ + index, offset_ - index));
+
+ if (type == CYTokenWord && OperatorWords_.find(value) != OperatorWords_.end())
+ type = CYTokenPunctuation;
+
+ CYToken *token(new(pool_) CYToken());
+ token->type_ = type;
+ token->value_ = value;
+ token->next_ = token;
+ token->prev_ = &token->next_;
+ return token;
+ }
+
+ CYToken *ParseExpression(const char *prompt) {
+ CYToken *token(ParseToken(prompt));
+ return token;
+ }
+};