ساخت زبان برنامه نویسی — آموزش کامل به زبان ساده

۲۶۷۳ بازدید
آخرین به‌روزرسانی: ۲۶ اردیبهشت ۱۴۰۲
زمان مطالعه: ۱۴ دقیقه
ساخت زبان برنامه نویسی — آموزش کامل به زبان ساده

افراد بسیاری با یک یا چند زبان برنامه نویسی آشنایی دارند و ممکن است این ایده به ذهن‌شان خطور کند که چطور می‌توان زبان برنامه نویسی اختصاصی خود را ساخت؟ زبان برنامه نویسی در واقع به هر مجموعه‌ای از قوانینی گفته می‌شود که براساس آن‌ها رشته‌ها به انواع مختلفی از خروجی به صورت کدهای ماشین تبدیل می‌شوند. بنابراین می‌توان با پیاده‌سازی چنین ساز و کاری، نسبت به ساخت زبان برنامه نویسی دلخواه خود اقدام کرد. در این مطلب سعی شده است به‌طور جامع به این پرسش پاسخ داده شود که چگونه زبان برنامه نویسی بسازیم و تا حد امکان تلاش داشته‌ایم تا تمام زوایای ساخت زبان برنامه نویسی را پوشش دهیم.

پیش از آنکه به شرح نحوه ساخت زبان برنامه نویسی بپردازیم و به این پرسش پاسخ دهیم که چگونه زبان برنامه نویسی بسازیم ، ابتدا لازم است بدانیم زبان برنامه نویسی چیست. البته پیش‌تر به‌طور جامع، این سوال در نوشته‌ای مجزا پاسخ داده شده است. بنابراین در این مطلب وارد جزئیات نمی‌شویم و هر چه خلاصه‌تر از مقدمه عبور می‌کنیم.

زبان برنامه نویسی چیست ؟

به‌طور خلاصه، به مجموعه‌ای از قوانین از پیش تعریف شده زبان برنامه نویسی می‌گویند. برای اینکه بتوان از این مجموعه قوانین از پیش تعریف شده بهره برد، لازم است موجودیتی وجود داشته باشد که بتواند آن قوانین را درک کند. چنین موجودیتی در واقع همان کامپایلرها (Compiler)، مفسرها (Interpreter) و سایر موارد هستند. با توجه اینکه مشخص شد ساز و کار زبان برنامه نویسی به چه ترتیب است، حالا می‌توان به این سوال پاسخ داد که چگونه زبان برنامه نویسی بسازیم و لذا در ادامه به این بحث پرداخته‌ایم.

ساخت یک زبان برنامه نویسی جدید

چگونه زبان برنامه نویسی بسازیم ؟

برای ساخت زبان برنامه نویسی ابتدا لازم است مجموعه قوانین زبان مورد نظر خود را تعریف و مشخص کنیم و بعد برای اینکه امکان استفاده از این قوانین فراهم شود، می‌توان به وسیله یکی از زبان‌های برنامه نویسی فعلی، برنامه‌ای را ساخت که بتواند آن قوانین را درک کند و این همان مفسر ما خواهد بود.

در ادامه به‌طور خلاصه به شرح مفهوم کامپایلر و مفسر پرداخته شده است. اگرچه به منظور تبدیل کدهای سطح بالا به زبان ماشین، برای هر یک از این دو روش پیش‌تر مقاله‌هایی جامع در مجله فرادرس منتشر شده‌اند.

کامپایلر چیست ؟

کامپایلر کدهای سطح بالا را به کدهای زبان ماشین تبدیل می‌کند و با این کار پردازنده می‌تواند کدهای ماشین را اجرا کند. کامپایلر C++‎ نمونه و مثالی از یک کامپایلر به حساب می‌آید.

 

مفسر چیست ؟

مفسر خط به خط در طول برنامه پیش می‌رود و هر دستور را اجرا می‌کند.

 

