Kajetan Johannes Hammerle 6 years ago
commit
7dedb03b25
17 changed files with 883 additions and 0 deletions
  1. 2 0
      .gitignore
  2. 96 0
      ArrayList.h
  3. 29 0
      Exception.cpp
  4. 21 0
      Exception.h
  5. 44 0
      File.cpp
  6. 22 0
      File.h
  7. 43 0
      Main.cpp
  8. 9 0
      Makefile
  9. 79 0
      Token.cpp
  10. 34 0
      Token.h
  11. 70 0
      TokenType.cpp
  12. 80 0
      TokenType.h
  13. 259 0
      Tokenizer.cpp
  14. 30 0
      Tokenizer.h
  15. 22 0
      Utils.cpp
  16. 10 0
      Utils.h
  17. 33 0
      tests/if.snuvi

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+/nbproject
+LonelyTiger

+ 96 - 0
ArrayList.h

@@ -0,0 +1,96 @@
+#ifndef ARRAYLIST_H
+#define ARRAYLIST_H
+
+#include <cstring>
+
+template<class T>
+class ArrayList
+{
+public:
+    ArrayList()
+    {
+        pos = 0;
+        capacity = 4;
+        data = new T[capacity];
+    }
+    
+    ArrayList(const ArrayList& orig)
+    {
+        pos = orig.pos;
+        capacity = orig.capacity;
+        data = new T[capacity];
+        memcpy(data, orig.data, capacity * sizeof(T));
+    }
+    
+    ArrayList& operator=(const ArrayList& orig)
+    {
+        delete[] data;
+        
+        pos = orig.pos;
+        capacity = orig.capacity;
+        data = new T[capacity];
+        memcpy(data, orig.data, capacity * sizeof(T));
+        
+        return *this;
+    }
+    
+    virtual ~ArrayList()
+    {
+        delete[] data;
+    }
+    
+    int getSize()
+    {
+        return pos;
+    }
+    
+    void clear()
+    {
+        memset(data, 0, sizeof(T) * pos);
+        pos = 0;
+    }
+    
+    void add(T t)
+    {
+        if(pos >= capacity)
+        {
+            int newCapacity = capacity * 2;
+            T* t = new T[newCapacity];
+            memcpy(t, data, capacity * sizeof(T));
+            delete[] data;
+            data = t;
+            capacity = newCapacity;
+        }
+        data[pos] = t;
+        pos++;
+    }
+    
+    void remove(int index)
+    {
+        if(index < 0 || index >= pos)
+        {
+            return;
+        }
+        for(int i = index; i < pos - 1; i++)
+        {
+            data[i] = data[i + 1];
+        }
+        memset(data + pos - 1, 0, sizeof(T));
+        pos--;
+    }
+    
+    void forEach(void (*f) (T))
+    {
+        for(int i = 0; i < pos; i++)
+        {
+            f(data[i]);
+        }
+    }
+private:
+    int capacity;
+    int pos;
+    T* data;
+};
+
+#endif
+

+ 29 - 0
Exception.cpp

@@ -0,0 +1,29 @@
+#include "Exception.h"
+
+#include <iostream>
+
+using namespace std;
+
+Exception::Exception(string message)
+{
+    this->message = message;
+    this->line = -1;
+}
+
+Exception::Exception(string message, int line)
+{
+    this->message = message;
+    this->line = line;
+}
+
+void Exception::print() const
+{
+    cout << message;
+    if(line != -1)
+    {
+        cout << "(" << line << ")";
+    }
+    cout << endl;
+}
+
+

+ 21 - 0
Exception.h

@@ -0,0 +1,21 @@
+#ifndef EXCEPTION_H
+#define EXCEPTION_H
+
+#include <string>
+
+using namespace std;
+
+class Exception
+{
+public:
+    Exception(string message);
+    Exception(string message, int line);
+    
+    void print() const;
+private:
+    string message;
+    int line;
+};
+
+#endif
+

