문제

내일 일을 포함한 작업을 개발하는 파스칼은 같은 컴파일러입니다.나는 모두 함께 작동 하에 최적화 및 코드가 생성됩니다.

또한 것을 배우기 시작하면 빌드 단순한 파서에 대해 다양한 구성되어 있습니다.나는 그러나,정말로 확실하지 않는 방법에 대해 이동하다.플렉스 및 Bison 될 것으로 보인 선택입니다.하지만,그렇지 않습니다 가능하 쓰기 분석을 사용하여 C++또는 C#?나아와 C.

Yacc++지원합 C#지만,그것은 라이센스 하나입니다.내가 찾는 모든 도움을 찾을 수 있습니다.제안이 높게 평가될 것입니다.

도움이 되었습니까?

해결책

C#과 함께 Antlr을 사용할 수 있다고 생각합니다. 나는 그것을 직접 시도한 적이 없지만 (아직) 튜토리얼이 있습니다. 여기 그것은 당신을 올바른 방향으로 가리킬 수 있습니다.

다른 팁

개인적으로, 나는 내 자신의 Lexer와 Parser (LL)를 굴립니다. 다음은 매우 교외 예입니다. 그것은 C ++에 있지만, 당신은 그것을 적응할 수 있기를 바랍니다. 매크로 파스 _higher를 사용하여 많은 코드를 변경하지 않고 다른 우선 순위 수준에서 운영자를 쉽게 삽입 할 수 있습니다.

 // routine to scan over whitespace/comments
void ScanWhite(const char* &pc){
  while(true){
    if(0);
    else if (WHITESPACE(*pc)) pc++;
    else if (pc[0]=='/' && pc[1]=='/'){
      while(*pc && *pc++ != '\n');
    }
    else break;
  }
}
// routine to lex an identifier
bool SeeId(const char* &pc, string sId){
  ScanWhite(pc);
  const char* pc0 = pc;
  if (alpha(*pc)){
    sId = "";
    while(alphanum(*pc)) sId += (*pc++);
    return true;
  }
  pc = pc0;
  return false;
}
// routine to lex a number
bool SeeNum(const char* &pc, double &dNum){
  ScanWhite(pc);
  const char* pc0 = pc;
  if (digit(*pc)){
    dNum = 0;
    while(digit(*pc)) dNum = dNum * 10 + (*pc++ - '0');
    if (*pc == '.'){
      double divisor = 1, frac = 0;
      while(digit(*pc)){
        divisor *= 0.1;
        frac += (*pc++ - '0') * divisor;
      }
      dNum += frac;
    }
    return true;
  }
  pc = pc0;
  return false;
}
// routine to lex some constant word
bool SeeWord(const char* &pc, const char* sWord){
  ScanWhite(pc);
  const char* pc0 = pc;
  int len = strlen(sWord);
  if (strncmp(pc, sWord, len)==0 && !alphanum(pc[len])){
    pc += len;
    return true;
  }
  pc = pc0;
  return false;
}
// routine to lex a single character like an operator
bool SeeChar(const char* &pc, const char c){
  ScanWhite(pc);
  const char* pc0 = pc;
  if (*pc == c){
    pc++;
    return true;
  }
  pc = pc0;
  return false;
}
// primitive expression parser
void ParsePrimitiveExpr(const char* &pc, CNode* &p){
  double dNum;
  char sId[100];
  if (0);
  else if (SeeNum(pc, dNum)){
    p = new CNode(dNum);
  }
  else if (SeeId(pc, sId)){
    // see if its a function call
    if (SeeChar(pc, '(')){
      p = MakeNewFunctionCallNode(sId);
      while(!SeeChar(pc, ')')){
        CNode* p1 = null;
        ParseExpression(pc, p1);
        AddArgumentExprToFunctionCallNode(p, p1);
        SeeChar(pc, ','); /* optional comma separator */
      }
    }
    // otherwise its just a variable reference
    else {
      p = new CNode(sId);
    }
  }
  // handle embedded expressions
  else if (SeeChar(pc, '(')){
    ParseExpression(pc, p);
    if (!SeeChar(pc, ')')) /* deal with syntax error */
  }
}
#define PARSE_HIGHER ParsePrimitiveExpr
// product parser
void ParseProduct(const char* &pc, CNode* &p){
  PARSE_HIGHER(pc, p);
  while(true){
    if (0);
    else if (SeeChar(pc, '*')){
      CNode p1 = null;
      PARSE_HIGHER(pc, p1);
      p = new CNode('*', p, p1);
    }
    else if (SeeChar(pc, '/')){
     CNode p1 = null;
     PARSE_HIGHER(pc, p1);
     p = new CNode('/', p, p1);
   }
   else break;
  }
}
#undef  PARSE_HIGHER
#define PARSE_HIGHER ParseProduct
// sum parser
void ParseSum(const char* &pc, CNode* &p){
  PARSE_HIGHER(pc, p);
  while(true){
    if (0);
    else if (SeeChar(pc, '+')){
      CNode p1 = null;
      PARSE_HIGHER(pc, p1);
      p = new CNode('+', p, p1);
    }
    else if (SeeChar(pc, '-')){
      CNode p1 = null;
      PARSE_HIGHER(pc, p1);
      p = new CNode('-', p, p1);
    }
   else break;
  }
}
#undef  PARSE_HIGHER
// can insert more routines like the above
// to handle move operators
#define PARSE_HIGHER ParseSum
// overall expression parser
void ParseExpression(const char* &pc, CNode* &p){
  PARSE_HIGHER(pc, p);
}