برای درک بهتر اینکه چگونه زبان برنامه نویسی بسازیم در ادامه به آموزش نحوه ساخت یک زبان برنامه نویسی ساده پرداخته شده است.

معرفی فیلم های آموزش برنامه نویسی

فیلم آموزش برنامه نویسی فرادرس

یکی از بهترین شیوه‌های یادگیری مهارت‌های برنامه نویسی استفاده از دوره‌های آموزش آنلاین است. با استفاده از فیلم‌های آنلاین آموزش برنامه نویسی می‌توان در هر مکان و هر زمانی به یادگیری ادامه داد. در وب سایت فرادرس، یکی از جامع‌ترین و کاربردی‌ترین مجموعه دوره‌های آموزش برنامه نویسی تهیه و گردآوری شده است. علاقه‌مندان می‌توانند هر یک از دوره‌های مجموعه برنامه نویسی فراردس را براساس نیاز خود و حوزه‌ای از برنامه نویسی انتخاب که قصد فعالیت در آن را دارند.

در مجموعه آموزش برنامه نویسی فرادرس دوره‌های آموزشی کاربردی و جامعی برای بسیاری از بهترین زبان‌های برنامه نویسی مختلف موجود است. در اکثر این دوره‌ها، آموزش زبان‌های برنامه نویسی از سطح مقدماتی و از صفر آغاز می‌شود و تا سطوح بالاتر ادامه پیدا می‌کند؛ تا جایی که دانشجویان می‌توانند پروژه‌ای آزمایشی را با استفاده از آن زبان پیاده‌سازی کنند. در تصویر فوق تنها تعدادی از دوره‌های موجود در مجموعه آموزش برنامه نویسی فرادرس به عنوان نمونه نشان داده شده‌اند.

  • برای شروع یادگیری برنامه نویسی و دسترسی به همه فیلم های آموزش برنامه نویسی فرادرس + اینجا کلیک کنید.

آموزش ساخت زبان برنامه نویسی بسیار ساده

در این بخش به شرح نحوه ساخت زبان برنامه نویسی بسیار ساده‌ای پرداخته شده است که خروجی‌های سُرخابی رنگی را در کنسول چاپ می‌کند. چون به انگلیسی سرخابی، «Magenta» نامیده می‌شود، بنابراین، به نظر، نام Magenta برای این زبان برنامه نویسی ساده، برازنده است.

ساخت یک زبان برنامه نویسی بسیار ساده

در ساخت این زبان برنامه نویسی ساده، متغیری به نام codes  ایجاد می‌شود. این متغیر حاوی متنی است که در کنسول با استفاده از این زبان برنامه نویسی جدید به نام Magneta چاپ خواهد شد.

مراحل ساخت زبان برنامه نویسی ساده Magneta

در این بخش برای ساخت زبان برنامه نویسی ساده به نام فرضی Magneta از Node.js (جاوا اسکریپت) استفاده شده است، اما می‌توان با همین روش از هر زبان برنامه نویسی دیگری هم استفاده کرد. ابتدا باید فایلی با نام index.js را ساخته و تنظیمات لازم را در آن ذخیره کرد.

1class Magenta {
2  constructor(codes) {
3    this.codes = codes
4  }
5  run() {
6    console.log(this.codes)
7  }
8}
9
10// For now, we are storing codes in a string variable called `codes`
11// Later, we will read codes from a file
12const codes = 
13`print "hello world"
14print "hello again"`
15const magenta = new Magenta(codes)
16magenta.run()

کاری که اینجا انجام شده این است که کلاسی به نام Magneta اعلان یا تعریف شده است. این کلاس شیئی را تعریف و مقداردهی اولیه می‌کند که مسئولیت ثبت متن‌هایی را در کنسول بر عهده دارد که برنامه نویس با استفاده از متغیری به نام codes  برایش فراهم می‌کند. فعلاً به‌طور موقت متغیر codes  مستقیماً در فایلی تعریف شده است که داخلش تعدادی پیام «Hello» وجود دارد.

زبان برنامه نویسی ساخته شده با Node.js