+ 44 - 0
File.cpp

@@ -0,0 +1,44 @@
+#include "File.h"
+#include <iostream>
+#include <fstream>
+#include <sstream>
+
+File::File(string path)
+{
+    this->path = path;
+}
+
+File::File(const File& orig)
+{
+}
+
+File::~File()
+{
+}
+
+bool File::exists()
+{
+    ifstream fileStream(path);
+    return fileStream.good();
+}
+
+string File::read()
+{
+    ifstream fileStream(path);
+    if(!fileStream.good())
+    {
+        return "";
+    }
+
+    stringstream stream;
+    string s;
+    while(!fileStream.eof())
+    {
+        getline(fileStream, s);
+        stream << s;
+        stream << '\n';
+    }
+
+    return stream.str();
+}
+

+ 22 - 0
File.h

@@ -0,0 +1,22 @@
+#ifndef FILE_H
+#define FILE_H
+
+#include <string>
+
+using namespace std;
+
+class File 
+{
+public:
+    File(string path);
+    File(const File& orig);
+    virtual ~File();
+    
+    bool exists();
+    string read();
+private:
+    string path;
+};
+
+#endif
+

+ 43 - 0
Main.cpp

@@ -0,0 +1,43 @@
+#include <iostream>
+#include "File.h"
+#include "Tokenizer.h"
+#include "Exception.h"
+
+using namespace std;
+
+int main(int argc, char** argv) 
+{    
+    File f("tests/if.snuvi");
+    if(f.exists())
+    {
+        Tokenizer t(f.read());
+        ArrayList<Token*> tokens;
+        try
+        {
+            t.tokenize(tokens);
+        }
+        catch(Exception ex)
+        {
+            ex.print();
+        }
+        
+        tokens.forEach([](Token* t) 
+        {
+            cout << *t << endl;
+        });
+        
+        tokens.forEach([](Token* t) 
+        {
+            delete t;
+        });
+        tokens.clear();
+    }
+    else
+    {
+        cout << "no" << endl;
+    }
+    return 0;
+}
+
+
+

+ 9 - 0
Makefile

@@ -0,0 +1,9 @@
+
+run: all
+	./LonelyTiger
+
+all: *.cpp *.h
+	g++ -Wall -std=c++14 *.cpp -o LonelyTiger
+	
+clean:
+	rm LonelyTiger

+ 79 - 0
Token.cpp

@@ -0,0 +1,79 @@
+#include "Token.h"
+#include "Exception.h"
+#include <iostream>
+#include "TokenType.h"
+
+Token::Token(Tokens::Type type, int line)
+{
+    this->type = type;
+    this->line = line;
+    f = 0.0f;
+    s = "";
+}
+
+Token::~Token() 
+{
+}
+
+void Token::setFloat(float f)
+{
+    if(type != Tokens::FLOAT)
+    {
+        throw Exception("token contains no float");
+    }
+    this->f = f;
+}
+
+void Token::setString(string s)
+{
+    if(type != Tokens::TEXT && type != Tokens::LABEL && type != Tokens::VAR)
+    {
+        throw Exception("token contains no string");
+    }
+    this->s.assign(s);
+}
+
+float Token::getFloat() const
+{
+    return f;
+}
+
+bool Token::getBool() const
+{
+    if(type == Tokens::TRUE)
+    {
+        return true;
+    }
+    return false;
+}
+
+string Token::getString() const
+{
+    return s;
+}
+
+int Token::getLine() const
+{
+    return line;
+}
+
+Tokens::Type Token::getType() const
+{
+    return type;
+}
+
+std::ostream& operator<<(std::ostream& stream, const Token& t)
+{
+    stream << t.getLine() << " ";
+    stream << t.getType();
+    string s = t.getString();
+    if(s.size() != 0)
+    {
+        stream << "(\"" << s << "\")"; 
+    }
+    if(t.getType() == Tokens::FLOAT)
+    {
+        stream << '(' << t.getFloat() << ')'; 
+    }
+    return stream;
+}