Pascal 스타일의 명령문 구문이 추가되었습니다.

void ParseStatement(const char* &pc){
  char sId[100];
  if(0);
  else if (SeeWord(pc, "begin")){
    while(!SeeWord(pc, "end")){
      ParseStatement(pc);
      SeeChar(pc, ';');
    }
  }
  else if (SeeWord(pc, "while")){
    CNode* p1 = null;
    ParseExpression(pc, p1);
    ParseStatement(pc);
    /* semantics for while statement */
  }
  else if (SeeWord(pc, "if")){
    CNode* p1 = null;
    ParseExpression(pc, p1);
    ParseStatement(pc);
    if (SeeWord(pc, "else")){
      ParseStatement(pc);
    }
    /* semantics for if statement */
  }
  else if (SeeWord(pc, "for")){
    /* you do it */
  }
  // handle assignments and subroutine calls
  else if (SeeId(pc, sId)){
    if(0);
    else if (SeeChar(pc, '=')){
      CNode* p1 = null;
      ParseExpression(pc, p1);
      /* semantics for assignment statement */
    }
    else if (SeeChar(pc, '(')){
      CNode* p = MakeNewFunctionCallNode(sId);
      while(!SeeChar(pc, ')')){
        CNode* p1 = null;
        ParseExpression(pc, p1);
        AddArgumentExprToFunctionCallNode(p, p1);
        SeeChar(pc, ','); /* optional comma separator */
      }
    }
    else {
      /* we have a 1-word statement, which is OK in pascal */
    }
  }
  else {
    /* syntax error */
  }
}

배열 인덱싱, 가변 선언 및 함수 정의에는 여전히 구문이 필요하지만이를 수행하는 방법이 분명하기를 바랍니다.

그의 고전적인 프로그래밍 텍스트에서 알고리즘 + 데이터 구조 = 프로그램, Niklaus wirth는 간단한 파스칼과 같은 언어를 위해 전체 재귀 하강 파서 (Pascal)를 개발합니다.

당신이 Java로 그것을 쓰고 있다면 antlr을 추천합니다. Java로 작성된 멋진 LL (*) 파서 제너레이터입니다. 아마존에는 훌륭한 책이 있습니다.

Bison & Flex는 표준 파서 생성기입니다. C ++에 관심이 있다면 찾았습니다 정신을 부스트하십시오 유용한. 나는 컴파일러만큼 복잡한 것에 대해 그것을 사용한 적이 없습니다. 나는 다른 사람들이 C#과 같은 다른 언어에 대한 흥미로운 제안을 할 것이라고 확신합니다.

실제로 C ++와 함께 Flex & Bison을 사용할 수 있습니다. ~ 안에 이 튜토리얼, 예를 들어, 섹션 5가 그 문제에 전념하고 있음을 알 수 있습니다. Google만이, 많은 예를 찾을 수있을 것입니다.