اگر کدهایی که تا اینجا نوشته شده است را اجرا کنیم، متن ذخیره شده در متغیر codes  در داخل کنسول نوشته می‌شود. حالا باید چیزی را ساخت که به آن Lexer می‌گویند.

Lexer چیست ؟

برای پاسخ به این پرسش، بهتر است ابتدا لحظه‌ای به زبان انگلیسی رجوع شود. مثلاً می‌توان عبارت زیر را در زبان انگلیسی در نظر گرفت:

How are you?

در جمله یا عبارت فوق، کلمه «How» یک قید به حساب می‌آید و «you» ضمیر است. علاوه‌بر این، یک علامت سوال (؟) هم در انتها وجود دارد. در جاوا اسکریپت می‌توان هر جمله یا عبارتی مثل عبارت فوق را به تعداد زیادی از اجزای گرامری تقسیم کرد. یک راه دیگر برای تشخیص این بخش‌ها این است که آن‌ها را به توکن‌های (نشانه | علامت) کوچکی تقسیم کنیم. برنامه‌ای که متن را به توکن‌ها تقسیم می‌کند Lexer نامیده می‌شود.

Lexer در ساخت زبان برنامه نویسی چیست

با توجه به اینکه زبان برنامه نویسی ساخته شده در این بخش از این مطلب بسیار کوچک و خلاصه است، تنها ۲ نوع توکن بیشتر تخواهیم داشت که هر یک دارای ۲ مقدار زیر است:

  1. keyword   (کلمه کلیدی)
  2. string   (رشته)

این امکان وجود داشت که از «عبارت منظم» (Regular Expression) برای استخراج توکن‌ها از رشته codes  استفاده کنیم، اما در این صورت، عملکرد برنامه بسیار کند می‌شد. یک رویکرد بهتر این است که پیمایش در هر یک از کاراکترهای رشته code  با استفاده از حلقه انجام شود و توکن‌ها استخراج شوند. بنابراین لازم است متدی با نام فرضی tokenize  در کلاس Magenta ایجاد شود که به عنوان Lexer عمل خواهد کرد. تمام کدهای کلاس Magneta  در ادامه آمده است:

1class Magenta {
2  constructor(codes) {
3    this.codes = codes
4  }
5  tokenize() {
6    const length = this.codes.length
7    // pos keeps track of current position/index
8    let pos = 0
9    let tokens = []
10    const BUILT_IN_KEYWORDS = ["print"]
11    // allowed characters for variable/keyword
12    const varChars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_'
13    while (pos < length) {
14      let currentChar = this.codes[pos]
15      // if current char is space or newline,  continue
16      if (currentChar === " " || currentChar === "n") {
17        pos++
18        continue
19      } else if (currentChar === '"') {
20        // if current char is " then we have a string
21        let res = ""
22        pos++
23        // while next char is not " or n and we are not at the end of the code
24        while (this.codes[pos] !== '"' && this.codes[pos] !== 'n' && pos < length) {
25          // adding the char to the string
26          res += this.codes[pos]
27          pos++
28        }
29        // if the loop ended because of the end of the code and we didn't find the closing "
30        if (this.codes[pos] !== '"') {
31          return {
32            error: `Unterminated string`
33          }
34        }
35        pos++
36        // adding the string to the tokens
37        tokens.push({
38          type: "string",
39          value: res
40        })
41      } else if (varChars.includes(currentChar)) {
42        let res = currentChar
43        pos++
44        // while the next char is a valid variable/keyword charater
45        while (varChars.includes(this.codes[pos]) && pos < length) {
46          // adding the char to the string
47          res += this.codes[pos]
48          pos++
49        }
50        // if the keyword is not a built in keyword
51        if (!BUILT_IN_KEYWORDS.includes(res)) {
52          return {
53            error: `Unexpected token ${res}`
54          }
55        }
56        // adding the keyword to the tokens
57        tokens.push({
58          type: "keyword",
59          value: res
60        })
61      } else { // we have a invalid character in our code
62        return {
63          error: `Unexpected character ${this.codes[pos]}`
64        }
65      }
66    }
67    // returning the tokens
68    return {
69      error: false,
70      tokens
71    }
72  }
73  run() {
74    const {
75      tokens,
76      error
77    } = this.tokenize()
78    if (error) {
79      console.log(error)
80      return
81    }
82    console.log(tokens)
83  }
84}

