ProgramingTip

R은 할당 연산자 인`->`를 정확히 어떻게 구문 분석 할 수 있습니까?

bestdevel 2020. 10. 17. 11:53
반응형

R은 할당 연산자 인`->`를 정확히 어떻게 구문 분석 할 수 있습니까?


그래서 대답은 무엇입니까? 뭐라고 대답할까요? 그래서 대답은 무엇입니까?

제목은 모든 것을 사실입니다. R ->은 모호한 오른쪽 할당 함수 인 어떻게 구문 분석 ?

이것에 잠수하는 나의 일반적인 트릭은 실패했습니다.

`->`

오류 : 개체 ->를 사용할 수 없습니다.

getAnywhere("->")

이름 ->지정된 개체 없습니다.

그리고 우리는 그것을 직접 부를 수 없습니다.

`->`(3,x)

오류 : 기능을 사용할 수 없습니다. "->"

그러나 물론 작동합니다.

(3 -> x) #assigns the value 3 to the name x
# [1] 3

R이 주장을 뒤집는 방법을 알고있는 것처럼 보이지만 위의 접근 방식으로 확실히 문제가 해결 될 것이라고 생각했습니다.

pryr::ast(3 -> y)
# \- ()
#   \- `<- #R interpreter clearly flipped things around
#   \- `y  #  (by the time it gets to `ast`, at least...)
#   \-  3  #  (note: this is because `substitute(3 -> y)` 
#          #   already returns the reversed version)

관리자 일반 할당 연산자와 비교하십시오.

`<-`
.Primitive("<-")

`<-`(x, 3) #assigns the value 3 to the name x, as expected

?"->", ?assignOpsR 언어 정의는 모두 올바른 할당 연산자로 때에있을 것입니다.

그러나 ->사용 방법은 고유 한 것이 있습니다. 함수 / 연산자가 아닙니다 (에 대한 호출 getAnywhere과 직접적으로 `->`마치 것처럼 보임). 그것은 무엇입니까? 완전히 자체 클래스입니까?

" ->R 언어 내에서 해석 및 처리 방법이 완전히 독특합니다 . 암기하고 계속 진행하십시오" 외에 배울 것이 있습니까?


파서의 작동 방식에 대해 전혀 모른다고 말하면서 서문을 시작하겠습니다. 즉, 말로 미루어 보아, gram.y 라인 296은 제 (? YACC) 파서 R의 용도에 할당을 표현하기 위해 다음과 같은 토큰을 정의한다 :

%token      LEFT_ASSIGN EQ_ASSIGN RIGHT_ASSIGN LBB

그런 다음 gram.c의 5140 ~ 5150 행 에서 해당하는 C 코드와 가변합니다.

case '-':
  if (nextchar('>')) {
    if (nextchar('>')) {
      yylval = install_and_save2("<<-", "->>");
      return RIGHT_ASSIGN;
    }
    else {
      yylval = install_and_save2("<-", "->");
      return RIGHT_ASSIGN;
    }
  }

마지막으로 gram.c의 5044 행 에서 시작하여 다음 과 같은 정의가 있습니다 install_and_save2.

/* Get an R symbol, and set different yytext.  Used for translation of -> to <-. ->> to <<- */
static SEXP install_and_save2(char * text, char * savetext)
{
    strcpy(yytext, savetext);
    return install(text);
}

그래서 다시, 파서 제로 경험을 가지고, 보인다 ->->>직접 번역 작업 <-하고 <<-(A)에서 매우 낮은 수준 해석 과정이다.


당신은 파서가 인수를 반대하는 "알고"어떻게 질문에 아주 좋은 지적을 제기하는 ->것을- ->나타납니다 같은 R 고려 테이블에 설치하기 <-때문에 해석 할 수- x -> yy <- x없습니다 x <- y . 제가 할 수있는 최선의 방법은 제 주장을 뒷받침하는 "증거"를 계속 발견하면서 추가 추측을 제공하는 것입니다. 자비로운 YACC 전문가 가이 질문을 우연히 발견하고 약간의 요청을 제공하기 바랍니다. 그래도 숨을 참지 꼭 보겠습니다.

