Code Monkey home page Code Monkey logo

apus's Introduction

Build Status

apus

Build

Linux or Mac OS X

$ cmake ./    
$ make

apus's People

Contributors

enghqii avatar namhyung avatar junghyun4425 avatar

Stargazers

Hyun Yi avatar DrJ avatar Herin Chung avatar pikamon avatar Kim Jaehyun avatar  avatar YounJae Lee avatar  avatar Juhong Jung avatar JeongminCha (Everett) avatar

Watchers

James Cloos avatar JeongminCha (Everett) avatar

Forkers

junghyun4425

apus's Issues

coding style 규칙 정하기

기본적으로 google c++ coding style 규칙으로 정하나, 이에 있어서 핵심적인 부분에 대해서 따로 위키에 정리해야 할 필요가 있으므로 coding style 규칙에 대해서 중요하고 빈번하게 마주하게 되는 부분에 대해서 작성할 것.

github 프로젝트에 CI 연동

travis 라던가 뭐든 github와 연동되는 CI 도구가 있으면 우리 프로젝트랑 연동해서 자동으로 빌드 및 테스트를 돌릴 수 있는 환경을 구축하면 좋겠습니다.

data type에 copy가 필요할 거 같네요..

하..ㅠㅠ 모든 경우를 미리 다 재보고 코드를 구현할 수 있었다면 좋았겠지만...
계속해서 새로운 문제가 보이네요

struct A {
s16 a = 5
s16 b = 7
s16 c
s16 d
}
A라고 하는 DataType안에 a,b,c,d라고 하는 DataType이 들어간 형태일겁니다.

원래 저희가 data type table에 primitive type들은 자주 사용되니깐 미리 추가하자는 식으로 구현을 하기로 했었는데요. c랑 d같은 경우 가리키는 DataType 인스턴스가 완전히 똑같아도 문제 없겠습니다만,
a랑 b같은 경우, 같은 타입이면서 primitive임에도 불구하고 초기화 expression이 5와 7로 서로 다릅니다.. 즉, a랑 b는 다른 DataType 인스턴스를 가리켜야 겠죠.

위 예는 간단히 primitive에 대해서 처리한 것이고 예를 들어서
struct B {
struct A aa = {1,2,3,4}
struct A bb = {5,6,7,8}
}
이렇게 짜여진 경우에는 struct A라는 데이터 타입을 복사한 후에 init expression을 다르게 갖는 인스턴스 aa, bb를 새로 만들어야 할 것입니다.

제가 봤을 땐 이런 상황 때문에 아무래도 Copy함수를 만들어야 할 거 같습니다.

VM이 접근할 수 있는 symbol table들을 추가해야 함

  1. data type
  2. variable
  3. function
    에 대해서 심볼 테이블을 추가하애 함
Type: (class) - name: - field_list { - name: - length - offset } - size - read() - print() SymTab (class) - scope - block - 키-값 자료구조 (key = name, value = variable)

cf. Variable (class)

  • name:
  • type:
  • Value:
FunctionTab (class) - scope: - block - 키-값 자료구조 (key = name, value = function)

cf. Function (class)

  • name:
  • arg (Variable list)
  • stmt-list (definition에 대한 것을 갖고 있음)
  • Execute()

'include' 기능 구현

데이터 정의 파일이 여러 개로 분리되어 있을 때 한 파일에서 다른 파일의 내용을 참조할 수 있도록 하는 기능을 구현해야 합니다.

$ cat struct-def.aps
struct abc {
    u8 a = 1
    u8 b
    u8 c
}

$ cat struct-use.aps
include "struct-def.aps"

var abc _abc

common 파일 안에 네임스페이스를 적용해야할것 같습니다.

apus.y 파일 안에서 Expression, Value, Statement 클래스들을 사용해 보기 위해, 아래와 같이 헤더파일을 include시켰습니다.

%code requires {
    #include <ast/value/value.h>
    #include <ast/expression.h>
}

%union {
    int64_t int_val;
    double double_val;
    int char_val;
    char* str_val;

    Expression* a;
}

그랬더니 빌드시 다음과 같은 오류가 발생합니다.

[ 18%] Building CXX object src/CMakeFiles/apus.dir/lex.yy.cc.o
In file included from /Users/enghqii/Workspace/apus/src/apus.l:3:
y.tab.hh:62:5: error: redefinition of enumerator 'U8'
    U8 = 263,
    ^
/Users/enghqii/Workspace/apus/src/../include/common/common.h:16:9: note: previous definition is here
        U8, U16, U32, U64,  // Unsigned Integer
        ^