اگر کدها را در یک ترمینال با دستور node index.js  اجرا کنیم، باید فهرستی از توکن‌ها در کنسول چاپ شوند.

چاپ توکن ها در کنسول از مراحل ساخت زبان برنامه نویسی

تعریف قوانین و سینتکس ها در ساخت زبان برنامه نویسی

در ساخت زبان برنامه نویسی لازم است بررسی شود آیا ترتیب کدهای نوشته شده از نوعی قاعده نحوی یا سینتکس تبعیت می‌کند یا خیر، اما ابتدا باید آن قوانین و سینتکس‌ها تعریف شوند. چون زبان Magneta زبان خیلی کوچکی است، تنها یک سینتکس یا قاعده نحوی ساده دارد که آن همه کلمه کلیدی print  است که به دنبال آن یک رشته می‌آید.

1keyword:print string

حالا لازم است متدی با نام فرضی parse  ایجاد شود که با استفاده از حلقه در توکن‌ها پیمایش می‌کند تا تعیین کند آیا سینتکس معتبری شکل گرفته است یا خیر. اگر این چنین باشد، اقدامات لازم انجام خواهند شد.

1class Magenta {
2  constructor(codes) {
3    this.codes = codes
4  }
5  tokenize(){
6    /* previous codes for tokenizer */
7  }
8  parse(tokens){
9    const len = tokens.length
10    let pos = 0
11    while(pos < len) {
12      const token = tokens[pos]
13      // if token is a print keyword
14      if(token.type === "keyword" && token.value === "print") {
15        // if the next token doesn't exist
16        if(!tokens[pos + 1]) {
17          return console.log("Unexpected end of line, expected string")
18        }
19        // check if the next token is a string
20        let isString = tokens[pos + 1].type === "string"
21        // if the next token is not a string
22        if(!isString) {
23          return console.log(`Unexpected token ${tokens[pos + 1].type}, expected string`)
24        }
25        // if we reach this point, we have valid syntax
26        // so we can print the string
27        console.log('x1b[35m%sx1b[0m', tokens[pos + 1].value)
28        // we add 2 because we also check the token after print keyword
29        pos += 2
30      } else{ // if we didn't match any rules
31        return console.log(`Unexpected token ${token.type}`)
32      }
33    }
34  }
35  run(){
36    const {tokens, error} = this.tokenize()
37    if(error){
38      console.log(error)
39      return
40    }
41    this.parse(tokens)
42  }
43}

به این ترتیب اکنون ساخت زبان برنامه نویسی به اتمام رسیده است و این زبان به درستی کار می‌کند.

تست زبان برنامه نویسی ساخته شده

تا اینجا همه چیز رو‌به‌راه است، اما اینکه بخواهیم کدها را در یک متغیر رشته‌ای داشته باشیم، چندان جذاب و جالب نیست. بنابراین، بهتر است کدهای زبان برنامه نویسی Magneta را در فایلی به نام code.m.‎ ذخیره کنیم. با این کار می‌توان کدهای Magneta را از منطق کامپایلر جدا کرد.

از عبارت « .m  » به عنوان پسوند فایل استفاده می‌کنیم تا مشخص شود که این فایل حاوی کدهای مربوط به زبان برنامه نویسی ساخته شده‌ی ما است. کدهای مربوط به این فایل در ادامه آمده است.

