From 349646171a966aba3926735baad83a8ea7d4d08e Mon Sep 17 00:00:00 2001 From: liulinboyi <814921718@qq.com> Date: Sat, 27 Feb 2021 13:33:16 +0800 Subject: [PATCH] feat: Add Function && RETURN --- README.md | 4 + demo/hello-world-5.pineapple | 8 ++ dist/src/lexer1.js | 33 +++++++- dist/src/parser.js | 9 ++- dist/src/parser/Assignment.js | 12 ++- dist/src/parser/Expression.js | 44 +++++++++++ dist/src/parser/Function.js | 136 ++++++++++++++++++++++++++++++++ dist/test/test.js | 2 +- src/lexer1.ts | 38 +++++++++ src/parser.ts | 10 ++- src/parser/Assignment.ts | 12 ++- src/parser/Expression.ts | 43 ++++++++++ src/parser/Function.ts | 142 ++++++++++++++++++++++++++++++++++ test/test.js | 2 +- 14 files changed, 483 insertions(+), 12 deletions(-) create mode 100644 demo/hello-world-5.pineapple create mode 100644 dist/src/parser/Expression.js create mode 100644 dist/src/parser/Function.js create mode 100644 src/parser/Expression.ts create mode 100644 src/parser/Function.ts diff --git a/README.md b/README.md index fe0be9f..60d0b6d 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,10 @@ Comment ::= Ignored "#" SourceCharacter // 注释 BinaryExpression::= (Variable | Number) Ignored Operator Ignored (Variable | Number) Operator ::= "+" | "-" | "*" | "/" BinaryExpressions ::= (BinaryExpression Operator)+ Ignored (Variable | Number) // eg: 1: (2 + 1 +) 3 2: ((2 + 1 +) (5 + 6 -)) 3 +FunctionDeclaration ::= "func" Ignored Name Ignored "(" Variable ("," Variable)* ")" BlockStatement // eg: 1: func foo ($a) {} 2: func foo ($a[,$b][,$c]) {} ("," Variable)*这部分是一个或多个 +BlockStatement ::= "{" Ignored ReturnStatement Ignored "}" +ReturnStatement ::= "return" BinaryExpression +CallFunction ::= Name "(" (Variable | Number) ("," (Variable | Number))* ")" Ignored ``` diff --git a/demo/hello-world-5.pineapple b/demo/hello-world-5.pineapple new file mode 100644 index 0000000..585f794 --- /dev/null +++ b/demo/hello-world-5.pineapple @@ -0,0 +1,8 @@ + +func add($a,$b) { + return $a + $b +} + +$res = add(1,2) + +print($res) diff --git a/dist/src/lexer1.js b/dist/src/lexer1.js index 9de2b15..1108f09 100644 --- a/dist/src/lexer1.js +++ b/dist/src/lexer1.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.NewLexer = exports.Lexer = exports.tokenNameMap = exports.keywords = exports.Operator = exports.SourceCharacter = exports.COMMENT = exports.STRING = exports.NUMBER = exports.INTERGER = exports.TOKEN_IGNORED = exports.TOKEN_PRINT = exports.TOKEN_NAME = exports.TOKEN_DUOQUOTE = exports.TOKEN_QUOTE = exports.TOKEN_EQUAL = exports.TOKEN_RIGHT_PAREN = exports.TOKEN_LEFT_PAREN = exports.TOKEN_VAR_PREFIX = exports.TOKEN_EOF = exports.Tokens = void 0; +exports.NewLexer = exports.Lexer = exports.tokenNameMap = exports.keywords = exports.TOKEN_FUNC_PARAMS_DIV = exports.TOKEN_RETURN = exports.BLOCK_END = exports.BLOCK_START = exports.TOKEN_FUNC = exports.Operator = exports.SourceCharacter = exports.COMMENT = exports.STRING = exports.NUMBER = exports.INTERGER = exports.TOKEN_IGNORED = exports.TOKEN_PRINT = exports.TOKEN_NAME = exports.TOKEN_DUOQUOTE = exports.TOKEN_QUOTE = exports.TOKEN_EQUAL = exports.TOKEN_RIGHT_PAREN = exports.TOKEN_LEFT_PAREN = exports.TOKEN_VAR_PREFIX = exports.TOKEN_EOF = exports.Tokens = void 0; // token const var Tokens; (function (Tokens) { @@ -20,8 +20,13 @@ var Tokens; Tokens[Tokens["COMMENT"] = 13] = "COMMENT"; Tokens[Tokens["SourceCharacter"] = 14] = "SourceCharacter"; Tokens[Tokens["Operator"] = 15] = "Operator"; + Tokens[Tokens["TOKEN_FUNC"] = 16] = "TOKEN_FUNC"; + Tokens[Tokens["BLOCK_START"] = 17] = "BLOCK_START"; + Tokens[Tokens["BLOCK_END"] = 18] = "BLOCK_END"; + Tokens[Tokens["TOKEN_RETURN"] = 19] = "TOKEN_RETURN"; + Tokens[Tokens["TOKEN_FUNC_PARAMS_DIV"] = 20] = "TOKEN_FUNC_PARAMS_DIV"; // , })(Tokens = exports.Tokens || (exports.Tokens = {})); -exports.TOKEN_EOF = Tokens.TOKEN_EOF, exports.TOKEN_VAR_PREFIX = Tokens.TOKEN_VAR_PREFIX, exports.TOKEN_LEFT_PAREN = Tokens.TOKEN_LEFT_PAREN, exports.TOKEN_RIGHT_PAREN = Tokens.TOKEN_RIGHT_PAREN, exports.TOKEN_EQUAL = Tokens.TOKEN_EQUAL, exports.TOKEN_QUOTE = Tokens.TOKEN_QUOTE, exports.TOKEN_DUOQUOTE = Tokens.TOKEN_DUOQUOTE, exports.TOKEN_NAME = Tokens.TOKEN_NAME, exports.TOKEN_PRINT = Tokens.TOKEN_PRINT, exports.TOKEN_IGNORED = Tokens.TOKEN_IGNORED, exports.INTERGER = Tokens.INTERGER, exports.NUMBER = Tokens.NUMBER, exports.STRING = Tokens.STRING, exports.COMMENT = Tokens.COMMENT, exports.SourceCharacter = Tokens.SourceCharacter, exports.Operator = Tokens.Operator; +exports.TOKEN_EOF = Tokens.TOKEN_EOF, exports.TOKEN_VAR_PREFIX = Tokens.TOKEN_VAR_PREFIX, exports.TOKEN_LEFT_PAREN = Tokens.TOKEN_LEFT_PAREN, exports.TOKEN_RIGHT_PAREN = Tokens.TOKEN_RIGHT_PAREN, exports.TOKEN_EQUAL = Tokens.TOKEN_EQUAL, exports.TOKEN_QUOTE = Tokens.TOKEN_QUOTE, exports.TOKEN_DUOQUOTE = Tokens.TOKEN_DUOQUOTE, exports.TOKEN_NAME = Tokens.TOKEN_NAME, exports.TOKEN_PRINT = Tokens.TOKEN_PRINT, exports.TOKEN_IGNORED = Tokens.TOKEN_IGNORED, exports.INTERGER = Tokens.INTERGER, exports.NUMBER = Tokens.NUMBER, exports.STRING = Tokens.STRING, exports.COMMENT = Tokens.COMMENT, exports.SourceCharacter = Tokens.SourceCharacter, exports.Operator = Tokens.Operator, exports.TOKEN_FUNC = Tokens.TOKEN_FUNC, exports.BLOCK_START = Tokens.BLOCK_START, exports.BLOCK_END = Tokens.BLOCK_END, exports.TOKEN_RETURN = Tokens.TOKEN_RETURN, exports.TOKEN_FUNC_PARAMS_DIV = Tokens.TOKEN_FUNC_PARAMS_DIV; // regex match patterns const regexName = /^[_\d\w]+/; // 关键字 @@ -45,6 +50,11 @@ exports.tokenNameMap = { [exports.COMMENT]: "COMMENT", [exports.SourceCharacter]: "SourceCharacter", [exports.Operator]: "Operator", + [exports.TOKEN_FUNC]: "TOKEN_FUNC", + [exports.BLOCK_START]: "BLOCK_START", + [exports.BLOCK_END]: "BLOCK_END", + [exports.TOKEN_RETURN]: "TOKEN_RETURN", + [exports.TOKEN_FUNC_PARAMS_DIV]: "TOKEN_FUNC_PARAMS_DIV", }; class Lexer { constructor(sourceCode, lineNum, nextToken, nextTokenType, nextTokenLineNum) { @@ -168,6 +178,25 @@ class Lexer { case '#': this.skipSourceCode(1); return { lineNum: this.lineNum, tokenType: exports.COMMENT, token: "#" }; + case ",": + this.skipSourceCode(1); + return { lineNum: this.lineNum, tokenType: exports.TOKEN_FUNC_PARAMS_DIV, token: "," }; + case "{": + this.skipSourceCode(1); + return { lineNum: this.lineNum, tokenType: exports.BLOCK_START, token: "{" }; + case "}": + this.skipSourceCode(1); + return { lineNum: this.lineNum, tokenType: exports.BLOCK_END, token: "}" }; + } + // return + if (this.sourceCode[0] === 'r' && this.sourceCode.slice(0, 6) === 'return') { + this.skipSourceCode(6); + return { lineNum: this.lineNum, tokenType: exports.TOKEN_RETURN, token: "return" }; + } + // func + if (this.sourceCode[0] === 'f' && this.sourceCode.slice(0, 4) === "func") { + this.skipSourceCode(4); + return { lineNum: this.lineNum, tokenType: exports.TOKEN_FUNC, token: "func" }; } // Operator if (/\+|\-|\*|\//.test(this.sourceCode[0])) { diff --git a/dist/src/parser.js b/dist/src/parser.js index 5d0425c..f7ab2b3 100644 --- a/dist/src/parser.js +++ b/dist/src/parser.js @@ -1,10 +1,12 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.parse = exports.parseString = exports.parseNumber = exports.parseVariable = exports.Program = void 0; +exports.parse = exports.parseString = exports.parseNumber = exports.parseName = exports.parseVariable = exports.Program = void 0; const lexer1_1 = require("./lexer1"); const Comment_1 = require("./parser/Comment"); const Print_1 = require("./parser/Print"); const Assignment_1 = require("./parser/Assignment"); +const Function_1 = require("./parser/Function"); +const Expression_1 = require("./parser/Expression"); class Program { constructor(type, body, LineNum) { this.type = 'Program'; @@ -46,6 +48,10 @@ function parseStatement(lexer) { return Assignment_1.parseAssignment(lexer); case lexer1_1.COMMENT: return Comment_1.paseComment(lexer); + case lexer1_1.TOKEN_FUNC: + return Function_1.parseFunction(lexer); + case lexer1_1.TOKEN_NAME: + return Expression_1.parseExpression(lexer); default: throw new Error("parseStatement(): unknown Statement."); } @@ -68,6 +74,7 @@ function parseName(lexer) { let { nowLineNum: _, nowToken: name } = lexer.NextTokenIs(lexer1_1.TOKEN_NAME); return name; } +exports.parseName = parseName; // Integer ::= [0-9]+ // Number ::= Integer Ignored function parseNumber(lexer) { diff --git a/dist/src/parser/Assignment.js b/dist/src/parser/Assignment.js index c0f4d23..a5b226f 100644 --- a/dist/src/parser/Assignment.js +++ b/dist/src/parser/Assignment.js @@ -1,8 +1,9 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.parseAssignment = exports.Assignment = exports.Identifier = exports.Literal = void 0; +exports.parseBinaryExpression = exports.parseAssignment = exports.Assignment = exports.Identifier = exports.Literal = void 0; const lexer1_1 = require("../lexer1"); const parser_1 = require("../parser"); +const Expression_1 = require("./Expression"); class Literal { constructor(value, type = 'Literal') { this.type = type; @@ -71,7 +72,13 @@ function parseAssignment(lexer) { } } else { - if (tokenType === lexer1_1.NUMBER) { + if (tokenType === lexer1_1.TOKEN_NAME) { // 函数执行并赋值 + const expression = Expression_1.parseExpression(lexer); + console.log(expression); + VariableDeclarator.init = expression.expression; + assignment.type = "VariableDeclaration"; + } + else if (tokenType === lexer1_1.NUMBER) { // console.log('parseNumber start') const literial = new Literal(parser_1.parseNumber(lexer)); // 这里面会把邻近的空格回车删掉 VariableDeclarator.init = literial; @@ -138,3 +145,4 @@ function parseBinaryExpression(lexer, idAndinit, assignment, leftType) { assignment.declarations.push(VariableDeclarator); return assignment; } +exports.parseBinaryExpression = parseBinaryExpression; diff --git a/dist/src/parser/Expression.js b/dist/src/parser/Expression.js new file mode 100644 index 0000000..0fd0a08 --- /dev/null +++ b/dist/src/parser/Expression.js @@ -0,0 +1,44 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.parseExpression = void 0; +const lexer1_1 = require("../lexer1"); +const parser_1 = require("../parser"); +const Assignment_1 = require("./Assignment"); +function parseExpression(lexer) { + const ExpressionStatement = { + type: "ExpressionStatement", + expression: { + type: "CallExpression", + callee: { + type: "Identifier", + }, + arguments: [] + } + }; + const IdentifierName = parser_1.parseName(lexer); + ExpressionStatement.expression.callee.name = IdentifierName; + lexer.NextTokenIs(lexer1_1.TOKEN_LEFT_PAREN); // ( + const params = []; + const tokenType = lexer.LookAhead().tokenType; + while (tokenType !== lexer1_1.TOKEN_RIGHT_PAREN) { + let p; + // $ + if (tokenType === lexer1_1.TOKEN_VAR_PREFIX) { + p = parser_1.parseVariable(lexer); + params.push(new Assignment_1.Identifier(p)); + } + else if (tokenType === lexer1_1.NUMBER) { + p = parser_1.parseNumber(lexer); + params.push(new Assignment_1.Literal(p)); + } + if (lexer.nextTokenType === lexer1_1.TOKEN_RIGHT_PAREN) { + break; + } + lexer.NextTokenIs(lexer1_1.TOKEN_FUNC_PARAMS_DIV); // , + } + lexer.NextTokenIs(lexer1_1.TOKEN_RIGHT_PAREN); // ) + lexer.LookAheadAndSkip(lexer1_1.TOKEN_IGNORED); // 空格 + ExpressionStatement.expression.arguments = params; + return ExpressionStatement; +} +exports.parseExpression = parseExpression; diff --git a/dist/src/parser/Function.js b/dist/src/parser/Function.js new file mode 100644 index 0000000..46f9fc2 --- /dev/null +++ b/dist/src/parser/Function.js @@ -0,0 +1,136 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.paseReturnStatement = exports.paseBlock = exports.parseFunction = void 0; +const lexer1_1 = require("../lexer1"); +const parser_1 = require("../parser"); +const Assignment_1 = require("./Assignment"); +function parseFunction(lexer) { + const FunctionDeclaration = { + type: "FunctionDeclaration", + id: { + type: "Identifier", + }, + params: [ + // { + // type: "Identifier", + // name: "" + // } + ], + body: { + type: "BlockStatement", + body: [ + // { + // type: "ReturnStatement", + // argument: { + // type: "BinaryExpression", + // left: { + // }, + // operator: '+', + // right: { + // } + // } + // } + ] + } + }; + lexer.NextTokenIs(lexer1_1.TOKEN_FUNC); + lexer.LookAheadAndSkip(lexer1_1.TOKEN_IGNORED); // 空格 + const Identifier = parser_1.parseName(lexer); + FunctionDeclaration.id.name = Identifier; + lexer.NextTokenIs(lexer1_1.TOKEN_LEFT_PAREN); // ( + const params = []; + while (lexer.LookAhead().tokenType !== lexer1_1.TOKEN_RIGHT_PAREN) { + const p = parser_1.parseVariable(lexer); + params.push(p); + if (lexer.nextTokenType === lexer1_1.TOKEN_RIGHT_PAREN) { + break; + } + lexer.NextTokenIs(lexer1_1.TOKEN_FUNC_PARAMS_DIV); + } + for (let item of params) { + FunctionDeclaration.params.push({ + type: "Identifier", + name: item.Name + }); + } + lexer.NextTokenIs(lexer1_1.TOKEN_RIGHT_PAREN); // ) + lexer.LookAheadAndSkip(lexer1_1.TOKEN_IGNORED); // 去除空格回车等 + lexer.NextTokenIs(lexer1_1.BLOCK_START); + lexer.LookAheadAndSkip(lexer1_1.TOKEN_IGNORED); // 去除空格回车等 + const block = paseBlock(lexer); + FunctionDeclaration.body.body.push({ + type: "ReturnStatement", + argument: block.declarations[0].init + }); + lexer.NextTokenIs(lexer1_1.BLOCK_END); + lexer.LookAheadAndSkip(lexer1_1.TOKEN_IGNORED); + return FunctionDeclaration; +} +exports.parseFunction = parseFunction; +function paseBlock(lexer) { + const ahead = lexer.LookAhead(); + if (ahead.tokenType === lexer1_1.TOKEN_RETURN) { + lexer.NextTokenIs(lexer1_1.TOKEN_RETURN); + lexer.LookAheadAndSkip(lexer1_1.TOKEN_IGNORED); + return paseReturnStatement(lexer); + } +} +exports.paseBlock = paseBlock; +function paseReturnStatement(lexer) { + let assignment = new Assignment_1.Assignment(); + assignment.LineNum = lexer.GetLineNum(); + assignment.declarations = []; + let VariableDeclarator = { type: "VariableDeclarator" }; + VariableDeclarator.id = { type: "Identifier" }; + const tokenType = lexer.LookAhead().tokenType; + console.log(tokenType, 'lexer.LookAhead().tokenType'); + // 如果后面仍是$ + if (tokenType === lexer1_1.TOKEN_VAR_PREFIX) { + const Variable = parser_1.parseVariable(lexer); // 标识符,这里面会把邻近的空格回车删掉 + console.log(Variable, 'Variable'); + const identifier = new Assignment_1.Identifier(Variable.Name); + VariableDeclarator.init = identifier; + assignment.type = "VariableDeclaration"; + assignment.declarations.push(VariableDeclarator); // 一行只允许声明和初始化一个变量 + let ahead = lexer.LookAhead(); + console.log(ahead, 'parseAssignment Variable ahead'); + if (ahead.tokenType !== lexer1_1.Operator) { + return assignment; + } + else { + lexer.NextTokenIs(lexer1_1.Operator); // +-*/ + // lexer.LookAheadAndSkip(TOKEN_IGNORED) // 空格 + lexer.isIgnored(); + const idAndinit = assignment.declarations.pop(); + return Assignment_1.parseBinaryExpression(lexer, idAndinit, assignment, "Identifier"); + } + } + else { + if (tokenType === lexer1_1.NUMBER) { + // console.log('parseNumber start') + const literial = new Assignment_1.Literal(parser_1.parseNumber(lexer)); // 这里面会把邻近的空格回车删掉 + VariableDeclarator.init = literial; + assignment.type = "VariableDeclaration"; + // console.log('parseNumber end') + } + else { + const literial = new Assignment_1.Literal(parser_1.parseString(lexer)); // 这里面会把邻近的空格回车删掉 + VariableDeclarator.init = literial; + assignment.type = "VariableDeclaration"; + } + assignment.declarations.push(VariableDeclarator); // 一行只允许声明和初始化一个变量 + let ahead = lexer.LookAhead(); + console.log(ahead, 'parseAssignment not Variable ahead'); + if (ahead.tokenType !== lexer1_1.Operator) { + return assignment; + } + else { + lexer.NextTokenIs(lexer1_1.Operator); // +-*/ + // lexer.LookAheadAndSkip(TOKEN_IGNORED); // 空格 + lexer.isIgnored(); + const idAndinit = assignment.declarations.pop(); + return Assignment_1.parseBinaryExpression(lexer, idAndinit, assignment, "Literal"); + } + } +} +exports.paseReturnStatement = paseReturnStatement; diff --git a/dist/test/test.js b/dist/test/test.js index 3e944d0..25ceee8 100644 --- a/dist/test/test.js +++ b/dist/test/test.js @@ -2,7 +2,7 @@ const fs = require('fs'); const path = require('path'); const Execute = require('../dist/src/backend.js').Execute; -code = fs.readFileSync(path.resolve(__dirname, '../demo/hello-world-4.pineapple'), { encoding: 'utf-8' }); +code = fs.readFileSync(path.resolve(__dirname, '../demo/hello-world-5.pineapple'), { encoding: 'utf-8' }); console.log(code, 'code'); if (code.length > 0) { Execute(code); diff --git a/src/lexer1.ts b/src/lexer1.ts index 0b8be31..782124c 100644 --- a/src/lexer1.ts +++ b/src/lexer1.ts @@ -16,6 +16,10 @@ Comment ::= Ignored "#" SourceCharacter // 注释 BinaryExpression::= (Variable | Number) Ignored Operator Ignored (Variable | Number) Operator ::= "+" | "-" | "*" | "/" BinaryExpressions ::= (BinaryExpression Operator)+ Ignored (Variable | Number) // eg: 1: (2 + 1 +) 3 2: ((2 + 1 +) (5 + 6 -)) 3 +FunctionDeclaration ::= "func" Ignored Name Ignored "(" Variable ("," Variable)* ")" BlockStatement // eg: 1: func foo ($a) {} 2: func foo ($a[,$b][,$c]) {} ("," Variable)*这部分是一个或多个 +BlockStatement ::= "{" Ignored ReturnStatement Ignored "}" +ReturnStatement ::= "return" BinaryExpression +CallFunction ::= Name "(" (Variable | Number) ("," (Variable | Number))* ")" Ignored */ @@ -47,6 +51,11 @@ export enum Tokens { COMMENT, // Ignored "#" SourceCharacter Ignored SourceCharacter, // 所有代码字符串 Operator, // +-*/ Operator + TOKEN_FUNC, // func + BLOCK_START, // { + BLOCK_END, // } + TOKEN_RETURN, // return + TOKEN_FUNC_PARAMS_DIV // , } export const { TOKEN_EOF, // end-of-file @@ -65,6 +74,11 @@ export const { TOKEN_EOF, // end-of-file COMMENT, // Ignored "#" SourceCharacter Ignored SourceCharacter, // 所有代码字符串 Operator, // +-*/ Operator + TOKEN_FUNC, // func + BLOCK_START, // { + BLOCK_END, // } + TOKEN_RETURN, // return + TOKEN_FUNC_PARAMS_DIV, // , } = Tokens // regex match patterns @@ -92,6 +106,11 @@ export const tokenNameMap: TokenNameMap = { [COMMENT]: "COMMENT", [SourceCharacter]: "SourceCharacter", [Operator]: "Operator", + [TOKEN_FUNC]: "TOKEN_FUNC", + [BLOCK_START]: "BLOCK_START", + [BLOCK_END]: "BLOCK_END", + [TOKEN_RETURN]: "TOKEN_RETURN", + [TOKEN_FUNC_PARAMS_DIV]: "TOKEN_FUNC_PARAMS_DIV", } export class Lexer { @@ -220,6 +239,25 @@ export class Lexer { case '#': this.skipSourceCode(1) return { lineNum: this.lineNum, tokenType: COMMENT, token: "#" } + case ",": + this.skipSourceCode(1) + return { lineNum: this.lineNum, tokenType: TOKEN_FUNC_PARAMS_DIV, token: "," } + case "{": + this.skipSourceCode(1) + return { lineNum: this.lineNum, tokenType: BLOCK_START, token: "{" } + case "}": + this.skipSourceCode(1) + return { lineNum: this.lineNum, tokenType: BLOCK_END, token: "}" } + } + // return + if (this.sourceCode[0] === 'r' && this.sourceCode.slice(0, 6) === 'return') { + this.skipSourceCode(6) + return { lineNum: this.lineNum, tokenType: TOKEN_RETURN, token: "return" } + } + // func + if (this.sourceCode[0] === 'f' && this.sourceCode.slice(0, 4) === "func") { + this.skipSourceCode(4) + return { lineNum: this.lineNum, tokenType: TOKEN_FUNC, token: "func" } } // Operator if (/\+|\-|\*|\//.test(this.sourceCode[0])) { diff --git a/src/parser.ts b/src/parser.ts index fb01cf4..6c6fd18 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1,8 +1,10 @@ -import { COMMENT, Lexer, NewLexer, NUMBER, tokenNameMap, TOKEN_DUOQUOTE, TOKEN_EOF, TOKEN_IGNORED, TOKEN_NAME, TOKEN_PRINT, TOKEN_QUOTE, TOKEN_VAR_PREFIX } from "./lexer1" +import { COMMENT, Lexer, NewLexer, NUMBER, tokenNameMap, TOKEN_DUOQUOTE, TOKEN_EOF, TOKEN_FUNC, TOKEN_IGNORED, TOKEN_NAME, TOKEN_PRINT, TOKEN_QUOTE, TOKEN_VAR_PREFIX } from "./lexer1" import { Variable } from './definition' import { paseComment } from './parser/Comment' import { parsePrint, Print } from "./parser/Print" import { Assignment, parseAssignment } from "./parser/Assignment" +import { parseFunction } from "./parser/Function" +import { parseExpression } from "./parser/Expression" export class Program { @@ -57,6 +59,10 @@ function parseStatement(lexer: Lexer) { return parseAssignment(lexer) case COMMENT: return paseComment(lexer) + case TOKEN_FUNC: + return parseFunction(lexer) + case TOKEN_NAME: + return parseExpression(lexer) default: throw new Error("parseStatement(): unknown Statement.") } @@ -82,7 +88,7 @@ export function parseVariable(lexer: Lexer) { } // Name ::= [_A-Za-z][_0-9A-Za-z]* -function parseName(lexer: Lexer) { +export function parseName(lexer: Lexer) { let { nowLineNum: _, nowToken: name } = lexer.NextTokenIs(TOKEN_NAME) return name } diff --git a/src/parser/Assignment.ts b/src/parser/Assignment.ts index 839270c..15197cb 100644 --- a/src/parser/Assignment.ts +++ b/src/parser/Assignment.ts @@ -1,6 +1,7 @@ import { Variable } from "../definition"; -import { Lexer, NUMBER, Operator, tokenNameMap, Tokens, TOKEN_EQUAL, TOKEN_IGNORED, TOKEN_VAR_PREFIX } from "../lexer1"; +import { Lexer, NUMBER, Operator, tokenNameMap, Tokens, TOKEN_EQUAL, TOKEN_IGNORED, TOKEN_NAME, TOKEN_VAR_PREFIX } from "../lexer1"; import { parseNumber, parseString, parseVariable } from "../parser"; +import { parseExpression } from "./Expression"; export interface Assignment { LineNum?: number, @@ -95,7 +96,12 @@ export function parseAssignment(lexer: Lexer) { return parseBinaryExpression(lexer, idAndinit, assignment, "Identifier") } } else { - if (tokenType === NUMBER) { + if (tokenType === TOKEN_NAME) { // 函数执行并赋值 + const expression = parseExpression(lexer) + console.log(expression) + VariableDeclarator.init = expression.expression + assignment.type = "VariableDeclaration" + } else if (tokenType === NUMBER) { // console.log('parseNumber start') const literial = new Literal(parseNumber(lexer)) // 这里面会把邻近的空格回车删掉 VariableDeclarator.init = literial @@ -124,7 +130,7 @@ export function parseAssignment(lexer: Lexer) { } } -function parseBinaryExpression(lexer: Lexer, idAndinit: { init: Literal | Identifier, id: Identifier }, assignment: Assignment, leftType: string) { +export function parseBinaryExpression(lexer: Lexer, idAndinit: { init: Literal | Identifier, id: Identifier }, assignment: Assignment, leftType: string) { const BinaryExpression: { type: string, left: { diff --git a/src/parser/Expression.ts b/src/parser/Expression.ts new file mode 100644 index 0000000..0dbfae5 --- /dev/null +++ b/src/parser/Expression.ts @@ -0,0 +1,43 @@ +import { Lexer, NUMBER, TOKEN_FUNC_PARAMS_DIV, TOKEN_IGNORED, TOKEN_LEFT_PAREN, TOKEN_NAME, TOKEN_RIGHT_PAREN, TOKEN_VAR_PREFIX } from "../lexer1"; +import { parseName, parseNumber, parseVariable } from "../parser"; +import { Identifier, Literal } from "./Assignment"; + +export function parseExpression(lexer: Lexer) { + const ExpressionStatement: any = { + type: "ExpressionStatement", + expression: { + type: "CallExpression", + callee: { + type: "Identifier", + // name: "" + }, + arguments: [ + + ] + } + } + const IdentifierName = parseName(lexer) + ExpressionStatement.expression.callee.name = IdentifierName + lexer.NextTokenIs(TOKEN_LEFT_PAREN) // ( + const params = [] + const tokenType = lexer.LookAhead().tokenType + while (tokenType !== TOKEN_RIGHT_PAREN) { + let p: any + // $ + if (tokenType === TOKEN_VAR_PREFIX) { + p = parseVariable(lexer) + params.push(new Identifier(p)) + } else if (tokenType === NUMBER) { + p = parseNumber(lexer) + params.push(new Literal(p)) + } + if (lexer.nextTokenType === TOKEN_RIGHT_PAREN) { + break + } + lexer.NextTokenIs(TOKEN_FUNC_PARAMS_DIV) // , + } + lexer.NextTokenIs(TOKEN_RIGHT_PAREN) // ) + lexer.LookAheadAndSkip(TOKEN_IGNORED) // 空格 + ExpressionStatement.expression.arguments = params + return ExpressionStatement +} \ No newline at end of file diff --git a/src/parser/Function.ts b/src/parser/Function.ts new file mode 100644 index 0000000..35ba8ed --- /dev/null +++ b/src/parser/Function.ts @@ -0,0 +1,142 @@ +import { TOKEN_IGNORED, TOKEN_LEFT_PAREN, Lexer, TOKEN_RIGHT_PAREN, TOKEN_FUNC_PARAMS_DIV, TOKEN_FUNC, BLOCK_START, TOKEN_RETURN, NUMBER, TOKEN_VAR_PREFIX, Operator, BLOCK_END } from "../lexer1"; +import { parseName, parseNumber, parseString, parseVariable } from "../parser"; +import { Assignment, Identifier, Literal, parseBinaryExpression } from "./Assignment"; + +export function parseFunction(lexer: Lexer) { + const FunctionDeclaration: any = { + type: "FunctionDeclaration", + id: { + type: "Identifier", + // name: "" + }, + params: [ + // { + // type: "Identifier", + // name: "" + // } + ], + body: { + type: "BlockStatement", + body: [ + // { + // type: "ReturnStatement", + // argument: { + // type: "BinaryExpression", + // left: { + + // }, + // operator: '+', + // right: { + + // } + // } + // } + ] + } + } + lexer.NextTokenIs(TOKEN_FUNC) + lexer.LookAheadAndSkip(TOKEN_IGNORED) // 空格 + const Identifier = parseName(lexer) + FunctionDeclaration.id.name = Identifier + lexer.NextTokenIs(TOKEN_LEFT_PAREN) // ( + const params = [] + while (lexer.LookAhead().tokenType !== TOKEN_RIGHT_PAREN) { + const p = parseVariable(lexer) + params.push(p) + if (lexer.nextTokenType === TOKEN_RIGHT_PAREN) { + break + } + lexer.NextTokenIs(TOKEN_FUNC_PARAMS_DIV) + } + for (let item of params) { + FunctionDeclaration.params.push({ + type: "Identifier", + name: item.Name + }) + } + lexer.NextTokenIs(TOKEN_RIGHT_PAREN) // ) + lexer.LookAheadAndSkip(TOKEN_IGNORED) // 去除空格回车等 + + lexer.NextTokenIs(BLOCK_START) + lexer.LookAheadAndSkip(TOKEN_IGNORED) // 去除空格回车等 + const block = paseBlock(lexer) + FunctionDeclaration.body.body.push({ + type: "ReturnStatement", + argument: block.declarations[0].init + }) + lexer.NextTokenIs(BLOCK_END) + lexer.LookAheadAndSkip(TOKEN_IGNORED) + return FunctionDeclaration +} + +export function paseBlock(lexer: Lexer) { + const ahead = lexer.LookAhead() + if (ahead.tokenType === TOKEN_RETURN) { + lexer.NextTokenIs(TOKEN_RETURN) + lexer.LookAheadAndSkip(TOKEN_IGNORED) + return paseReturnStatement(lexer) + } +} + +export function paseReturnStatement(lexer: Lexer) { + let assignment: any = new Assignment() + + assignment.LineNum = lexer.GetLineNum() + assignment.declarations = [] + let VariableDeclarator: any = { type: "VariableDeclarator" } + VariableDeclarator.id = { type: "Identifier" } + + + const tokenType = lexer.LookAhead().tokenType + + console.log(tokenType, 'lexer.LookAhead().tokenType') + // 如果后面仍是$ + if (tokenType === TOKEN_VAR_PREFIX) { + const Variable = parseVariable(lexer) // 标识符,这里面会把邻近的空格回车删掉 + console.log(Variable, 'Variable') + const identifier = new Identifier(Variable.Name); + VariableDeclarator.init = identifier + assignment.type = "VariableDeclaration" + assignment.declarations.push(VariableDeclarator) // 一行只允许声明和初始化一个变量 + + let ahead = lexer.LookAhead() + console.log(ahead, 'parseAssignment Variable ahead') + + if (ahead.tokenType !== Operator) { + return assignment + } else { + lexer.NextTokenIs(Operator) // +-*/ + // lexer.LookAheadAndSkip(TOKEN_IGNORED) // 空格 + lexer.isIgnored() + const idAndinit = assignment.declarations.pop() + return parseBinaryExpression(lexer, idAndinit, assignment, "Identifier") + } + } else { + if (tokenType === NUMBER) { + // console.log('parseNumber start') + const literial = new Literal(parseNumber(lexer)) // 这里面会把邻近的空格回车删掉 + VariableDeclarator.init = literial + assignment.type = "VariableDeclaration" + // console.log('parseNumber end') + } else { + const literial = new Literal(parseString(lexer)) // 这里面会把邻近的空格回车删掉 + VariableDeclarator.init = literial + assignment.type = "VariableDeclaration" + } + + assignment.declarations.push(VariableDeclarator) // 一行只允许声明和初始化一个变量 + + let ahead = lexer.LookAhead() + console.log(ahead, 'parseAssignment not Variable ahead') + + if (ahead.tokenType !== Operator) { + return assignment + } else { + lexer.NextTokenIs(Operator); // +-*/ + // lexer.LookAheadAndSkip(TOKEN_IGNORED); // 空格 + lexer.isIgnored() + const idAndinit = assignment.declarations.pop(); + return parseBinaryExpression(lexer, idAndinit, assignment, "Literal"); + } + } +} diff --git a/test/test.js b/test/test.js index c739328..d3a8bfb 100644 --- a/test/test.js +++ b/test/test.js @@ -2,7 +2,7 @@ const fs = require('fs') const path = require('path') const Execute = require('../dist/src/backend.js').Execute -code = fs.readFileSync(path.resolve(__dirname, '../demo/hello-world-4.pineapple'), {encoding: 'utf-8'}) +code = fs.readFileSync(path.resolve(__dirname, '../demo/hello-world-5.pineapple'), {encoding: 'utf-8'}) console.log(code, 'code') if (code.length > 0) { Execute(code)