2011-12-08 33 views
8

Tôi có một ngôn ngữ với cú pháp rất giống C++. Các lexer và phân tích cú pháp được đặt ra và sản xuất đúng AST. Đối với phần lớn nhất phụ trợ cũng được thực hiện.Viết trình biên dịch: làm cách nào để lấy các mẫu đơn giản để hoạt động?

Hệ thống cơ bản mà trình biên dịch sử dụng để tạo kiểu rất đơn giản: tất cả các loại được coi là tích hợp và tất cả các phiên bản đều là toàn cầu. Vì vậy, chỉ có một bản đồ đơn giản khớp với tên kiểu cho một phương thức tạo ra một biến số Biến số về cơ bản là một loại chung chung như boost :: any. bản đồ khác với tên của biến như chủ chốt và các biến như giá trị đóng vai trò như phạm vi toàn cầu:

std::map< std::string, std::function< Variable() > typeList; 

    //register some types 
typeList[ "X" ] = Variable::Create<X>; 
typeList[ "Y" ] = CreateInstanceOfY; 
.... 

Khi trình biên dịch được nút AST cho một khởi như X myVar; nó về cơ bản không

std::map< std::string, Variable > globalScope; 
globalScope[ "myVar" ] = typeList[ "X" ](); 

Khi myVar được sử dụng sau này có thể được truy cập bằng cách gửi đơn giản như

X& x = myVar.GetReference<X>(); 

Bây giờ tôi muốn mở rộng một chút và sử dụng các mẫu đơn giản. Giả sử có một loại "mảng" được thực hiện bằng cách sử dụng một vectơ. Tôi có thể đăng ký mọi thứ như

typeList[ "array<X>" ] = Variable::Create< std::vector<X> >; 

nhưng không thể quản lý được vì nó sẽ phải được lặp lại cho tất cả các kết hợp. Lý tưởng nhất là tôi cần chức năng cho phép để viết một cái gì đó như thế này:

typeList.CreateTemplateVariable("array", "X") 

mà sau đó sẽ tạo ra một trường hợp biến mà trong nội bộ tổ chức một std :: vector < X>. Tôi đã cố gắng hết sức nhưng không thể tìm ra cách để làm điều này. Có lẽ tôi vừa mới bắt đầu sai cách với ánh xạ kiểu đơn giản và đó là lý do tôi không thể có được cái đầu xung quanh nó.

Vì vậy, câu hỏi rất đơn giản: có thể thực hiện việc này không? Và làm thế nào?

+0

khi bạn tạo mã c + + từ AST, nó vẫn là trình biên dịch. – belgther

+0

Một chút về thuật ngữ: Trình biên dịch dịch mã từ định dạng này sang định dạng khác.Một thông dịch viên thực hiện một số mã. –

+0

@ JoachimPileborg cảm ơn vì đã chỉ ra điều đó .. Tôi thực sự không giỏi về thuật ngữ. – stijn

Trả lời

2

Tôi không chắc là tôi có vấn đề của bạn đúng, nhưng nếu bạn có M loại tham số (vector<>, list<> ...) và N loại đơn giản (int, double ...), bạn sẽ cần M * N triển khai thực tế nếu bạn muốn hỗ trợ tất cả các kết hợp. Tất cả những việc triển khai này phải được biết ở thời gian biên dịch (hoặc về nguyên tắc bạn có thể gọi trình biên dịch C++ một cách nhanh chóng). Bạn có thực sự muốn điều này?

Giải pháp thay thế có thể là sử dụng vùng chứa không được nhập thay thế. Ví dụ: vector<Object*> lưu trữ con trỏ mà sau đó có thể được chuyển đổi thành loại được yêu cầu, ví dụ: dynamic_cast. Bằng cách này, bạn sẽ chỉ cần triển khai M cho các loại tham số và có thể giải quyết "mảng" thành vector và "X" thành X một cách độc lập.

+0

bạn đúng về M * N, tuy nhiên tốt hơn là nên có một số hệ thống động cũng hỗ trợ hoặc có thể được mở rộng tới, các mẫu lồng nhau và nhiều tham số mẫu. Tôi sẽ xem nếu cách tiếp cận không gõ được tôi một nơi nào đó mặc dù, có vẻ thú vị. – stijn

+0

@stijn, bạn vẫn có thể có mọi thứ được nhập bằng ngôn ngữ của mình, có mẫu và bất kỳ thứ gì khác. Vấn đề phát sinh khi bạn cố gắng ánh xạ các loại từ ngôn ngữ của bạn vào C++ một-một, chẳng hạn như bạn đang cố gắng làm cho "mảng " -> vectơ . Bạn không cần phải làm điều đó, mặc dù - bất cứ điều gì mà trông gõ vào ngôn ngữ của bạn không phải được gõ trong việc thực hiện, ngay sau khi trình biên dịch của bạn không kiểm tra loại. –

1

Nói chung cách bạn làm các kiểu giống như mẫu như bạn mô tả, nhưng thay vì tạo tất cả các kết hợp có thể trước thời hạn, bạn tạo chúng theo yêu cầu. Vì vậy, bạn có thể có một thói quen getType như:

std::function< Variable() > getType(std::string name) { 
    auto rv = typeList[name]; 
    if (rv) return rv; 
    auto template_start = name.find('<'); 
    if (template_start != string::npos) { 
     auto template_end = name.rfind('>'); 
     std::string arg = name.substr(template_start+1, template_end); 
     std::string base = name.substr(0, template_start); 
     typeList[name] = rv = InstantiateTemplate(base, arg); 
     return rv; } 
    throw UnknownTypeError(name); 
} 

này được gọi cho bất kỳ loại đề cập đến trong chương trình, tạo mẫu instantiations cần thiết theo yêu cầu.

+0

cảm ơn cho đầu vào, nhưng phần lớn nhất của hàm của bạn thực sự là những gì mà trình phân tích cú pháp đã làm; hơn nữa nó đệ quy để trình phân tích cú pháp của tôi xử lý các mẫu lồng nhau với các đối số không giới hạn như mảng >> và tạo ra một nút AST có tên TypeSpecifier cho nó. Câu hỏi của tôi là làm thế nào để viết các chức năng 'InstantiateTemplate', tức là làm thế nào để chuyển đổi TypeSpecifier thành một thể hiện thực tế của một loại. – stijn

Các vấn đề liên quan