1// importing file system module
2const fs = require('fs')
3//importing path module for convenient path joining
4const path = require('path')
5class Magenta{
6  constructor(codes){
7    this.codes = codes
8  }
9  tokenize(){
10    /* previous codes for tokenizer */
11 }
12  parse(tokens){
13    /* previous codes for parse method */
14 }
15  run(){
16    /* previous codes for run method */
17  }
18}
19
20// Reading code.m file
21// Some text editors use rn for new line instead of n, so we are removing r
22const codes = fs.readFileSync(path.join(__dirname, 'code.m'), 'utf8').toString().replace(/r/g, "")
23const magenta = new Magenta(codes)
24magenta.run()

جمع‌بندی ساخت زبان Magneta

در این بخش از این مطلب، ساخت زبان برنامه نویسی کوچکی به نام Magneta از صفر تا انتها با موفقیت انجام شد. مشخص شد که ساخت زبان برنامه نویسی می‌تواند به سادگی زبانی باشد که تنها می‌تواند یک وظیفه ساده را انجام دهد. البته بسیار غیر محتمل است که زبان بسیار ساده و ابتدایی مثل Magneta به اندازه کافی کاربردی و مفید باشد تا بتوان از آن در یک فریمورک توسعه نرم‌افزار یا چیزی شبیه به آن استفاده کرد. اما با ساخت Magneta تقریباً مشخص شد که برای ساخت زبان برنامه نویسی چه مراحلی باید طی شوند.

ساخت زبان برنامه نویسی هیچ حد و مرزی ندارد و اگر قصد دارید در این زمینه بیشتر بدانید و وارد این حوزه شوید، می‌توانید از دوره آموزشی زیر استفاده کنید و آشنایی بیشتری با طراحی و پیاده‌سازی زبان‌های برنامه نویسی بدست آورید.

برای ساخت زبان برنامه نویسی چه چیزهایی را باید یاد بگیریم؟

بسیاری از افراد در خصوص زبان برنامه نویسی مورد استفاده خود دچار چالش‌ها و مشکلاتی می‌شوند. برخی می‌خواهند در سطح انتزاع بالاتری کدنویسی کنند، برخی از سایر افراد هم از پیاده‌سازی ویژگی‌ها و قابلیت‌هایی ناخشنود هستند که استاندارد نیستند و ترجیح می‌دهند این امکانات به صورت استانداردسازی شده در دسترس آن‌ها قرار داشته باشند.

آموزش ساخت زبان برنامه نویسی

