MYC 컴 파일 러 소스 코드 생 성
컴 파일 러 가 분석 할 때 emit 류 를 사용 하여 중간 문법 트 리 를 만 들 고 문법 트 리 의 데이터 구조 와 조작 방법 은 iasm 이라는 유형 에서 이 루어 집 니 다. 소스 프로그램의 문법 해석 이 끝 난 후에 Exe 와 Asm 두 가지 유형 이 각각 생 성 된 문법 트 리 를 옮 겨 다 니 며 최종 코드 를 만 듭 니 다.
우 리 는 몇 가지 코드 의 예 를 살 펴 보 겠 습 니 다. 다음 표 의 함수 Parser. program 에서 함수 시작 과 끝 에 각각 prolog 와 epilog 두 함 수 를 호출 했 습 니 다. 이 두 함수 의 목적 은 문법 해석 전후 에 준비 와 마무리 작업 을 수행 하 는 것 입 니 다.컴 파일 과정의 시작 단계 에서. net assembly 의 요구 에 따라 모듈 (module) 과 클래스 (class) 를 만 듭 니 다. c 언어 는 과정 을 대상 으로 하 는 언어 이지 만. net 은 대상 을 대상 으로 하 는 환경 이 므 로 모든 코드 는 하나의 클래스 에 저장 해 야 합 니 다.
public void program()
{
prolog();
while (tok.NotEOF())
{
outerDecl();
}
if (Io.genexe && !mainseen)
io.Abort("Generating executable with no main entrypoint");
epilog();
}
void prolog()
{
emit = new Emit(io);
emit.BeginModule(); // need assembly module
emit.BeginClass();
}
그리고 emit 에서 BeginModule 과 BeginClass 두 함수 의 코드 는 다음 과 같 습 니 다.
public void BeginModule()
{
// Exe module, .net , assembly
// module , C , module ,
// IL module。
exe.BeginModule(io.GetInputFilename());
}
public void BeginClass()
{
// Exe class, ,
// 。
exe.BeginClass(Io.GetClassname(), TypeAttributes.Public);
// , ,
// IL class 。
if (Io.genlist)
io.Out(".class " + Io.GetClassname() + "{\r
");
}
. NET 에 서 는 반사 기술 을 사용 하여 assembly, 유형 과 함 수 를 생 성 할 수 있 습 니 다. 다음 표 는 Exe 류 의 BeginModule 함수 의 소스 코드 입 니 다.
public void BeginModule(string ifile)
{
// .net assembly , appdomain
appdomain = System.Threading.Thread.GetDomain();
appname = getAssemblyName(filename);
// AppDomain.DefineDynamiceAssembly Assembly,
// , , 。 ,.net IronPython
// 。
appbuild = appdomain.DefineDynamicAssembly(appname,
AssemblyBuilderAccess.Save,
Io.genpath);
// .net , module 。
emodule = appbuild.DefineDynamicModule(
filename+"_module",
Io.GetOutputFilename(),
Io.gendebug);
Guid g = System.Guid.Empty;
if (Io.gendebug)
srcdoc = emodule.DefineDocument(ifile, g, g, g);
}
준비 작업 이 끝 난 후에 문법 트 리 를 생 성 할 수 있 습 니 다. 컴 파일 러 는 문법 을 해석 하 는 과정 에서 문법 트 리 에 요 소 를 계속 추가 합 니 다. 예 를 들 어 컴 파일 함수 과정 에서 while 순환 을 처리 하 는 것 을 예 로 들 면 (그 중의 호출 경 로 는:
program -> outerDecl -> declFunc -> blockOuter -> fcWhile
입 니 다.void fcWhile()
{
// il ,
// (label), label
String label1 = newLabel();
String label2 = newLabel();
// , IL IL
CommentHolder(); /* mark the position in insn stream */
// , , ,
// , , label
// ,
emit.Label(label1);
tok.scan();
//
if (tok.getFirstChar() != '(')
io.Abort("Expected '('");
//
boolExpr();
CommentFillPreTok();
// label
emit.Branch("brfalse", label2);
// , blockInner
blockInner(label2, label1); /* outer label, top of loop */
// ,
emit.Branch("br", label1);
// ,
emit.Label(label2);
}
한편, emit 유형 에서 각 방법 은 분 석 된 문법 요 소 를 문법 트 리 에 추가 할 뿐 문법 트 리 의 노드, 데이터 구조 와 조작 방법 은 모두 IAsm 류 에서 정 의 됩 니 다. 다음 표 는 Branch 의 소스 코드 입 니 다.
public void Branch(String s, String lname)
{ // this is the branch source
NextInsn(1);
// Branch
icur.setIType(IAsm.I_BRANCH);
//
icur.setInsn(s);
//
icur.setLabel(lname);
}
프로그램 컴 파일 이 완료 되면 Exe 클래스 와 Asm 클래스 는 각각 문법 트 리 를 옮 겨 다 니 며 최종 결 과 를 생 성 합 니 다. my c 컴 파일 러 의 소스 코드 에서 Parser. declFunc 함 수 는 Emit. IL 함 수 를 호출 하여 프로그램의 생 성 을 완성 합 니 다.
// C , ,
// ,
void declFunc(Var e)
{
#if DEBUG
Console.WriteLine("declFunc token=["+tok+"]
");
#endif
CommentHolder(); // start new comment
//
e.setName(tok.getValue()); /* value is the function name */
// main, - mainseen true
// ,
if (e.getName().Equals("main"))
{
if (Io.gendll)
io.Abort("Using main entrypoint when generating a DLL");
mainseen = true;
}
// , ,
// , ,
//
staticvar.add(e); /* add function name to static VarList */
paramvar = paramList(); // track current param list
e.setParams(paramvar); // and set it in func var
//
localvar = new VarList(); // track new local parameters
CommentFillPreTok();
// prolog, ,this
emit.FuncBegin(e);
if (tok.getFirstChar() != '{')
io.Abort("Expected ‘{'");
//
blockOuter(null, null);
emit.FuncEnd();
// ,
emit.IL();
// IL , LIST IL
if (Io.genlist)
emit.LIST();
emit.Finish();
}
emit. IL 함 수 는 전체 문법 트 리 를 Exe 형식 으로 옮 겨 다 니 며 결과 프로그램 을 만 드 는 것 입 니 다.
public void IL()
{
IAsm a = iroot;
IAsm p;
//
while (a != null)
{
//
switch (a.getIType())
{
case IAsm.I_INSN:
exe.Insn(a);
break;
case IAsm.I_LABEL:
exe.Label(a);
break;
case IAsm.I_BRANCH:
exe.Branch(a);
break;
//
default:
io.Abort("Unhandled instruction type " + a.getIType());
break;
}
p = a;
a = a.getNext();
}
}
그리고 Exe 형식 은 실제 코드 생 성 을 수행 합 니 다. 예 를 들 어 앞의 IL 함수 와 같이 I 를 만 나 고 있 습 니 다.BRANCH 형식의 노드 를 호출 할 때 Exe. Branch 함 수 를 동적 Assembly (DynamicAssemby) 에서 코드 를 생 성 합 니 다.
public void Branch(IAsm a)
{
Object o = opcodehash[a.getInsn()];
if (o == null)
Io.ICE("Instruction branch opcode (" + a.getInsn() + ") not found in hash”);
// ILGenerator IL 。
il.Emit((OpCode) o, (Label) getILLabel(a));
}
그리고 Asm 류 도 비슷 한 방법 으로 IL 소스 코드 를 생 성 한다.
마지막 으로 myc 컴 파일 러 에 도 일부 의미 처리 가 있 습 니 다. 예 를 들 어 앞에서 말 한 함수 호출 시 호출 된 함수 가 정의 되 지 않 으 면 이상 한 상황 을 던 져 야 합 니 다. Parser. statement (즉, 실제 C 문 구 를 컴 파일 하 는 함수) 에 나타 납 니 다.
void statement()
{
Var e;
String vname = tok.getValue();
CommentHolder(); /* mark the position in insn stream */
switch (io.getNextChar())
{
case '(': /* this is a function call */
//
tok.scan(); /* move to next token */
// ,
// , ,
e = staticvar.FindByName(vname); /* find the symbol (e cannot be null) */
emit.Call(e);
//
}
if (tok.getFirstChar() != ';')
io.Abort("Expected ';'");
tok.scan();
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.