gram.y의 383 및 384으로 행 돌아 가면 앞서 언급 한 LEFT_ASSIGNRIGHT_ASSIGN기호 관련된 구문 분석 논리가 더 많아 보입니다 .

|   expr LEFT_ASSIGN expr       { $$ = xxbinary($2,$1,$3);  setId( $$, @$); }
|   expr RIGHT_ASSIGN expr      { $$ = xxbinary($2,$3,$1);  setId( $$, @$); }

이 미친 구문의 앞면이나 것을 만들 수는 없습니다 두 번째와 세 번째 인수 xxbinary가 WRT LEFT_ASSIGN( xxbinary($2,$1,$3)) 및 RIGHT_ASSIGN( xxbinary($2,$3,$1)) 로 바뀐다는 것을 습니다 .

내 머릿속에서 내가 그리는 것은 다음과 같다.

LEFT_ASSIGN 대본 : y <- x

  • $2 위 나가에서 파서의 두 번째 "인수"입니다. <-
  • $1첫 번째입니다. y
  • $3 세 번째입니다. x

따라서 결과 (C?) 호출은 xxbinary(<-, y, x).

이 논리를 적용 RIGHT_ASSIGNx -> y에 대한 내 이전 추측과 결합 <-->교환하기,

  • $2에서 ->번역 됩니다.<-
  • $1 이다 x
  • $3 이다 y

그러나 결과가 xxbinary($2,$3,$1)대신 xxbinary($2,$1,$3)결과는 그대로 xxbinary(<-, y, x) 입니다.


이것을 조금 더 구축하여 gram.c의 3310 행xxbinary대한 정의가 있습니다 .

static SEXP xxbinary(SEXP n1, SEXP n2, SEXP n3)
{
    SEXP ans;
    if (GenerateCode)
    PROTECT(ans = lang3(n1, n2, n3));
    else
    PROTECT(ans = R_NilValue);
    UNPROTECT_PTR(n2);
    UNPROTECT_PTR(n3);
    return ans;
}

불행하게도 나는 적절한의 정의를 찾을 수 없습니다 lang3(또는 그 변종 lang1, lang2은 R 소스 코드를, 등),하지만 난이와 동기화하는 방법으로 특수 기능 (예 : 문자) 평가에 사용되는 겠지 통역사.


업데이트 파싱 ​​프로세스에 대한 (매우) 제한된 지식을 제공 할 수있는 한 댓글에 추가 질문 중 일부를 해결하려고 노력할 것입니다.

1) 이것이 실제로 이와 같이 작동하는 R의 유일한 객체입니까 ?? (나는 Hadley의 책을 통해 John Chambers의 인용문을 염두에두고 있습니다. "존재하는 모든 것은 객체입니다. 일어나는 모든 것은 함수 호출입니다."이것은 분명히 해당 영역 밖에 있습니다. 이와 같은 다른 것이 있습니까?

첫째, 나는 이것이 그 영역 밖에 있다는 것에 동의합니다. Chambers의 인용문은 R 환경, 즉이 낮은 수준의 구문 분석 단계 이후에 모두 발생하는 프로세스와 관련이 있다고 생각합니다. 그러나 아래에서 조금 더 다루겠습니다. 어쨌든, 제가 찾을 수있는 이런 종류의 행동의 유일한 다른 예는 **연산자 ^입니다. 이것은 더 일반적인 지수 연산자의 동의어입니다 . 올바른 할당과 마찬가지로 **인터프리터에 의해 함수 호출 등으로 "인식"되지 않는 것 같습니다.

R> `->`
#Error: object '->' not found
R> `**`
#Error: object '**' not found 

install_and_save2 C 파서가 사용 하는 유일한 다른 경우이기 때문에 이것을 발견했습니다 .

case '*':
  /* Replace ** by ^.  This has been here since 1998, but is
     undocumented (at least in the obvious places).  It is in
     the index of the Blue Book with a reference to p. 431, the
     help for 'Deprecated'.  S-PLUS 6.2 still allowed this, so
     presumably it was for compatibility with S. */
  if (nextchar('*')) {
    yylval = install_and_save2("^", "**");
    return '^';
  } else
    yylval = install_and_save("*");
return c;

2) 정확히 언제 발생합니까? 나는 replacement (3-> y)가 이미 표현식을 뒤집 었다는 것을 염두에두고 있습니다. 나는 소스에서 YACC를 핑했을 대체가 무엇인지 알아낼 수 없었습니다 ...