چه فردی یک متخصص IT باشد یا تنها به عنوان سرگرمی در زمینه برنامه نویسی فعالیت می‌کند، در بسیاری از مواقع افراد تصمیم می‌گیرند ساخت زبان برنامه نویسی جدیدی را شروع کنند. بنابراین در این بخش به مواردی اشاره شده است که برای ساخت زبان برنامه نویسی مورد نظر خود باید یاد بگیریم و انجام دهیم.

  • آشنایی با فناوری کامپیوتر: اگر ندانیم چطور از کامپیوتر استفاده کنیم، قطعاً امکان ساخت زبان برنامه نویسی خود را هم نخواهیم داشت.
  • آشنایی با اصطلاحات مربوط به ساخت زبان برنامه نویسی: سازندگان کامپایلر اغلب از اصطلاحات نا‌آشنایی استفاده می‌کنند. بنابراین بهتر است پیش از شروع ساخت زبان برنامه نویسی در خصوص کامپایلرها مطالعه کافی انجام شود و باید مطمئن شویم همه آنچه لازم است را می‌دانیم.
  • مشخص کردن اینکه با ساخت زبان برنامه نویسی مورد نظر چه مشکل و مسئله‌ای قرار است حل شود؟ آیا زبان برنامه نویسی مربوطه مسئله‌ای مختص حوزه‌ای خاص را هدف قرار می‌دهد؟ یا اینکه زبان برنامه نویسی که می‌خواهیم بسازیم زبانی همه‌منظوره به حساب می‌آید و در حوزه‌ها و زمینه‌های بسیاری قابل استفاده است؟
  • تفکر پیرامون معناشناسی زبان برنامه نویسی که می‌خواهیم بسازیم و مفاهیم آن
  • تفکر راجع به برخی از وظایف خاصی که یک فرد ممکن است بخواهد با زبان برنامه نویسی ساخته شده اجرا کند: مثلاً ممکن است فردی بخواهد رباتی را برای دنبال کردن خطوط هدایت کند یا ممکن است فرد دیگری بخواهد با زبان ساخته شده برنامه دسکتاپ قابل حملی را بسازد یا با آن برنامه‌های کاربردی تحت وب بسازد.
  • فعالیت و آزمون و خطا در زمینه ایده‌های مرتبط با سینتکس برای هر یک از مثال‌هایی که در مورد قبل به آن‌ها اشاره شد.
  • نوشتن گرامر رسمی برای سینتکس زبان برنامه نویسی که می‌خواهیم بسازیم.
  • تصمیم‌گیری در خصوص اینکه آیا زبان برنامه نویسی ما قرار است مفسری باشد یا کامپایلری؟ این یعنی در دنیای مفسرها، برنامه نویس معمولاً برنامه را در یک کد ادیتور ویرایش و سپس آن را مستقیماً در یک مفسر اجرا می‌کند؛ این در حالی است که در دنیای کامپایلرها، برنامه نویس برنامه را ویرایش می‌کند، پس از آن کامپایل برنامه را انجام می‌دهد و فایل اجرایی حاصل شده در جایی ذخیره و سپس اجرا می‌شود.
  • نوشتن اسکنر فرانت‌اند و تجزیه‌گر (Parser) یا پیدا کردن ابزاری برای کمک به این کار: همچنین لازم است برای چگونگی هشدار دادن کامپایلر/مفسر به برنامه نویس راجع به برنامه‌های خطادار و اشتباهات سینتکسی هم چاره‌ای اندیشیده شود.
  • استفاده از اطلاعات تجزیه‌گر برای نوشتن کدهای شی یا ایجاد بازنمایی و نمایشی حد واسط: باید با استفاده از تجزیه‌گر یک AST (درخت سینتکس انتزاعی) ساخته شود، سپس باید کدهای شی خود را از روی AST با استفاده از کدهای آدرس یا برادر بزرگ‌تر آن، SSA بسازیم؛ پس از آن لازم است جدول نمادها برای تعریف توابع، متغیرهای سراسری و سایر موارد ایجاد شود.
    • همچنین، بسته به ویژگی‌ها و قابلیت‌های زبان برنامه نویسی خود، ممکن است بخواهیم جدول‌های اشاره‌گر مجازی یا جدول‌های اطلاعات را برای کلاس‌های خود بسازیم (با هدف پشتیبانی از بازتاب یا RTTI).
  • نوشتن اجرا کننده یا تولید کننده کد که همه چیز را با یکدیگر ترکیب خواهد کرد.
  • نوشتن چندین برنامه آزمایشی برای تست کردن زبان برنامه نویسی ساخته شده:
    • باید برنامه‌هایی را با زبان برنامه نویسی جدید بسازیم که بر گرامر رسمی زبان ما تاکید کنند تا مشخص شود آیا کامپایلر هر چیزی را می‌پذیرد که در تعریف وجود دارد و هر چیزی که خارج از آن است را رد می کند یا خیر.
  • باید در نظر بگیریم که برنامه نویس چگونه قرار است برنامه خودش را دیباگ (عیب‌یابی) کند.
  • نوشتن کتابخانه استاندارد در صورتی که نیاز باشد زبان برنامه نویسی که می‌خواهیم بسازیم از آن استفاده کند؛ همچنین در صورت لزوم نیاز به ساخت «بازیافت‌کننده زباله» (Garbage Collector) یا سایر قابلیت‌ها و ویژگی‌های زمان اجرا نیز وجود دارد.
    • خصوصاً اگر کامپایلر می‌نویسیم، به کدهایی نیاز خواهیم داشت که سیستم‌عامل آن‌ها را برای شروع اجرای کدهای برنامه نویس اجرا خواهد کرد (مثلاً کدهایی که برای تخصیص تمام متغیرهای سراسری مورد نیاز هستند).
  • انتشار زبان برنامه نویسی خود به همراه مشخصه‌های آن و ارائه برخی مثال‌هایی از آنچه می‌توان در آن انجام داد.
    • نباید فراموش کرد که چگونه می‌توان با کتابخانه‌ها و زبان‌های فعلی ادغام‌سازی انجام داد و اینکه چگونه از قابلیت‌های «زمان اجرا» (Runtime) و کتابخانه استاندارد بهره برد.