+ 34 - 0
Token.h

@@ -0,0 +1,34 @@
+#ifndef TOKEN_H
+#define TOKEN_H
+
+#include "TokenType.h"
+#include <string>
+
+using namespace std;
+
+class Token
+{
+public:
+    Token(Tokens::Type type, int line);
+    virtual ~Token();
+    
+    void setFloat(float f);
+    void setBool(bool b);
+    void setString(string s);
+    
+    float getFloat() const;
+    bool getBool() const;
+    string getString() const;
+    int getLine() const;
+    Tokens::Type getType() const;
+private:
+    Tokens::Type type;
+    float f;
+    string s;
+    int line;
+};
+
+std::ostream& operator<< (std::ostream& stream, const Token& t);
+
+#endif
+

+ 70 - 0
TokenType.cpp

@@ -0,0 +1,70 @@
+#include "TokenType.h"
+
+std::ostream& operator<<(std::ostream& os, const Tokens::Type& c)
+{
+    switch(c)
+    {
+        case Tokens::FLOAT: os << "float"; break;
+        case Tokens::TRUE: os << "true"; break;
+        case Tokens::FALSE: os << "false"; break;
+        case Tokens::TNULL: os << "null"; break;
+        case Tokens::TEXT: os << "String"; break;
+        case Tokens::LABEL: os << "Label"; break;
+        case Tokens::VAR: os << "var"; break;
+        case Tokens::GLOBAL: os << "$"; break;
+        case Tokens::INC: os << "++"; break;
+        case Tokens::DEC: os << "--"; break;
+        case Tokens::INVERT: os << "!"; break;
+        case Tokens::BIT_INVERT: os << "~"; break;
+        case Tokens::MUL: os << "*"; break;
+        case Tokens::DIV: os << "/"; break;
+        case Tokens::MOD: os << "%"; break;
+        case Tokens::ADD: os << "+"; break;
+        case Tokens::SUB: os << "-"; break;
+        case Tokens::LEFT_SHIFT: os << "<<"; break;
+        case Tokens::RIGHT_SHIFT: os << ">>"; break;
+        case Tokens::LESS: os << "<"; break;
+        case Tokens::LESS_EQUAL: os << "<="; break;
+        case Tokens::GREATER: os << ">"; break;
+        case Tokens::GREATER_EQUAL: os << ">="; break;
+        case Tokens::EQUAL: os << "=="; break;
+        case Tokens::NOT_EQUAL: os << "!="; break;
+        case Tokens::BIT_AND: os << "&"; break;
+        case Tokens::BIT_XOR: os << "^"; break;
+        case Tokens::BIT_OR: os << "|"; break;
+        case Tokens::AND: os << "&&"; break;
+        case Tokens::OR: os << "||"; break;
+        case Tokens::SET: os << "="; break;
+        case Tokens::ADD_SET: os << "+="; break;
+        case Tokens::SUB_SET: os << "-="; break;
+        case Tokens::MUL_SET: os << "*="; break;
+        case Tokens::DIV_SET: os << "/="; break;
+        case Tokens::MOD_SET: os << "%="; break;
+        case Tokens::LEFT_SHIFT_SET: os << "<<="; break;
+        case Tokens::RIGHT_SHIFT_SET: os << ">>="; break;
+        case Tokens::BIT_AND_SET: os << "&="; break;
+        case Tokens::BIT_XOR_SET: os << "^="; break;
+        case Tokens::BIT_OR_SET: os << "|="; break;
+        case Tokens::COMMA: os << ","; break;
+        case Tokens::OPEN_BRACKET: os << ")"; break;
+        case Tokens::CLOSE_BRACKET: os << ")"; break;
+        case Tokens::OPEN_SQUARE_BRACKET: os << "["; break;
+        case Tokens::CLOSE_SQUARE_BRACKET: os << "]"; break;
+        case Tokens::OPEN_CURVED_BRACKET: os << "{"; break;
+        case Tokens::CLOSE_CURVED_BRACKET: os << "}"; break;
+        case Tokens::SEMICOLON: os <<";"; break;
+        case Tokens::IF: os << "if"; break;
+        case Tokens::ELSE_IF: os << "else if"; break;
+        case Tokens::ELSE: os << "else"; break;
+        case Tokens::FOR: os << "for"; break;
+        case Tokens::WHILE: os << "while"; break;
+        case Tokens::FUNCTION: os << "function"; break;
+        case Tokens::BREAK: os << "break"; break;
+        case Tokens::CONTINUE: os << "continue"; break;
+        case Tokens::RETURN: os << "return"; break;
+        case Tokens::TRY: os << "try"; break;
+        case Tokens::CATCH: os << "catch"; break;
+        case Tokens::END_OF_FILE: os << "end_of_file"; break;
+    }
+    return os;
+}

