سؤال

بعد إنشاء شجرة التحليل ، لا بد لي من ملء جدول الرموز الآن.

لا بد لي من تخزين المعلومات مثل

النوع والنطاق والإزاحة وما إلى ذلك للمعرفات.

الآن كيف أعرف نوع ونطاق المعرفات ، لأن كل ما أعرفه هو قيمة المعجم ورقم السطر لهذا المعرف المعين (بعد التحليل المعجمي).

كيف حصلت على كل شيء.شكرا.

هل كانت مفيدة؟

المحلول

الآن كيف أعرف نوع ونطاق المعرفات ، لأن كل ما تعرف هو قيمة ليكسيم ورقم السطر لهذا المعرف معين (بعد التحليل المعجمي).

كما ذكر إجب ، تحتاج إلى خطوة من خلال شجرة تحليل.يجب إنشاء شجرتك بحيث يمكنك إجراء اجتياز بالترتيب ، وزيارة كل عقدة بنفس الترتيب الذي يتم فيه تقييم عبارات وتعبيرات التعليمات البرمجية المصدر.يجب أن تتوافق عقد الشجرة أيضا مع بنية لغة معينة ، على سبيل المثال. WhileStmtNode, MethodDeclNode, ، إلخ.

لنفترض أنني بناء الجدول رمز ، يخطو بشكل متكرر من خلال شجرة ، ولقد دخلت للتو عقدة الجسم الأسلوب.قد يكون لدي شيء مثل ما يلي:

public void doAction(MethodBodyNode methodBody) {
    currScope = 2;
    methodBody.getExpr().applyAction(this);
    currScope = 2;
}

وأظل متغير عالمي لإدارة النطاق.في كل مرة أدخل كتلة حيث يتغير النطاق ، كنت زيادة currScope.وبالمثل ، فما استقاموا لكم فاستقيموا الحفاظ على currClass و currMethod المتغيرات لتخزينها مع اسم الرمز والنوع والإزاحة وما إلى ذلك.لمراحل لاحقة.

تحديث:

أقول الآن ، وأنا عبور الشجرة ، في كل مرة جئت عبر معرف ط سيتعين عليك إدخال القيمة إلى جدول الرموز مع النوع, نطاق وغيرها ، ويقول لنطاق أتحقق مما إذا جئت عبر ' {'أو اسم الوظيفة ، ولكن كيف أعرف نوع المعرف هذا.

يجب أن تحتوي كل عقدة شجرة على جميع المعلومات اللازمة للبناء بأكمله.إذا كنت تستخدم مولد محلل ، مثل كوب أو البيسون ، يمكنك تحديد كيفية بناء الشجرة في الإجراءات النحوية.على سبيل المثال.

variableDeclaration::= identifier:i identifier:i2 SEMICOLON {: RESULT = new VarDeclNode(i, i2, null); :};
identifier::= ID:i {: RESULT = new IdNode(i.getLineNum(), i.getCharNum(), i.getStringValue()); :};

تلك المنتجات سوف تتطابق Foo f; وإلحاق عقدة إعلان متغير إلى الشجرة.تقوم هذه العقدة بتغليف عقدتين للمعرف تحتوي على رقم السطر ورقم الحرف وقيمة السلسلة للمعجم.عقدة المعرف الأولى هي النوع والثاني هو اسم المتغير. ID هو رمز المحطة الطرفية التي تم إرجاعها بواسطة ليكسر عند مطابقة معرف.أفترض أنك على دراية بهذا إلى حد ما.

public class VarDeclNode extends StmtNode {

    private IdNode id;
    private IdNode type;
    private ExprNode expr;

    public VarDeclNode(IdNode id, IdNode type, ExprNode expr) {
        super();
        this.id = id;
        this.type = type;
        this.expr = expr;
    }

}

عندما كنت قد حصلت على شجرة بناء الجملة مع العقد مثل هذا ، كنت قد حصلت على كل ما تحتاجه من معلومات.

2 تحديث:

