전공과목 정리/프로그래밍언어론

[프로그래밍언어론📐] 4장 변수 및 유효범위

최연재 2025. 8. 29. 23:23

출처 : 프로그래밍 언어론 : 원리와 실제 (창병모, 인피니티북스, 2021)

 

4.1 변수 선언

1) 변수 선언과 유효범위

- 변수 선언 : 사용 전 선언

- 변수의 유효범위 (scope) : 선언된 변수가 유효한(사용될 수 있는) 프로그램 내의 범위/영역

- 정적 유효범위(Static scope) 규칙

  • 선언된 이름은 선언된 블록 내에서만 유효함
  • 대부분의 언어에서 표준 규칙으로 사용됨

2) 변수 선언

- 변수 id는 <type>타입 변수이며 초기화가 가능하다.

- 변수 id는 지역 변수로 유효범위는 선언된 블록 내이다.

<stmt> → ... | let <decls> in <stmts> end;
<decls> → {<type> id [=<expr>];}

 

3) 블록의 중첩

- let 블록 내의 문장 S에 다시 let 블록이 나타날 수 있다.

 

4) 언어 S의 전역 변수

- 지역 변수 : let문 내에서 선언된 변수

- 전역 변수 : let문 밖에서 선언된 변수

 

5) 타입 없는 변수 선언

- 동적 타입 언어 (dynamically typed language)

  • 변수의 타입을 선언하지 않고 바로 사용
  • 변수에 어떤 타입의 값이든지 서장 가능
  • Lisp/Scheme, JavaScript, Python 등

 

4.2 블록 구조 언어

1) 블록

- 블록 

  • 서로 연관된 선언문과 실행문들을 묶어놓은 프로그래밍 단위
  • 블록은 변수나 함수를 선언하는 선언문들과 실행문들로 구성됨

- 블록을 나타내는 기호

  • 중괄호 : C
  • begin-end : Ada
  • 프로시저 또는 함수 : C, Pascal 등

2) 블록 구조 언어

- 블록의 중첩을 허용하는 언어

- 대형 프로그램을 여러 블록으로 나눠 작성 ➡️ 복잡한 수행 내용을 단순화하며 프로그램의 해독성을 높여줌.

- 프로그램의 오류 발생 ➡️ 범위가 블록 단위로 한정되므로 수정이 쉬워짐.

- 블록의 첨가, 수정, 삭제 등이 용이

- 블록 내에 선언된 변수들은 그 안에서만 유효하며 실행이 종료되면 기존에 선언되었던 변수들은 모두 무효화됨.

- 사용자로 하여금 변수의 사용과 기억장소의 할당에 대한 경계를 명확히 할 수 있음.

 

3) C언어의 유효범위 규칙

- 핵심 아이디어

  • 사용 전 선언
  • 선언의 유효범위는 선언된 지점~선언된 블록 끝까지.

- 지역 변수의 유효 범위 : 선언된 지점 ~ 함수 끝까지

- 전역 변수의 유효 범위 : 선언된 지점 ~ 파일 끝까지

 

4.3 변수의 상태와 의미

1) 변수의 의미

- 변수 : 메모리 위치(주소)를 나타내는 이름 

- 대입문의 예

  • x = x + 1;

- 오른쪽 변수 x의 의미 : 메모리 위치에 저장된 값 (r-value) 

- 왼쪽 변수 x의 의미 : 메모리 위치 (l-value) 

 

2) 상태

- 상태 (state) : 변수들의 현재 값

- 모든 가능한 상태들의 집합 

  • State = Identifier → Value

- 상태 s에서 변수 값 : s(x)

- 상태 갱신 : s' = s[y ↦  v]

  • s'(x) = s(x) if x != y
  • s'(x) = v if x == y

3) 수식

- 상태에서 수식의 값

- V(State, Expr) → Value

 

4) 문장의 의미

- 문장 S의 의미

  • 문장 S가 상태 s를 후상태 s'으로 변경시킨다.
  • 상태 변환

- 상태 변환 함수 (state transform function)

  • Eval : (State, Statement) → State
  • Eval(s, S) = s' for each statement S

- 의미론

  • 각 문장 S마다 상태 변환 함수 정의
  • 프로그램의 실행 과정을 상태 변환 과정으로 설명

 ex)

  • 대입문 id = E
    • Eval(s, id) = s[id ↦ V(s, E)]
  • 복합문 S;S
    • Eval(s, S1;S2) = Eval(Eval(s, S1), S2)

4.4 변수의 유효범위 관리

1) 블록 구조를 위한 상태 관리

- 블록 시작을 만났을 때 

  • 블록 내에 선언된 변수는 유효해짐
  • 선언된 변수에 대한 상태 정보를 새로 생성

- 블록 내 문장을 만났을 때

  • 유효한 변수들의 상태 정보를 이용해서 문장들을 해석(실행)

- 블록 끝을 만났을 때

  • 블록 내의 선언된 변수들은 더 이상 유효하지 않음
  • 블록 내의 선언된 변수들의 상태 정보를 제거

- 상태(state)를 스택(stack) 형태로 유지 관리

 

4.5 구현

1) 상태 구현

- 상태 구현 : 변수의 값을 나타내는 <변수 이름, 값> 쌍들의 집합으로 표현

class Pair {
   Identifier id;
   Value val;
   
   Pair (Identifier id, Value v) {
     this.id = id;
     this.val = v;
   }
}

 

- 스택의 형태로 유지 관리

class State extends Stack<Pair> {
    // 
}

 

2) 수식의 값 계산

Value V(Expr e, State state) {
    if (e instanceof Value) 
        return (Value) e;

    if (e instanceof Identifier) {
        Identifier v = (Identifier) e;
        return (Value)(state.get(v));
 }

    if (e instanceof Binary) {
        Binary b = (Binary) e;
        Value v1 = V(b.expr1, state);
        Value v2 = V(b.expr2, state);
        return binaryOperation (b.op, v1, v2); 
    }

    if (e instanceof Unary) {
        Unary u = (Unary) e;
        Value v = V(u.expr, state);
        return unaryOperation(u.op, v); 
    }
}
Value binaryOperation(Operator op, Value v1, Value v2) {
    switch (op.val) {
    case "+":
        return new Value(v1.intValue() + v2.intValue());
    // ...
    }
}

 

3) 대입문 실행

State Eval(Assignment a, State state) {
    Value value = V(a.expr, state);
    return state.set(a.id, value);
}

 

4) let 문 실행

State Eval(Let l, State state) {
    State s = allocate(l.decls, state);
    s = Eval(l.stmts,s);
    return free(l.decls, s);
}

 

 

5) let 블록 실행

- allocate 함수

  • State allocate (Decls ds, State state) { ... }
  • 선언된 변수들을 위한 엔트리들을 상태에 추가
  • 엔트리 추가 함수 : State push(Identifier id, Value val)

- free 함수

  • State free (Decls ds, State state) { ... }
  • 선언된 변수들의 엔트리를 상태에서 제거

 

6) 전역 변수 선언

State Eval(Command c, State state) {
    if (c instanceof Decl) {
        Decls decls = new Decls();
        decls.add((Decl) c);
        return allocate(decls, state);
    }

    if (c instanceof Stmt)
        return Eval((Stmt) c, state);
}