+ 80 - 0
TokenType.h

@@ -0,0 +1,80 @@
+#ifndef TOKENTYPE_H
+#define TOKENTYPE_H
+
+#include <iostream>
+
+namespace Tokens
+{
+    enum Type 
+    {
+        FLOAT, // double
+        TRUE, // true
+        FALSE, // false
+        TNULL, // null
+        TEXT, // String
+        LABEL, // Label
+        VAR, // var
+        GLOBAL, // $
+
+        INC, // ++
+        DEC, // --
+        INVERT, // ! 
+        BIT_INVERT, // ~ 
+        MUL, // * 
+        DIV, // / 
+        MOD, // % 
+        ADD, // + 
+        SUB, // - 
+        LEFT_SHIFT, // << 
+        RIGHT_SHIFT, // >> 
+        LESS, // < 
+        LESS_EQUAL, // <= 
+        GREATER, // > 
+        GREATER_EQUAL, // >= 
+        EQUAL, // == 
+        NOT_EQUAL, // != 
+        BIT_AND, // & 
+        BIT_XOR, // ^ 
+        BIT_OR, // | 
+        AND, // && 
+        OR, // || 
+        SET, // = 
+        ADD_SET, // += 
+        SUB_SET, // -= 
+        MUL_SET, // *= 
+        DIV_SET, // /= 
+        MOD_SET, // %= 
+        LEFT_SHIFT_SET, // <<= 
+        RIGHT_SHIFT_SET, // >>= 
+        BIT_AND_SET, // &= 
+        BIT_XOR_SET, // ^= 
+        BIT_OR_SET, // |= 
+        COMMA, // , 
+        OPEN_BRACKET, // ) 
+        CLOSE_BRACKET, // ) 
+        OPEN_SQUARE_BRACKET, // [ 
+        CLOSE_SQUARE_BRACKET, // ] 
+        OPEN_CURVED_BRACKET, // { 
+        CLOSE_CURVED_BRACKET, // } 
+        SEMICOLON, // ; 
+
+        IF, // if
+        ELSE_IF, // else if
+        ELSE, // else
+        FOR, // for
+        WHILE, // while
+        FUNCTION, // function
+        BREAK, // break
+        CONTINUE, // continue
+        RETURN, // return
+        TRY, // try
+        CATCH, // catch
+
+        END_OF_FILE // end_of_file      
+    };
+};
+
+std::ostream& operator<<(std::ostream& os, const Tokens::Type& c);
+
+#endif
+

+ 259 - 0
Tokenizer.cpp