내가 쓴 XSLT parser 플렉스 및 bison.더 최근에 나가 사용하여 프로젝트 ANTLR,지

은 JFig 어 구문에 효율적이고 명확한(그리고 보다 더 나은 봄이-프레임워크의 XML DSL)?

내가 좋아하는 작업에 ANTLR 더 많은 코드고 Bison.ANTLR 를 둔 당신을 더 높은 수준에서 추상화의 몇 가지 측면에서.어휘의 정의와 문법을 파서 수 있는 모든 파일 하나에.(ANTLR 을 생성하는 토큰 파일입니다.)

주요 항목 중 하나를 정의할 수 있는 트리 grammars.기본적으로 당신이 할 문법 분석을 통해 입력 언어 있는 행동을 다시 작성하여 고도로 최적의 AST 트리 출력(남아있으로 연결된 데이터 구조 메모리에서).당신은 다음을 통과할 수 있는 이 나무는 또 다른 파서에서 정의한 별도의 나무 파서 파일입니다.트리 parser 은 당신이 실제 작업을 수행 활동의 당신이 원하는 항목.

이것은 좋은 방법으로 유지할 수 있습니다 AST 형태와 반복적으로 다시 처리하는것으로 필요한 벗겨 보시려리 하위 노드 프로세스에 대한 기반으로 후반 작업,etc.무언가를 생각 같은 언어로 통역관.대신 루프 및 처리하는 언어로 지상에서,또 다시 수 있습 과정을 통해 그것의 AST 표현입니다.

내 경우 고안했 콩 공장을 하기를 위한 IoC 종속성을 주입입니다.내 콩 공장을 유지 AST 의 콩 설명자의 주위에 있습니다.필요한 경우를 만들(거나 검색하는)새로운 콩 인스턴스,저는 그냥 통과 콩 설명 AST subtree 을 내리 parser-는 결과가 원하는 콩 인스턴스(의 많은 요인에는에서 이동하는 방법을 결정하는 인스턴스를 요청된 콩을 포함하여 다른 모든 콩는 참조되 및/또는 적용하는 다른 특별한 동작을 통해 메타 속).

마지막으로,현재 콩 공장 타겟팅 Java,그러나 내가 원하는 대상 액션스크립트 3 고 있습니다.NET.ANTLR 지원을 위해 하는 것입니다.

언급했듯이,Terrence 파 책을 썼을 사용하는 방법에 대 ANTLR.그것은 작업을 목표로 하는 프로그래머는 무언가를 할 필요가 실용적으로 ANTLR(반대하는 학문적 치료를 피사체의).

이에 따라 원하는 C#을 원하는 경우 의문 Gardens Point GPPG 및 GPLEX를 사용해보십시오.

Lex와 YACC를 사용하면 실제로 C에서 많은 것을 쓰지 않습니다. 법률 YACC와 마찬가지로 자체 언어입니다. 그래서 당신은 Lex와 Parser에 어휘 분석기를 작성합니다. YACC. 그러나 Pascal의 경우 Lex 및 YACC 입력은 이미 사용 가능합니다.

결과 파서와 Lexer에는 C 인터페이스가 있습니다. 그러나 C ++를 포함한 대부분의 언어에는 C 인터페이스를 호출하거나 랩하는 간단한 방법이 있습니다.

나는 그것의 전문가가 아니지만, 위의 모든 것이 Antlr에도 갈 것이라고 확신합니다.

"Pure C ++"(그 의미가 무엇이든)로 수행하도록 요청하는 경우 Boost를 사용하여 살펴보십시오. 영혼. 그래도 톤이 더 많은 작업을 일으키면 이론적 순도의 요점을 실제로 보지 못합니다.

손으로 자신의 렉서스와 파서를 쓰는 것은 실제로 재미 있습니다. Lexer는 둘 다 사용을 정당화 할 수있는 몇 안되는 상황 중 하나입니다. 이동S와 전처리 서. 그러나 피할 수 있다면 Pascal과 같은 본격적인 언어에 대해서는 제안하지 않을 것입니다. 그것은 많은 일이 될 것입니다. 나는 남자 년을 말하고있다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top