apus.y에서 %token부분에 U8, U16등의 타입관련 토큰에 대해 선언을 해 놓았기 때문에, yacc에 의해 만들어지는 파일인 y.tab.hh 헤더파일에 이 부분에 대한 선언부가 자동으로 생성됩니다.

common.h에 TypeSpecifier라는 enum안에 미리 U8, U16.. 등을 미리 정의해 놓아서 충돌이 일어난 것입니다.

// apus.y 파일
%token<int_val> U8 U16 U32 U64
%token<int_val> S8 S16 S32 S64
// 자동 생성된 y.tab.hh 파일
/* Token type.  */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
  enum yytokentype
  {
  .
  .
    U8 = 263,
    U16 = 264,
    U32 = 265,
    U64 = 266,
    S8 = 267,
    S16 = 268,
    S32 = 269,
    S64 = 270,
    F32 = 271,
    F64 = 272,
    C8 = 273,
    C16 = 274,
    C32 = 275,
    STR = 276,
    STR8 = 277,
    STR16 = 278,
    STR32 = 279,
.
.
  };

제 생각에는 common안에 있는 선언들을 apus나, apus::common등의 네임스페이스로 감싸는게 좋을것 같습니다.

폴더 디렉토리 구조 체계 수정 요구

@junghyun4425
지금 src폴더 아래에 lex, yacc 파일이 바로 위치하게 되어 있고, 완전 메인에 Makefile이 위치하는 구조인데, 이게 한단계 아래의 하위 디렉토리로 이동하였으면 함.

일단 제가 생각하는 큰 디렉토리는
/gtest_src
/test
/include
/src
와 같이 폴더 체계가 잡히면 좋겠습니다. 1)vm이라던지 2) lex, yacc을 사용하는 부분도 src폴더 아래의 하위계층으로 존재하였으면 좋겠고, 최상위층에 존재하는 make파일이나 CMake파일은 나중에 최종적으로 우리 프로젝트의 실행 파일이 만들어지도록 하는 것이 좀 더 직관적일 거 같습니다.

  1. gtest_src는 gtest.h와 gtest-all.cc 파일이 존재
  2. test폴더 아래에 test를 위한 코드를 추가하면 됩니다.
  3. include폴더 아래에는 헤더파일들이 존재.
  4. src폴더 아래에는 소스코드들이 존재. (소스 코드들 자체도 폴더를 계층화하여 더 자세히 분류할 것)

@namhyung
현재 제가 pull request한 것은 gtest-1.7.0 하위에 있는 필요없는 파일도 다 들어있어서 상당히 비합리적인 부분이 많습니다. 제가 다시 폴더 디렉터리 구조 체계를 제대로 잡아서 다시 pull request하겠습니다.

function call 구현

함수 호출 기능을 구현합니다. 데이터 타입 혹은 변수와 마찬가지로 주어진 이름으로 함수를 찾을 수 있는 테이블이 먼저 필요할 것입니다. 함수 호출은 전달받은 인자를 매개 변수에 넣고 실행하게 되므로 새로운 scope/context에서 실행할 필요가 있겠습니다. 제 생각에는 함수 호출은 Expression의 일종으로 구현되는 것이 맞을 것 같고, Evaluate 시에 함수 호출 결과로 리턴값을 (있다면) 반환해주면 될 것 같습니다.

DataType 이슈

@namhyung
생각을 많이 해봤는데, Copy관련 메서드를 구현하거나 해야 할 것 같습니다.

이유는 배열에 대한 고려 때문입니다.

struct A {
}
struct B {
struct A c
struct A[3] d
}
B에다가 c를 추가하는 경우에야, B->Insert("c", (struct A에 대한 shared ptr))을 하면 될테지만
d를 추가할 경우에는 어떻게 해야 할까요??
map에서는 key-value pair만을 가질 수 있으므로, array에 대한 정보 (array size, dimension list 등)을 가질 공간은 어쩔 수 없이 DataType class 내에 있어야 하며, copy가 반드시 필요하다고 생각되는 부분입니다.
(c와 d가 실질적으로 의미하는 DataType 인스턴스가 다르기 때문에 그런것입니다.)

parser와 vm/ast 클래스 연결

이제 vm이 사용하는 기본 클래스가 어느 정도 완성되었으니 parser와 연결하여 실제 객체를 생성하고 VM에게 넘겨주는 작업을 진행해야 할 것입니다. 작업하면서 빠진 부분은 차차 채워나가야 겠지만 일단 기본적인 예제에서 parser가 파싱을 한 결과로 VM이 실행할 statement들을 생성할 수 있었으면 합니다.

