방금 합류하신 분들을 위해 지난 몇 달 동안 저의”자바 인 심층”칼럼에서 자바로 인터프리터를 구축하는 방법에 대해 논의했습니다. 첫 번째 인터프리터 열에서는 인터프리터의 바람직한 특성 중 일부를 다루었고,두 번째 열에서는 인터프리터를 구현하기 위한 클래스 패키지의 구문 분석 및 레이아웃에 대해 논의했습니다. 이 칼럼에서는 인터프리터 실행과 이를 수행하는 데 필요한 지원 클래스를 살펴보겠습니다. 마지막으로,나는 따라서 자신의 능력을 향상,통역사가 다른 자바 클래스에 중독 될 수있는 방법에 대한 논의와 함께 여기에 시리즈를 마무리합니다.
관련 비트 검토
지금까지 다룬 내용을 스케치하고 실행 모드에 대해 논의 할 때 더 중요해질 디자인의 부분을 지적하겠습니다. 이러한 클래스에 대한 자세한 설명은 아래의
리소스 섹션
에 있는 내 이전 열 또는 소스 코드 링크를 참조하십시오.
인터프리터의 구현에는Program
,Statement
및Expression
의 세 가지 기초 클래스가 있습니다.
프로그램
이
Program
클래스는 파서의 구문 분석 및 실행 구성 요소를 함께 붙입니다. 이 클래스는load
과run
의 두 가지 주요 메서드를 정의합니다.load
메서드는 입력 스트림에서 문을 읽고 문 모음으로 구문 분석하고run
메서드는 컬렉션을 반복하여 각 문을 실행합니다. 또한Program
클래스는 프로그램을 사용할 변수 모음과 데이터를 저장하기 위한 스택을 제공합니다.
문
Statement
클래스에는 구문 분석된 단일 문이 포함됩니다. 이 클래스는 실제로 특정 유형의 문(인쇄,이동,경우 등)으로 서브 클래스되지만 모든 문에는Program
클래스 인스턴스의 컨텍스트에서 문을 실행하기 위해 호출되는 메서드execute
이 포함됩니다.
식
Expression
클래스는 식의 구문 분석 트리를 포함합니다. 실행하는 동안value
메서드는 식을 평가하고 해당 값을 반환하는 데 사용됩니다.Statement
와 마찬가지로Expression
클래스는 주로 특정 유형의 표현식에 의해 하위 클래스되도록 설계되었습니다.
이 모든 클래스는 통역사의 기초를 형성하기 위해 함께 작동합니다. Program
클래스는 구문 분석 작업과 실행 작업을 동시에 캡슐화하는 반면Statement
및Expression
클래스는 구현 한 언어의 실제 계산 개념을 캡슐화합니다. 건물 통역에 이 3 개의 기사를 위해,보기 언어는 계속 기본적 이다.
계산 기능
인터프리터에는 두 개의 실행 가능한 클래스가 있습니다,
Statement
그리고
Expression
. 먼저 살펴 보자
Expression
Expression
의 인스턴스는ParseExpression
클래스의expression
메서드에 의해 만들어집니다. ParseExpression
클래스는 이 인터프리터에서 식 파서를 구현합니다. 이 클래스는statement
메서드를 사용하여 기본 문을 구문 분석하는ParseStatement
클래스의 피어입니다. Expression
의 인스턴스에는 인스턴스가 나타내는 연산자를 식별하는 내부type
와 식의 계산된 값을 반환하는value
과stringValue
의 두 메서드가 있습니다. 또한 식 인스턴스를 만들 때 식 연산의 왼쪽 및 오른쪽을 나타내는 두 개의 매개 변수가 명목상 지정됩니다. 소스 형태로 표시,식의 첫 번째 부분은 다음과 같습니다:
class Expression { Expression arg1, arg2; int oper; final static int OP_ADD = 1; // Addition '+' final static int OP_SUB = 2; // Subtraction '-' final static int OP_MUL = 3; // Multiplication '*' final static int OP_DIV = 4; // Division '/' final static int OP_BNOT = 19; // Boolean negation '.NOT.' final static int OP_NEG = 20; // Unary minus
당신은 위의 코드에서 볼 수 있듯이,인스턴스 변수,운영자라는 연산자 유형 및 아르 또한 식 파서에서 사용하는 두 개의 생성자가 있습니다. 그들의 소스는 다음과 같습니다:
protected Expression(int op, Expression a, Expression b) throws BASICSyntaxError { arg1 = a; arg2 = b; oper = op; /* * If the operator is a boolean, both arguments must be boolean. */ if (op > OP_GE) { if ( (! (arg1 instanceof BooleanExpression)) || (! (arg2 instanceof BooleanExpression)) ) throw new BASICSyntaxError(typeError); } else { if ((arg1 instanceof BooleanExpression) || (arg2 instanceof BooleanExpression)) throw new BASICSyntaxError(typeError); } } protected Expression(int op, Expression a) throws BASICSyntaxError { arg2 = a; oper = op; if ((oper == OP_BNOT) && (! (arg2 instanceof BooleanExpression))) throw new BASICSyntaxError(typeError); }
첫 번째 생성자는 임의의 표현식 개체를 만들고 두 번째 생성자는 단항 마이너스와 같은”단항”표현식 개체를 만듭니다. 한 가지 주목해야 할 점은 인수가 하나만 있으면 값을 저장하는 데 사용되는 것입니다.
Expression
클래스에서 가장 자주 사용되는 메서드는value
이며 다음과 같이 정의됩니다:
double value(Program pgm) throws BASICRuntimeError { switch (oper) { case OP_ADD : return arg1.value(pgm) + arg2.value(pgm); case OP_SUB : return arg1.value(pgm) - arg2.value(pgm); ... etc for all of the other operator types. ...
각 표현식 개체는 연산자와 하나 또는 두 개의 인수로 구성된 튜플을 나타냅니다. 이러한 방식으로 식 실행 엔진을 디자인할 때의 재미있는 부분은Expression
개체를 기반으로 식 튜플 집합을 생성할 때value
메서드를 호출하여 식의 값을 계산할 수 있다는 것입니다. value
메서드는 이 식을 구성하는 두 인수의value
메서드를 재귀적으로 호출하고,이 메서드에 연산을 적용하고,결과를 반환합니다. 이 디자인은 표현을 쉽게 이해할 수 있도록 사용되었습니다.
클래스 구조를 깨끗하게 유지하기 위해 상수에서 삼각 함수에 이르기까지 모든 계산 단위는Expression
의 하위 클래스입니다. 리스프에서 뻔뻔스럽게 도난 당한이 아이디어는 평가가 발생하는”방법”의 실제 구현에서 평가가 발생하는”원인”이라는 개념을 완전히 캡슐화합니다. 이 원리가 어떻게 적용되는지 보여주기 위해Expression
의 특수 하위 클래스 중 일부만 살펴 보겠습니다.
내가 코코아라는 이름의 기본 버전의 상수는Expression
을 서브 클래스하고 단순히 숫자 값을 멤버 값에 저장하는 클래스ConstantExpression
로 표시됩니다. ConstantExpression
에 대한 소스 코드는 개념적으로 아래에 나와 있습니다. 나는StringConstantExpression
과NumericConstantExpression
가 될 것을 단일 클래스로 묶기로 선택했기 때문에”개념적으로”말합니다. 따라서 실제 클래스에는 문자열 인수가 있는 상수를 만들고 해당 값을 문자열로 반환하기 위한 생성자가 포함됩니다. 다음 코드에서는ConstantExpression
클래스가 숫자 상수를 처리하는 방법을 보여 줍니다.
class ConstantExpression extends Expression { private double v; ConstantExpression(double a) { super(); v = a; } double value(Program pgm) throws BASICRuntimeError { return v; }}
위의 코드는Expression
의 더 복잡한 생성자를 인스턴스 변수의 간단한 저장소로 대체합니다.
는Expression
클래스를 코딩하여 생성자에서 클래스를 절약 할 수있는 상수를 받아 들일 수 있다는 사실입니다. 그러나Expression
을 디자인 할 때의 한 가지 이점은Expression
의 코드가 최대한 일반적인 상태로 유지된다는 것입니다. 이 코딩 스타일은 특별한 경우의 복잡성을 제거하는 데 도움이되므로Expression
코드로”완료”될 때 기본 클래스를 반복해서 다시 방문하지 않고 표현식의 다른 측면으로 이동할 수 있습니다. FunctionExpression
이라는Expression
의 또 다른 하위 클래스를 탐구 할 때 이점이 더 명확 해집니다.
수업FunctionExpression
에서는 통역사를 유연하게 유지하기 위해 두 가지 설계 요구 사항을 충족해야한다고 느꼈습니다. 첫 번째는 표준 기본 기능을 구현하는 것이 었습니다; 다른 하나는 함수 인수의 구문 분석을 이러한 함수를 구현한 동일한 클래스로 캡슐화하는 것입니다. 두 번째 요구 사항 인 구문 분석은FunctionExpression
의 하위 클래스로 파서에 전달 될 수있는 추가 함수 라이브러리를 만들어이 기본 확장을 가능하게하려는 욕구에 의해 동기 부여되었습니다. 또한,전달 된 클래스는 파서에 의해 사용자의 프로그램에서 사용할 수있는 함수의 수를 늘리는 데 사용될 수 있습니다.
FunctionExpression
클래스는ConstantExpression
보다 약간 더 복잡하며 아래에 압축 된 형태로 표시됩니다:
1 class FunctionExpression extends Expression { 2 3 double value(Program p) throws BASICRuntimeError { 4 try { 5 switch (oper) { 6 case RND : 7 if (r == null) 8 r = p.getRandom(); 9 return (r.nextDouble() * arg2.value(p));10 case INT :11 return Math.floor(arg2.value(p));12 case SIN :13 return Math.sin(arg2.value(p));14 15 default :16 throw new BASICRuntimeError("Unknown or non-numeric function.");17 }18 } catch (Exception e) {19 if (e instanceof BASICRuntimeError)20 throw (BASICRuntimeError) e;21 else22 throw new BASICRuntimeError("Arithmetic Exception.");23 }24 }
위의 소스는value
메소드가 구현되는 방법을 보여줍니다. 함수 식별을 유지하기 위해 다시 사용되며,함수 자체에 대한 인수로 사용됩니다. 마지막으로 요청을 전달하는 큰 스위치 문이 있습니다. 한 가지 흥미로운 측면은value
방법이 잠재적 인 산술 예외를 포착하고BASICRuntimeError
의 인스턴스로 변환한다는 것입니다. FunctionExpression
의 구문 분석 코드는 아래에 나와 있으며 공간을 절약하기 위해 다시 압축됩니다. (모든 소스 코드는 리소스 섹션의 링크를 사용하여 사용할 수 있습니다.)
1 static FunctionExpression parse(int ty, LexicalTokenizer lt) throws BASICSyntaxError { 2 FunctionExpression result; 3 Expression a; 4 Expression b; 5 Expression se; 6 Token t; 7 8 t = lt.nextToken(); 9 if (! t.isSymbol('(')) {10 if (ty == RND) {11 lt.unGetToken();12 return new FunctionExpression(ty, new ConstantExpression(1));13 } else if (ty == FRE) {14 lt.unGetToken();15 return new FunctionExpression(ty, new ConstantExpression(0));16 }17 throw new BASICSyntaxError("Missing argument for function.");18 }19 switch (ty) {20 case RND:21 case INT:22 case SIN:23 case COS:24 case TAN:25 case ATN:26 case SQR:27 case ABS:28 case CHR:29 case VAL:30 case STR:31 case SPC:32 case TAB:33 case LOG:34 a = ParseExpression.expression(lt);35 if (a instanceof BooleanExpression) {36 throw new BASICSyntaxError(functions.toUpperCase()+" function cannot accept boolean expression.");37 }38 if ((ty == VAL) && (! a.isString()))39 throw new BASICSyntaxError(functions.toUpperCase()+" requires a string valued argument.");40 result = new FunctionExpression(ty, a);41 break; 42 default:43 throw new BASICSyntaxError("Unknown function on input.");4445 }46 t = lt.nextToken();47 if (! t.isSymbol(')')) {48 throw new BASICSyntaxError("Missing closing parenthesis for function.");49 }50 return result;51 }
이 코드는ParseStatement
의 식 파서가 이미 식을 보고 있고 매개 변수 타이로 식의 정체성을 전달했다는 사실을 활용합니다. 이 파서는 여는 괄호와 인수가 포함 된 닫는 괄호 만 찾으면 됩니다. #9~#18 행에서 파서를 사용하면 일부 함수에 인수가 없을 수 있습니다(이 경우 인수 및 인수). 이렇게 하면 모든 함수가 일부 미리 정의된 템플릿을 따르도록 하는 대신 함수 하위 파저를 이 클래스에 내장함으로써 유연성을 얻을 수 있습니다. 매개 변수 타이에 함수 형식이 지정되면 스위치 문은 해당 함수에 필요한 인수(문자열,숫자,기타 식 등)를 구문 분석할 수 있는 분기를 선택합니다.
기타 측면:문자열 및 배열
기본 언어의 다른 두 부분은 코코아 인터프리터에 의해 구현됩니다:문자열 및 배열. 먼저 문자열의 구현을 살펴 보겠습니다.
문자열을 변수로 구현하기 위해Expression
클래스는”문자열”표현식의 개념을 포함하도록 수정되었습니다. 이 수정은isString
과stringValue
의 두 가지 추가 형식을 취했습니다. 이 두 가지 새로운 방법에 대한 소스는 다음과 같습니다.
String stringValue(Program pgm) throws BASICRuntimeError { throw new BASICRuntimeError("No String representation for this."); } boolean isString() { return false; }
분명히 기본 프로그램에서 기본 표현식(항상 숫자 또는 부울 표현식)의 문자열 값을 얻는 것은 너무 유용하지 않습니다. 유틸리티가 부족하여 이러한 메서드가Expression
에 속하지 않고 대신Expression
의 하위 클래스에 속한다고 결론을 내릴 수 있습니다. 그러나 이러한 두 메서드를 기본 클래스에 넣으면 모든Expression
개체를 테스트하여 실제로 문자열인지 확인할 수 있습니다.
또 다른 디자인 방법은StringBuffer
개체를 사용하여 숫자 값을 문자열로 반환하여 값을 생성하는 것입니다. 예를 들어,동일한 코드를 다음과 같이 다시 작성할 수 있습니다:
String stringValue(Program pgm) throws BASICRuntimeError { StringBuffer sb = new StringBuffer(); sb.append(this.value(pgm)); return sb.toString(); }
위의 코드를 사용하는 경우 모든 표현식이 문자열 값을 반환 할 수 있기 때문에isString
의 사용을 제거 할 수 있습니다. 또한value
메서드를 수정하여java.lang.Double
의valueOf
메서드를 통해 식을 실행하여 문자열로 계산하는 경우 숫자를 반환하도록 시도할 수 있습니다. 다음과 같은 많은 언어에서 펄,티클,및 렉스,이런 종류의 비정질 타이핑은 큰 이점에 사용됩니다. 두 가지 방법 모두 유효하며,통역사의 설계에 따라 선택해야 합니다. 기본적으로 인터프리터는 문자열이 숫자 변수에 할당 될 때 오류를 반환해야하므로 첫 번째 접근 방식(오류 반환)을 선택했습니다.
배열에 관해서는,당신이 그(것)들을 해석하기 위하여 당신의 언어를 디자인할 수 있는 다른 방법이 있다. 배열 요소 주위에 대괄호를 사용하여 배열의 인덱스 참조를 인수 주위에 괄호가있는 함수 참조와 구별합니다. 그러나 기본 언어 디자이너는 함수와 배열 모두에 괄호를 사용하기로 선택했기 때문에 구문 분석기에NAME(V1, V2)
텍스트가 표시되면 함수 호출 또는 배열 참조가 될 수 있습니다.
어휘 분석기는 괄호 뒤에 오는 토큰을 먼저 함수라고 가정하고 이를 테스트함으로써 구별합니다. 그때 그것은 그들이 키워드 또는 가변적 이으면 보기 위하여 계속한다. 이 결정은 프로그램이”죄”라는 변수를 정의하지 못하게합니다.”이름이 함수 이름과 일치하는 모든 변수는 어휘 분석기에서 함수 토큰으로 대신 반환됩니다. 어휘 분석기에서 사용하는 두 번째 트릭은 변수 이름 뒤에 바로`(‘이 있는지 확인하는 것입니다. 이 경우 분석기는 배열 참조라고 가정합니다. 어휘 분석기에서이를 구문 분석함으로써 문자열`MYARRAY ( 2 )
‘가 유효한 배열로 해석되는 것을 제거합니다(변수 이름과 열린 괄호 사이의 공백에 유의하십시오).
배열을 구현하는 마지막 트릭은Variable
클래스에 있습니다. 이 클래스는 변수의 인스턴스에 사용되며 지난 달 열에서 설명한 것처럼Token
의 하위 클래스입니다. 그러나,그것은 또한 배열을 지원하는 몇 가지 기계를 가지고 있으며,그것은 내가 아래에 보여 드리겠습니다 것입니다:
class Variable extends Token { // Legal variable sub types final static int NUMBER = 0; final static int STRING = 1; final static int NUMBER_ARRAY = 2; final static int STRING_ARRAY = 4; String name; int subType; /* * If the variable is in the symbol table these values are * initialized. */ int ndx; // array indices. int mult; // array multipliers double nArrayValues; String sArrayValues;
위의 코드는ConstantExpression
클래스에서와 같이 변수와 연결된 인스턴스 변수를 보여줍니다. 하나는 클래스의 복잡성에 비해 사용되는 클래스의 수에 대한 선택을해야합니다. 한 가지 디자인 선택은 스칼라 변수 만 포함하는Variable
클래스를 작성한 다음ArrayVariable
하위 클래스를 추가하여 배열의 복잡한 부분을 처리하는 것입니다. 스칼라 변수를 본질적으로 길이 1 의 배열로 바꾸어 결합하기로 결정했습니다.
위의 코드를 읽으면 배열 인덱스와 승수가 표시됩니다. 기본 다차원 배열은 하나의 선형 자바 배열을 사용하여 구현되기 때문에 이들은 여기에 있습니다. 자바 배열에 선형 인덱스는 승수 배열의 요소를 사용하여 수동으로 계산된다. 기본 프로그램에서 사용되는 인덱스는 인덱스의 최대 법적 인덱스와 비교하여 유효성을 검사합니다.
예를 들어,10,10 및 8 의 세 가지 차원을 가진 기본 배열에는 값 10,10 및 8 이 저장됩니다. 따라서 식 계산기는 기본 프로그램에서 사용된 수를 현재 저장된 최대 법적 수와 비교하여”범위를 벗어난 인덱스”조건을 테스트할 수 있습니다. 이 예제의 승수 배열에는 값 1,10 및 100 이 포함됩니다. 이러한 상수는 다차원 배열 인덱스 사양에서 선형 배열 인덱스 사양으로 매핑하는 데 사용하는 숫자를 나타냅니다. 실제 방정식은 다음과 같습니다:
자바 인덱스=인덱스 1+인덱스 2*인덱스 1+인덱스 3 의 최대 크기*(인덱스 1 의 최대 크기*인덱스 2 최대 크기)
Variable
클래스의 다음 자바 배열이 아래에 나와 있습니다.
Expression expns;
“A(10*B, i)
로 작성된 배열을 처리하는 데 사용됩니다.”이 경우 인덱스는 실제로 상수가 아닌 표현식이므로 참조에는 런타임에 계산되는 표현식에 대한 포인터가 포함되어야합니다. 마지막으로 프로그램에서 전달 된 내용에 따라 인덱스를 계산하는 상당히 못생긴 코드 조각이 있습니다. 이 개인 방법은 다음과 같습니다.
private int computeIndex(int ii) throws BASICRuntimeError { int offset = 0; if ((ndx == null) || (ii.length != ndx.length)) throw new BASICRuntimeError("Wrong number of indices."); for (int i = 0; i < ndx.length; i++) { if ((ii < 1) || (ii > ndx)) throw new BASICRuntimeError("Index out of range."); offset = offset + (ii-1) * mult; } return offset; }
위의 코드를 보면 배열을 참조 할 때 올바른 수의 인덱스가 사용되었는지 확인한 다음 각 인덱스가 해당 인덱스의 법적 범위 내에 있는지 확인합니다. 오류가 감지되면 인터프리터에 예외가 발생합니다. 메서드numValue
및stringValue
은 변수의 값을 각각 숫자 또는 문자열로 반환합니다. 이 두 가지 방법은 다음과 같습니다.
double numValue(int ii) throws BASICRuntimeError { return nArrayValues; } String stringValue(int ii) throws BASICRuntimeError { if (subType == NUMBER_ARRAY) return ""+nArrayValues; return sArrayValues; }
여기에 표시되지 않는 변수 값을 설정하는 추가 방법이 있습니다.
각 조각이 구현되는 방법의 복잡성을 많이 숨김으로써,마침내 기본 프로그램을 실행할 시간이 올 때,자바 코드는 매우 간단합니다.
코드 실행
기본 문을 해석하고 실행하는 코드는
run
의 방법
Program
클래스. 이 메서드의 코드는 아래에 나와 있으며 흥미로운 부분을 지적하기 위해 단계별로 설명합니다.
1 public void run(InputStream in, OutputStream out) throws BASICRuntimeError { 2 PrintStream pout; 3 Enumeration e = stmts.elements(); 4 stmtStack = new Stack(); // assume no stacked statements ... 5 dataStore = new Vector(); // ... and no data to be read. 6 dataPtr = 0; 7 Statement s; 8 9 vars = new RedBlackTree();1011 // if the program isn't yet valid.12 if (! e.hasMoreElements())13 return;1415 if (out instanceof PrintStream) {16 pout = (PrintStream) out;17 } else {18 pout = new PrintStream(out);19 }
위의 코드는run
메서드가 실행 프로그램의”콘솔”으로 사용하기 위해InputStream
과OutputStream
을 사용함을 보여줍니다. 열거형 개체 3 행에서 열거형 개체는 명명된 컬렉션의 문 집합으로 설정됩니다. 이 컬렉션의 경우”빨강-검정”트리라는 이진 검색 트리에 변형을 사용했습니다. 이진 검색 트리에 대한 자세한 내용은 일반 컬렉션 작성에 대한 이전 열을 참조하십시오.)그 다음 두 개의 추가 컬렉션이 생성됩니다-하나는Stack
을 사용하고 하나는Vector
를 사용합니다. 스택은 모든 컴퓨터의 스택처럼 사용되지만 벡터는 기본 프로그램의 데이터 문에 명시 적으로 사용됩니다. 최종 컬렉션은 기본 프로그램에 의해 정의 된 변수에 대한 참조를 보유하는 또 다른 빨강-검정 트리입니다. 이 트리는 프로그램이 실행하는 동안 사용되는 기호 테이블입니다.
초기화 후,입력 및 출력 스트림이 설정되고,만약 전자가 널이 아니라면,선언된 모든 데이터를 수집하는 것으로 시작한다. 이 작업은 다음 코드와 같이 수행됩니다.
/* First we load all of the data statements */ while (e.hasMoreElements()) { s = (Statement) e.nextElement(); if (s.keyword == Statement.DATA) { s.execute(this, in, pout); } }
위의 루프는 단순히 모든 문을 살펴보고 찾은 모든 데이터 문이 실행됩니다. 각 데이터 문을 실행하면 해당 문이 선언한 값이 데이터스토어 벡터에 삽입됩니다. 다 리는 로그램 실,드 다 각 사 료되는:
e = stmts.elements(); s = (Statement) e.nextElement(); do { int yyy; /* While running we skip Data statements. */ try { yyy = in.available(); } catch (IOException ez) { yyy = 0; } if (yyy != 0) { pout.println("Stopped at :"+s); push(s); break; } if (s.keyword != Statement.DATA) { if (traceState) { s.trace(this, (traceFile != null) ? traceFile : pout); } s = s.execute(this, in, pout); } else s = nextStatement(s); } while (s != null); }
다음 단계는 첫 번째 문을 변수에 가져온 다음 실행 루프를 입력하는 것입니다. 이 프로그램의 진행이 프로그램에서 입력하여 중단 할 수 있도록 입력 스트림에 대한 보류중인 입력을 확인하는 몇 가지 코드이며,다음 루프는 실행할 문이 데이터 문이 될 것인지 확인합니다. 이 경우 루프는 이미 실행 된대로 문을 건너 뜁니다. 모든 데이터 문을 먼저 실행하는 다소 복잡한 기술은 기본 읽기 문을 만족하는 데이터 문이 소스 코드의 아무 곳이나 표시 할 수 있기 때문에 필요합니다. 마지막으로 추적이 활성화되면 추적 레코드가 인쇄되고 매우 인상적이지 않은 문s = s.execute(this, in, pout);
가 호출됩니다. 장점은 기본 개념을 이해하기 쉬운 클래스로 캡슐화하는 모든 노력이 최종 코드를 사소한 것으로 만드는 것입니다. 그것이 사소한 것이 아니라면 아마도 당신은 당신의 디자인을 분할하는 또 다른 방법이있을 수 있다는 단서가 있습니다.
마무리 및 추가 생각
인터프리터는 스레드로 실행할 수 있도록 설계되었으므로 프로그램 공간에서 동시에 실행되는 여러 코코아 인터프리터 스레드가 동시에 실행될 수 있습니다. 또한 함수 확장을 사용하여 이러한 스레드가 서로 상호 작용할 수있는 수단을 제공 할 수 있습니다. 이 프로그램은 간단한 기본 파생 언어를 사용하여 프로그래밍 된”로봇”엔티티와 상호 작용하는 시스템이었습니다. 이 게임은 엔터테인먼트의 많은 시간과 함께 저와 다른 사람을 제공뿐만 아니라(실수로 그들은 단지 연주와 학습하지 믿고)어린 학생들에게 계산의 기본 원리를 소개하는 훌륭한 방법이었다. 그들은 어떤 자바 플랫폼에서 즉시 사용할 수 있기 때문에 자바 기반의 인터프리터 서브 시스템은 사전 자바 대응보다 훨씬 더 강력하다. 코코아는 유닉스 시스템과 매킨토시에서 실행 나는 윈도우 95 기반 컴퓨터에서 작업있어 같은 날. 자바는 스레드 또는 창 툴킷 구현의 호환성에 의해 구타되는 동안,무엇 종종 간과하는 것은 이것이다:코드의 많은”그냥 작동합니다.”
척 맥매니스는 현재 인터넷 시장에서 기회를 모색하고 있는 벤처투자 스타트업인 프리게이트(주)의 시스템 소프트웨어 디렉터입니다. 프리게이트에 합류하기 전에 척은 자바 그룹의 일원이었다. 그는 자바그룹에 가입하여 주식회사 퍼스트펀 설립 직후입니다. 그리고 휴대용 운영 체제 그룹(자바의 운영 체제를 담당하는 그룹)의 일원이었습니다. 나중에,첫 번째 사람이 해산되었을 때,그는 머물렀다.자바 플랫폼의 알파 및 베타 버전의 개발을 통해 그룹과 함께. 그는 1995 년 5 월 썬홈페이지의 자바버전 프로그래밍을 할 때 인터넷에서 최초의”올 자바”홈페이지를 만들었다. 또한 디지털 서명을 기반으로 클래스를 스크리닝 할 수있는 자바 클래스 로더 및 자바 버전 용 아크릴 그래픽 라이브러리를 개발했습니다.첫 번째 사람에 합류하기 전에,척은 그가 한 네트워킹 응용 프로그램을 개발,선 소프트의 운영 체제 영역에서 일했다 국정원+의 초기 디자인. 또한,자신의 홈 페이지를 확인하십시오. 이 주제에 대해 자세히 알아보기
- 다음은 위에서 참조한 소스 파일에 대한 링크입니다:
- 상수표현.자바
- 함수 표현.자바
- 프로그램.자바
- 문.자바
- 문자열 표현식.자바
- 변수.자바
- 가변 표현식.자바
- 그리고 여기 있습니다.소스 파일의 압축 파일:
심층.3478> - “드문 리스프”-자바로 작성된 리스프 인터프리터
http://user03.blue.aol.com/thingtone/workshop/lisp.htm - 자바로 작성된 마이크 카울 리쇼의 넷 렉스 통역사
http://www2.hursley.ibm.com/netrexx/ - 유즈넷 기본 자주 묻는 질문의 오래된 사본(그것은 여전히 유용한 정보가 있습니다.)
http://whitworth.me.ic.ac.uk/people/students/djbur/qbasic.htm - 코코아,자바로 작성된 기본 통역사
http://www.mcmanis.com/~cmcmanis/java/javaworld/examples/BASIC.html - 척의 자바 리소스 페이지
http://www.mcmanis.com/~cmcmanis/java/javaworld/ - 자바로 작성된 티클 인터프리터
http://www.cs.cornell.edu/home/ioi/Jacl/
- :
- “자바에서 인터프리터를 만드는 방법,파트 2 구조”
간단한 인터프리터를위한 기초 클래스를 조립하는 트릭. - “자바에서 인터프리터를 구축하는 방법,파트 1 기본 사항”
스크립팅 언어가 필요한 복잡한 응용 프로그램의 경우 자바를 사용하여 인터프리터를 구현하여 모든 자바 앱에 스크립팅 기능을 추가 할 수 있습니다. - “어휘 분석,파트 2 응용 프로그램 빌드”
스트림 토큰 화기 개체를 사용하여 대화 형 계산기를 구현하는 방법. - “어휘 분석 및 자바파트 1”
스트링토케나이저 및 스트링토케나이저 클래스를 사용하여 사람이 읽을 수 있는 텍스트를 기계가 읽을 수 있는 데이터로 변환하는 방법을 학습합니다. - “코드 재사용 및 객체 지향 시스템”
도우미 클래스를 사용하여 동적 동작을 적용합니다. - “자바 1.0.2 의 객체에 대한 컨테이너 지원”
객체를 컨테이너에 넣을 때 쉽게 구성 할 수 있습니다. 이 문서에서는 컨테이너의 디자인 및 구현을 안내합니다. - “자바 클래스 로더의 기초”
자바 아키텍처의 핵심 구성 요소의 기본. - “가비지 수집을 사용하지 않음”
자바 프로그램에서 힙 스 래싱을 최소화하십시오. - “스레드 및 애플릿 및 시각적 컨트롤”
이 시리즈의 마지막 부분은 여러 데이터 채널을 읽는 것을 탐구합니다. - “애플릿에서 통신 채널 사용,3 부”
애플릿 디자인에 비주얼 베이직 스타일 기술을 개발하고 프로세스에서 온도를 변환합니다. - “자바에서 스레드 동기화,2 부”
데이터 채널 클래스를 작성 하 고 클래스의 실제 구현을 보여 주는 간단한 예제 응용 프로그램을 만드는 방법을 알아봅니다. - “자바에서 스레드 동기화”
전 자바 팀 개발자 척 맥매니스는 스레드를 동기화하여 안정적이고 예측 가능한 애플릿 동작을 보장하는 방법을 보여주는 간단한 예제를 안내합니다.