@@ -0,0 +1,259 @@
+#include "Tokenizer.h"
+#include "Utils.h"
+#include "Exception.h"
+
+Tokenizer::Tokenizer(string s) 
+{
+    data = s;
+    line = 0;
+    pos = 0;
+    length = 0;
+}
+
+Tokenizer::Tokenizer(const Tokenizer& orig) 
+{
+}
+
+Tokenizer::~Tokenizer() 
+{
+}
+
+void Tokenizer::tokenize(ArrayList<Token*>& tokens, char c, Tokens::Type type1, Tokens::Type type2)
+{
+    if(pos + 1 < length && data[pos + 1] == c)
+    {
+        tokens.add(new Token(type1, line));
+        pos++;
+    }
+    else
+    {
+        tokens.add(new Token(type2, line));
+    }
+}
+
+void Tokenizer::tokenize(ArrayList<Token*>& tokens, Tokens::Type type1, char c2, Tokens::Type type2, char c3, Tokens::Type type3)
+{
+    if(pos + 1 >= length)
+    {
+        tokens.add(new Token(type1, line));
+    }
+    else if(data[pos + 1] == c2)
+    {
+        tokens.add(new Token(type2, line));
+        pos++;
+    }
+    else if(data[pos + 1] == c3)
+    {
+        tokens.add(new Token(type3, line));
+        pos++;
+    }
+    else
+    {
+        tokens.add(new Token(type1, line));
+    }
+}
+
+void Tokenizer::tokenize(ArrayList<Token*>& tokens, Tokens::Type type1, char c2, char c3, Tokens::Type type2, Tokens::Type type3, char c4, Tokens::Type type4)
+{
+    if(pos + 1 >= length)
+    {
+        tokens.add(new Token(type1, line));
+    }
+    else if(data[pos + 1] == c2)
+    {
+        if(pos + 2 < length && data[pos + 2] == c3)
+        {
+            tokens.add(new Token(type2, line));
+            pos += 2;
+        }
+        else
+        {
+            tokens.add(new Token(type3, line));
+            pos++;
+        }
+    }
+    else if(data[pos + 1] == c4)
+    {
+        tokens.add(new Token(type4, line));
+        pos++;
+    }
+    else
+    {
+        tokens.add(new Token(type1, line));
+    }
+}
+
+void Tokenizer::tokenize(ArrayList<Token*>& tokens)
+{
+    line = 1;
+    pos = 0;
+    length = data.size();
+    
+    while(pos < length)
+    {
+        if(isLetter(data[pos]))
+        {
+            int old = pos;
+            pos++;
+            while(pos < length && isAllowedInName(data[pos]))
+            {
+                pos++;
+            }
+            string s = data.substr(old, pos - old);
+            if(s == "if") {tokens.add(new Token(Tokens::IF, line));}
+            else if(s == "elseif") {tokens.add(new Token(Tokens::ELSE_IF, line));}
+            else if(s == "else") {tokens.add(new Token(Tokens::ELSE, line));}
+            else if(s == "for") {tokens.add(new Token(Tokens::FOR, line));}
+            else if(s == "while") {tokens.add(new Token(Tokens::WHILE, line));}
+            else if(s == "function") {tokens.add(new Token(Tokens::FUNCTION, line));}
+            else if(s == "break") {tokens.add(new Token(Tokens::BREAK, line));}
+            else if(s == "continue") {tokens.add(new Token(Tokens::CONTINUE, line));}
+            else if(s == "return") {tokens.add(new Token(Tokens::RETURN, line));}
+            else if(s == "try") {tokens.add(new Token(Tokens::TRY, line));}
+            else if(s == "catch") {tokens.add(new Token(Tokens::CATCH, line));}
+            else
+            {
+                Token* t = new Token(Tokens::VAR, line);
+                t->setString(s);
+                tokens.add(t);
+            }
+            pos--;
+        }
+        else if(isDigit(data[pos]))
+        {
+            int old = pos;
+            pos++;
+            while(pos < length && isDigit(data[pos]))
+            {
+                pos++;
+            }
+            if(pos < length && data[pos] == '.')
+            {
+                pos++;
+                while(pos < length && isDigit(data[pos]))
+                {
+                    pos++;
+                }
+            }
+            string s = data.substr(old, pos - old);
+            try
+            {
+                float f = stof(s);
+                
+                Token* t = new Token(Tokens::FLOAT, line);
+                t->setFloat(f);
+                tokens.add(t);
+            }
+            catch(std::out_of_range ex)
+            {
+                throw Exception("invalid float", line);
+            }
+            catch(std::invalid_argument ex)
+            {
+                throw Exception("invalid float", line);
+            }
+            pos--;
+        }
+        else
+        {
+            switch(data[pos])
+            {
+                case '@':
+                {
+                    int old = pos;
+                    pos++;
+                    while(pos < length && isAllowedInName(data[pos]))
+                    {
+                        pos++;
+                    }
+                    string s = data.substr(old, pos - old);
+                    Token* t = new Token(Tokens::LABEL, line);
+                    t->setString(s);
+                    tokens.add(t);
+                    pos--;
+                    break;
+                }
+                case '"':
+                {
+                    pos++;
+                    int old = pos;
+                    while(pos < length && data[pos] != '"')
+                    {
+                        pos++;
+                    }
+                    string s = data.substr(old, pos - old);
+                    Token* t = new Token(Tokens::TEXT, line);
+                    t->setString(s);
+                    tokens.add(t);
+                    break;
+                }
+                case '/':
+                {
+                    if(pos + 1 >= length)
+                    {
+                        tokens.add(new Token(Tokens::DIV, line));
+                    }
+                    else
+                    {
+                        switch(data[pos + 1])
+                        {
+                            case '/':
+                                pos += 2;
+                                while(pos < length && data[pos] != '\n')
+                                {
+                                    pos++;
+                                }
+                                pos--;
+                                break;
+                            case '*':
+                                pos += 2;
+                                while(pos + 1 < length && (data[pos] != '*' || data[pos + 1] != '/'))
+                                {
+                                    if(data[pos] == '\n')
+                                    {
+                                        line++;
+                                    }
+                                    pos++;
+                                }
+                                pos++;
+                                break;
+                            case '=':
+                                tokens.add(new Token(Tokens::DIV_SET, line));
+                                pos++;
+                                break;
+                            default:
+                                tokens.add(new Token(Tokens::DIV, line));
+                        }
+                    }
+                    break;
+                }
+                case '<': tokenize(tokens, Tokens::LESS, '<', '=', Tokens::LEFT_SHIFT_SET, Tokens::LEFT_SHIFT, '=', Tokens::LESS_EQUAL); break;
+                case '>': tokenize(tokens, Tokens::GREATER, '>', '=', Tokens::RIGHT_SHIFT_SET, Tokens::RIGHT_SHIFT, '=', Tokens::GREATER_EQUAL); break;
+                case '&': tokenize(tokens, Tokens::BIT_AND, '&', Tokens::AND, '=', Tokens::BIT_AND_SET); break;
+                case '|': tokenize(tokens, Tokens::BIT_OR, '|', Tokens::OR, '=', Tokens::BIT_OR_SET); break;
+                case '+': tokenize(tokens, Tokens::ADD, '+', Tokens::INC, '=', Tokens::ADD_SET); break;
+                case '-': tokenize(tokens, Tokens::SUB, '-', Tokens::DEC, '=', Tokens::SUB_SET); break;
+                case '*': tokenize(tokens, '=', Tokens::MUL_SET, Tokens::MUL); break;
+                case '\n': line++; break;
+                case '!': tokenize(tokens, '=', Tokens::NOT_EQUAL, Tokens::INVERT); break;
+                case '%': tokenize(tokens, '=', Tokens::MOD_SET, Tokens::MOD); break;
+                case '=': tokenize(tokens, '=', Tokens::EQUAL, Tokens::SET); break;
+                case '^': tokenize(tokens, '=', Tokens::BIT_XOR_SET, Tokens::BIT_XOR); break;
+                case '~': tokens.add(new Token(Tokens::BIT_INVERT, line)); break;
+                case ',': tokens.add(new Token(Tokens::COMMA, line)); break;
+                case '(': tokens.add(new Token(Tokens::OPEN_BRACKET, line)); break;
+                case ')': tokens.add(new Token(Tokens::CLOSE_BRACKET, line)); break;
+                case '[': tokens.add(new Token(Tokens::OPEN_SQUARE_BRACKET, line)); break;
+                case ']': tokens.add(new Token(Tokens::CLOSE_SQUARE_BRACKET, line)); break;
+                case '{': tokens.add(new Token(Tokens::OPEN_CURVED_BRACKET, line)); break;
+                case '}': tokens.add(new Token(Tokens::CLOSE_CURVED_BRACKET, line)); break;
+                case ';': tokens.add(new Token(Tokens::SEMICOLON, line)); break;
+                case '$': tokens.add(new Token(Tokens::GLOBAL, line)); break;
+                case ' ': break;
+                default: throw Exception(string("invalid token ") + data[pos], line);
+            }
+        } 
+        pos++;
+    }
+    tokens.add(new Token(Tokens::END_OF_FILE, line));
+}