variable 구현

변수를 구현하기 위한 VariableClass를 작성합니다. Variable 클래스는 데이터 타입 정보와 그에 대한 값을 가지고 있어야 할텐데 이를 위해 기존의 DataType 클래스와 Value 클래스를 이용할 수 있을 것입니다. 변수는 초기값을 가질 수 있으니 이에 대한 처리는 물론, 배열이나 구조체에 대한 지원을 위해 내부 표현을 고려해야 합니다.

expression 및 value 구현

VM에서 사용할 자료형 및 그 연산에 대한 클래스를 구현합니다. 최대한 중복되는 코드를 줄이도록 통합하는 것을 목표로 하고, 특히 연산에 대해서 서로 다른 타입의 경우 같은 타입이 되도록 type-promotion을 수행한 후에 해당 타입에 대해서 연산이 이루어지도록 구현해야 할 것입니다.

apus 응용 프로그램 작성

실제로 apus 스크립트를 읽어서 실행할 apus 라는 이름의 툴을 작성합니다. 콘솔 기반으로 동작했으면 하고 다음과 같은 정도의 간단한 옵션을 처리할 수 있었으면 합니다.

$ apus
Usage: apus [options] <binary file>

-h, --help         Print help message
--version          Print version info
-f, --file=FILE    Use FILE as apus script
-v, --verbose      Print detailed message

$ apus -f test.aps  a.out
...

parser: 테스트 코드 생성

이제 gtest가 추가되었으니 parser 동작에 대한 테스트 코드가 추가되어야 할 것 같습니다. 그리고 저번에도 말했듯이 매번 PR을 보내기 전에 해당 작업에 대한 테스트 케이스를 추가하여 누구나 테스트를 통해 코드가 잘 동작한다는 것을 확인할 수 있도록 할 수 있게 되었으면 좋겠습니다.

type reader 구현

바이너리 파일에서 지정한 타입에 대해 데이터를 읽어들일 수 있는 기능을 구현해야 합니다. 기본적으로 primitive type에 대해서 구현을 한 뒤, 이를 사용자가 지정한 데이터 타입 (struct)에 대해서도 동작하도록 확장하는 작업이 필요합니다.

G++ 버전이 4.8이하일때 나오는 빌드 오류

install 스크립트가 아예 없는 버전입니다.

https://travis-ci.org/swmaestro06-apus/apus/builds/75441666

g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
================================

[ 15%] Building CXX object src/CMakeFiles/apus.dir/ast/expression.cpp.o

In file included from /home/travis/build/swmaestro06-apus/apus/src/ast/expression.cpp:1:0:

/home/travis/build/swmaestro06-apus/apus/src/../include/ast/expression.h:54:65: error: expected ‘;’ at end of member declaration

/home/travis/build/swmaestro06-apus/apus/src/../include/ast/expression.h:54:67: error: ‘override’ does not name a type

make[2]: *** [src/CMakeFiles/apus.dir/ast/expression.cpp.o] Error 1

make[1]: *** [src/CMakeFiles/apus.dir/all] Error 2

make: *** [all] Error 2

BNF 수정 및 추가하기

배열 표현에 대한 것. (u8[60] name)
특정 변수가 반드시 특정 상수값을 갖는 것에 대해서 제한을 두는 표현. (c8 name = 'a')

Value: Promote 규칙을 변경해야 할 것같습니다.

기존에는 단순히 '같은 타입인지, 같은 클래스지만 사이즈만 다른건지, 아예 다른 클래스인지' 이렇게 세 가지 경우로 판단했는데, 이것보다 아래의 경우가 더 간단할것 같다고 생각합니다.

  1. (상대방이) 같은 타입일때는 변환하지 않는다.
  2. 숫자 타입(Signed, Char, 그리고 앞으로 추가될 Unsigned 까지)과, 실수(Float) 타입이 만났을때는 무조건 실수 타입에 맞춘다.
  3. 숫자 타입끼리 만났을 경우, 바이트 사이즈가 큰 데이터 타입으로 변환한다. (C32 + S8 => C32, C16 + S64 => S64)
  4. 어떤 타입이든 문자열 타입을 만날경우, 문자열로 변환한다.

위 규칙에 따르면 '문자열 > 실수형 > s정수 = u정수 = 문자' 와 같이, 타입 변환시 우선 순위가 자연스럽게 만들어질 것 같습니다.

Context Chaining을 어떤 방식으로 하는게 좋을까요

현재 변수 테이블을 어디에 둘지 고민중인데, 제 생각은 이렇습니다.