물론 나는 여전히 여기서 추측하고 있지만, 그렇다 . 대체 함수substitute(3 -> y) 의 관점에서 를 호출 할 때 표현식은 항상 다음과 같았다고 안전하게 가정 할 수 있다고 생각한다 . 예를 들어 함수는 사용자가 입력 한 것을 완전히 인식하지 못합니다 . , R에서 사용하는 C 함수의 99 %와 마찬가지로 (== ) 의 경우 인수 만 처리합니다 . 이것이 제가 R 환경과 파싱 프로세스를 구분할 때 위에서 언급 한 것입니다. 나는 특별히 파서가 작동하도록 트리거하는 것이 없다고 생각하지만 인터프리터에 입력 한 모든 것이 파싱됩니다. 나는 조금했다 y <- 33 -> ydo_substituteSEXPEXPRSXP3 -> yy <- 3어젯밤 YACC / Bison 파서 생성기 에 대한 더 많은 읽기 , 그리고 내가 이해하는 것처럼 (일명 농장에 베팅하지 마십시오) Bison은 사용자가 정의한 문법 ( .y파일 에서 )을 사용 하여 C로 파서 생성 합니다. 즉, 입력의 실제 구문 분석을 수행하는 C 함수입니다. 차례로, R 세션에 입력 한 모든 것은 먼저이 C 구문 분석 함수에 의해 처리되고, 그런 다음 R 환경에서 수행 할 적절한 작업을 위임합니다 (이 용어는 매우 느슨하게 사용합니다). 이 단계 lhs -> rhs로 변환 얻을 것이다 rhs <- lhs, **^등 ... 예를 들어,이 중 하나에서 발췌 한 것입니다, names.c의 기본 기능의 테이블 :

/* Language Related Constructs */

/* Primitives */
{"if",      do_if,      0,  200,    -1, {PP_IF,      PREC_FN,     1}},
{"while",   do_while,   0,  100,    2,  {PP_WHILE,   PREC_FN,     0}},
{"for",     do_for,     0,  100,    3,  {PP_FOR,     PREC_FN,     0}},
{"repeat",  do_repeat,  0,  100,    1,  {PP_REPEAT,  PREC_FN,     0}},
{"break",   do_break, CTXT_BREAK,   0,  0,  {PP_BREAK,   PREC_FN,     0}},
{"next",    do_break, CTXT_NEXT,    0,  0,  {PP_NEXT,    PREC_FN,     0}},
{"return",  do_return,  0,  0,  -1, {PP_RETURN,  PREC_FN,     0}},
{"function",    do_function,    0,  0,  -1, {PP_FUNCTION,PREC_FN,     0}},
{"<-",      do_set,     1,  100,    -1, {PP_ASSIGN,  PREC_LEFT,   1}},
{"=",       do_set,     3,  100,    -1, {PP_ASSIGN,  PREC_EQ,     1}},
{"<<-",     do_set,     2,  100,    -1, {PP_ASSIGN2, PREC_LEFT,   1}},
{"{",       do_begin,   0,  200,    -1, {PP_CURLY,   PREC_FN,     0}},
{"(",       do_paren,   0,  1,  1,  {PP_PAREN,   PREC_FN,     0}},

당신은 그 알 ->, ->>그리고 **여기에 정의되지 않습니다. 내가 아는 한 <-등의 R 기본 표현식 [은 R 환경이 기본 C 코드와 가장 가까운 상호 작용입니다. 내가 제안하는 것은이 단계의 과정에서 (유효한 R 표현식의 실제 평가를 통해 인터프리터에 설정된 문자를 입력하고 'Enter'를 누르는 것으로부터) 파서가 이미 마법을 사용했다는 것입니다. 일반적으로 할 수있는 것처럼 백틱으로 둘러싸 ->거나 함수 정의를 가져올 수 없습니다 **.

참고 URL : https://stackoverflow.com/questions/34599027/how-exactly-does-r-parse-the-right-assignment-operator

반응형