لا يهم ما إذا كنت تستخدم محلل مخصص أو واحد تم إنشاؤه ، فهناك نقطة واحدة مميزة حيث يمكنك إضافة عقدة إلى الشجرة عند مطابقة الإنتاج.ولا يهم اللغة التي تستخدمها.ج الهياكل سوف تفعل ما يرام.

إذا كان غير محطة لديه معلومات كاسم نونترمينالس ، وإذا كان هو محطة أي.رمز مميز ، ثم المعلومات في الرمز المميز أي.قيمة ليكسيم, يتم تخزين اسم الرمز المميز ورقم السطر

يجب أن يكون لديك عقد متخصصة في الشجرة ، على سبيل المثال.كلاسنود ، تيبينود ، ميثودديكلنود ، إفستمتنود ، إكسبرنود.لا يمكنك فقط تخزين نوع واحد من العقدة ووضع غير المحطات الطرفية والمحطات الطرفية فيه.يتم تمثيل غير الطرفية كعقدة شجرة ، وليس هناك معلومات أخرى لتخزين حول هذا الموضوع بجانب الأجزاء التي يتكون منها ، والتي هي عموما غير المحطات نفسها.لن تخزن أي معلومات رمزية.هناك فقط ولكن عدد قليل من الحالات حيث كنت في الواقع تخزين قيمة سلسلة ليكسيم:لمعرف ولسلسلة/منطقية / عدد صحيح حرفي.

إلقاء نظرة على هذا مثال.خلال التخفيض الأول عندما S يتم تقليله إلى (S + F), ، يمكنك إلحاق ParenExprNode إلى جذر الشجرة.يمكنك أيضا إلحاق AddExprNode كطفل من ParenExprNode.يجب أن يكون هذا المنطق مشفرا في المحلل اللغوي الخاص بك عند تطبيق تخفيض بالقاعدة 2 من القواعد.

الشجرة:

    ExprNode (root)
       |
  ParenExprNode
       |
   AddExprNode
   /         \
ExprNode   ExprNode

الرمز:

struct ExprNode { void* exprNode; };
struct ParenExprNode { void* exprNode; };
struct AddExprNode { void* op1, * op2; };
struct IdNode { char* val; int line; int charNum; };
struct IntLiteralNode { int val; int line; int charNum; };

void reduce_rule_2(ExprNode* expr) {

    //remove stack symbols

    //create nodes
    struct ParenExprNode* parenExpr = malloc(sizeof(struct ParenExprNode));
    struct AddExprNode* addExpr = malloc(sizeof(struct AddExprNode));
    addExpr->op1 = malloc(sizeof(struct ExprNode));
    addExpr->op2 = malloc(sizeof(struct ExprNode));

    //link them
    parenExpr->exprNode = (void*)addExpr;
    expr->exprNode = (void*)parenExpr;
}

في الخطوة التالية ، تتم إزالة القوس الأيسر من الإدخال.بعد ذلك, S على رأس المكدس ويتم تقليله إلى F بموجب القاعدة 1.منذ F هو غير الطرفية لمعرف ، انها ممثلة من قبل IdNode.

الشجرة:

    ExprNode
       |
  ParenExprNode
       |
   AddExprNode
   /         \
ExprNode   ExprNode
   |
 IdNode

الرمز:

reduce_rule_2(addExpr->op1);

void reduce_rule_1(ExprNode* expr) {
    //reduce stack symbols
    struct IdNode* id = malloc(sizeof(struct IdNode));
    id->val = parser_matched_text();
    id->lineNum = parser_line_num();
    id->charNum = parser_char_num();
    expr->exprNode = (void*)id;
}

وهلم جرا...

نصائح أخرى

كل ما أعرفه هو قيمة Lexeme ورقم الخط لهذا المعرف المعين

هذا ليس صحيحا.أنت تعرف أين يتم الإعلان عن تحليل شجرة، والتي تخبرك بكل ما تحتاجه.تقوم بهذه الخطوة بواسطة معالجة تحليل شجرة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top