1 . 변수테이블을 VM이 아니라 Context에 둡니다.

2 . Block이나 Function을 실행시킬때 (얘도 Block이죠 사실) 가지고 있는 Context를 그냥 넘겨주지 않고 @namhyung 전에 말씀하신것 처럼 새로운 자식 Context객체를 만들어 넘깁니다.

  • Variable,Function을 검색할때 쓰기 위해 Context::FindVariable(), Context::FindFunction()같은 멤버 함수를 제공해줘야 할것 같습니다. 각 함수들은 부모들을 따라가면서 변수, 함수들을 찾겠죠.

3 . 자식 Context 객체를 만들때 DataTypeTable은 shallow copy, FunctionTable과 Variable Table은 deep copy 각자 빈 테이블을 새로 생성합니다 그리고 부모 Context에 있는 Parameter( shared_ptr Value의 list 타입으로 생각하고 있습니다)에서 부터 값들을 가져와, 현재 Context의 VariableTable에 그 값들을 가지는 Variable객체를 생성해서 넣어줍니다

FunctionExpression에서 위 행동은 parameter passing이 될 것이고, 그냥 블록을 실행할때는 아무 의미 없는 행동이 될겁니다. 그땐 parameter 리스트 사이즈가 0일테니까요.

4 . 블록이 끝날때, 자식 Context에서 부모 Context로 (만약에 있다면) return_value를 가져옵니다. 이것 역시 그냥 block에서는 아무 의미 없을것입니다. FunctionExpression에서는 이 return_value를 Evaluate의 return 값으로 사용합니다.

shared_ptr<Value> FunctionExpression::Evaluate(Context& context) {
    Function func = context->FindFunction(name_);

    // 여기에서 현재 Context에 parameter를 설정합니다.

    func->Execute(context);

    return context.return_value_; 
}

void Block::Execute(Context& context) {

        Context child = context->BlockBegin(); // 여기에서 3. 행동을 합니다.

        for (std::shared_ptr<Statement> stmt : statements_) {
            stmt->Execute(child);

            if (context.GetBreak() || context.GetContinue()
                || context.GetReturn() || context.GetExit()) {

                break;
            }
        }

       child.BlockEnd(); // 여기에서 4. 행동을 합니다.
    }

이쯤 될것 같군요. 이러면 제 생각에는 Block을 고치지 않고 && context 리스트를 구성하면서 && 함수 호출도 할 수 있을것 같습니다.

struct variable 구현

사용자 정의 타입 (struct)을 지원하기 위한 variable/value 타입을 구현합니다. 기존의 DataType을 이용하여 struct 내부에 대한 variable/value 처리를 재귀적으로 할 수 있어야 합니다.

struct foo {
  u8 c
}

struct bar {
  struct foo b
}

var bar a
a.b.c = 1

vm: VM 구조 설계

Apus 언어를 받아들여 실행하기 위해 필요한 virtual machine의 구조를 개략적으로 정의하고 이를 class 형태로 표현한다.

AssignExpression 문법, 클래스 구조 수정.

현재 다른 브랜치를 참고해서 변수부분을 구현하고 있습니다. VarDefStatement와 VariableExpression는 괜찮은데 AssignExpression에서 좀 귀찮은 문제가 나왔습니다.

1 .
apus.y에서
expression : expression assign_operator expression 으로 되어있던것은
expression : value_expression assign_operator expression 으로 수정되어야 할 것 같습니다.

(예상했었던 우선순위 문제는 없었습니다. 항상 대입 연산 규칙이 마지막에 수행됩니다.)

2 .

위 문법대로 수정한다면 AssignExpression는 ValueExpression과 Expression을 가지고 있게됩니다. Expression의 값을 얻어내, ValueExpression이 가리키는 Value에다 SetValue를 해야하는데, 문제는 Evaluate함수 특성상 결과값이 Variable이 아닌 Value라는겁니다. 게다가 그냥 Value도 아니고, Promote와 연산을 거치며 이리저리 복사된값이라 메모리 값을 수정해도 의미가 없을것입니다.

몇가지 생각을 잠깐 해봤는데

첫 번째는 ValueExpression에서 Variable을 Evaluate한 다음에도 보관하고 있던가, 아니면 즉시 계산하던가 해서 GetVariable(Context) 멤버 함수를 제공하게 하고, 이를 AssignExpression에서 사용한다. 이고

두 번째는 그냥 만만한 Context에 보관하는 방법입니다.

어떤 방식이 괜찮을까요, 혹은 다른 방식이 있다면 공유 바랍니다

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.