برای ساخت زبان برنامه نویسی در خصوص معناشناسی یا Semantics باید چه مواردی را در نظر بگیریم؟

در بخش قبل در پاسخ به این سوال که چگونه زبان برنامه نویسی بسازیم به این مسئله اشاره شد که در ساخت زبان برنامه نویسی لازم است راجع به معناشناسی زبان خود و مفاهیم آن بیاندیشیم و تدابیر لازم را برای آن اتخاذ کنیم. برخی از این موارد در ادامه فهرست شده‌اند:

  • آیا قرار است امکان دسترسی مستقیم اشاره‌گر فراهم شود یا خیر؟
  • انواع داده‌ زبان برنامه نویسی ما چه خواهند بود؟
  • آیا قرار است زبانی با تخصیص و تعیین نوع ایستا بسازیم یا پویا؟
  • مدل مدیریت حافظه به چه شکل خواهد بود؟ آیا قرار است از بازیافت زباله استفاده شود یا مدیریت حافظه به صورت دستی انجام خواهد شد؟ (اگر از جمع‌آوری زباله استفاده شود، باید آماده نوشتن آن باشیم یا می‌توان از بازیافت زباله آماده‌ای که قبلاً نوشته شده استفاده کرد).
  • «همزمانی» (Concurrency) چگونه قرار است مدیریت شود؟ آیا قرار است از مدل نخ‌بندی/قفل کردن یا چیزی پیچیده‌تر از آن مثل Linda یا مدل actor استفاده شود؟ (چون امروزه کامپیوترها دارای چندین هسته هستند)
  • آیا قرار است تابع‌های اصلی و اولیه در زبان ما وجود داشته باشد یا همه چیز از طریق کتابخانه قابل استفاده خواهد بود؟
  • رویکرد یا پارادایم زبان برنامه نویسی که می‌خواهیم بسازیم چیست؟ آیا زبان برنامه نویسی ما تابعی خواهد بود یا شی‌گرا؟ آیا مثل جاوا اسکریپت مبتنی بر پیش‌نمونه (Prototype) است؟ آیا زبانی جنبه‌گرا (Aspect Oriented) خواهد بود؟ آیا قالب‌محور (Template-Oriented) است یا پارادایم کاملاً جدیدی را ارائه خواهد کرد؟
  • زبان برنامه نویسی مربوطه چگونه قرار است با کتابخانه‌ها و زبان‌های فعلی (مثلاً زبان C) ارتباط بگیرد؟ این نکته خصوصاً زمانی بیشتر اهمیت پیدا می‌کند که قصد ساخت «زبان برنامه نویسی مختص دامنه» (Domain Specific Language) وجود داشته باشد.

مراحل ساخت زبان برنامه نویسی چیست؟