+ 30 - 0
Tokenizer.h

@@ -0,0 +1,30 @@
+#ifndef TOKENIZER_H
+#define TOKENIZER_H
+
+#include <string>
+#include "ArrayList.h"
+#include "Token.h"
+
+using namespace std;
+
+class Tokenizer 
+{
+public:
+    Tokenizer(string s);
+    Tokenizer(const Tokenizer& orig);
+    virtual ~Tokenizer();
+    
+    void tokenize(ArrayList<Token*>& tokens);
+private:
+    string data;
+    int pos;
+    int line;
+    int length;
+    
+    void tokenize(ArrayList<Token*>& tokens, char c, Tokens::Type type1, Tokens::Type type2);
+    void tokenize(ArrayList<Token*>& tokens, Tokens::Type type1, char c2, Tokens::Type type2, char c3, Tokens::Type type3);
+    void tokenize(ArrayList<Token*>& tokens, Tokens::Type type1, char c2, char c3, Tokens::Type type2, Tokens::Type type3, char c4, Tokens::Type type4);
+};
+
+#endif
+

+ 22 - 0
Utils.cpp

@@ -0,0 +1,22 @@
+#include "Utils.h"
+
+bool isLetter(char c)
+{
+    return ('a' <= c && 'z' >= c) || ('A' <= c && 'Z' >= c);
+}
+
+bool isDigit(char c)
+{
+    return '0' <= c && '9' >= c;
+}
+
+bool isLetterOrDigit(char c)
+{
+    return isLetter(c) || isDigit(c);
+}
+
+bool isAllowedInName(char c)
+{
+    return isLetter(c) || isDigit(c) || c == '.' || c == '_';
+}
+

+ 10 - 0
Utils.h

@@ -0,0 +1,10 @@
+#ifndef UTILS_H
+#define UTILS_H
+
+bool isLetter(char c);
+bool isDigit(char c);
+bool isLetterOrDigit(char c);
+bool isAllowedInName(char c);
+
+#endif
+

+ 33 - 0
tests/if.snuvi

@@ -0,0 +1,33 @@
+a = 3.0046
+<<<<=< <=
+>>>>=> >=
+b = 4;
+if(a < b)
+{
+    print(a % b);
+    a %= 3;
+}
+elseif(a == b)
+{
+    print(a);
+    print(" dgfdg dgdfg dgdf");
+}$
+else
+{
+    prin.t(!b);
+}
+@wusi_gdf
+a++;
+a--;
+
+for(i = 3; i <= 4; ++i)
+{
+    print(add(~a + b + i));
+}
+
+i = 5;
+while(i < 20)
+{
+    print(i);
+    i++;
+}