بهتر است زبانی که با آن زبان جدیدی می‌سازیم شی‌گرا باشد. ساخت هر زبان برنامه نویسی مراحل و گام‌های متعددی را از کدهای منبع گرفته تا فایل اجرایی نهایی شامل می‌شود. در هر یک از این مراحل، داده‌های دریافتی به روش خاصی قالب‌بندی می‌شوند که در ادامه به این روش‌ها پرداخته شده است:

  1. تجزیه و تحلیل لغوی (lexical Analysis): به بیان ساده به تقسیم کدهای منبع در قالب توکن‌ها گفته می‌شود. هر توکن می‌تواند حاوی واژگان متفاوتی باشد:
    • کلمه کلیدی
    • شناساگر/متغیر
    • عملگری با مقدار متناظرش
    • سایر موارد
  2. تحلیل‌گر سینتکس یا تجزیه-تحلیل تجزیه کننده (Parser) فهرستی از توکن‌های ورودی را به درخت سینتکس انتزاعی (Abstract Syntax Tree) یا همان AST تبدیل می‌کند که به این وسیله امکان ارائه قوانین زبان ما فراهم خواهد شد. این فرایند به خودی خود نسبتاً آسان است، چرا که می‌توان آن را در نگاه اول دید، اما با افزایش ساختارهای زبانی (Language Construction) این این روند می‌تواند بسیار پیچیده‌تر شود.
  3. پس از آنکه AST ساخته شد، می‌توان کدها را تولید کرد. کدها معمولاً به صورت بازگشتی با استفاده از یک درخت سینتکس انتزاعی تولید می‌شوند. در طول تجزیه و تحلیل نحوی، کامپایلر گزاره‌‌هایی (عبارت‌هایی | Statement) را به منظور سادگی تولید خواهد کرد.

در ساخت یک زبان برنامه نویسی ساده چه قابلیت هایی تعبیه خواهند شد؟

در ادامه هر یک از قابلیت‌هایی فهرست شده‌اند که برای ساخت زبان برنامه نویسی ساده باید پیاده‌سازی شوند:

  1. تخصیص‌دهی متغیرها (عددی، منطقی و متنی)
  2. اعلان و تعریف ساختارها (Structures)، ایجاد «نمونه‌ها» (Instance) و فیلدهای دسترسی
  3. اجرای عملیات ساده ریاضی (مثل جمع، تفریق و NOT)
  4. چاپ متغیرها، مقادیر و عبارت‌های پیچیده‌تر با عملگرهای ریاضی
  5. خواندن مقادیر عددی، منطقی و متنی از کنسول
  6. اجرای عبارت‌های if-then

مثالی از کدهای یک زبان برنامه نویسی ساخته شده با جاوا

در این زیربخش، مثالی از کدهای آن ارائه شده است. سینتکس این زبان، ترکیبی از سینتکس پایتون و روبی است.

1struct Person
2    arg name
3    arg experience
4    arg is_developer
5end
6
7input your_name
8input your_experience_in_years
9input do_you_like_programming
10
11person = new Person [your_name your_experience_in_years do_you_like_programming == "yes"]
12print person
13
14if person :: is_developer then
15
16    person_name = person :: name
17    print "hey " + person_name + "!"
18
19    experience = person :: experience
20
21    if experience > 0 then
22        started_in = 2022 - experience
23        print "you had started your career in " + started_in
24    end
25
26end

جمع‌بندی

در این نوشته به این موضوع پرداخته شد که چگونه زبان برنامه نویسی بسازیم و نحوه ساخت زبان برنامه نویسی به‌طور جامع شرح داده شد. آموزش ساخت یک زبان برنامه نویسی ساده با جاوا اسکریپت (Node.js) نیز در این مطلب ارائه شد و سایر نکات مهم پیرامون ساخت زبان برنامه نویسی نیز شرح داده شدند. امید است این مقاله مفید واقع شود.

بر اساس رای ۱۵ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
CSS-TRICKSwikiHow
۲ دیدگاه برای «ساخت زبان برنامه نویسی — آموزش کامل به زبان ساده»

“آموزش ساخت یک زبان برنامه نویسی ساده با جاوا (Node.js) نیز در این مطلب ارائه شد”

سلام ، اینجا نیاز به اصلاح کوچک دارد ! خیلی ممنون

با سلام و احترام؛

صمیمانه از همراهی شما با مجله فرادرس و ارائه بازخورد سپاس‌گزاریم.

این مورد اصلاح شد.

برای شما آرزوی سلامتی و موفقیت داریم.

نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *